mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
Merge pull request #581 from AppFlowy-IO/refactor/grid_filter
Refactor/grid filter
This commit is contained in:
commit
582cde444e
@ -3,7 +3,7 @@ import 'package:flowy_sdk/dispatch/dispatch.dart';
|
||||
|
||||
import 'package:flowy_sdk/protobuf/flowy-folder-data-model/view.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-sync/text_block_info.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-sync/text_block.pb.dart';
|
||||
|
||||
class DocumentService {
|
||||
Future<Either<TextBlockDelta, FlowyError>> openDocument({
|
||||
|
@ -7,13 +7,12 @@ import 'package:dartz/dartz.dart';
|
||||
import 'package:flowy_infra/notifier.dart';
|
||||
import 'package:flowy_sdk/log.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid/block_entities.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid/dart_notification.pb.dart';
|
||||
|
||||
class GridBlockCache {
|
||||
final String gridId;
|
||||
void Function(GridBlockUpdateNotifierValue)? _onBlockChanged;
|
||||
|
||||
final LinkedHashMap<String, _GridBlockListener> _listeners = LinkedHashMap();
|
||||
GridBlockCache({required this.gridId});
|
||||
|
||||
|
@ -6,10 +6,9 @@ import 'package:equatable/equatable.dart';
|
||||
import 'package:flowy_sdk/dispatch/dispatch.dart';
|
||||
import 'package:flowy_sdk/log.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/field.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid/cell_entities.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid/date_type_option.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid/selection_type_option.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid/url_type_option.pb.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
|
@ -1,5 +1,5 @@
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/field.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid/date_type_option.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'dart:async';
|
||||
|
@ -1,5 +1,5 @@
|
||||
import 'package:flowy_sdk/log.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/field.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'dart:async';
|
||||
|
@ -1,7 +1,7 @@
|
||||
import 'package:app_flowy/workspace/application/grid/field/field_listener.dart';
|
||||
import 'package:app_flowy/workspace/application/grid/field/field_service.dart';
|
||||
import 'package:flowy_sdk/log.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/field.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'dart:async';
|
||||
|
@ -1,4 +1,4 @@
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/field.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'dart:async';
|
||||
|
@ -1,11 +1,11 @@
|
||||
import 'package:dartz/dartz.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/field.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid/dart_notification.pb.dart';
|
||||
import 'package:flowy_infra/notifier.dart';
|
||||
import 'dart:async';
|
||||
import 'dart:typed_data';
|
||||
import 'package:app_flowy/core/notification_helper.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart';
|
||||
|
||||
typedef UpdateFieldNotifiedValue = Either<Field, FlowyError>;
|
||||
|
||||
|
@ -2,9 +2,8 @@ import 'package:dartz/dartz.dart';
|
||||
import 'package:flowy_sdk/dispatch/dispatch.dart';
|
||||
import 'package:flowy_sdk/log.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/field.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid/grid_entities.pb.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'package:protobuf/protobuf.dart';
|
||||
|
@ -1,11 +1,11 @@
|
||||
import 'package:dartz/dartz.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/field.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid/dart_notification.pb.dart';
|
||||
import 'package:flowy_infra/notifier.dart';
|
||||
import 'dart:async';
|
||||
import 'dart:typed_data';
|
||||
import 'package:app_flowy/core/notification_helper.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart';
|
||||
|
||||
typedef UpdateFieldNotifiedValue = Either<GridFieldChangeset, FlowyError>;
|
||||
|
||||
|
@ -86,7 +86,7 @@ extension NumberFormatExtension on NumberFormat {
|
||||
return "New Zealand dollar";
|
||||
case NumberFormat.NorwegianKrone:
|
||||
return "Norwegian krone";
|
||||
case NumberFormat.Number:
|
||||
case NumberFormat.Num:
|
||||
return "Number";
|
||||
case NumberFormat.Percent:
|
||||
return "Percent";
|
||||
|
@ -4,7 +4,6 @@ import 'package:app_flowy/workspace/application/grid/field/field_service.dart';
|
||||
import 'package:dartz/dartz.dart';
|
||||
import 'package:flowy_sdk/dispatch/dispatch.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/field.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid/cell_entities.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid/selection_type_option.pb.dart';
|
||||
|
@ -4,7 +4,7 @@ import 'package:equatable/equatable.dart';
|
||||
import 'package:flowy_sdk/log.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-folder-data-model/view.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/protobuf.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid/protobuf.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'block/block_listener.dart';
|
||||
@ -30,6 +30,7 @@ class GridBloc extends Bloc<GridEvent, GridState> {
|
||||
super(GridState.initial(view.id)) {
|
||||
rowCache = GridRowCache(
|
||||
gridId: view.id,
|
||||
blockId: "",
|
||||
fieldDelegate: GridRowCacheDelegateImpl(fieldCache),
|
||||
);
|
||||
|
||||
@ -96,8 +97,8 @@ class GridBloc extends Bloc<GridEvent, GridState> {
|
||||
for (final block in grid.blocks) {
|
||||
blockCache.addBlockListener(block.id);
|
||||
}
|
||||
final rowOrders = grid.blocks.expand((block) => block.rowOrders).toList();
|
||||
rowCache.initialRows(rowOrders);
|
||||
final rowInfos = grid.blocks.expand((block) => block.rowInfos).toList();
|
||||
rowCache.initialRows(rowInfos);
|
||||
|
||||
await _loadFields(grid, emit);
|
||||
},
|
||||
|
@ -1,6 +1,6 @@
|
||||
import 'package:app_flowy/workspace/application/grid/field/field_service.dart';
|
||||
import 'package:flowy_sdk/log.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/field.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'dart:async';
|
||||
|
@ -6,8 +6,10 @@ import 'package:flowy_sdk/dispatch/dispatch.dart';
|
||||
import 'package:flowy_sdk/log.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-folder-data-model/view.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/field.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid/block_entities.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid/grid_entities.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid/row_entities.pb.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'cell/cell_service/cell_service.dart';
|
||||
import 'row/row_service.dart';
|
||||
|
@ -12,7 +12,11 @@ class RowActionSheetBloc extends Bloc<RowActionSheetEvent, RowActionSheetState>
|
||||
final RowService _rowService;
|
||||
|
||||
RowActionSheetBloc({required GridRow rowData})
|
||||
: _rowService = RowService(gridId: rowData.gridId, rowId: rowData.rowId),
|
||||
: _rowService = RowService(
|
||||
gridId: rowData.gridId,
|
||||
blockId: rowData.blockId,
|
||||
rowId: rowData.rowId,
|
||||
),
|
||||
super(RowActionSheetState.initial(rowData)) {
|
||||
on<RowActionSheetEvent>(
|
||||
(event, emit) async {
|
||||
|
@ -1,7 +1,7 @@
|
||||
import 'dart:collection';
|
||||
import 'package:app_flowy/workspace/application/grid/cell/cell_service/cell_service.dart';
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/field.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'dart:async';
|
||||
@ -17,7 +17,11 @@ class RowBloc extends Bloc<RowEvent, RowState> {
|
||||
RowBloc({
|
||||
required GridRow rowData,
|
||||
required GridRowCache rowCache,
|
||||
}) : _rowService = RowService(gridId: rowData.gridId, rowId: rowData.rowId),
|
||||
}) : _rowService = RowService(
|
||||
gridId: rowData.gridId,
|
||||
blockId: rowData.blockId,
|
||||
rowId: rowData.rowId,
|
||||
),
|
||||
_rowCache = rowCache,
|
||||
super(RowState.initial(rowData, rowCache.loadGridCells(rowData.rowId))) {
|
||||
on<RowEvent>(
|
||||
|
@ -1,12 +1,12 @@
|
||||
import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/field.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid/block_entities.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid/dart_notification.pb.dart';
|
||||
import 'package:flowy_infra/notifier.dart';
|
||||
import 'dart:async';
|
||||
import 'dart:typed_data';
|
||||
import 'package:app_flowy/core/notification_helper.dart';
|
||||
import 'package:dartz/dartz.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart';
|
||||
|
||||
typedef UpdateRowNotifiedValue = Either<Row, FlowyError>;
|
||||
typedef UpdateFieldNotifiedValue = Either<List<Field>, FlowyError>;
|
||||
|
@ -5,8 +5,9 @@ import 'package:dartz/dartz.dart';
|
||||
import 'package:flowy_sdk/dispatch/dispatch.dart';
|
||||
import 'package:flowy_sdk/log.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/field.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid/block_entities.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid/grid_entities.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid/row_entities.pb.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
@ -22,18 +23,23 @@ abstract class GridRowFieldDelegate {
|
||||
|
||||
class GridRowCache {
|
||||
final String gridId;
|
||||
final String blockId;
|
||||
final RowsNotifier _rowsNotifier;
|
||||
final GridRowFieldDelegate _fieldDelegate;
|
||||
List<GridRow> get clonedRows => _rowsNotifier.clonedRows;
|
||||
|
||||
GridRowCache({required this.gridId, required GridRowFieldDelegate fieldDelegate})
|
||||
: _rowsNotifier = RowsNotifier(
|
||||
rowBuilder: (rowOrder) {
|
||||
GridRowCache({
|
||||
required this.gridId,
|
||||
required this.blockId,
|
||||
required GridRowFieldDelegate fieldDelegate,
|
||||
}) : _rowsNotifier = RowsNotifier(
|
||||
rowBuilder: (rowInfo) {
|
||||
return GridRow(
|
||||
gridId: gridId,
|
||||
blockId: "test",
|
||||
fields: fieldDelegate.fields,
|
||||
rowId: rowOrder.rowId,
|
||||
height: rowOrder.height.toDouble(),
|
||||
rowId: rowInfo.rowId,
|
||||
height: rowInfo.height.toDouble(),
|
||||
);
|
||||
},
|
||||
),
|
||||
@ -119,13 +125,14 @@ class GridRowCache {
|
||||
return _makeGridCells(rowId, data);
|
||||
}
|
||||
|
||||
void initialRows(List<RowOrder> rowOrders) {
|
||||
_rowsNotifier.initialRows(rowOrders);
|
||||
void initialRows(List<BlockRowInfo> rowInfos) {
|
||||
_rowsNotifier.initialRows(rowInfos);
|
||||
}
|
||||
|
||||
Future<void> _loadRow(String rowId) async {
|
||||
final payload = RowIdentifierPayload.create()
|
||||
final payload = GridRowIdPayload.create()
|
||||
..gridId = gridId
|
||||
..blockId = blockId
|
||||
..rowId = rowId;
|
||||
|
||||
final result = await GridEventGetRow(payload).send();
|
||||
@ -155,34 +162,34 @@ class GridRowCache {
|
||||
}
|
||||
|
||||
class RowsNotifier extends ChangeNotifier {
|
||||
List<GridRow> _rows = [];
|
||||
HashMap<String, Row> _rowDataMap = HashMap();
|
||||
List<GridRow> _allRows = [];
|
||||
HashMap<String, Row> _rowByRowId = HashMap();
|
||||
GridRowChangeReason _changeReason = const InitialListState();
|
||||
final GridRow Function(RowOrder) rowBuilder;
|
||||
final GridRow Function(BlockRowInfo) rowBuilder;
|
||||
|
||||
RowsNotifier({
|
||||
required this.rowBuilder,
|
||||
});
|
||||
|
||||
List<GridRow> get clonedRows => [..._rows];
|
||||
List<GridRow> get clonedRows => [..._allRows];
|
||||
|
||||
void initialRows(List<RowOrder> rowOrders) {
|
||||
_rowDataMap = HashMap();
|
||||
final rows = rowOrders.map((rowOrder) => rowBuilder(rowOrder)).toList();
|
||||
void initialRows(List<BlockRowInfo> rowInfos) {
|
||||
_rowByRowId = HashMap();
|
||||
final rows = rowInfos.map((rowOrder) => rowBuilder(rowOrder)).toList();
|
||||
_update(rows, const GridRowChangeReason.initial());
|
||||
}
|
||||
|
||||
void deleteRows(List<RowOrder> deletedRows) {
|
||||
void deleteRows(List<GridRowId> deletedRows) {
|
||||
if (deletedRows.isEmpty) {
|
||||
return;
|
||||
}
|
||||
|
||||
final List<GridRow> newRows = [];
|
||||
final DeletedIndexs deletedIndex = [];
|
||||
final Map<String, RowOrder> deletedRowMap = {for (var e in deletedRows) e.rowId: e};
|
||||
final Map<String, GridRowId> deletedRowByRowId = {for (var e in deletedRows) e.rowId: e};
|
||||
|
||||
_rows.asMap().forEach((index, row) {
|
||||
if (deletedRowMap[row.rowId] == null) {
|
||||
_allRows.asMap().forEach((index, row) {
|
||||
if (deletedRowByRowId[row.rowId] == null) {
|
||||
newRows.add(row);
|
||||
} else {
|
||||
deletedIndex.add(DeletedIndex(index: index, row: row));
|
||||
@ -202,10 +209,10 @@ class RowsNotifier extends ChangeNotifier {
|
||||
for (final insertRow in insertRows) {
|
||||
final insertIndex = InsertedIndex(
|
||||
index: insertRow.index,
|
||||
rowId: insertRow.rowOrder.rowId,
|
||||
rowId: insertRow.rowInfo.rowId,
|
||||
);
|
||||
insertIndexs.add(insertIndex);
|
||||
newRows.insert(insertRow.index, (rowBuilder(insertRow.rowOrder)));
|
||||
newRows.insert(insertRow.index, (rowBuilder(insertRow.rowInfo)));
|
||||
}
|
||||
_update(newRows, GridRowChangeReason.insert(insertIndexs));
|
||||
}
|
||||
@ -218,14 +225,15 @@ class RowsNotifier extends ChangeNotifier {
|
||||
final UpdatedIndexs updatedIndexs = UpdatedIndexs();
|
||||
final List<GridRow> newRows = clonedRows;
|
||||
for (final updatedRow in updatedRows) {
|
||||
final rowOrder = updatedRow.rowOrder;
|
||||
final index = newRows.indexWhere((row) => row.rowId == rowOrder.rowId);
|
||||
final rowOrder = updatedRow.rowInfo;
|
||||
final rowId = updatedRow.rowInfo.rowId;
|
||||
final index = newRows.indexWhere((row) => row.rowId == rowId);
|
||||
if (index != -1) {
|
||||
_rowDataMap[rowOrder.rowId] = updatedRow.row;
|
||||
_rowByRowId[rowId] = updatedRow.row;
|
||||
|
||||
newRows.removeAt(index);
|
||||
newRows.insert(index, rowBuilder(rowOrder));
|
||||
updatedIndexs[rowOrder.rowId] = UpdatedIndex(index: index, rowId: rowOrder.rowId);
|
||||
updatedIndexs[rowId] = UpdatedIndex(index: index, rowId: rowId);
|
||||
}
|
||||
}
|
||||
|
||||
@ -233,11 +241,11 @@ class RowsNotifier extends ChangeNotifier {
|
||||
}
|
||||
|
||||
void fieldDidChange() {
|
||||
_update(_rows, const GridRowChangeReason.fieldDidChange());
|
||||
_update(_allRows, const GridRowChangeReason.fieldDidChange());
|
||||
}
|
||||
|
||||
void _update(List<GridRow> rows, GridRowChangeReason reason) {
|
||||
_rows = rows;
|
||||
_allRows = rows;
|
||||
_changeReason = reason;
|
||||
|
||||
_changeReason.map(
|
||||
@ -252,13 +260,13 @@ class RowsNotifier extends ChangeNotifier {
|
||||
set rowData(Row rowData) {
|
||||
rowData.freeze();
|
||||
|
||||
_rowDataMap[rowData.id] = rowData;
|
||||
final index = _rows.indexWhere((row) => row.rowId == rowData.id);
|
||||
_rowByRowId[rowData.id] = rowData;
|
||||
final index = _allRows.indexWhere((row) => row.rowId == rowData.id);
|
||||
if (index != -1) {
|
||||
// update the corresponding row in _rows if they are not the same
|
||||
if (_rows[index].data != rowData) {
|
||||
final row = _rows.removeAt(index).copyWith(data: rowData);
|
||||
_rows.insert(index, row);
|
||||
if (_allRows[index].data != rowData) {
|
||||
final row = _allRows.removeAt(index).copyWith(data: rowData);
|
||||
_allRows.insert(index, row);
|
||||
|
||||
// Calculate the update index
|
||||
final UpdatedIndexs updatedIndexs = UpdatedIndexs();
|
||||
@ -272,15 +280,16 @@ class RowsNotifier extends ChangeNotifier {
|
||||
}
|
||||
|
||||
Row? rowDataWithId(String rowId) {
|
||||
return _rowDataMap[rowId];
|
||||
return _rowByRowId[rowId];
|
||||
}
|
||||
}
|
||||
|
||||
class RowService {
|
||||
final String gridId;
|
||||
final String blockId;
|
||||
final String rowId;
|
||||
|
||||
RowService({required this.gridId, required this.rowId});
|
||||
RowService({required this.gridId, required this.blockId, required this.rowId});
|
||||
|
||||
Future<Either<Row, FlowyError>> createRow() {
|
||||
CreateRowPayload payload = CreateRowPayload.create()
|
||||
@ -302,24 +311,27 @@ class RowService {
|
||||
}
|
||||
|
||||
Future<Either<OptionalRow, FlowyError>> getRow() {
|
||||
final payload = RowIdentifierPayload.create()
|
||||
final payload = GridRowIdPayload.create()
|
||||
..gridId = gridId
|
||||
..blockId = blockId
|
||||
..rowId = rowId;
|
||||
|
||||
return GridEventGetRow(payload).send();
|
||||
}
|
||||
|
||||
Future<Either<Unit, FlowyError>> deleteRow() {
|
||||
final payload = RowIdentifierPayload.create()
|
||||
final payload = GridRowIdPayload.create()
|
||||
..gridId = gridId
|
||||
..blockId = blockId
|
||||
..rowId = rowId;
|
||||
|
||||
return GridEventDeleteRow(payload).send();
|
||||
}
|
||||
|
||||
Future<Either<Unit, FlowyError>> duplicateRow() {
|
||||
final payload = RowIdentifierPayload.create()
|
||||
final payload = GridRowIdPayload.create()
|
||||
..gridId = gridId
|
||||
..blockId = blockId
|
||||
..rowId = rowId;
|
||||
|
||||
return GridEventDuplicateRow(payload).send();
|
||||
@ -330,6 +342,7 @@ class RowService {
|
||||
class GridRow with _$GridRow {
|
||||
const factory GridRow({
|
||||
required String gridId,
|
||||
required String blockId,
|
||||
required String rowId,
|
||||
required UnmodifiableListView<Field> fields,
|
||||
required double height,
|
||||
|
@ -1,7 +1,7 @@
|
||||
import 'package:app_flowy/workspace/application/grid/field/field_service.dart';
|
||||
import 'package:app_flowy/workspace/application/grid/grid_service.dart';
|
||||
import 'package:flowy_sdk/log.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/field.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'dart:async';
|
||||
|
@ -1,4 +1,4 @@
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/field.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart';
|
||||
import 'sizes.dart';
|
||||
|
||||
class GridLayout {
|
||||
|
@ -1,5 +1,5 @@
|
||||
import 'package:app_flowy/workspace/application/grid/cell/cell_service/cell_service.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/field.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
@ -6,7 +6,7 @@ import 'package:flowy_infra/theme.dart';
|
||||
import 'package:flowy_infra_ui/style_widget/button.dart';
|
||||
import 'package:flowy_infra_ui/style_widget/hover.dart';
|
||||
import 'package:flowy_infra_ui/style_widget/text.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/field.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'field_type_extension.dart';
|
||||
|
@ -10,7 +10,7 @@ import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
||||
import 'package:flowy_infra_ui/style_widget/button.dart';
|
||||
import 'package:flowy_infra_ui/style_widget/text.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/field.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:app_flowy/workspace/application/grid/prelude.dart';
|
||||
|
@ -1,6 +1,6 @@
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/field.pb.dart';
|
||||
import 'package:app_flowy/generated/locale_keys.g.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart';
|
||||
|
||||
extension FieldTypeListExtension on FieldType {
|
||||
String iconName() {
|
||||
|
@ -6,7 +6,7 @@ import 'package:flowy_infra_ui/style_widget/button.dart';
|
||||
import 'package:flowy_infra_ui/style_widget/scrolling/styled_list.dart';
|
||||
import 'package:flowy_infra_ui/style_widget/text.dart';
|
||||
import 'package:flowy_infra_ui/widget/spacing.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/field.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'field_type_extension.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
|
@ -5,7 +5,7 @@ import 'package:flowy_infra/image.dart';
|
||||
import 'package:flowy_infra/theme.dart';
|
||||
import 'package:flowy_infra_ui/style_widget/button.dart';
|
||||
import 'package:flowy_infra_ui/style_widget/text.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/field.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:reorderables/reorderables.dart';
|
||||
|
@ -14,9 +14,9 @@ import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
||||
import 'package:flowy_infra_ui/style_widget/icon_button.dart';
|
||||
import 'package:flowy_infra_ui/style_widget/scrolling/styled_scroll_bar.dart';
|
||||
import 'package:flowy_infra_ui/widget/spacing.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/field.pb.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:app_flowy/generated/locale_keys.g.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:window_size/window_size.dart';
|
||||
|
@ -12,7 +12,7 @@ import 'package:flowy_infra_ui/style_widget/button.dart';
|
||||
import 'package:flowy_infra_ui/style_widget/icon_button.dart';
|
||||
import 'package:flowy_infra_ui/style_widget/text.dart';
|
||||
import 'package:flowy_infra_ui/widget/spacing.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/field.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:styled_widget/styled_widget.dart';
|
||||
|
@ -4,15 +4,9 @@ import 'package:flowy_sdk/log.dart';
|
||||
// ignore: unnecessary_import
|
||||
import 'package:flowy_sdk/protobuf/dart-ffi/ffi_response.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid/cell_entities.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid/date_type_option.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid/row_entities.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid/selection_type_option.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-net/network_state.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-user/event_map.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-folder/event_map.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid/event_map.pb.dart';
|
||||
import 'package:isolates/isolates.dart';
|
||||
import 'package:isolates/ports.dart';
|
||||
import 'package:ffi/ffi.dart';
|
||||
@ -25,7 +19,7 @@ import 'package:flowy_sdk/protobuf/flowy-user-data-model/protobuf.dart';
|
||||
import 'package:flowy_sdk/protobuf/dart-ffi/protobuf.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-folder-data-model/protobuf.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-text-block/protobuf.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/protobuf.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid/protobuf.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-sync/protobuf.dart';
|
||||
|
||||
// ignore: unused_import
|
||||
|
4
frontend/rust-lib/Cargo.lock
generated
4
frontend/rust-lib/Cargo.lock
generated
@ -973,17 +973,13 @@ name = "flowy-grid-data-model"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"flowy-derive",
|
||||
"flowy-error-code",
|
||||
"indexmap",
|
||||
"lib-infra",
|
||||
"nanoid",
|
||||
"protobuf",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_repr",
|
||||
"strum",
|
||||
"strum_macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -17,7 +17,7 @@ use flowy_database::kv::KV;
|
||||
use flowy_folder_data_model::entities::view::{gen_view_id, ViewDataType};
|
||||
use flowy_folder_data_model::entities::ViewInfo;
|
||||
use flowy_folder_data_model::revision::ViewRevision;
|
||||
use flowy_sync::entities::text_block_info::TextBlockId;
|
||||
use flowy_sync::entities::text_block::TextBlockId;
|
||||
use futures::{FutureExt, StreamExt};
|
||||
use std::{collections::HashSet, sync::Arc};
|
||||
|
||||
|
@ -17,7 +17,7 @@ use flowy_folder_data_model::entities::{
|
||||
|
||||
use flowy_revision::disk::RevisionState;
|
||||
use flowy_revision::REVISION_WRITE_INTERVAL_IN_MILLIS;
|
||||
use flowy_sync::entities::text_block_info::TextBlockInfo;
|
||||
use flowy_sync::entities::text_block::TextBlockInfo;
|
||||
use flowy_test::{event_builder::*, FlowySDKTest};
|
||||
use std::{sync::Arc, time::Duration};
|
||||
use tokio::time::sleep;
|
||||
|
213
frontend/rust-lib/flowy-grid/src/entities/block_entities.rs
Normal file
213
frontend/rust-lib/flowy-grid/src/entities/block_entities.rs
Normal file
@ -0,0 +1,213 @@
|
||||
use crate::entities::GridRowId;
|
||||
use flowy_derive::ProtoBuf;
|
||||
use flowy_error::ErrorCode;
|
||||
use flowy_grid_data_model::parser::NotEmptyStr;
|
||||
use flowy_grid_data_model::revision::RowRevision;
|
||||
use std::sync::Arc;
|
||||
|
||||
#[derive(Debug, Clone, Default, ProtoBuf)]
|
||||
pub struct GridBlock {
|
||||
#[pb(index = 1)]
|
||||
pub id: String,
|
||||
|
||||
#[pb(index = 2)]
|
||||
pub row_infos: Vec<BlockRowInfo>,
|
||||
}
|
||||
|
||||
impl GridBlock {
|
||||
pub fn new(block_id: &str, row_orders: Vec<BlockRowInfo>) -> Self {
|
||||
Self {
|
||||
id: block_id.to_owned(),
|
||||
row_infos: row_orders,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone, ProtoBuf)]
|
||||
pub struct BlockRowInfo {
|
||||
#[pb(index = 1)]
|
||||
pub block_id: String,
|
||||
|
||||
#[pb(index = 2)]
|
||||
pub row_id: String,
|
||||
|
||||
#[pb(index = 3)]
|
||||
pub height: i32,
|
||||
}
|
||||
|
||||
impl BlockRowInfo {
|
||||
pub fn row_id(&self) -> &str {
|
||||
&self.row_id
|
||||
}
|
||||
|
||||
pub fn block_id(&self) -> &str {
|
||||
&self.block_id
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::From<&RowRevision> for BlockRowInfo {
|
||||
fn from(rev: &RowRevision) -> Self {
|
||||
Self {
|
||||
block_id: rev.block_id.clone(),
|
||||
row_id: rev.id.clone(),
|
||||
height: rev.height,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::From<&Arc<RowRevision>> for BlockRowInfo {
|
||||
fn from(rev: &Arc<RowRevision>) -> Self {
|
||||
Self {
|
||||
block_id: rev.block_id.clone(),
|
||||
row_id: rev.id.clone(),
|
||||
height: rev.height,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, ProtoBuf)]
|
||||
pub struct Row {
|
||||
#[pb(index = 1)]
|
||||
pub id: String,
|
||||
|
||||
#[pb(index = 2)]
|
||||
pub height: i32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, ProtoBuf)]
|
||||
pub struct OptionalRow {
|
||||
#[pb(index = 1, one_of)]
|
||||
pub row: Option<Row>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, ProtoBuf)]
|
||||
pub struct RepeatedRow {
|
||||
#[pb(index = 1)]
|
||||
pub items: Vec<Row>,
|
||||
}
|
||||
|
||||
impl std::convert::From<Vec<Row>> for RepeatedRow {
|
||||
fn from(items: Vec<Row>) -> Self {
|
||||
Self { items }
|
||||
}
|
||||
}
|
||||
#[derive(Debug, Default, ProtoBuf)]
|
||||
pub struct RepeatedGridBlock {
|
||||
#[pb(index = 1)]
|
||||
pub items: Vec<GridBlock>,
|
||||
}
|
||||
|
||||
impl std::convert::From<Vec<GridBlock>> for RepeatedGridBlock {
|
||||
fn from(items: Vec<GridBlock>) -> Self {
|
||||
Self { items }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, ProtoBuf)]
|
||||
pub struct IndexRowOrder {
|
||||
#[pb(index = 1)]
|
||||
pub row_info: BlockRowInfo,
|
||||
|
||||
#[pb(index = 2, one_of)]
|
||||
pub index: Option<i32>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, ProtoBuf)]
|
||||
pub struct UpdatedRowOrder {
|
||||
#[pb(index = 1)]
|
||||
pub row_info: BlockRowInfo,
|
||||
|
||||
#[pb(index = 2)]
|
||||
pub row: Row,
|
||||
}
|
||||
|
||||
impl UpdatedRowOrder {
|
||||
pub fn new(row_rev: &RowRevision, row: Row) -> Self {
|
||||
Self {
|
||||
row_info: BlockRowInfo::from(row_rev),
|
||||
row,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::From<BlockRowInfo> for IndexRowOrder {
|
||||
fn from(row_info: BlockRowInfo) -> Self {
|
||||
Self { row_info, index: None }
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::From<&RowRevision> for IndexRowOrder {
|
||||
fn from(row: &RowRevision) -> Self {
|
||||
let row_order = BlockRowInfo::from(row);
|
||||
Self::from(row_order)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, ProtoBuf)]
|
||||
pub struct GridRowsChangeset {
|
||||
#[pb(index = 1)]
|
||||
pub block_id: String,
|
||||
|
||||
#[pb(index = 2)]
|
||||
pub inserted_rows: Vec<IndexRowOrder>,
|
||||
|
||||
#[pb(index = 3)]
|
||||
pub deleted_rows: Vec<GridRowId>,
|
||||
|
||||
#[pb(index = 4)]
|
||||
pub updated_rows: Vec<UpdatedRowOrder>,
|
||||
}
|
||||
impl GridRowsChangeset {
|
||||
pub fn insert(block_id: &str, inserted_rows: Vec<IndexRowOrder>) -> Self {
|
||||
Self {
|
||||
block_id: block_id.to_owned(),
|
||||
inserted_rows,
|
||||
deleted_rows: vec![],
|
||||
updated_rows: vec![],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn delete(block_id: &str, deleted_rows: Vec<GridRowId>) -> Self {
|
||||
Self {
|
||||
block_id: block_id.to_owned(),
|
||||
inserted_rows: vec![],
|
||||
deleted_rows,
|
||||
updated_rows: vec![],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update(block_id: &str, updated_rows: Vec<UpdatedRowOrder>) -> Self {
|
||||
Self {
|
||||
block_id: block_id.to_owned(),
|
||||
inserted_rows: vec![],
|
||||
deleted_rows: vec![],
|
||||
updated_rows,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(ProtoBuf, Default)]
|
||||
pub struct QueryGridBlocksPayload {
|
||||
#[pb(index = 1)]
|
||||
pub grid_id: String,
|
||||
|
||||
#[pb(index = 2)]
|
||||
pub block_ids: Vec<String>,
|
||||
}
|
||||
|
||||
pub struct QueryGridBlocksParams {
|
||||
pub grid_id: String,
|
||||
pub block_ids: Vec<String>,
|
||||
}
|
||||
|
||||
impl TryInto<QueryGridBlocksParams> for QueryGridBlocksPayload {
|
||||
type Error = ErrorCode;
|
||||
|
||||
fn try_into(self) -> Result<QueryGridBlocksParams, Self::Error> {
|
||||
let grid_id = NotEmptyStr::parse(self.grid_id).map_err(|_| ErrorCode::GridIdIsEmpty)?;
|
||||
Ok(QueryGridBlocksParams {
|
||||
grid_id: grid_id.0,
|
||||
block_ids: self.block_ids,
|
||||
})
|
||||
}
|
||||
}
|
@ -2,6 +2,8 @@ use crate::entities::{FieldIdentifier, FieldIdentifierPayload};
|
||||
use flowy_derive::ProtoBuf;
|
||||
use flowy_error::ErrorCode;
|
||||
use flowy_grid_data_model::parser::NotEmptyStr;
|
||||
use flowy_grid_data_model::revision::{CellRevision, RowMetaChangeset};
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[derive(ProtoBuf, Default)]
|
||||
pub struct CreateSelectOptionPayload {
|
||||
@ -70,3 +72,85 @@ impl TryInto<CellIdentifier> for CellIdentifierPayload {
|
||||
})
|
||||
}
|
||||
}
|
||||
#[derive(Debug, Default, ProtoBuf)]
|
||||
pub struct Cell {
|
||||
#[pb(index = 1)]
|
||||
pub field_id: String,
|
||||
|
||||
#[pb(index = 2)]
|
||||
pub data: Vec<u8>,
|
||||
}
|
||||
|
||||
impl Cell {
|
||||
pub fn new(field_id: &str, data: Vec<u8>) -> Self {
|
||||
Self {
|
||||
field_id: field_id.to_owned(),
|
||||
data,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn empty(field_id: &str) -> Self {
|
||||
Self {
|
||||
field_id: field_id.to_owned(),
|
||||
data: vec![],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, ProtoBuf)]
|
||||
pub struct RepeatedCell {
|
||||
#[pb(index = 1)]
|
||||
pub items: Vec<Cell>,
|
||||
}
|
||||
|
||||
impl std::ops::Deref for RepeatedCell {
|
||||
type Target = Vec<Cell>;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.items
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::DerefMut for RepeatedCell {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.items
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::From<Vec<Cell>> for RepeatedCell {
|
||||
fn from(items: Vec<Cell>) -> Self {
|
||||
Self { items }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, ProtoBuf)]
|
||||
pub struct CellChangeset {
|
||||
#[pb(index = 1)]
|
||||
pub grid_id: String,
|
||||
|
||||
#[pb(index = 2)]
|
||||
pub row_id: String,
|
||||
|
||||
#[pb(index = 3)]
|
||||
pub field_id: String,
|
||||
|
||||
#[pb(index = 4, one_of)]
|
||||
pub cell_content_changeset: Option<String>,
|
||||
}
|
||||
|
||||
impl std::convert::From<CellChangeset> for RowMetaChangeset {
|
||||
fn from(changeset: CellChangeset) -> Self {
|
||||
let mut cell_by_field_id = HashMap::with_capacity(1);
|
||||
let field_id = changeset.field_id;
|
||||
let cell_rev = CellRevision {
|
||||
data: changeset.cell_content_changeset.unwrap_or_else(|| "".to_owned()),
|
||||
};
|
||||
cell_by_field_id.insert(field_id, cell_rev);
|
||||
|
||||
RowMetaChangeset {
|
||||
row_id: changeset.row_id,
|
||||
height: None,
|
||||
visibility: None,
|
||||
cell_by_field_id,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,571 @@
|
||||
use flowy_derive::ProtoBuf;
|
||||
use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
|
||||
use flowy_error::ErrorCode;
|
||||
use flowy_grid_data_model::parser::NotEmptyStr;
|
||||
use flowy_grid_data_model::revision::{FieldRevision, FieldTypeRevision};
|
||||
use flowy_sync::entities::grid::FieldChangesetParams;
|
||||
use serde_repr::*;
|
||||
use std::sync::Arc;
|
||||
|
||||
use strum_macros::{Display, EnumCount as EnumCountMacro, EnumIter, EnumString};
|
||||
|
||||
#[derive(Debug, Clone, Default, ProtoBuf)]
|
||||
pub struct Field {
|
||||
#[pb(index = 1)]
|
||||
pub id: String,
|
||||
|
||||
#[pb(index = 2)]
|
||||
pub name: String,
|
||||
|
||||
#[pb(index = 3)]
|
||||
pub desc: String,
|
||||
|
||||
#[pb(index = 4)]
|
||||
pub field_type: FieldType,
|
||||
|
||||
#[pb(index = 5)]
|
||||
pub frozen: bool,
|
||||
|
||||
#[pb(index = 6)]
|
||||
pub visibility: bool,
|
||||
|
||||
#[pb(index = 7)]
|
||||
pub width: i32,
|
||||
|
||||
#[pb(index = 8)]
|
||||
pub is_primary: bool,
|
||||
}
|
||||
|
||||
impl std::convert::From<FieldRevision> for Field {
|
||||
fn from(field_rev: FieldRevision) -> Self {
|
||||
Self {
|
||||
id: field_rev.id,
|
||||
name: field_rev.name,
|
||||
desc: field_rev.desc,
|
||||
field_type: field_rev.field_type_rev.into(),
|
||||
frozen: field_rev.frozen,
|
||||
visibility: field_rev.visibility,
|
||||
width: field_rev.width,
|
||||
is_primary: field_rev.is_primary,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::From<Arc<FieldRevision>> for Field {
|
||||
fn from(field_rev: Arc<FieldRevision>) -> Self {
|
||||
let field_rev = field_rev.as_ref().clone();
|
||||
Field::from(field_rev)
|
||||
}
|
||||
}
|
||||
#[derive(Debug, Clone, Default, ProtoBuf)]
|
||||
pub struct FieldOrder {
|
||||
#[pb(index = 1)]
|
||||
pub field_id: String,
|
||||
}
|
||||
|
||||
impl std::convert::From<&str> for FieldOrder {
|
||||
fn from(s: &str) -> Self {
|
||||
FieldOrder { field_id: s.to_owned() }
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::From<String> for FieldOrder {
|
||||
fn from(s: String) -> Self {
|
||||
FieldOrder { field_id: s }
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::From<&Arc<FieldRevision>> for FieldOrder {
|
||||
fn from(field_rev: &Arc<FieldRevision>) -> Self {
|
||||
Self {
|
||||
field_id: field_rev.id.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
#[derive(Debug, Clone, Default, ProtoBuf)]
|
||||
pub struct GridFieldChangeset {
|
||||
#[pb(index = 1)]
|
||||
pub grid_id: String,
|
||||
|
||||
#[pb(index = 2)]
|
||||
pub inserted_fields: Vec<IndexField>,
|
||||
|
||||
#[pb(index = 3)]
|
||||
pub deleted_fields: Vec<FieldOrder>,
|
||||
|
||||
#[pb(index = 4)]
|
||||
pub updated_fields: Vec<Field>,
|
||||
}
|
||||
|
||||
impl GridFieldChangeset {
|
||||
pub fn insert(grid_id: &str, inserted_fields: Vec<IndexField>) -> Self {
|
||||
Self {
|
||||
grid_id: grid_id.to_owned(),
|
||||
inserted_fields,
|
||||
deleted_fields: vec![],
|
||||
updated_fields: vec![],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn delete(grid_id: &str, deleted_fields: Vec<FieldOrder>) -> Self {
|
||||
Self {
|
||||
grid_id: grid_id.to_string(),
|
||||
inserted_fields: vec![],
|
||||
deleted_fields,
|
||||
updated_fields: vec![],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update(grid_id: &str, updated_fields: Vec<Field>) -> Self {
|
||||
Self {
|
||||
grid_id: grid_id.to_string(),
|
||||
inserted_fields: vec![],
|
||||
deleted_fields: vec![],
|
||||
updated_fields,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, ProtoBuf)]
|
||||
pub struct IndexField {
|
||||
#[pb(index = 1)]
|
||||
pub field: Field,
|
||||
|
||||
#[pb(index = 2)]
|
||||
pub index: i32,
|
||||
}
|
||||
|
||||
impl IndexField {
|
||||
pub fn from_field_rev(field_rev: &Arc<FieldRevision>, index: usize) -> Self {
|
||||
Self {
|
||||
field: Field::from(field_rev.as_ref().clone()),
|
||||
index: index as i32,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, ProtoBuf)]
|
||||
pub struct GetEditFieldContextPayload {
|
||||
#[pb(index = 1)]
|
||||
pub grid_id: String,
|
||||
|
||||
#[pb(index = 2, one_of)]
|
||||
pub field_id: Option<String>,
|
||||
|
||||
#[pb(index = 3)]
|
||||
pub field_type: FieldType,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, ProtoBuf)]
|
||||
pub struct EditFieldPayload {
|
||||
#[pb(index = 1)]
|
||||
pub grid_id: String,
|
||||
|
||||
#[pb(index = 2)]
|
||||
pub field_id: String,
|
||||
|
||||
#[pb(index = 3)]
|
||||
pub field_type: FieldType,
|
||||
|
||||
#[pb(index = 4)]
|
||||
pub create_if_not_exist: bool,
|
||||
}
|
||||
|
||||
pub struct EditFieldParams {
|
||||
pub grid_id: String,
|
||||
pub field_id: String,
|
||||
pub field_type: FieldType,
|
||||
}
|
||||
|
||||
impl TryInto<EditFieldParams> for EditFieldPayload {
|
||||
type Error = ErrorCode;
|
||||
|
||||
fn try_into(self) -> Result<EditFieldParams, Self::Error> {
|
||||
let grid_id = NotEmptyStr::parse(self.grid_id).map_err(|_| ErrorCode::GridIdIsEmpty)?;
|
||||
let field_id = NotEmptyStr::parse(self.field_id).map_err(|_| ErrorCode::FieldIdIsEmpty)?;
|
||||
Ok(EditFieldParams {
|
||||
grid_id: grid_id.0,
|
||||
field_id: field_id.0,
|
||||
field_type: self.field_type,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub struct CreateFieldParams {
|
||||
pub grid_id: String,
|
||||
pub field_type: FieldType,
|
||||
}
|
||||
|
||||
impl TryInto<CreateFieldParams> for EditFieldPayload {
|
||||
type Error = ErrorCode;
|
||||
|
||||
fn try_into(self) -> Result<CreateFieldParams, Self::Error> {
|
||||
let grid_id = NotEmptyStr::parse(self.grid_id).map_err(|_| ErrorCode::GridIdIsEmpty)?;
|
||||
|
||||
Ok(CreateFieldParams {
|
||||
grid_id: grid_id.0,
|
||||
field_type: self.field_type,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, ProtoBuf)]
|
||||
pub struct FieldTypeOptionContext {
|
||||
#[pb(index = 1)]
|
||||
pub grid_id: String,
|
||||
|
||||
#[pb(index = 2)]
|
||||
pub grid_field: Field,
|
||||
|
||||
#[pb(index = 3)]
|
||||
pub type_option_data: Vec<u8>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, ProtoBuf)]
|
||||
pub struct FieldTypeOptionData {
|
||||
#[pb(index = 1)]
|
||||
pub grid_id: String,
|
||||
|
||||
#[pb(index = 2)]
|
||||
pub field: Field,
|
||||
|
||||
#[pb(index = 3)]
|
||||
pub type_option_data: Vec<u8>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, ProtoBuf)]
|
||||
pub struct RepeatedField {
|
||||
#[pb(index = 1)]
|
||||
pub items: Vec<Field>,
|
||||
}
|
||||
impl std::ops::Deref for RepeatedField {
|
||||
type Target = Vec<Field>;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.items
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::DerefMut for RepeatedField {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.items
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::From<Vec<Field>> for RepeatedField {
|
||||
fn from(items: Vec<Field>) -> Self {
|
||||
Self { items }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, ProtoBuf)]
|
||||
pub struct RepeatedFieldOrder {
|
||||
#[pb(index = 1)]
|
||||
pub items: Vec<FieldOrder>,
|
||||
}
|
||||
|
||||
impl std::ops::Deref for RepeatedFieldOrder {
|
||||
type Target = Vec<FieldOrder>;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.items
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::From<Vec<FieldOrder>> for RepeatedFieldOrder {
|
||||
fn from(field_orders: Vec<FieldOrder>) -> Self {
|
||||
RepeatedFieldOrder { items: field_orders }
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::From<String> for RepeatedFieldOrder {
|
||||
fn from(s: String) -> Self {
|
||||
RepeatedFieldOrder {
|
||||
items: vec![FieldOrder::from(s)],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(ProtoBuf, Default)]
|
||||
pub struct InsertFieldPayload {
|
||||
#[pb(index = 1)]
|
||||
pub grid_id: String,
|
||||
|
||||
#[pb(index = 2)]
|
||||
pub field: Field,
|
||||
|
||||
#[pb(index = 3)]
|
||||
pub type_option_data: Vec<u8>,
|
||||
|
||||
#[pb(index = 4, one_of)]
|
||||
pub start_field_id: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct InsertFieldParams {
|
||||
pub grid_id: String,
|
||||
pub field: Field,
|
||||
pub type_option_data: Vec<u8>,
|
||||
pub start_field_id: Option<String>,
|
||||
}
|
||||
|
||||
impl TryInto<InsertFieldParams> for InsertFieldPayload {
|
||||
type Error = ErrorCode;
|
||||
|
||||
fn try_into(self) -> Result<InsertFieldParams, Self::Error> {
|
||||
let grid_id = NotEmptyStr::parse(self.grid_id).map_err(|_| ErrorCode::GridIdIsEmpty)?;
|
||||
let _ = NotEmptyStr::parse(self.field.id.clone()).map_err(|_| ErrorCode::FieldIdIsEmpty)?;
|
||||
|
||||
let start_field_id = match self.start_field_id {
|
||||
None => None,
|
||||
Some(id) => Some(NotEmptyStr::parse(id).map_err(|_| ErrorCode::FieldIdIsEmpty)?.0),
|
||||
};
|
||||
|
||||
Ok(InsertFieldParams {
|
||||
grid_id: grid_id.0,
|
||||
field: self.field,
|
||||
type_option_data: self.type_option_data,
|
||||
start_field_id,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(ProtoBuf, Default)]
|
||||
pub struct UpdateFieldTypeOptionPayload {
|
||||
#[pb(index = 1)]
|
||||
pub grid_id: String,
|
||||
|
||||
#[pb(index = 2)]
|
||||
pub field_id: String,
|
||||
|
||||
#[pb(index = 3)]
|
||||
pub type_option_data: Vec<u8>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct UpdateFieldTypeOptionParams {
|
||||
pub grid_id: String,
|
||||
pub field_id: String,
|
||||
pub type_option_data: Vec<u8>,
|
||||
}
|
||||
|
||||
impl TryInto<UpdateFieldTypeOptionParams> for UpdateFieldTypeOptionPayload {
|
||||
type Error = ErrorCode;
|
||||
|
||||
fn try_into(self) -> Result<UpdateFieldTypeOptionParams, Self::Error> {
|
||||
let grid_id = NotEmptyStr::parse(self.grid_id).map_err(|_| ErrorCode::GridIdIsEmpty)?;
|
||||
let _ = NotEmptyStr::parse(self.field_id.clone()).map_err(|_| ErrorCode::FieldIdIsEmpty)?;
|
||||
|
||||
Ok(UpdateFieldTypeOptionParams {
|
||||
grid_id: grid_id.0,
|
||||
field_id: self.field_id,
|
||||
type_option_data: self.type_option_data,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(ProtoBuf, Default)]
|
||||
pub struct QueryFieldPayload {
|
||||
#[pb(index = 1)]
|
||||
pub grid_id: String,
|
||||
|
||||
#[pb(index = 2)]
|
||||
pub field_orders: RepeatedFieldOrder,
|
||||
}
|
||||
|
||||
pub struct QueryFieldParams {
|
||||
pub grid_id: String,
|
||||
pub field_orders: RepeatedFieldOrder,
|
||||
}
|
||||
|
||||
impl TryInto<QueryFieldParams> for QueryFieldPayload {
|
||||
type Error = ErrorCode;
|
||||
|
||||
fn try_into(self) -> Result<QueryFieldParams, Self::Error> {
|
||||
let grid_id = NotEmptyStr::parse(self.grid_id).map_err(|_| ErrorCode::GridIdIsEmpty)?;
|
||||
Ok(QueryFieldParams {
|
||||
grid_id: grid_id.0,
|
||||
field_orders: self.field_orders,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, ProtoBuf)]
|
||||
pub struct FieldChangesetPayload {
|
||||
#[pb(index = 1)]
|
||||
pub field_id: String,
|
||||
|
||||
#[pb(index = 2)]
|
||||
pub grid_id: String,
|
||||
|
||||
#[pb(index = 3, one_of)]
|
||||
pub name: Option<String>,
|
||||
|
||||
#[pb(index = 4, one_of)]
|
||||
pub desc: Option<String>,
|
||||
|
||||
#[pb(index = 5, one_of)]
|
||||
pub field_type: Option<FieldType>,
|
||||
|
||||
#[pb(index = 6, one_of)]
|
||||
pub frozen: Option<bool>,
|
||||
|
||||
#[pb(index = 7, one_of)]
|
||||
pub visibility: Option<bool>,
|
||||
|
||||
#[pb(index = 8, one_of)]
|
||||
pub width: Option<i32>,
|
||||
|
||||
#[pb(index = 9, one_of)]
|
||||
pub type_option_data: Option<Vec<u8>>,
|
||||
}
|
||||
|
||||
impl TryInto<FieldChangesetParams> for FieldChangesetPayload {
|
||||
type Error = ErrorCode;
|
||||
|
||||
fn try_into(self) -> Result<FieldChangesetParams, Self::Error> {
|
||||
let grid_id = NotEmptyStr::parse(self.grid_id).map_err(|_| ErrorCode::GridIdIsEmpty)?;
|
||||
let field_id = NotEmptyStr::parse(self.field_id).map_err(|_| ErrorCode::FieldIdIsEmpty)?;
|
||||
let field_type = self.field_type.map(FieldTypeRevision::from);
|
||||
if let Some(type_option_data) = self.type_option_data.as_ref() {
|
||||
if type_option_data.is_empty() {
|
||||
return Err(ErrorCode::TypeOptionDataIsEmpty);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(FieldChangesetParams {
|
||||
field_id: field_id.0,
|
||||
grid_id: grid_id.0,
|
||||
name: self.name,
|
||||
desc: self.desc,
|
||||
field_type,
|
||||
frozen: self.frozen,
|
||||
visibility: self.visibility,
|
||||
width: self.width,
|
||||
type_option_data: self.type_option_data,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
Clone,
|
||||
PartialEq,
|
||||
Hash,
|
||||
Eq,
|
||||
ProtoBuf_Enum,
|
||||
EnumCountMacro,
|
||||
EnumString,
|
||||
EnumIter,
|
||||
Display,
|
||||
Serialize_repr,
|
||||
Deserialize_repr,
|
||||
)]
|
||||
#[repr(u8)]
|
||||
pub enum FieldType {
|
||||
RichText = 0,
|
||||
Number = 1,
|
||||
DateTime = 2,
|
||||
SingleSelect = 3,
|
||||
MultiSelect = 4,
|
||||
Checkbox = 5,
|
||||
URL = 6,
|
||||
}
|
||||
|
||||
impl std::default::Default for FieldType {
|
||||
fn default() -> Self {
|
||||
FieldType::RichText
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<FieldType> for FieldType {
|
||||
fn as_ref(&self) -> &FieldType {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&FieldType> for FieldType {
|
||||
fn from(field_type: &FieldType) -> Self {
|
||||
field_type.clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl FieldType {
|
||||
pub fn type_id(&self) -> String {
|
||||
(self.clone() as u8).to_string()
|
||||
}
|
||||
|
||||
pub fn default_cell_width(&self) -> i32 {
|
||||
match self {
|
||||
FieldType::DateTime => 180,
|
||||
_ => 150,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_number(&self) -> bool {
|
||||
self == &FieldType::Number
|
||||
}
|
||||
|
||||
pub fn is_text(&self) -> bool {
|
||||
self == &FieldType::RichText
|
||||
}
|
||||
|
||||
pub fn is_checkbox(&self) -> bool {
|
||||
self == &FieldType::Checkbox
|
||||
}
|
||||
|
||||
pub fn is_date(&self) -> bool {
|
||||
self == &FieldType::DateTime
|
||||
}
|
||||
|
||||
pub fn is_single_select(&self) -> bool {
|
||||
self == &FieldType::SingleSelect
|
||||
}
|
||||
|
||||
pub fn is_multi_select(&self) -> bool {
|
||||
self == &FieldType::MultiSelect
|
||||
}
|
||||
|
||||
pub fn is_url(&self) -> bool {
|
||||
self == &FieldType::URL
|
||||
}
|
||||
|
||||
pub fn is_select_option(&self) -> bool {
|
||||
self == &FieldType::MultiSelect || self == &FieldType::SingleSelect
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::From<&FieldType> for FieldTypeRevision {
|
||||
fn from(ty: &FieldType) -> Self {
|
||||
ty.clone() as u8
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::From<FieldType> for FieldTypeRevision {
|
||||
fn from(ty: FieldType) -> Self {
|
||||
ty as u8
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::From<&FieldTypeRevision> for FieldType {
|
||||
fn from(ty: &FieldTypeRevision) -> Self {
|
||||
FieldType::from(*ty)
|
||||
}
|
||||
}
|
||||
impl std::convert::From<FieldTypeRevision> for FieldType {
|
||||
fn from(ty: FieldTypeRevision) -> Self {
|
||||
match ty {
|
||||
0 => FieldType::RichText,
|
||||
1 => FieldType::Number,
|
||||
2 => FieldType::DateTime,
|
||||
3 => FieldType::SingleSelect,
|
||||
4 => FieldType::MultiSelect,
|
||||
5 => FieldType::Checkbox,
|
||||
6 => FieldType::URL,
|
||||
_ => {
|
||||
tracing::error!("Can't parser FieldTypeRevision: {} to FieldType", ty);
|
||||
FieldType::RichText
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#[derive(Debug, Clone, Default, ProtoBuf)]
|
||||
pub struct FieldIdentifierPayload {
|
||||
#[pb(index = 1)]
|
||||
|
@ -1,10 +1,11 @@
|
||||
use crate::parser::NotEmptyStr;
|
||||
use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
|
||||
use flowy_error_code::ErrorCode;
|
||||
|
||||
use crate::entities::FieldType;
|
||||
use crate::revision::{FieldRevision, GridFilterRevision};
|
||||
use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
|
||||
use flowy_error::ErrorCode;
|
||||
use flowy_grid_data_model::parser::NotEmptyStr;
|
||||
use flowy_grid_data_model::revision::{FieldRevision, GridFilterRevision};
|
||||
use flowy_sync::entities::grid::{CreateGridFilterParams, DeleteFilterParams};
|
||||
use std::convert::TryInto;
|
||||
use std::sync::Arc;
|
||||
|
||||
#[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)]
|
||||
pub struct GridFilter {
|
||||
@ -18,14 +19,14 @@ pub struct RepeatedGridFilter {
|
||||
pub items: Vec<GridFilter>,
|
||||
}
|
||||
|
||||
impl std::convert::From<&GridFilterRevision> for GridFilter {
|
||||
fn from(rev: &GridFilterRevision) -> Self {
|
||||
impl std::convert::From<&Arc<GridFilterRevision>> for GridFilter {
|
||||
fn from(rev: &Arc<GridFilterRevision>) -> Self {
|
||||
Self { id: rev.id.clone() }
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::From<&Vec<GridFilterRevision>> for RepeatedGridFilter {
|
||||
fn from(revs: &Vec<GridFilterRevision>) -> Self {
|
||||
impl std::convert::From<&Vec<Arc<GridFilterRevision>>> for RepeatedGridFilter {
|
||||
fn from(revs: &Vec<Arc<GridFilterRevision>>) -> Self {
|
||||
RepeatedGridFilter {
|
||||
items: revs.iter().map(|rev| rev.into()).collect(),
|
||||
}
|
||||
@ -38,6 +39,29 @@ impl std::convert::From<Vec<GridFilter>> for RepeatedGridFilter {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(ProtoBuf, Debug, Default, Clone)]
|
||||
pub struct DeleteFilterPayload {
|
||||
#[pb(index = 1)]
|
||||
pub filter_id: String,
|
||||
|
||||
#[pb(index = 2)]
|
||||
pub field_type: FieldType,
|
||||
}
|
||||
|
||||
impl TryInto<DeleteFilterParams> for DeleteFilterPayload {
|
||||
type Error = ErrorCode;
|
||||
|
||||
fn try_into(self) -> Result<DeleteFilterParams, Self::Error> {
|
||||
let filter_id = NotEmptyStr::parse(self.filter_id)
|
||||
.map_err(|_| ErrorCode::UnexpectedEmptyString)?
|
||||
.0;
|
||||
Ok(DeleteFilterParams {
|
||||
filter_id,
|
||||
field_type_rev: self.field_type.into(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(ProtoBuf, Debug, Default, Clone)]
|
||||
pub struct CreateGridFilterPayload {
|
||||
#[pb(index = 1)]
|
||||
@ -58,20 +82,13 @@ impl CreateGridFilterPayload {
|
||||
pub fn new<T: Into<i32>>(field_rev: &FieldRevision, condition: T, content: Option<String>) -> Self {
|
||||
Self {
|
||||
field_id: field_rev.id.clone(),
|
||||
field_type: field_rev.field_type.clone(),
|
||||
field_type: field_rev.field_type_rev.into(),
|
||||
condition: condition.into(),
|
||||
content,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct CreateGridFilterParams {
|
||||
pub field_id: String,
|
||||
pub field_type: FieldType,
|
||||
pub condition: u8,
|
||||
pub content: Option<String>,
|
||||
}
|
||||
|
||||
impl TryInto<CreateGridFilterParams> for CreateGridFilterPayload {
|
||||
type Error = ErrorCode;
|
||||
|
||||
@ -81,9 +98,12 @@ impl TryInto<CreateGridFilterParams> for CreateGridFilterPayload {
|
||||
.0;
|
||||
let condition = self.condition as u8;
|
||||
match self.field_type {
|
||||
FieldType::RichText | FieldType::Checkbox | FieldType::URL => {
|
||||
FieldType::RichText | FieldType::URL => {
|
||||
let _ = TextFilterCondition::try_from(condition)?;
|
||||
}
|
||||
FieldType::Checkbox => {
|
||||
let _ = CheckboxCondition::try_from(condition)?;
|
||||
}
|
||||
FieldType::Number => {
|
||||
let _ = NumberFilterCondition::try_from(condition)?;
|
||||
}
|
||||
@ -97,7 +117,7 @@ impl TryInto<CreateGridFilterParams> for CreateGridFilterPayload {
|
||||
|
||||
Ok(CreateGridFilterParams {
|
||||
field_id,
|
||||
field_type: self.field_type,
|
||||
field_type_rev: self.field_type.into(),
|
||||
condition,
|
||||
content: self.content,
|
||||
})
|
||||
@ -154,11 +174,11 @@ impl std::convert::TryFrom<u8> for TextFilterCondition {
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::From<GridFilterRevision> for GridTextFilter {
|
||||
fn from(rev: GridFilterRevision) -> Self {
|
||||
impl std::convert::From<Arc<GridFilterRevision>> for GridTextFilter {
|
||||
fn from(rev: Arc<GridFilterRevision>) -> Self {
|
||||
GridTextFilter {
|
||||
condition: TextFilterCondition::try_from(rev.condition).unwrap_or(TextFilterCondition::Is),
|
||||
content: rev.content,
|
||||
content: rev.content.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -213,11 +233,11 @@ impl std::convert::TryFrom<u8> for NumberFilterCondition {
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::From<GridFilterRevision> for GridNumberFilter {
|
||||
fn from(rev: GridFilterRevision) -> Self {
|
||||
impl std::convert::From<Arc<GridFilterRevision>> for GridNumberFilter {
|
||||
fn from(rev: Arc<GridFilterRevision>) -> Self {
|
||||
GridNumberFilter {
|
||||
condition: NumberFilterCondition::try_from(rev.condition).unwrap_or(NumberFilterCondition::Equal),
|
||||
content: rev.content,
|
||||
content: rev.content.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -266,11 +286,11 @@ impl std::convert::TryFrom<u8> for SelectOptionCondition {
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::From<GridFilterRevision> for GridSelectOptionFilter {
|
||||
fn from(rev: GridFilterRevision) -> Self {
|
||||
impl std::convert::From<Arc<GridFilterRevision>> for GridSelectOptionFilter {
|
||||
fn from(rev: Arc<GridFilterRevision>) -> Self {
|
||||
GridSelectOptionFilter {
|
||||
condition: SelectOptionCondition::try_from(rev.condition).unwrap_or(SelectOptionCondition::OptionIs),
|
||||
content: rev.content,
|
||||
content: rev.content.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -318,11 +338,56 @@ impl std::convert::TryFrom<u8> for DateFilterCondition {
|
||||
}
|
||||
}
|
||||
}
|
||||
impl std::convert::From<GridFilterRevision> for GridDateFilter {
|
||||
fn from(rev: GridFilterRevision) -> Self {
|
||||
impl std::convert::From<Arc<GridFilterRevision>> for GridDateFilter {
|
||||
fn from(rev: Arc<GridFilterRevision>) -> Self {
|
||||
GridDateFilter {
|
||||
condition: DateFilterCondition::try_from(rev.condition).unwrap_or(DateFilterCondition::DateIs),
|
||||
content: rev.content,
|
||||
content: rev.content.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)]
|
||||
pub struct GridCheckboxFilter {
|
||||
#[pb(index = 1)]
|
||||
pub condition: CheckboxCondition,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, ProtoBuf_Enum)]
|
||||
#[repr(u8)]
|
||||
pub enum CheckboxCondition {
|
||||
IsChecked = 0,
|
||||
IsUnChecked = 1,
|
||||
}
|
||||
|
||||
impl std::convert::From<CheckboxCondition> for i32 {
|
||||
fn from(value: CheckboxCondition) -> Self {
|
||||
value as i32
|
||||
}
|
||||
}
|
||||
|
||||
impl std::default::Default for CheckboxCondition {
|
||||
fn default() -> Self {
|
||||
CheckboxCondition::IsChecked
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::TryFrom<u8> for CheckboxCondition {
|
||||
type Error = ErrorCode;
|
||||
|
||||
fn try_from(value: u8) -> Result<Self, Self::Error> {
|
||||
match value {
|
||||
0 => Ok(CheckboxCondition::IsChecked),
|
||||
1 => Ok(CheckboxCondition::IsUnChecked),
|
||||
_ => Err(ErrorCode::InvalidData),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::From<Arc<GridFilterRevision>> for GridCheckboxFilter {
|
||||
fn from(rev: Arc<GridFilterRevision>) -> Self {
|
||||
GridCheckboxFilter {
|
||||
condition: CheckboxCondition::try_from(rev.condition).unwrap_or(CheckboxCondition::IsChecked),
|
||||
}
|
||||
}
|
||||
}
|
106
frontend/rust-lib/flowy-grid/src/entities/grid_entities.rs
Normal file
106
frontend/rust-lib/flowy-grid/src/entities/grid_entities.rs
Normal file
@ -0,0 +1,106 @@
|
||||
use crate::entities::{FieldOrder, GridBlock};
|
||||
use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
|
||||
use flowy_error::ErrorCode;
|
||||
use flowy_grid_data_model::parser::NotEmptyStr;
|
||||
#[derive(Debug, Clone, Default, ProtoBuf)]
|
||||
pub struct Grid {
|
||||
#[pb(index = 1)]
|
||||
pub id: String,
|
||||
|
||||
#[pb(index = 2)]
|
||||
pub field_orders: Vec<FieldOrder>,
|
||||
|
||||
#[pb(index = 3)]
|
||||
pub blocks: Vec<GridBlock>,
|
||||
}
|
||||
|
||||
#[derive(ProtoBuf, Default)]
|
||||
pub struct CreateGridPayload {
|
||||
#[pb(index = 1)]
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, ProtoBuf, Default, Debug)]
|
||||
pub struct GridId {
|
||||
#[pb(index = 1)]
|
||||
pub value: String,
|
||||
}
|
||||
|
||||
impl AsRef<str> for GridId {
|
||||
fn as_ref(&self) -> &str {
|
||||
&self.value
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, ProtoBuf, Default, Debug)]
|
||||
pub struct GridBlockId {
|
||||
#[pb(index = 1)]
|
||||
pub value: String,
|
||||
}
|
||||
|
||||
impl AsRef<str> for GridBlockId {
|
||||
fn as_ref(&self) -> &str {
|
||||
&self.value
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::From<&str> for GridBlockId {
|
||||
fn from(s: &str) -> Self {
|
||||
GridBlockId { value: s.to_owned() }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, ProtoBuf_Enum)]
|
||||
pub enum MoveItemType {
|
||||
MoveField = 0,
|
||||
MoveRow = 1,
|
||||
}
|
||||
|
||||
impl std::default::Default for MoveItemType {
|
||||
fn default() -> Self {
|
||||
MoveItemType::MoveField
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, ProtoBuf)]
|
||||
pub struct MoveItemPayload {
|
||||
#[pb(index = 1)]
|
||||
pub grid_id: String,
|
||||
|
||||
#[pb(index = 2)]
|
||||
pub item_id: String,
|
||||
|
||||
#[pb(index = 3)]
|
||||
pub from_index: i32,
|
||||
|
||||
#[pb(index = 4)]
|
||||
pub to_index: i32,
|
||||
|
||||
#[pb(index = 5)]
|
||||
pub ty: MoveItemType,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct MoveItemParams {
|
||||
pub grid_id: String,
|
||||
pub item_id: String,
|
||||
pub from_index: i32,
|
||||
pub to_index: i32,
|
||||
pub ty: MoveItemType,
|
||||
}
|
||||
|
||||
impl TryInto<MoveItemParams> for MoveItemPayload {
|
||||
type Error = ErrorCode;
|
||||
|
||||
fn try_into(self) -> Result<MoveItemParams, Self::Error> {
|
||||
let grid_id = NotEmptyStr::parse(self.grid_id).map_err(|_| ErrorCode::GridIdIsEmpty)?;
|
||||
let item_id = NotEmptyStr::parse(self.item_id).map_err(|_| ErrorCode::InvalidData)?;
|
||||
Ok(MoveItemParams {
|
||||
grid_id: grid_id.0,
|
||||
item_id: item_id.0,
|
||||
from_index: self.from_index,
|
||||
to_index: self.to_index,
|
||||
ty: self.ty,
|
||||
})
|
||||
}
|
||||
}
|
@ -1,8 +1,8 @@
|
||||
use crate::parser::NotEmptyStr;
|
||||
use flowy_derive::ProtoBuf;
|
||||
use flowy_error_code::ErrorCode;
|
||||
|
||||
use crate::revision::GridGroupRevision;
|
||||
use flowy_error::ErrorCode;
|
||||
use flowy_grid_data_model::parser::NotEmptyStr;
|
||||
use flowy_grid_data_model::revision::GridGroupRevision;
|
||||
use flowy_sync::entities::grid::CreateGridGroupParams;
|
||||
use std::convert::TryInto;
|
||||
|
||||
#[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)]
|
||||
@ -56,11 +56,6 @@ pub struct CreateGridGroupPayload {
|
||||
pub sub_field_id: Option<String>,
|
||||
}
|
||||
|
||||
pub struct CreateGridGroupParams {
|
||||
pub field_id: Option<String>,
|
||||
pub sub_field_id: Option<String>,
|
||||
}
|
||||
|
||||
impl TryInto<CreateGridGroupParams> for CreateGridGroupPayload {
|
||||
type Error = ErrorCode;
|
||||
|
@ -1,7 +1,19 @@
|
||||
mod block_entities;
|
||||
mod cell_entities;
|
||||
mod field_entities;
|
||||
mod filter_entities;
|
||||
mod grid_entities;
|
||||
mod group_entities;
|
||||
mod row_entities;
|
||||
mod setting_entities;
|
||||
mod sort_entities;
|
||||
|
||||
pub use block_entities::*;
|
||||
pub use cell_entities::*;
|
||||
pub use field_entities::*;
|
||||
pub use filter_entities::*;
|
||||
pub use grid_entities::*;
|
||||
pub use group_entities::*;
|
||||
pub use row_entities::*;
|
||||
pub use setting_entities::*;
|
||||
pub use sort_entities::*;
|
||||
|
@ -3,29 +3,77 @@ use flowy_error::ErrorCode;
|
||||
use flowy_grid_data_model::parser::NotEmptyStr;
|
||||
|
||||
#[derive(ProtoBuf, Default)]
|
||||
pub struct RowIdentifierPayload {
|
||||
pub struct GridRowIdPayload {
|
||||
#[pb(index = 1)]
|
||||
pub grid_id: String,
|
||||
|
||||
#[pb(index = 2)]
|
||||
pub block_id: String,
|
||||
|
||||
#[pb(index = 3)]
|
||||
pub row_id: String,
|
||||
}
|
||||
|
||||
pub struct RowIdentifier {
|
||||
#[derive(Debug, Default, Clone, ProtoBuf)]
|
||||
pub struct GridRowId {
|
||||
#[pb(index = 1)]
|
||||
pub grid_id: String,
|
||||
|
||||
#[pb(index = 2)]
|
||||
pub block_id: String,
|
||||
|
||||
#[pb(index = 3)]
|
||||
pub row_id: String,
|
||||
}
|
||||
|
||||
impl TryInto<RowIdentifier> for RowIdentifierPayload {
|
||||
impl TryInto<GridRowId> for GridRowIdPayload {
|
||||
type Error = ErrorCode;
|
||||
|
||||
fn try_into(self) -> Result<RowIdentifier, Self::Error> {
|
||||
fn try_into(self) -> Result<GridRowId, Self::Error> {
|
||||
let grid_id = NotEmptyStr::parse(self.grid_id).map_err(|_| ErrorCode::GridIdIsEmpty)?;
|
||||
// let block_id = NotEmptyStr::parse(self.block_id).map_err(|_| ErrorCode::BlockIdIsEmpty)?;
|
||||
let row_id = NotEmptyStr::parse(self.row_id).map_err(|_| ErrorCode::RowIdIsEmpty)?;
|
||||
|
||||
Ok(RowIdentifier {
|
||||
Ok(GridRowId {
|
||||
grid_id: grid_id.0,
|
||||
block_id: self.block_id,
|
||||
row_id: row_id.0,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone, ProtoBuf)]
|
||||
pub struct BlockRowId {
|
||||
#[pb(index = 1)]
|
||||
pub block_id: String,
|
||||
|
||||
#[pb(index = 2)]
|
||||
pub row_id: String,
|
||||
}
|
||||
|
||||
#[derive(ProtoBuf, Default)]
|
||||
pub struct CreateRowPayload {
|
||||
#[pb(index = 1)]
|
||||
pub grid_id: String,
|
||||
|
||||
#[pb(index = 2, one_of)]
|
||||
pub start_row_id: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct CreateRowParams {
|
||||
pub grid_id: String,
|
||||
pub start_row_id: Option<String>,
|
||||
}
|
||||
|
||||
impl TryInto<CreateRowParams> for CreateRowPayload {
|
||||
type Error = ErrorCode;
|
||||
|
||||
fn try_into(self) -> Result<CreateRowParams, Self::Error> {
|
||||
let grid_id = NotEmptyStr::parse(self.grid_id).map_err(|_| ErrorCode::GridIdIsEmpty)?;
|
||||
Ok(CreateRowParams {
|
||||
grid_id: grid_id.0,
|
||||
start_row_id: self.start_row_id,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,12 @@
|
||||
use crate::entities::{
|
||||
CreateGridFilterParams, CreateGridFilterPayload, CreateGridGroupParams, CreateGridGroupPayload,
|
||||
CreateGridSortParams, CreateGridSortPayload, RepeatedGridFilter, RepeatedGridGroup, RepeatedGridSort,
|
||||
CreateGridFilterPayload, CreateGridGroupPayload, CreateGridSortPayload, DeleteFilterPayload, RepeatedGridFilter,
|
||||
RepeatedGridGroup, RepeatedGridSort,
|
||||
};
|
||||
use crate::parser::NotEmptyStr;
|
||||
use crate::revision::{GridLayoutRevision, GridSettingRevision};
|
||||
use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
|
||||
use flowy_error_code::ErrorCode;
|
||||
use flowy_error::ErrorCode;
|
||||
use flowy_grid_data_model::parser::NotEmptyStr;
|
||||
use flowy_grid_data_model::revision::GridLayoutRevision;
|
||||
use flowy_sync::entities::grid::GridSettingChangesetParams;
|
||||
use std::collections::HashMap;
|
||||
use std::convert::TryInto;
|
||||
|
||||
@ -21,34 +22,35 @@ pub struct GridSetting {
|
||||
pub sorts_by_layout_ty: HashMap<String, RepeatedGridSort>,
|
||||
}
|
||||
|
||||
impl std::convert::From<&GridSettingRevision> for GridSetting {
|
||||
fn from(rev: &GridSettingRevision) -> Self {
|
||||
let filters_by_layout_ty: HashMap<String, RepeatedGridFilter> = rev
|
||||
.filters
|
||||
.iter()
|
||||
.map(|(layout_rev, filter_revs)| (layout_rev.to_string(), filter_revs.into()))
|
||||
.collect();
|
||||
|
||||
let groups_by_layout_ty: HashMap<String, RepeatedGridGroup> = rev
|
||||
.groups
|
||||
.iter()
|
||||
.map(|(layout_rev, group_revs)| (layout_rev.to_string(), group_revs.into()))
|
||||
.collect();
|
||||
|
||||
let sorts_by_layout_ty: HashMap<String, RepeatedGridSort> = rev
|
||||
.sorts
|
||||
.iter()
|
||||
.map(|(layout_rev, sort_revs)| (layout_rev.to_string(), sort_revs.into()))
|
||||
.collect();
|
||||
|
||||
GridSetting {
|
||||
filters_by_layout_ty,
|
||||
groups_by_layout_ty,
|
||||
sorts_by_layout_ty,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// impl std::convert::From<&GridSettingRevision> for GridSetting {
|
||||
// fn from(rev: &GridSettingRevision) -> Self {
|
||||
// let filters_by_layout_ty: HashMap<String, RepeatedGridFilter> = rev
|
||||
// .filters
|
||||
// .iter()
|
||||
// .map(|(layout_rev, filter_revs)| (layout_rev.to_string(), filter_revs.into()))
|
||||
// .collect();
|
||||
//
|
||||
// let groups_by_layout_ty: HashMap<String, RepeatedGridGroup> = rev
|
||||
// .groups
|
||||
// .iter()
|
||||
// .map(|(layout_rev, group_revs)| (layout_rev.to_string(), group_revs.into()))
|
||||
// .collect();
|
||||
//
|
||||
// let sorts_by_layout_ty: HashMap<String, RepeatedGridSort> = rev
|
||||
// .sorts
|
||||
// .iter()
|
||||
// .map(|(layout_rev, sort_revs)| (layout_rev.to_string(), sort_revs.into()))
|
||||
// .collect();
|
||||
//
|
||||
// GridSetting {
|
||||
// filters_by_layout_ty,
|
||||
// groups_by_layout_ty,
|
||||
// sorts_by_layout_ty,
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
#[derive(Debug, Clone, PartialEq, Eq, ProtoBuf_Enum)]
|
||||
#[repr(u8)]
|
||||
pub enum GridLayoutType {
|
||||
@ -92,7 +94,7 @@ pub struct GridSettingChangesetPayload {
|
||||
pub insert_filter: Option<CreateGridFilterPayload>,
|
||||
|
||||
#[pb(index = 4, one_of)]
|
||||
pub delete_filter: Option<String>,
|
||||
pub delete_filter: Option<DeleteFilterPayload>,
|
||||
|
||||
#[pb(index = 5, one_of)]
|
||||
pub insert_group: Option<CreateGridGroupPayload>,
|
||||
@ -107,23 +109,6 @@ pub struct GridSettingChangesetPayload {
|
||||
pub delete_sort: Option<String>,
|
||||
}
|
||||
|
||||
pub struct GridSettingChangesetParams {
|
||||
pub grid_id: String,
|
||||
pub layout_type: GridLayoutType,
|
||||
pub insert_filter: Option<CreateGridFilterParams>,
|
||||
pub delete_filter: Option<String>,
|
||||
pub insert_group: Option<CreateGridGroupParams>,
|
||||
pub delete_group: Option<String>,
|
||||
pub insert_sort: Option<CreateGridSortParams>,
|
||||
pub delete_sort: Option<String>,
|
||||
}
|
||||
|
||||
impl GridSettingChangesetParams {
|
||||
pub fn is_filter_changed(&self) -> bool {
|
||||
self.insert_filter.is_some() || self.delete_filter.is_some()
|
||||
}
|
||||
}
|
||||
|
||||
impl TryInto<GridSettingChangesetParams> for GridSettingChangesetPayload {
|
||||
type Error = ErrorCode;
|
||||
|
||||
@ -139,7 +124,7 @@ impl TryInto<GridSettingChangesetParams> for GridSettingChangesetPayload {
|
||||
|
||||
let delete_filter = match self.delete_filter {
|
||||
None => None,
|
||||
Some(filter_id) => Some(NotEmptyStr::parse(filter_id).map_err(|_| ErrorCode::FieldIdIsEmpty)?.0),
|
||||
Some(payload) => Some(payload.try_into()?),
|
||||
};
|
||||
|
||||
let insert_group = match self.insert_group {
|
||||
@ -164,7 +149,7 @@ impl TryInto<GridSettingChangesetParams> for GridSettingChangesetPayload {
|
||||
|
||||
Ok(GridSettingChangesetParams {
|
||||
grid_id: view_id,
|
||||
layout_type: self.layout_type,
|
||||
layout_type: self.layout_type.into(),
|
||||
insert_filter,
|
||||
delete_filter,
|
||||
insert_group,
|
@ -1,8 +1,8 @@
|
||||
use crate::parser::NotEmptyStr;
|
||||
use flowy_derive::ProtoBuf;
|
||||
use flowy_error_code::ErrorCode;
|
||||
|
||||
use crate::revision::GridSortRevision;
|
||||
use flowy_error::ErrorCode;
|
||||
use flowy_grid_data_model::parser::NotEmptyStr;
|
||||
use flowy_grid_data_model::revision::GridSortRevision;
|
||||
use flowy_sync::entities::grid::CreateGridSortParams;
|
||||
use std::convert::TryInto;
|
||||
|
||||
#[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)]
|
||||
@ -50,10 +50,6 @@ pub struct CreateGridSortPayload {
|
||||
pub field_id: Option<String>,
|
||||
}
|
||||
|
||||
pub struct CreateGridSortParams {
|
||||
pub field_id: Option<String>,
|
||||
}
|
||||
|
||||
impl TryInto<CreateGridSortParams> for CreateGridSortPayload {
|
||||
type Error = ErrorCode;
|
||||
|
@ -3,8 +3,8 @@ use crate::manager::GridManager;
|
||||
use crate::services::field::type_options::*;
|
||||
use crate::services::field::{default_type_option_builder_from_type, type_option_builder_from_json_str};
|
||||
use flowy_error::{ErrorCode, FlowyError, FlowyResult};
|
||||
use flowy_grid_data_model::entities::*;
|
||||
use flowy_grid_data_model::revision::FieldRevision;
|
||||
use flowy_sync::entities::grid::{FieldChangesetParams, GridSettingChangesetParams};
|
||||
use lib_dispatch::prelude::{data_result, AppData, Data, DataResult};
|
||||
use std::sync::Arc;
|
||||
|
||||
@ -59,7 +59,12 @@ pub(crate) async fn get_fields_handler(
|
||||
) -> DataResult<RepeatedField, FlowyError> {
|
||||
let params: QueryFieldParams = data.into_inner().try_into()?;
|
||||
let editor = manager.get_grid_editor(¶ms.grid_id)?;
|
||||
let field_orders = params.field_orders.items;
|
||||
let field_orders = params
|
||||
.field_orders
|
||||
.items
|
||||
.into_iter()
|
||||
.map(|field_order| field_order.field_id)
|
||||
.collect();
|
||||
let field_revs = editor.get_field_revs(Some(field_orders)).await?;
|
||||
let repeated_field: RepeatedField = field_revs.into_iter().map(Field::from).collect::<Vec<_>>().into();
|
||||
data_result(repeated_field)
|
||||
@ -126,7 +131,7 @@ pub(crate) async fn switch_to_field_handler(
|
||||
let field_rev = editor
|
||||
.get_field_rev(¶ms.field_id)
|
||||
.await
|
||||
.unwrap_or(editor.next_field_rev(¶ms.field_type).await?);
|
||||
.unwrap_or(Arc::new(editor.next_field_rev(¶ms.field_type).await?));
|
||||
|
||||
let type_option_data = get_type_option_data(&field_rev, ¶ms.field_type).await?;
|
||||
let data = FieldTypeOptionData {
|
||||
@ -160,7 +165,8 @@ pub(crate) async fn get_field_type_option_data_handler(
|
||||
match editor.get_field_rev(¶ms.field_id).await {
|
||||
None => Err(FlowyError::record_not_found()),
|
||||
Some(field_rev) => {
|
||||
let type_option_data = get_type_option_data(&field_rev, &field_rev.field_type).await?;
|
||||
let field_type = field_rev.field_type_rev.into();
|
||||
let type_option_data = get_type_option_data(&field_rev, &field_type).await?;
|
||||
let data = FieldTypeOptionData {
|
||||
grid_id: params.grid_id,
|
||||
field: field_rev.into(),
|
||||
@ -180,7 +186,8 @@ pub(crate) async fn create_field_type_option_data_handler(
|
||||
let params: CreateFieldParams = data.into_inner().try_into()?;
|
||||
let editor = manager.get_grid_editor(¶ms.grid_id)?;
|
||||
let field_rev = editor.create_next_field_rev(¶ms.field_type).await?;
|
||||
let type_option_data = get_type_option_data(&field_rev, &field_rev.field_type).await?;
|
||||
let field_type: FieldType = field_rev.field_type_rev.into();
|
||||
let type_option_data = get_type_option_data(&field_rev, &field_type).await?;
|
||||
|
||||
data_result(FieldTypeOptionData {
|
||||
grid_id: params.grid_id,
|
||||
@ -205,7 +212,8 @@ async fn get_type_option_data(field_rev: &FieldRevision, field_type: &FieldType)
|
||||
let s = field_rev
|
||||
.get_type_option_str(field_type)
|
||||
.unwrap_or_else(|| default_type_option_builder_from_type(field_type).entry().json_str());
|
||||
let builder = type_option_builder_from_json_str(&s, &field_rev.field_type);
|
||||
let field_type: FieldType = field_rev.field_type_rev.into();
|
||||
let builder = type_option_builder_from_json_str(&s, &field_type);
|
||||
let type_option_data = builder.entry().protobuf_bytes().to_vec();
|
||||
|
||||
Ok(type_option_data)
|
||||
@ -213,10 +221,10 @@ async fn get_type_option_data(field_rev: &FieldRevision, field_type: &FieldType)
|
||||
|
||||
#[tracing::instrument(level = "debug", skip(data, manager), err)]
|
||||
pub(crate) async fn get_row_handler(
|
||||
data: Data<RowIdentifierPayload>,
|
||||
data: Data<GridRowIdPayload>,
|
||||
manager: AppData<Arc<GridManager>>,
|
||||
) -> DataResult<OptionalRow, FlowyError> {
|
||||
let params: RowIdentifier = data.into_inner().try_into()?;
|
||||
let params: GridRowId = data.into_inner().try_into()?;
|
||||
let editor = manager.get_grid_editor(¶ms.grid_id)?;
|
||||
let row = OptionalRow {
|
||||
row: editor.get_row(¶ms.row_id).await?,
|
||||
@ -226,10 +234,10 @@ pub(crate) async fn get_row_handler(
|
||||
|
||||
#[tracing::instrument(level = "debug", skip(data, manager), err)]
|
||||
pub(crate) async fn delete_row_handler(
|
||||
data: Data<RowIdentifierPayload>,
|
||||
data: Data<GridRowIdPayload>,
|
||||
manager: AppData<Arc<GridManager>>,
|
||||
) -> Result<(), FlowyError> {
|
||||
let params: RowIdentifier = data.into_inner().try_into()?;
|
||||
let params: GridRowId = data.into_inner().try_into()?;
|
||||
let editor = manager.get_grid_editor(¶ms.grid_id)?;
|
||||
let _ = editor.delete_row(¶ms.row_id).await?;
|
||||
Ok(())
|
||||
@ -237,10 +245,10 @@ pub(crate) async fn delete_row_handler(
|
||||
|
||||
#[tracing::instrument(level = "debug", skip(data, manager), err)]
|
||||
pub(crate) async fn duplicate_row_handler(
|
||||
data: Data<RowIdentifierPayload>,
|
||||
data: Data<GridRowIdPayload>,
|
||||
manager: AppData<Arc<GridManager>>,
|
||||
) -> Result<(), FlowyError> {
|
||||
let params: RowIdentifier = data.into_inner().try_into()?;
|
||||
let params: GridRowId = data.into_inner().try_into()?;
|
||||
let editor = manager.get_grid_editor(¶ms.grid_id)?;
|
||||
let _ = editor.duplicate_row(¶ms.row_id).await?;
|
||||
Ok(())
|
||||
@ -307,7 +315,8 @@ pub(crate) async fn update_select_option_handler(
|
||||
let editor = manager.get_grid_editor(&changeset.cell_identifier.grid_id)?;
|
||||
|
||||
if let Some(mut field_rev) = editor.get_field_rev(&changeset.cell_identifier.field_id).await {
|
||||
let mut type_option = select_option_operation(&field_rev)?;
|
||||
let mut_field_rev = Arc::make_mut(&mut field_rev);
|
||||
let mut type_option = select_option_operation(mut_field_rev)?;
|
||||
let mut cell_content_changeset = None;
|
||||
|
||||
if let Some(option) = changeset.insert_option {
|
||||
@ -324,7 +333,7 @@ pub(crate) async fn update_select_option_handler(
|
||||
type_option.delete_option(option);
|
||||
}
|
||||
|
||||
field_rev.insert_type_option_entry(&*type_option);
|
||||
mut_field_rev.insert_type_option_entry(&*type_option);
|
||||
let _ = editor.replace_field(field_rev).await?;
|
||||
|
||||
let changeset = CellChangeset {
|
||||
|
@ -99,13 +99,13 @@ pub enum GridEvent {
|
||||
#[event(input = "CreateRowPayload", output = "Row")]
|
||||
CreateRow = 50,
|
||||
|
||||
#[event(input = "RowIdentifierPayload", output = "OptionalRow")]
|
||||
#[event(input = "GridRowIdPayload", output = "OptionalRow")]
|
||||
GetRow = 51,
|
||||
|
||||
#[event(input = "RowIdentifierPayload")]
|
||||
#[event(input = "GridRowIdPayload")]
|
||||
DeleteRow = 52,
|
||||
|
||||
#[event(input = "RowIdentifierPayload")]
|
||||
#[event(input = "GridRowIdPayload")]
|
||||
DuplicateRow = 53,
|
||||
|
||||
#[event(input = "CellIdentifierPayload", output = "Cell")]
|
||||
|
@ -30,7 +30,16 @@ macro_rules! impl_type_option {
|
||||
($target: ident, $field_type:expr) => {
|
||||
impl std::convert::From<&FieldRevision> for $target {
|
||||
fn from(field_rev: &FieldRevision) -> $target {
|
||||
match field_rev.get_type_option_entry::<$target>(&$field_type) {
|
||||
match field_rev.get_type_option_entry::<$target, _>(&$field_type) {
|
||||
None => $target::default(),
|
||||
Some(target) => target,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::From<&std::sync::Arc<FieldRevision>> for $target {
|
||||
fn from(field_rev: &std::sync::Arc<FieldRevision>) -> $target {
|
||||
match field_rev.get_type_option_entry::<$target, _>(&$field_type) {
|
||||
None => $target::default(),
|
||||
Some(target) => target,
|
||||
}
|
||||
@ -44,10 +53,6 @@ macro_rules! impl_type_option {
|
||||
}
|
||||
|
||||
impl TypeOptionDataEntry for $target {
|
||||
fn field_type(&self) -> FieldType {
|
||||
$field_type
|
||||
}
|
||||
|
||||
fn json_str(&self) -> String {
|
||||
match serde_json::to_string(&self) {
|
||||
Ok(s) => s,
|
||||
|
@ -1,15 +1,13 @@
|
||||
use crate::dart_notification::{send_dart_notification, GridNotification};
|
||||
use crate::entities::{BlockRowInfo, CellChangeset, GridRowId, GridRowsChangeset, IndexRowOrder, Row, UpdatedRowOrder};
|
||||
use crate::manager::GridUser;
|
||||
use crate::services::block_revision_editor::GridBlockRevisionEditor;
|
||||
use crate::services::persistence::block_index::BlockIndexCache;
|
||||
use crate::services::row::{block_from_row_orders, GridBlockSnapshot};
|
||||
use dashmap::DashMap;
|
||||
use flowy_error::FlowyResult;
|
||||
use flowy_grid_data_model::entities::{
|
||||
CellChangeset, GridRowsChangeset, IndexRowOrder, Row, RowOrder, UpdatedRowOrder,
|
||||
};
|
||||
use flowy_grid_data_model::revision::{
|
||||
CellRevision, GridBlockMetaRevision, GridBlockMetaRevisionChangeset, RowMetaChangeset, RowRevision,
|
||||
GridBlockMetaRevision, GridBlockMetaRevisionChangeset, RowMetaChangeset, RowRevision,
|
||||
};
|
||||
use flowy_revision::disk::SQLiteGridBlockMetaRevisionPersistence;
|
||||
use flowy_revision::{RevisionManager, RevisionPersistence};
|
||||
@ -23,7 +21,7 @@ pub(crate) struct GridBlockManager {
|
||||
grid_id: String,
|
||||
user: Arc<dyn GridUser>,
|
||||
persistence: Arc<BlockIndexCache>,
|
||||
block_editor_map: DashMap<BlockId, Arc<GridBlockRevisionEditor>>,
|
||||
block_editors: DashMap<BlockId, Arc<GridBlockRevisionEditor>>,
|
||||
}
|
||||
|
||||
impl GridBlockManager {
|
||||
@ -33,13 +31,13 @@ impl GridBlockManager {
|
||||
block_meta_revs: Vec<Arc<GridBlockMetaRevision>>,
|
||||
persistence: Arc<BlockIndexCache>,
|
||||
) -> FlowyResult<Self> {
|
||||
let editor_map = make_block_meta_editor_map(user, block_meta_revs).await?;
|
||||
let block_editors = make_block_editors(user, block_meta_revs).await?;
|
||||
let user = user.clone();
|
||||
let grid_id = grid_id.to_owned();
|
||||
let manager = Self {
|
||||
grid_id,
|
||||
user,
|
||||
block_editor_map: editor_map,
|
||||
block_editors,
|
||||
persistence,
|
||||
};
|
||||
Ok(manager)
|
||||
@ -48,11 +46,11 @@ impl GridBlockManager {
|
||||
// #[tracing::instrument(level = "trace", skip(self))]
|
||||
pub(crate) async fn get_editor(&self, block_id: &str) -> FlowyResult<Arc<GridBlockRevisionEditor>> {
|
||||
debug_assert!(!block_id.is_empty());
|
||||
match self.block_editor_map.get(block_id) {
|
||||
match self.block_editors.get(block_id) {
|
||||
None => {
|
||||
tracing::error!("This is a fatal error, block with id:{} is not exist", block_id);
|
||||
let editor = Arc::new(make_block_meta_editor(&self.user, block_id).await?);
|
||||
self.block_editor_map.insert(block_id.to_owned(), editor.clone());
|
||||
let editor = Arc::new(make_block_editor(&self.user, block_id).await?);
|
||||
self.block_editors.insert(block_id.to_owned(), editor.clone());
|
||||
Ok(editor)
|
||||
}
|
||||
Some(editor) => Ok(editor.clone()),
|
||||
@ -135,12 +133,18 @@ impl GridBlockManager {
|
||||
let row_id = row_id.to_owned();
|
||||
let block_id = self.persistence.get_block_id(&row_id)?;
|
||||
let editor = self.get_editor(&block_id).await?;
|
||||
match editor.get_row_order(&row_id).await? {
|
||||
match editor.get_row_info(&row_id).await? {
|
||||
None => {}
|
||||
Some(row_order) => {
|
||||
Some(row_info) => {
|
||||
let _ = editor.delete_rows(vec![Cow::Borrowed(&row_id)]).await?;
|
||||
|
||||
let row_identifier = GridRowId {
|
||||
grid_id: self.grid_id.clone(),
|
||||
block_id: row_info.block_id,
|
||||
row_id: row_info.row_id,
|
||||
};
|
||||
let _ = self
|
||||
.notify_did_update_block(&block_id, GridRowsChangeset::delete(&block_id, vec![row_order]))
|
||||
.notify_did_update_block(&block_id, GridRowsChangeset::delete(&block_id, vec![row_identifier]))
|
||||
.await?;
|
||||
}
|
||||
}
|
||||
@ -150,18 +154,18 @@ impl GridBlockManager {
|
||||
|
||||
pub(crate) async fn delete_rows(
|
||||
&self,
|
||||
row_orders: Vec<RowOrder>,
|
||||
row_orders: Vec<BlockRowInfo>,
|
||||
) -> FlowyResult<Vec<GridBlockMetaRevisionChangeset>> {
|
||||
let mut changesets = vec![];
|
||||
for block_order in block_from_row_orders(row_orders) {
|
||||
let editor = self.get_editor(&block_order.id).await?;
|
||||
let row_ids = block_order
|
||||
.row_orders
|
||||
for grid_block in block_from_row_orders(row_orders) {
|
||||
let editor = self.get_editor(&grid_block.id).await?;
|
||||
let row_ids = grid_block
|
||||
.row_infos
|
||||
.into_iter()
|
||||
.map(|row_order| Cow::Owned(row_order.row_id))
|
||||
.map(|row_info| Cow::Owned(row_info.row_id().to_owned()))
|
||||
.collect::<Vec<Cow<String>>>();
|
||||
let row_count = editor.delete_rows(row_ids).await?;
|
||||
let changeset = GridBlockMetaRevisionChangeset::from_row_count(&block_order.id, row_count);
|
||||
let changeset = GridBlockMetaRevisionChangeset::from_row_count(&grid_block.id, row_count);
|
||||
changesets.push(changeset);
|
||||
}
|
||||
|
||||
@ -175,15 +179,21 @@ impl GridBlockManager {
|
||||
match editor.get_row_revs(Some(vec![Cow::Borrowed(row_id)])).await?.pop() {
|
||||
None => {}
|
||||
Some(row_rev) => {
|
||||
let row_order = RowOrder::from(&row_rev);
|
||||
let row_info = BlockRowInfo::from(&row_rev);
|
||||
let insert_row = IndexRowOrder {
|
||||
row_order: row_order.clone(),
|
||||
row_info: row_info.clone(),
|
||||
index: Some(to as i32),
|
||||
};
|
||||
|
||||
let deleted_row = GridRowId {
|
||||
grid_id: self.grid_id.clone(),
|
||||
block_id: row_info.block_id,
|
||||
row_id: row_info.row_id,
|
||||
};
|
||||
let notified_changeset = GridRowsChangeset {
|
||||
block_id: editor.block_id.clone(),
|
||||
inserted_rows: vec![insert_row],
|
||||
deleted_rows: vec![row_order],
|
||||
deleted_rows: vec![deleted_row],
|
||||
updated_rows: vec![],
|
||||
};
|
||||
|
||||
@ -217,38 +227,36 @@ impl GridBlockManager {
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn get_row_orders(&self, block_id: &str) -> FlowyResult<Vec<RowOrder>> {
|
||||
pub async fn get_row_orders(&self, block_id: &str) -> FlowyResult<Vec<BlockRowInfo>> {
|
||||
let editor = self.get_editor(block_id).await?;
|
||||
editor.get_row_orders::<&str>(None).await
|
||||
editor.get_row_infos::<&str>(None).await
|
||||
}
|
||||
|
||||
pub(crate) async fn make_block_snapshots(&self, block_ids: Vec<String>) -> FlowyResult<Vec<GridBlockSnapshot>> {
|
||||
pub(crate) async fn get_block_snapshots(
|
||||
&self,
|
||||
block_ids: Option<Vec<String>>,
|
||||
) -> FlowyResult<Vec<GridBlockSnapshot>> {
|
||||
let mut snapshots = vec![];
|
||||
for block_id in block_ids {
|
||||
let editor = self.get_editor(&block_id).await?;
|
||||
let row_revs = editor.get_row_revs::<&str>(None).await?;
|
||||
snapshots.push(GridBlockSnapshot { block_id, row_revs });
|
||||
match block_ids {
|
||||
None => {
|
||||
for iter in self.block_editors.iter() {
|
||||
let editor = iter.value();
|
||||
let block_id = editor.block_id.clone();
|
||||
let row_revs = editor.get_row_revs::<&str>(None).await?;
|
||||
snapshots.push(GridBlockSnapshot { block_id, row_revs });
|
||||
}
|
||||
}
|
||||
Some(block_ids) => {
|
||||
for block_id in block_ids {
|
||||
let editor = self.get_editor(&block_id).await?;
|
||||
let row_revs = editor.get_row_revs::<&str>(None).await?;
|
||||
snapshots.push(GridBlockSnapshot { block_id, row_revs });
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(snapshots)
|
||||
}
|
||||
|
||||
// Optimization: Using the shared memory(Arc, Cow,etc.) to reduce memory usage.
|
||||
#[allow(dead_code)]
|
||||
pub async fn get_cell_revs(
|
||||
&self,
|
||||
block_ids: Vec<String>,
|
||||
field_id: &str,
|
||||
row_ids: Option<Vec<Cow<'_, String>>>,
|
||||
) -> FlowyResult<Vec<CellRevision>> {
|
||||
let mut block_cell_revs = vec![];
|
||||
for block_id in block_ids {
|
||||
let editor = self.get_editor(&block_id).await?;
|
||||
let cell_revs = editor.get_cell_revs(field_id, row_ids.clone()).await?;
|
||||
block_cell_revs.extend(cell_revs);
|
||||
}
|
||||
Ok(block_cell_revs)
|
||||
}
|
||||
|
||||
async fn notify_did_update_block(&self, block_id: &str, changeset: GridRowsChangeset) -> FlowyResult<()> {
|
||||
send_dart_notification(block_id, GridNotification::DidUpdateGridBlock)
|
||||
.payload(changeset)
|
||||
@ -263,20 +271,20 @@ impl GridBlockManager {
|
||||
}
|
||||
}
|
||||
|
||||
async fn make_block_meta_editor_map(
|
||||
async fn make_block_editors(
|
||||
user: &Arc<dyn GridUser>,
|
||||
block_meta_revs: Vec<Arc<GridBlockMetaRevision>>,
|
||||
) -> FlowyResult<DashMap<String, Arc<GridBlockRevisionEditor>>> {
|
||||
let editor_map = DashMap::new();
|
||||
for block_meta_rev in block_meta_revs {
|
||||
let editor = make_block_meta_editor(user, &block_meta_rev.block_id).await?;
|
||||
let editor = make_block_editor(user, &block_meta_rev.block_id).await?;
|
||||
editor_map.insert(block_meta_rev.block_id.clone(), Arc::new(editor));
|
||||
}
|
||||
|
||||
Ok(editor_map)
|
||||
}
|
||||
|
||||
async fn make_block_meta_editor(user: &Arc<dyn GridUser>, block_id: &str) -> FlowyResult<GridBlockRevisionEditor> {
|
||||
async fn make_block_editor(user: &Arc<dyn GridUser>, block_id: &str) -> FlowyResult<GridBlockRevisionEditor> {
|
||||
tracing::trace!("Open block:{} meta editor", block_id);
|
||||
let token = user.token()?;
|
||||
let user_id = user.user_id()?;
|
||||
|
@ -1,6 +1,6 @@
|
||||
use crate::entities::BlockRowInfo;
|
||||
use bytes::Bytes;
|
||||
use flowy_error::{FlowyError, FlowyResult};
|
||||
use flowy_grid_data_model::entities::RowOrder;
|
||||
use flowy_grid_data_model::revision::{CellRevision, GridBlockRevision, RowMetaChangeset, RowRevision};
|
||||
use flowy_revision::{RevisionCloudService, RevisionCompactor, RevisionManager, RevisionObjectBuilder};
|
||||
use flowy_sync::client_grid::{GridBlockMetaChange, GridBlockRevisionPad};
|
||||
@ -123,24 +123,24 @@ impl GridBlockRevisionEditor {
|
||||
Ok(cell_revs)
|
||||
}
|
||||
|
||||
pub async fn get_row_order(&self, row_id: &str) -> FlowyResult<Option<RowOrder>> {
|
||||
pub async fn get_row_info(&self, row_id: &str) -> FlowyResult<Option<BlockRowInfo>> {
|
||||
let row_ids = Some(vec![Cow::Borrowed(row_id)]);
|
||||
Ok(self.get_row_orders(row_ids).await?.pop())
|
||||
Ok(self.get_row_infos(row_ids).await?.pop())
|
||||
}
|
||||
|
||||
pub async fn get_row_orders<T>(&self, row_ids: Option<Vec<Cow<'_, T>>>) -> FlowyResult<Vec<RowOrder>>
|
||||
pub async fn get_row_infos<T>(&self, row_ids: Option<Vec<Cow<'_, T>>>) -> FlowyResult<Vec<BlockRowInfo>>
|
||||
where
|
||||
T: AsRef<str> + ToOwned + ?Sized,
|
||||
{
|
||||
let row_orders = self
|
||||
let row_infos = self
|
||||
.pad
|
||||
.read()
|
||||
.await
|
||||
.get_row_revs(row_ids)?
|
||||
.iter()
|
||||
.map(RowOrder::from)
|
||||
.collect::<Vec<RowOrder>>();
|
||||
Ok(row_orders)
|
||||
.map(BlockRowInfo::from)
|
||||
.collect::<Vec<BlockRowInfo>>();
|
||||
Ok(row_infos)
|
||||
}
|
||||
|
||||
async fn modify<F>(&self, f: F) -> FlowyResult<()>
|
||||
|
@ -1,6 +1,6 @@
|
||||
use crate::entities::{Field, FieldType};
|
||||
use crate::services::field::type_options::*;
|
||||
use bytes::Bytes;
|
||||
use flowy_grid_data_model::entities::{Field, FieldType};
|
||||
use flowy_grid_data_model::revision::{FieldRevision, TypeOptionDataEntry};
|
||||
use indexmap::IndexMap;
|
||||
|
||||
@ -14,7 +14,9 @@ pub type BoxTypeOptionBuilder = Box<dyn TypeOptionBuilder + 'static>;
|
||||
impl FieldBuilder {
|
||||
pub fn new<T: Into<BoxTypeOptionBuilder>>(type_option_builder: T) -> Self {
|
||||
let type_option_builder = type_option_builder.into();
|
||||
let field_rev = FieldRevision::new("", "", type_option_builder.field_type(), false);
|
||||
let field_type = type_option_builder.field_type();
|
||||
let width = field_type.default_cell_width();
|
||||
let field_rev = FieldRevision::new("", "", field_type, width, false);
|
||||
Self {
|
||||
field_rev,
|
||||
type_option_builder,
|
||||
@ -31,7 +33,7 @@ impl FieldBuilder {
|
||||
id: field.id,
|
||||
name: field.name,
|
||||
desc: field.desc,
|
||||
field_type: field.field_type,
|
||||
field_type_rev: field.field_type.into(),
|
||||
frozen: field.frozen,
|
||||
visibility: field.visibility,
|
||||
width: field.width,
|
||||
@ -75,7 +77,6 @@ impl FieldBuilder {
|
||||
}
|
||||
|
||||
pub fn build(self) -> FieldRevision {
|
||||
debug_assert_eq!(self.field_rev.field_type, self.type_option_builder.field_type());
|
||||
let mut field_rev = self.field_rev;
|
||||
field_rev.insert_type_option_entry(self.type_option_builder.entry());
|
||||
field_rev
|
||||
|
@ -1,10 +1,10 @@
|
||||
use crate::entities::{FieldType, GridCheckboxFilter};
|
||||
use crate::impl_type_option;
|
||||
use crate::services::field::{BoxTypeOptionBuilder, TypeOptionBuilder};
|
||||
use crate::services::row::{CellContentChangeset, CellDataOperation, DecodedCellData};
|
||||
use bytes::Bytes;
|
||||
use flowy_derive::ProtoBuf;
|
||||
use flowy_error::{FlowyError, FlowyResult};
|
||||
use flowy_grid_data_model::entities::FieldType;
|
||||
use flowy_grid_data_model::revision::{CellRevision, FieldRevision, TypeOptionDataDeserializer, TypeOptionDataEntry};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
@ -22,7 +22,7 @@ impl CheckboxTypeOptionBuilder {
|
||||
|
||||
impl TypeOptionBuilder for CheckboxTypeOptionBuilder {
|
||||
fn field_type(&self) -> FieldType {
|
||||
self.0.field_type()
|
||||
FieldType::Checkbox
|
||||
}
|
||||
|
||||
fn entry(&self) -> &dyn TypeOptionDataEntry {
|
||||
@ -40,7 +40,7 @@ impl_type_option!(CheckboxTypeOption, FieldType::Checkbox);
|
||||
const YES: &str = "Yes";
|
||||
const NO: &str = "No";
|
||||
|
||||
impl CellDataOperation<String> for CheckboxTypeOption {
|
||||
impl CellDataOperation<String, GridCheckboxFilter> for CheckboxTypeOption {
|
||||
fn decode_cell_data<T>(
|
||||
&self,
|
||||
encoded_data: T,
|
||||
@ -62,6 +62,10 @@ impl CellDataOperation<String> for CheckboxTypeOption {
|
||||
Ok(DecodedCellData::default())
|
||||
}
|
||||
|
||||
fn apply_filter(&self, _filter: GridCheckboxFilter) -> bool {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn apply_changeset<C>(&self, changeset: C, _cell_rev: Option<CellRevision>) -> Result<String, FlowyError>
|
||||
where
|
||||
C: Into<CellContentChangeset>,
|
||||
@ -95,7 +99,7 @@ mod tests {
|
||||
use crate::services::field::FieldBuilder;
|
||||
use crate::services::row::{apply_cell_data_changeset, decode_cell_data};
|
||||
|
||||
use flowy_grid_data_model::entities::FieldType;
|
||||
use crate::entities::FieldType;
|
||||
|
||||
#[test]
|
||||
fn checkout_box_description_test() {
|
||||
|
@ -1,3 +1,4 @@
|
||||
use crate::entities::{CellChangeset, FieldType, GridDateFilter};
|
||||
use crate::entities::{CellIdentifier, CellIdentifierPayload};
|
||||
use crate::impl_type_option;
|
||||
use crate::services::field::{BoxTypeOptionBuilder, TypeOptionBuilder};
|
||||
@ -7,7 +8,6 @@ use chrono::format::strftime::StrftimeItems;
|
||||
use chrono::{NaiveDateTime, Timelike};
|
||||
use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
|
||||
use flowy_error::{ErrorCode, FlowyError, FlowyResult};
|
||||
use flowy_grid_data_model::entities::{CellChangeset, FieldType};
|
||||
use flowy_grid_data_model::revision::{CellRevision, FieldRevision, TypeOptionDataDeserializer, TypeOptionDataEntry};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use strum_macros::EnumIter;
|
||||
@ -115,7 +115,7 @@ impl DateTypeOption {
|
||||
}
|
||||
}
|
||||
|
||||
impl CellDataOperation<String> for DateTypeOption {
|
||||
impl CellDataOperation<String, GridDateFilter> for DateTypeOption {
|
||||
fn decode_cell_data<T>(
|
||||
&self,
|
||||
encoded_data: T,
|
||||
@ -138,6 +138,10 @@ impl CellDataOperation<String> for DateTypeOption {
|
||||
DecodedCellData::try_from_bytes(date)
|
||||
}
|
||||
|
||||
fn apply_filter(&self, _filter: GridDateFilter) -> bool {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn apply_changeset<C>(&self, changeset: C, _cell_rev: Option<CellRevision>) -> Result<String, FlowyError>
|
||||
where
|
||||
C: Into<CellContentChangeset>,
|
||||
@ -177,7 +181,7 @@ impl DateTypeOptionBuilder {
|
||||
}
|
||||
impl TypeOptionBuilder for DateTypeOptionBuilder {
|
||||
fn field_type(&self) -> FieldType {
|
||||
self.0.field_type()
|
||||
FieldType::DateTime
|
||||
}
|
||||
|
||||
fn entry(&self) -> &dyn TypeOptionDataEntry {
|
||||
@ -354,11 +358,11 @@ impl std::convert::From<DateCellContentChangeset> for CellContentChangeset {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::entities::FieldType;
|
||||
use crate::services::field::FieldBuilder;
|
||||
use crate::services::field::{DateCellContentChangeset, DateCellData, DateFormat, DateTypeOption, TimeFormat};
|
||||
use crate::services::row::CellDataOperation;
|
||||
use flowy_grid_data_model::entities::FieldType;
|
||||
use flowy_grid_data_model::revision::{FieldRevision, TypeOptionDataEntry};
|
||||
use flowy_grid_data_model::revision::FieldRevision;
|
||||
use strum::IntoEnumIterator;
|
||||
|
||||
#[test]
|
||||
@ -530,7 +534,7 @@ mod tests {
|
||||
fn date_type_option_apply_changeset_error_test() {
|
||||
let mut type_option = DateTypeOption::new();
|
||||
type_option.include_time = true;
|
||||
let field_rev = FieldBuilder::from_field_type(&type_option.field_type()).build();
|
||||
let field_rev = FieldBuilder::from_field_type(&FieldType::DateTime).build();
|
||||
let date_timestamp = "1653609600".to_owned();
|
||||
|
||||
assert_changeset_result(
|
||||
@ -539,7 +543,7 @@ mod tests {
|
||||
date: Some(date_timestamp.clone()),
|
||||
time: Some("1:".to_owned()),
|
||||
},
|
||||
&type_option.field_type(),
|
||||
&FieldType::DateTime,
|
||||
&field_rev,
|
||||
"May 27,2022 01:00",
|
||||
);
|
||||
@ -550,7 +554,7 @@ mod tests {
|
||||
date: Some(date_timestamp),
|
||||
time: Some("1:00".to_owned()),
|
||||
},
|
||||
&type_option.field_type(),
|
||||
&FieldType::DateTime,
|
||||
&field_rev,
|
||||
"May 27,2022 01:00",
|
||||
);
|
||||
@ -561,7 +565,7 @@ mod tests {
|
||||
fn date_type_option_twelve_hours_to_twenty_four_hours() {
|
||||
let mut type_option = DateTypeOption::new();
|
||||
type_option.include_time = true;
|
||||
let field_rev = FieldBuilder::from_field_type(&type_option.field_type()).build();
|
||||
let field_rev = FieldBuilder::from_field_type(&FieldType::DateTime).build();
|
||||
let date_timestamp = "1653609600".to_owned();
|
||||
|
||||
assert_changeset_result(
|
||||
@ -570,7 +574,7 @@ mod tests {
|
||||
date: Some(date_timestamp),
|
||||
time: Some("1:00 am".to_owned()),
|
||||
},
|
||||
&type_option.field_type(),
|
||||
&FieldType::DateTime,
|
||||
&field_rev,
|
||||
"May 27,2022 01:00",
|
||||
);
|
||||
|
@ -15,7 +15,7 @@ lazy_static! {
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, EnumIter, Serialize, Deserialize, ProtoBuf_Enum)]
|
||||
pub enum NumberFormat {
|
||||
Number = 0,
|
||||
Num = 0,
|
||||
USD = 1,
|
||||
CanadianDollar = 2,
|
||||
EUR = 4,
|
||||
@ -55,7 +55,7 @@ pub enum NumberFormat {
|
||||
|
||||
impl std::default::Default for NumberFormat {
|
||||
fn default() -> Self {
|
||||
NumberFormat::Number
|
||||
NumberFormat::Num
|
||||
}
|
||||
}
|
||||
|
||||
@ -400,7 +400,7 @@ define_currency_set!(
|
||||
impl NumberFormat {
|
||||
pub fn currency(&self) -> &'static number_currency::Currency {
|
||||
match self {
|
||||
NumberFormat::Number => number_currency::NUMBER,
|
||||
NumberFormat::Num => number_currency::NUMBER,
|
||||
NumberFormat::USD => number_currency::USD,
|
||||
NumberFormat::CanadianDollar => number_currency::CANADIAN_DOLLAR,
|
||||
NumberFormat::EUR => number_currency::EUR,
|
||||
|
@ -1,12 +1,12 @@
|
||||
use crate::impl_type_option;
|
||||
|
||||
use crate::entities::{FieldType, GridNumberFilter};
|
||||
use crate::services::field::type_options::number_type_option::format::*;
|
||||
use crate::services::field::{BoxTypeOptionBuilder, TypeOptionBuilder};
|
||||
use crate::services::row::{CellContentChangeset, CellDataOperation, DecodedCellData};
|
||||
use bytes::Bytes;
|
||||
use flowy_derive::ProtoBuf;
|
||||
use flowy_error::{FlowyError, FlowyResult};
|
||||
use flowy_grid_data_model::entities::FieldType;
|
||||
use flowy_grid_data_model::revision::{CellRevision, FieldRevision, TypeOptionDataDeserializer, TypeOptionDataEntry};
|
||||
use rust_decimal::Decimal;
|
||||
use serde::{Deserialize, Serialize};
|
||||
@ -41,7 +41,7 @@ impl NumberTypeOptionBuilder {
|
||||
|
||||
impl TypeOptionBuilder for NumberTypeOptionBuilder {
|
||||
fn field_type(&self) -> FieldType {
|
||||
self.0.field_type()
|
||||
FieldType::Number
|
||||
}
|
||||
|
||||
fn entry(&self) -> &dyn TypeOptionDataEntry {
|
||||
@ -76,7 +76,7 @@ impl NumberTypeOption {
|
||||
|
||||
fn cell_content_from_number_str(&self, s: &str) -> FlowyResult<String> {
|
||||
match self.format {
|
||||
NumberFormat::Number => {
|
||||
NumberFormat::Num => {
|
||||
if let Ok(v) = s.parse::<f64>() {
|
||||
return Ok(v.to_string());
|
||||
}
|
||||
@ -139,7 +139,7 @@ impl NumberTypeOption {
|
||||
}
|
||||
}
|
||||
|
||||
impl CellDataOperation<String> for NumberTypeOption {
|
||||
impl CellDataOperation<String, GridNumberFilter> for NumberTypeOption {
|
||||
fn decode_cell_data<T>(
|
||||
&self,
|
||||
encoded_data: T,
|
||||
@ -155,7 +155,7 @@ impl CellDataOperation<String> for NumberTypeOption {
|
||||
|
||||
let cell_data = encoded_data.into();
|
||||
match self.format {
|
||||
NumberFormat::Number => {
|
||||
NumberFormat::Num => {
|
||||
if let Ok(v) = cell_data.parse::<f64>() {
|
||||
return Ok(DecodedCellData::new(v.to_string()));
|
||||
}
|
||||
@ -179,6 +179,10 @@ impl CellDataOperation<String> for NumberTypeOption {
|
||||
}
|
||||
}
|
||||
|
||||
fn apply_filter(&self, _filter: GridNumberFilter) -> bool {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn apply_changeset<C>(&self, changeset: C, _cell_rev: Option<CellRevision>) -> Result<String, FlowyError>
|
||||
where
|
||||
C: Into<CellContentChangeset>,
|
||||
@ -206,10 +210,10 @@ impl std::default::Default for NumberTypeOption {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::entities::FieldType;
|
||||
use crate::services::field::FieldBuilder;
|
||||
use crate::services::field::{NumberFormat, NumberTypeOption};
|
||||
use crate::services::row::CellDataOperation;
|
||||
use flowy_grid_data_model::entities::FieldType;
|
||||
use flowy_grid_data_model::revision::FieldRevision;
|
||||
use strum::IntoEnumIterator;
|
||||
|
||||
@ -241,7 +245,7 @@ mod tests {
|
||||
for format in NumberFormat::iter() {
|
||||
type_option.format = format;
|
||||
match format {
|
||||
NumberFormat::Number => {
|
||||
NumberFormat::Num => {
|
||||
assert_equal(&type_option, "18443", "18443", &field_type, &field_rev);
|
||||
}
|
||||
NumberFormat::USD => {
|
||||
@ -270,7 +274,7 @@ mod tests {
|
||||
for format in NumberFormat::iter() {
|
||||
type_option.format = format;
|
||||
match format {
|
||||
NumberFormat::Number => {
|
||||
NumberFormat::Num => {
|
||||
assert_equal(&type_option, "18443", "18443", &field_type, &field_rev);
|
||||
assert_equal(&type_option, "0.2", "0.2", &field_type, &field_rev);
|
||||
}
|
||||
@ -310,7 +314,7 @@ mod tests {
|
||||
for format in NumberFormat::iter() {
|
||||
type_option.format = format;
|
||||
match format {
|
||||
NumberFormat::Number => {
|
||||
NumberFormat::Num => {
|
||||
assert_equal(&type_option, "18443", "18443", &field_type, &field_rev);
|
||||
}
|
||||
NumberFormat::USD => {
|
||||
|
@ -1,3 +1,4 @@
|
||||
use crate::entities::{CellChangeset, FieldType, GridSelectOptionFilter};
|
||||
use crate::entities::{CellIdentifier, CellIdentifierPayload};
|
||||
use crate::impl_type_option;
|
||||
use crate::services::field::type_options::util::get_cell_data;
|
||||
@ -6,7 +7,6 @@ use crate::services::row::{CellContentChangeset, CellDataOperation, DecodedCellD
|
||||
use bytes::Bytes;
|
||||
use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
|
||||
use flowy_error::{ErrorCode, FlowyError, FlowyResult};
|
||||
use flowy_grid_data_model::entities::{CellChangeset, FieldType};
|
||||
use flowy_grid_data_model::parser::NotEmptyStr;
|
||||
use flowy_grid_data_model::revision::{CellRevision, FieldRevision, TypeOptionDataDeserializer, TypeOptionDataEntry};
|
||||
use nanoid::nanoid;
|
||||
@ -49,7 +49,8 @@ pub trait SelectOptionOperation: TypeOptionDataEntry + Send + Sync {
|
||||
}
|
||||
|
||||
pub fn select_option_operation(field_rev: &FieldRevision) -> FlowyResult<Box<dyn SelectOptionOperation>> {
|
||||
match &field_rev.field_type {
|
||||
let field_type: FieldType = field_rev.field_type_rev.into();
|
||||
match &field_type {
|
||||
FieldType::SingleSelect => {
|
||||
let type_option = SingleSelectTypeOption::from(field_rev);
|
||||
Ok(Box::new(type_option))
|
||||
@ -94,7 +95,7 @@ impl SelectOptionOperation for SingleSelectTypeOption {
|
||||
}
|
||||
}
|
||||
|
||||
impl CellDataOperation<String> for SingleSelectTypeOption {
|
||||
impl CellDataOperation<String, GridSelectOptionFilter> for SingleSelectTypeOption {
|
||||
fn decode_cell_data<T>(
|
||||
&self,
|
||||
encoded_data: T,
|
||||
@ -122,6 +123,10 @@ impl CellDataOperation<String> for SingleSelectTypeOption {
|
||||
DecodedCellData::try_from_bytes(cell_data)
|
||||
}
|
||||
|
||||
fn apply_filter(&self, _filter: GridSelectOptionFilter) -> bool {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn apply_changeset<C>(&self, changeset: C, _cell_rev: Option<CellRevision>) -> Result<String, FlowyError>
|
||||
where
|
||||
C: Into<CellContentChangeset>,
|
||||
@ -155,7 +160,7 @@ impl SingleSelectTypeOptionBuilder {
|
||||
|
||||
impl TypeOptionBuilder for SingleSelectTypeOptionBuilder {
|
||||
fn field_type(&self) -> FieldType {
|
||||
self.0.field_type()
|
||||
FieldType::SingleSelect
|
||||
}
|
||||
|
||||
fn entry(&self) -> &dyn TypeOptionDataEntry {
|
||||
@ -192,7 +197,7 @@ impl SelectOptionOperation for MultiSelectTypeOption {
|
||||
}
|
||||
}
|
||||
|
||||
impl CellDataOperation<String> for MultiSelectTypeOption {
|
||||
impl CellDataOperation<String, GridSelectOptionFilter> for MultiSelectTypeOption {
|
||||
fn decode_cell_data<T>(
|
||||
&self,
|
||||
encoded_data: T,
|
||||
@ -220,6 +225,10 @@ impl CellDataOperation<String> for MultiSelectTypeOption {
|
||||
DecodedCellData::try_from_bytes(cell_data)
|
||||
}
|
||||
|
||||
fn apply_filter(&self, _filter: GridSelectOptionFilter) -> bool {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn apply_changeset<T>(&self, changeset: T, cell_rev: Option<CellRevision>) -> Result<String, FlowyError>
|
||||
where
|
||||
T: Into<CellContentChangeset>,
|
||||
@ -269,7 +278,7 @@ impl MultiSelectTypeOptionBuilder {
|
||||
|
||||
impl TypeOptionBuilder for MultiSelectTypeOptionBuilder {
|
||||
fn field_type(&self) -> FieldType {
|
||||
self.0.field_type()
|
||||
FieldType::MultiSelect
|
||||
}
|
||||
|
||||
fn entry(&self) -> &dyn TypeOptionDataEntry {
|
||||
@ -502,6 +511,7 @@ fn make_select_context_from(cell_rev: &Option<CellRevision>, options: &[SelectOp
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::entities::FieldType;
|
||||
use crate::services::field::FieldBuilder;
|
||||
use crate::services::field::{
|
||||
MultiSelectTypeOption, MultiSelectTypeOptionBuilder, SelectOption, SelectOptionCellContentChangeset,
|
||||
@ -606,10 +616,11 @@ mod tests {
|
||||
field_rev: &FieldRevision,
|
||||
expected: Vec<SelectOption>,
|
||||
) {
|
||||
let field_type: FieldType = field_rev.field_type_rev.into();
|
||||
assert_eq!(
|
||||
expected,
|
||||
type_option
|
||||
.decode_cell_data(cell_data, &field_rev.field_type, field_rev)
|
||||
.decode_cell_data(cell_data, &field_type, field_rev)
|
||||
.unwrap()
|
||||
.parse::<SelectOptionCellData>()
|
||||
.unwrap()
|
||||
@ -623,10 +634,11 @@ mod tests {
|
||||
field_rev: &FieldRevision,
|
||||
expected: Vec<SelectOption>,
|
||||
) {
|
||||
let field_type: FieldType = field_rev.field_type_rev.into();
|
||||
assert_eq!(
|
||||
expected,
|
||||
type_option
|
||||
.decode_cell_data(cell_data, &field_rev.field_type, field_rev)
|
||||
.decode_cell_data(cell_data, &field_type, field_rev)
|
||||
.unwrap()
|
||||
.parse::<SelectOptionCellData>()
|
||||
.unwrap()
|
||||
|
@ -1,10 +1,10 @@
|
||||
use crate::entities::{FieldType, GridTextFilter};
|
||||
use crate::impl_type_option;
|
||||
use crate::services::field::{BoxTypeOptionBuilder, TypeOptionBuilder};
|
||||
use crate::services::row::{try_decode_cell_data, CellContentChangeset, CellDataOperation, DecodedCellData};
|
||||
use bytes::Bytes;
|
||||
use flowy_derive::ProtoBuf;
|
||||
use flowy_error::{FlowyError, FlowyResult};
|
||||
use flowy_grid_data_model::entities::FieldType;
|
||||
use flowy_grid_data_model::revision::{CellRevision, FieldRevision, TypeOptionDataDeserializer, TypeOptionDataEntry};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
@ -15,7 +15,7 @@ impl_builder_from_json_str_and_from_bytes!(RichTextTypeOptionBuilder, RichTextTy
|
||||
|
||||
impl TypeOptionBuilder for RichTextTypeOptionBuilder {
|
||||
fn field_type(&self) -> FieldType {
|
||||
self.0.field_type()
|
||||
FieldType::RichText
|
||||
}
|
||||
|
||||
fn entry(&self) -> &dyn TypeOptionDataEntry {
|
||||
@ -30,7 +30,7 @@ pub struct RichTextTypeOption {
|
||||
}
|
||||
impl_type_option!(RichTextTypeOption, FieldType::RichText);
|
||||
|
||||
impl CellDataOperation<String> for RichTextTypeOption {
|
||||
impl CellDataOperation<String, GridTextFilter> for RichTextTypeOption {
|
||||
fn decode_cell_data<T>(
|
||||
&self,
|
||||
encoded_data: T,
|
||||
@ -45,13 +45,17 @@ impl CellDataOperation<String> for RichTextTypeOption {
|
||||
|| decoded_field_type.is_multi_select()
|
||||
|| decoded_field_type.is_number()
|
||||
{
|
||||
try_decode_cell_data(encoded_data, field_rev, decoded_field_type, decoded_field_type)
|
||||
try_decode_cell_data(encoded_data.into(), field_rev, decoded_field_type, decoded_field_type)
|
||||
} else {
|
||||
let cell_data = encoded_data.into();
|
||||
Ok(DecodedCellData::new(cell_data))
|
||||
}
|
||||
}
|
||||
|
||||
fn apply_filter(&self, _filter: GridTextFilter) -> bool {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn apply_changeset<C>(&self, changeset: C, _cell_rev: Option<CellRevision>) -> Result<String, FlowyError>
|
||||
where
|
||||
C: Into<CellContentChangeset>,
|
||||
@ -67,10 +71,10 @@ impl CellDataOperation<String> for RichTextTypeOption {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::entities::FieldType;
|
||||
use crate::services::field::FieldBuilder;
|
||||
use crate::services::field::*;
|
||||
use crate::services::row::CellDataOperation;
|
||||
use flowy_grid_data_model::entities::FieldType;
|
||||
|
||||
#[test]
|
||||
fn text_description_test() {
|
||||
|
@ -1,3 +1,4 @@
|
||||
use crate::entities::{FieldType, GridTextFilter};
|
||||
use crate::impl_type_option;
|
||||
use crate::services::field::{BoxTypeOptionBuilder, TypeOptionBuilder};
|
||||
use crate::services::row::{CellContentChangeset, CellDataOperation, DecodedCellData, EncodedCellData};
|
||||
@ -5,7 +6,6 @@ use bytes::Bytes;
|
||||
use fancy_regex::Regex;
|
||||
use flowy_derive::ProtoBuf;
|
||||
use flowy_error::{internal_error, FlowyError, FlowyResult};
|
||||
use flowy_grid_data_model::entities::FieldType;
|
||||
use flowy_grid_data_model::revision::{CellRevision, FieldRevision, TypeOptionDataDeserializer, TypeOptionDataEntry};
|
||||
use lazy_static::lazy_static;
|
||||
use serde::{Deserialize, Serialize};
|
||||
@ -18,7 +18,7 @@ impl_builder_from_json_str_and_from_bytes!(URLTypeOptionBuilder, URLTypeOption);
|
||||
|
||||
impl TypeOptionBuilder for URLTypeOptionBuilder {
|
||||
fn field_type(&self) -> FieldType {
|
||||
self.0.field_type()
|
||||
FieldType::URL
|
||||
}
|
||||
|
||||
fn entry(&self) -> &dyn TypeOptionDataEntry {
|
||||
@ -33,7 +33,7 @@ pub struct URLTypeOption {
|
||||
}
|
||||
impl_type_option!(URLTypeOption, FieldType::URL);
|
||||
|
||||
impl CellDataOperation<EncodedCellData<URLCellData>> for URLTypeOption {
|
||||
impl CellDataOperation<EncodedCellData<URLCellData>, GridTextFilter> for URLTypeOption {
|
||||
fn decode_cell_data<T>(
|
||||
&self,
|
||||
encoded_data: T,
|
||||
@ -50,6 +50,10 @@ impl CellDataOperation<EncodedCellData<URLCellData>> for URLTypeOption {
|
||||
DecodedCellData::try_from_bytes(cell_data)
|
||||
}
|
||||
|
||||
fn apply_filter(&self, _filter: GridTextFilter) -> bool {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn apply_changeset<C>(&self, changeset: C, _cell_rev: Option<CellRevision>) -> Result<String, FlowyError>
|
||||
where
|
||||
C: Into<CellContentChangeset>,
|
||||
@ -122,10 +126,10 @@ lazy_static! {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::entities::FieldType;
|
||||
use crate::services::field::FieldBuilder;
|
||||
use crate::services::field::{URLCellData, URLTypeOption};
|
||||
use crate::services::row::{CellDataOperation, EncodedCellData};
|
||||
use flowy_grid_data_model::entities::FieldType;
|
||||
use flowy_grid_data_model::revision::FieldRevision;
|
||||
|
||||
#[test]
|
||||
|
@ -1,58 +1,293 @@
|
||||
use crate::manager::GridTaskSchedulerRwLock;
|
||||
use crate::entities::{
|
||||
FieldType, GridCheckboxFilter, GridDateFilter, GridNumberFilter, GridSelectOptionFilter, GridTextFilter,
|
||||
};
|
||||
use crate::services::block_manager::GridBlockManager;
|
||||
use crate::services::tasks::Task;
|
||||
use crate::services::grid_editor_task::GridServiceTaskScheduler;
|
||||
use crate::services::row::GridBlockSnapshot;
|
||||
use crate::services::tasks::{FilterTaskContext, Task, TaskContent};
|
||||
use flowy_error::FlowyResult;
|
||||
|
||||
use flowy_grid_data_model::revision::{CellRevision, FieldId, FieldRevision, RowRevision};
|
||||
use flowy_sync::client_grid::GridRevisionPad;
|
||||
use flowy_sync::entities::grid::GridSettingChangesetParams;
|
||||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
use tokio::sync::RwLock;
|
||||
|
||||
pub(crate) struct GridFilterService {
|
||||
#[allow(dead_code)]
|
||||
scheduler: GridTaskSchedulerRwLock,
|
||||
#[allow(dead_code)]
|
||||
grid_id: String,
|
||||
scheduler: Arc<dyn GridServiceTaskScheduler>,
|
||||
grid_pad: Arc<RwLock<GridRevisionPad>>,
|
||||
#[allow(dead_code)]
|
||||
block_manager: Arc<GridBlockManager>,
|
||||
filter_cache: Arc<RwLock<FilterCache>>,
|
||||
filter_result_cache: Arc<RwLock<FilterResultCache>>,
|
||||
}
|
||||
impl GridFilterService {
|
||||
pub fn new(
|
||||
pub async fn new<S: GridServiceTaskScheduler>(
|
||||
grid_pad: Arc<RwLock<GridRevisionPad>>,
|
||||
block_manager: Arc<GridBlockManager>,
|
||||
scheduler: GridTaskSchedulerRwLock,
|
||||
scheduler: S,
|
||||
) -> Self {
|
||||
let grid_id = grid_pad.read().await.grid_id();
|
||||
let filter_cache = Arc::new(RwLock::new(FilterCache::from_grid_pad(&grid_pad).await));
|
||||
let filter_result_cache = Arc::new(RwLock::new(FilterResultCache::default()));
|
||||
Self {
|
||||
grid_id,
|
||||
grid_pad,
|
||||
block_manager,
|
||||
scheduler,
|
||||
scheduler: Arc::new(scheduler),
|
||||
filter_cache,
|
||||
filter_result_cache,
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn process_task(&self, _task: Task) -> FlowyResult<()> {
|
||||
pub async fn process(&self, task_context: FilterTaskContext) -> FlowyResult<()> {
|
||||
let field_revs = self
|
||||
.grid_pad
|
||||
.read()
|
||||
.await
|
||||
.get_field_revs(None)?
|
||||
.into_iter()
|
||||
.map(|field_rev| (field_rev.id.clone(), field_rev))
|
||||
.collect::<HashMap<String, Arc<FieldRevision>>>();
|
||||
|
||||
let mut show_rows = vec![];
|
||||
let mut hide_rows = vec![];
|
||||
for block in task_context.blocks {
|
||||
block.row_revs.iter().for_each(|row_rev| {
|
||||
let result = filter_row(row_rev, &self.filter_cache, &self.filter_result_cache, &field_revs);
|
||||
|
||||
if result.is_row_hidden() {
|
||||
hide_rows.push(result.row_id);
|
||||
} else {
|
||||
show_rows.push(result.row_id);
|
||||
}
|
||||
});
|
||||
}
|
||||
self.notify(hide_rows, show_rows).await;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn notify_changed(&self) {
|
||||
//
|
||||
// let grid_pad = self.grid_pad.read().await;
|
||||
// match grid_pad.get_filters(None) {
|
||||
// None => {}
|
||||
// Some(filter_revs) => {
|
||||
// filter_revs
|
||||
// .iter()
|
||||
// .for_each(|filter_rev| match grid_pad.get_field_rev(&filter_rev.field_id) {
|
||||
// None => {}
|
||||
// Some((_, _field_rev)) => match field_rev.field_type {
|
||||
// FieldType::RichText => {}
|
||||
// FieldType::Number => {}
|
||||
// FieldType::DateTime => {}
|
||||
// FieldType::SingleSelect => {}
|
||||
// FieldType::MultiSelect => {}
|
||||
// FieldType::Checkbox => {}
|
||||
// FieldType::URL => {}
|
||||
// },
|
||||
// });
|
||||
// }
|
||||
// }
|
||||
pub async fn apply_changeset(&self, changeset: GridFilterChangeset) {
|
||||
if !changeset.is_changed() {
|
||||
return;
|
||||
}
|
||||
|
||||
if let Some(filter_id) = &changeset.insert_filter {
|
||||
let mut cache = self.filter_cache.write().await;
|
||||
let field_ids = Some(vec![filter_id.field_id.clone()]);
|
||||
reload_filter_cache(&mut cache, field_ids, &self.grid_pad).await;
|
||||
}
|
||||
|
||||
if let Some(filter_id) = &changeset.delete_filter {
|
||||
self.filter_cache.write().await.remove(filter_id);
|
||||
}
|
||||
|
||||
if let Ok(blocks) = self.block_manager.get_block_snapshots(None).await {
|
||||
let task = self.gen_task(blocks).await;
|
||||
let _ = self.scheduler.register_task(task).await;
|
||||
}
|
||||
}
|
||||
|
||||
async fn gen_task(&self, blocks: Vec<GridBlockSnapshot>) -> Task {
|
||||
let task_id = self.scheduler.gen_task_id().await;
|
||||
let handler_id = self.grid_pad.read().await.grid_id();
|
||||
|
||||
let context = FilterTaskContext { blocks };
|
||||
Task {
|
||||
handler_id,
|
||||
id: task_id,
|
||||
content: TaskContent::Filter(context),
|
||||
}
|
||||
}
|
||||
|
||||
async fn notify(&self, _hide_rows: Vec<String>, _show_rows: Vec<String>) {
|
||||
// let notification = GridNotification {};
|
||||
// send_dart_notification(grid_id, GridNotification::DidUpdateGridBlock)
|
||||
// .payload(notification)
|
||||
// .send();
|
||||
}
|
||||
}
|
||||
|
||||
fn filter_row(
|
||||
row_rev: &Arc<RowRevision>,
|
||||
_filter_cache: &Arc<RwLock<FilterCache>>,
|
||||
_filter_result_cache: &Arc<RwLock<FilterResultCache>>,
|
||||
_field_revs: &HashMap<FieldId, Arc<FieldRevision>>,
|
||||
) -> FilterResult {
|
||||
let filter_result = FilterResult::new(row_rev);
|
||||
row_rev.cells.iter().for_each(|(_k, cell_rev)| {
|
||||
let _cell_rev: &CellRevision = cell_rev;
|
||||
});
|
||||
filter_result
|
||||
}
|
||||
|
||||
pub struct GridFilterChangeset {
|
||||
insert_filter: Option<FilterId>,
|
||||
delete_filter: Option<FilterId>,
|
||||
}
|
||||
|
||||
impl GridFilterChangeset {
|
||||
fn is_changed(&self) -> bool {
|
||||
self.insert_filter.is_some() || self.delete_filter.is_some()
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::From<&GridSettingChangesetParams> for GridFilterChangeset {
|
||||
fn from(params: &GridSettingChangesetParams) -> Self {
|
||||
let insert_filter = params.insert_filter.as_ref().map(|insert_filter_params| FilterId {
|
||||
field_id: insert_filter_params.field_id.clone(),
|
||||
field_type: insert_filter_params.field_type_rev.into(),
|
||||
});
|
||||
|
||||
let delete_filter = params.delete_filter.as_ref().map(|delete_filter_params| FilterId {
|
||||
field_id: delete_filter_params.filter_id.clone(),
|
||||
field_type: delete_filter_params.field_type_rev.into(),
|
||||
});
|
||||
GridFilterChangeset {
|
||||
insert_filter,
|
||||
delete_filter,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct FilterResultCache {
|
||||
#[allow(dead_code)]
|
||||
rows: HashMap<String, FilterResult>,
|
||||
}
|
||||
|
||||
impl FilterResultCache {
|
||||
#[allow(dead_code)]
|
||||
fn insert(&mut self, row_id: &str, result: FilterResult) {
|
||||
self.rows.insert(row_id.to_owned(), result);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct FilterResult {
|
||||
row_id: String,
|
||||
#[allow(dead_code)]
|
||||
cell_by_field_id: HashMap<String, bool>,
|
||||
}
|
||||
|
||||
impl FilterResult {
|
||||
fn new(row_rev: &RowRevision) -> Self {
|
||||
Self {
|
||||
row_id: row_rev.id.clone(),
|
||||
cell_by_field_id: row_rev.cells.iter().map(|(k, _)| (k.clone(), true)).collect(),
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn update_cell(&mut self, cell_id: &str, exist: bool) {
|
||||
self.cell_by_field_id.insert(cell_id.to_owned(), exist);
|
||||
}
|
||||
|
||||
fn is_row_hidden(&self) -> bool {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct FilterCache {
|
||||
text_filter: HashMap<FilterId, GridTextFilter>,
|
||||
url_filter: HashMap<FilterId, GridTextFilter>,
|
||||
number_filter: HashMap<FilterId, GridNumberFilter>,
|
||||
date_filter: HashMap<FilterId, GridDateFilter>,
|
||||
select_option_filter: HashMap<FilterId, GridSelectOptionFilter>,
|
||||
checkbox_filter: HashMap<FilterId, GridCheckboxFilter>,
|
||||
}
|
||||
|
||||
impl FilterCache {
|
||||
async fn from_grid_pad(grid_pad: &Arc<RwLock<GridRevisionPad>>) -> Self {
|
||||
let mut this = Self::default();
|
||||
let _ = reload_filter_cache(&mut this, None, grid_pad).await;
|
||||
this
|
||||
}
|
||||
|
||||
fn remove(&mut self, filter_id: &FilterId) {
|
||||
let _ = match filter_id.field_type {
|
||||
FieldType::RichText => {
|
||||
let _ = self.text_filter.remove(filter_id);
|
||||
}
|
||||
FieldType::Number => {
|
||||
let _ = self.number_filter.remove(filter_id);
|
||||
}
|
||||
FieldType::DateTime => {
|
||||
let _ = self.date_filter.remove(filter_id);
|
||||
}
|
||||
FieldType::SingleSelect => {
|
||||
let _ = self.select_option_filter.remove(filter_id);
|
||||
}
|
||||
FieldType::MultiSelect => {
|
||||
let _ = self.select_option_filter.remove(filter_id);
|
||||
}
|
||||
FieldType::Checkbox => {
|
||||
let _ = self.checkbox_filter.remove(filter_id);
|
||||
}
|
||||
FieldType::URL => {
|
||||
let _ = self.url_filter.remove(filter_id);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
async fn reload_filter_cache(
|
||||
cache: &mut FilterCache,
|
||||
field_ids: Option<Vec<String>>,
|
||||
grid_pad: &Arc<RwLock<GridRevisionPad>>,
|
||||
) {
|
||||
let grid_pad = grid_pad.read().await;
|
||||
let filters_revs = grid_pad.get_filters(None, field_ids).unwrap_or_default();
|
||||
|
||||
for filter_rev in filters_revs {
|
||||
match grid_pad.get_field_rev(&filter_rev.field_id) {
|
||||
None => {}
|
||||
Some((_, field_rev)) => {
|
||||
let filter_id = FilterId::from(field_rev);
|
||||
let field_type: FieldType = field_rev.field_type_rev.into();
|
||||
match &field_type {
|
||||
FieldType::RichText => {
|
||||
let _ = cache.text_filter.insert(filter_id, GridTextFilter::from(filter_rev));
|
||||
}
|
||||
FieldType::Number => {
|
||||
let _ = cache
|
||||
.number_filter
|
||||
.insert(filter_id, GridNumberFilter::from(filter_rev));
|
||||
}
|
||||
FieldType::DateTime => {
|
||||
let _ = cache.date_filter.insert(filter_id, GridDateFilter::from(filter_rev));
|
||||
}
|
||||
FieldType::SingleSelect | FieldType::MultiSelect => {
|
||||
let _ = cache
|
||||
.select_option_filter
|
||||
.insert(filter_id, GridSelectOptionFilter::from(filter_rev));
|
||||
}
|
||||
FieldType::Checkbox => {
|
||||
let _ = cache
|
||||
.checkbox_filter
|
||||
.insert(filter_id, GridCheckboxFilter::from(filter_rev));
|
||||
}
|
||||
FieldType::URL => {
|
||||
let _ = cache.url_filter.insert(filter_id, GridTextFilter::from(filter_rev));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#[derive(Hash, Eq, PartialEq)]
|
||||
struct FilterId {
|
||||
field_id: String,
|
||||
field_type: FieldType,
|
||||
}
|
||||
|
||||
impl std::convert::From<&Arc<FieldRevision>> for FilterId {
|
||||
fn from(rev: &Arc<FieldRevision>) -> Self {
|
||||
Self {
|
||||
field_id: rev.id.clone(),
|
||||
field_type: rev.field_type_rev.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,16 +3,17 @@ use crate::entities::CellIdentifier;
|
||||
use crate::manager::{GridTaskSchedulerRwLock, GridUser};
|
||||
use crate::services::block_manager::GridBlockManager;
|
||||
use crate::services::field::{default_type_option_builder_from_type, type_option_builder_from_bytes, FieldBuilder};
|
||||
use crate::services::filter::GridFilterService;
|
||||
use crate::services::filter::{GridFilterChangeset, GridFilterService};
|
||||
use crate::services::persistence::block_index::BlockIndexCache;
|
||||
use crate::services::row::*;
|
||||
|
||||
use crate::entities::*;
|
||||
use bytes::Bytes;
|
||||
use flowy_error::{ErrorCode, FlowyError, FlowyResult};
|
||||
use flowy_grid_data_model::entities::*;
|
||||
use flowy_grid_data_model::revision::*;
|
||||
use flowy_revision::{RevisionCloudService, RevisionCompactor, RevisionManager, RevisionObjectBuilder};
|
||||
use flowy_sync::client_grid::{GridChangeset, GridRevisionPad, JsonDeserializer};
|
||||
use flowy_sync::entities::grid::{FieldChangesetParams, GridSettingChangesetParams};
|
||||
use flowy_sync::entities::revision::Revision;
|
||||
use flowy_sync::errors::CollaborateResult;
|
||||
use flowy_sync::util::make_delta_from_revisions;
|
||||
@ -53,11 +54,8 @@ impl GridRevisionEditor {
|
||||
let grid_pad = Arc::new(RwLock::new(grid_pad));
|
||||
let block_meta_revs = grid_pad.read().await.get_block_meta_revs();
|
||||
let block_manager = Arc::new(GridBlockManager::new(grid_id, &user, block_meta_revs, persistence).await?);
|
||||
let filter_service = Arc::new(GridFilterService::new(
|
||||
grid_pad.clone(),
|
||||
block_manager.clone(),
|
||||
task_scheduler.clone(),
|
||||
));
|
||||
let filter_service =
|
||||
Arc::new(GridFilterService::new(grid_pad.clone(), block_manager.clone(), task_scheduler.clone()).await);
|
||||
let editor = Arc::new(Self {
|
||||
grid_id: grid_id.to_owned(),
|
||||
user,
|
||||
@ -87,7 +85,7 @@ impl GridRevisionEditor {
|
||||
grid_id,
|
||||
name: Some(field.name),
|
||||
desc: Some(field.desc),
|
||||
field_type: Some(field.field_type),
|
||||
field_type: Some(field.field_type.into()),
|
||||
frozen: Some(field.frozen),
|
||||
visibility: Some(field.visibility),
|
||||
width: Some(field.width),
|
||||
@ -126,7 +124,8 @@ impl GridRevisionEditor {
|
||||
let field_rev = result.unwrap();
|
||||
let _ = self
|
||||
.modify(|grid| {
|
||||
let deserializer = TypeOptionJsonDeserializer(field_rev.field_type.clone());
|
||||
let field_type = field_rev.field_type_rev.into();
|
||||
let deserializer = TypeOptionJsonDeserializer(field_type);
|
||||
let changeset = FieldChangesetParams {
|
||||
field_id: field_id.to_owned(),
|
||||
grid_id: grid_id.to_owned(),
|
||||
@ -164,7 +163,7 @@ impl GridRevisionEditor {
|
||||
let field_id = params.field_id.clone();
|
||||
let json_deserializer = match self.grid_pad.read().await.get_field_rev(params.field_id.as_str()) {
|
||||
None => return Err(ErrorCode::FieldDoesNotExist.into()),
|
||||
Some((_, field_rev)) => TypeOptionJsonDeserializer(field_rev.field_type.clone()),
|
||||
Some((_, field_rev)) => TypeOptionJsonDeserializer(field_rev.field_type_rev.into()),
|
||||
};
|
||||
|
||||
let _ = self
|
||||
@ -175,7 +174,7 @@ impl GridRevisionEditor {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn replace_field(&self, field_rev: FieldRevision) -> FlowyResult<()> {
|
||||
pub async fn replace_field(&self, field_rev: Arc<FieldRevision>) -> FlowyResult<()> {
|
||||
let field_id = field_rev.id.clone();
|
||||
let _ = self
|
||||
.modify(|grid_pad| Ok(grid_pad.replace_field_rev(field_rev)?))
|
||||
@ -204,8 +203,9 @@ impl GridRevisionEditor {
|
||||
// .get_cell_revs(block_ids, field_id, None)
|
||||
// .await?;
|
||||
|
||||
let type_option_json_builder = |field_type: &FieldType| -> String {
|
||||
return default_type_option_builder_from_type(field_type).entry().json_str();
|
||||
let type_option_json_builder = |field_type: &FieldTypeRevision| -> String {
|
||||
let field_type: FieldType = field_type.into();
|
||||
return default_type_option_builder_from_type(&field_type).entry().json_str();
|
||||
};
|
||||
|
||||
let _ = self
|
||||
@ -227,24 +227,20 @@ impl GridRevisionEditor {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn get_field_rev(&self, field_id: &str) -> Option<FieldRevision> {
|
||||
pub async fn get_field_rev(&self, field_id: &str) -> Option<Arc<FieldRevision>> {
|
||||
let field_rev = self.grid_pad.read().await.get_field_rev(field_id)?.1.clone();
|
||||
Some(field_rev)
|
||||
}
|
||||
|
||||
pub async fn get_field_revs<T>(&self, field_ids: Option<Vec<T>>) -> FlowyResult<Vec<FieldRevision>>
|
||||
where
|
||||
T: Into<FieldOrder>,
|
||||
{
|
||||
pub async fn get_field_revs(&self, field_ids: Option<Vec<String>>) -> FlowyResult<Vec<Arc<FieldRevision>>> {
|
||||
if field_ids.is_none() {
|
||||
let field_revs = self.grid_pad.read().await.get_field_revs(None)?;
|
||||
return Ok(field_revs);
|
||||
}
|
||||
|
||||
let to_field_orders = |item: Vec<T>| item.into_iter().map(|data| data.into()).collect();
|
||||
let field_orders = field_ids.map_or(vec![], to_field_orders);
|
||||
let expected_len = field_orders.len();
|
||||
let field_revs = self.grid_pad.read().await.get_field_revs(Some(field_orders))?;
|
||||
let field_ids = field_ids.unwrap_or_default();
|
||||
let expected_len = field_ids.len();
|
||||
let field_revs = self.grid_pad.read().await.get_field_revs(Some(field_ids))?;
|
||||
if expected_len != 0 && field_revs.len() != expected_len {
|
||||
tracing::error!(
|
||||
"This is a bug. The len of the field_revs should equal to {}",
|
||||
@ -269,14 +265,14 @@ impl GridRevisionEditor {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn create_row(&self, start_row_id: Option<String>) -> FlowyResult<RowOrder> {
|
||||
pub async fn create_row(&self, start_row_id: Option<String>) -> FlowyResult<BlockRowInfo> {
|
||||
let field_revs = self.grid_pad.read().await.get_field_revs(None)?;
|
||||
let block_id = self.block_id().await?;
|
||||
|
||||
// insert empty row below the row whose id is upper_row_id
|
||||
let row_rev_ctx = CreateRowRevisionBuilder::new(&field_revs).build();
|
||||
let row_rev = make_row_rev_from_context(&block_id, row_rev_ctx);
|
||||
let row_order = RowOrder::from(&row_rev);
|
||||
let row_order = BlockRowInfo::from(&row_rev);
|
||||
|
||||
// insert the row
|
||||
let row_count = self.block_manager.create_row(&block_id, row_rev, start_row_id).await?;
|
||||
@ -287,13 +283,13 @@ impl GridRevisionEditor {
|
||||
Ok(row_order)
|
||||
}
|
||||
|
||||
pub async fn insert_rows(&self, contexts: Vec<CreateRowRevisionPayload>) -> FlowyResult<Vec<RowOrder>> {
|
||||
pub async fn insert_rows(&self, contexts: Vec<CreateRowRevisionPayload>) -> FlowyResult<Vec<BlockRowInfo>> {
|
||||
let block_id = self.block_id().await?;
|
||||
let mut rows_by_block_id: HashMap<String, Vec<RowRevision>> = HashMap::new();
|
||||
let mut row_orders = vec![];
|
||||
for ctx in contexts {
|
||||
let row_rev = make_row_rev_from_context(&block_id, ctx);
|
||||
row_orders.push(RowOrder::from(&row_rev));
|
||||
row_orders.push(BlockRowInfo::from(&row_rev));
|
||||
rows_by_block_id
|
||||
.entry(block_id.clone())
|
||||
.or_insert_with(Vec::new)
|
||||
@ -307,7 +303,7 @@ impl GridRevisionEditor {
|
||||
}
|
||||
|
||||
pub async fn update_row(&self, changeset: RowMetaChangeset) -> FlowyResult<()> {
|
||||
let field_revs = self.get_field_revs::<FieldOrder>(None).await?;
|
||||
let field_revs = self.get_field_revs(None).await?;
|
||||
self.block_manager
|
||||
.update_row(changeset, |row_rev| make_row_from_row_rev(&field_revs, row_rev))
|
||||
.await
|
||||
@ -322,7 +318,7 @@ impl GridRevisionEditor {
|
||||
debug_assert_eq!(grid_block_snapshot.len(), 1);
|
||||
if grid_block_snapshot.len() == 1 {
|
||||
let snapshot = grid_block_snapshot.pop().unwrap();
|
||||
let field_revs = self.get_field_revs::<FieldOrder>(None).await?;
|
||||
let field_revs = self.get_field_revs(None).await?;
|
||||
let rows = make_rows_from_row_revs(&field_revs, &snapshot.row_revs);
|
||||
Ok(rows.into())
|
||||
} else {
|
||||
@ -334,7 +330,7 @@ impl GridRevisionEditor {
|
||||
match self.block_manager.get_row_rev(row_id).await? {
|
||||
None => Ok(None),
|
||||
Some(row_rev) => {
|
||||
let field_revs = self.get_field_revs::<FieldOrder>(None).await?;
|
||||
let field_revs = self.get_field_revs(None).await?;
|
||||
let row_revs = vec![row_rev];
|
||||
let mut rows = make_rows_from_row_revs(&field_revs, &row_revs);
|
||||
debug_assert!(rows.len() == 1);
|
||||
@ -399,7 +395,7 @@ impl GridRevisionEditor {
|
||||
cell_rev,
|
||||
field_rev,
|
||||
)?);
|
||||
let field_revs = self.get_field_revs::<FieldOrder>(None).await?;
|
||||
let field_revs = self.get_field_revs(None).await?;
|
||||
let cell_changeset = CellChangeset {
|
||||
grid_id,
|
||||
row_id,
|
||||
@ -425,7 +421,7 @@ impl GridRevisionEditor {
|
||||
Ok(block_meta_revs)
|
||||
}
|
||||
|
||||
pub async fn delete_rows(&self, row_orders: Vec<RowOrder>) -> FlowyResult<()> {
|
||||
pub async fn delete_rows(&self, row_orders: Vec<BlockRowInfo>) -> FlowyResult<()> {
|
||||
let changesets = self.block_manager.delete_rows(row_orders).await?;
|
||||
for changeset in changesets {
|
||||
let _ = self.update_block(changeset).await?;
|
||||
@ -435,13 +431,17 @@ impl GridRevisionEditor {
|
||||
|
||||
pub async fn get_grid_data(&self) -> FlowyResult<Grid> {
|
||||
let pad_read_guard = self.grid_pad.read().await;
|
||||
let field_orders = pad_read_guard.get_field_orders();
|
||||
let field_orders = pad_read_guard
|
||||
.get_field_revs(None)?
|
||||
.iter()
|
||||
.map(FieldOrder::from)
|
||||
.collect();
|
||||
let mut block_orders = vec![];
|
||||
for block_rev in pad_read_guard.get_block_meta_revs() {
|
||||
let row_orders = self.block_manager.get_row_orders(&block_rev.block_id).await?;
|
||||
let block_order = GridBlock {
|
||||
id: block_rev.block_id.clone(),
|
||||
row_orders,
|
||||
row_infos: row_orders,
|
||||
};
|
||||
block_orders.push(block_order);
|
||||
}
|
||||
@ -454,29 +454,31 @@ impl GridRevisionEditor {
|
||||
}
|
||||
|
||||
pub async fn get_grid_setting(&self) -> FlowyResult<GridSetting> {
|
||||
let read_guard = self.grid_pad.read().await;
|
||||
let grid_setting_rev = read_guard.get_grid_setting_rev();
|
||||
Ok(grid_setting_rev.into())
|
||||
// let read_guard = self.grid_pad.read().await;
|
||||
// let grid_setting_rev = read_guard.get_grid_setting_rev();
|
||||
// Ok(grid_setting_rev.into())
|
||||
todo!()
|
||||
}
|
||||
|
||||
pub async fn get_grid_filter(&self, layout_type: &GridLayoutType) -> FlowyResult<Vec<GridFilter>> {
|
||||
let read_guard = self.grid_pad.read().await;
|
||||
let layout_rev = layout_type.clone().into();
|
||||
match read_guard.get_filters(Some(&layout_rev)) {
|
||||
match read_guard.get_filters(Some(&layout_rev), None) {
|
||||
Some(filter_revs) => Ok(filter_revs.iter().map(GridFilter::from).collect::<Vec<GridFilter>>()),
|
||||
None => Ok(vec![]),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn update_grid_setting(&self, params: GridSettingChangesetParams) -> FlowyResult<()> {
|
||||
let is_filter_changed = params.is_filter_changed();
|
||||
let filter_changeset = GridFilterChangeset::from(¶ms);
|
||||
let _ = self
|
||||
.modify(|grid_pad| Ok(grid_pad.update_grid_setting_rev(params)?))
|
||||
.await?;
|
||||
|
||||
if is_filter_changed {
|
||||
self.filter_service.notify_changed().await;
|
||||
}
|
||||
let filter_service = self.filter_service.clone();
|
||||
tokio::spawn(async move {
|
||||
filter_service.apply_changeset(filter_changeset).await;
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -492,7 +494,7 @@ impl GridRevisionEditor {
|
||||
.collect::<Vec<String>>(),
|
||||
Some(block_ids) => block_ids,
|
||||
};
|
||||
let snapshots = self.block_manager.make_block_snapshots(block_ids).await?;
|
||||
let snapshots = self.block_manager.get_block_snapshots(Some(block_ids)).await?;
|
||||
Ok(snapshots)
|
||||
}
|
||||
|
||||
|
@ -1,9 +1,15 @@
|
||||
use crate::manager::GridTaskSchedulerRwLock;
|
||||
use crate::services::grid_editor::GridRevisionEditor;
|
||||
use crate::services::tasks::{GridTaskHandler, Task, TaskContent, TaskHandlerId};
|
||||
use crate::services::tasks::{GridTaskHandler, Task, TaskContent, TaskHandlerId, TaskId};
|
||||
use flowy_error::FlowyError;
|
||||
|
||||
use futures::future::BoxFuture;
|
||||
use lib_infra::future::BoxResultFuture;
|
||||
|
||||
pub(crate) trait GridServiceTaskScheduler: Send + Sync + 'static {
|
||||
fn gen_task_id(&self) -> BoxFuture<TaskId>;
|
||||
fn register_task(&self, task: Task) -> BoxFuture<()>;
|
||||
}
|
||||
|
||||
impl GridTaskHandler for GridRevisionEditor {
|
||||
fn handler_id(&self) -> &TaskHandlerId {
|
||||
&self.grid_id
|
||||
@ -11,11 +17,25 @@ impl GridTaskHandler for GridRevisionEditor {
|
||||
|
||||
fn process_task(&self, task: Task) -> BoxResultFuture<(), FlowyError> {
|
||||
Box::pin(async move {
|
||||
match &task.content {
|
||||
TaskContent::Snapshot { .. } => {}
|
||||
TaskContent::Filter => self.filter_service.process_task(task).await?,
|
||||
match task.content {
|
||||
TaskContent::Snapshot => {}
|
||||
TaskContent::Filter(context) => self.filter_service.process(context).await?,
|
||||
}
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl GridServiceTaskScheduler for GridTaskSchedulerRwLock {
|
||||
fn gen_task_id(&self) -> BoxFuture<TaskId> {
|
||||
let this = self.clone();
|
||||
Box::pin(async move { this.read().await.next_task_id() })
|
||||
}
|
||||
|
||||
fn register_task(&self, task: Task) -> BoxFuture<()> {
|
||||
let this = self.clone();
|
||||
Box::pin(async move {
|
||||
this.write().await.register_task(task);
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -1,13 +1,13 @@
|
||||
use crate::entities::FieldType;
|
||||
use crate::services::field::*;
|
||||
use bytes::Bytes;
|
||||
use flowy_error::{internal_error, ErrorCode, FlowyError, FlowyResult};
|
||||
use flowy_grid_data_model::entities::FieldType;
|
||||
use flowy_grid_data_model::revision::{CellRevision, FieldRevision};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt::Formatter;
|
||||
use std::str::FromStr;
|
||||
|
||||
pub trait CellDataOperation<ED> {
|
||||
pub trait CellDataOperation<D, F> {
|
||||
fn decode_cell_data<T>(
|
||||
&self,
|
||||
encoded_data: T,
|
||||
@ -15,9 +15,10 @@ pub trait CellDataOperation<ED> {
|
||||
field_rev: &FieldRevision,
|
||||
) -> FlowyResult<DecodedCellData>
|
||||
where
|
||||
T: Into<ED>;
|
||||
T: Into<D>;
|
||||
|
||||
fn apply_filter(&self, filter: F) -> bool;
|
||||
|
||||
//
|
||||
fn apply_changeset<C: Into<CellContentChangeset>>(
|
||||
&self,
|
||||
changeset: C,
|
||||
@ -115,12 +116,14 @@ impl TypeOptionCellData {
|
||||
|
||||
/// The changeset will be deserialized into specific data base on the FieldType.
|
||||
/// For example, it's String on FieldType::RichText, and SelectOptionChangeset on FieldType::SingleSelect
|
||||
pub fn apply_cell_data_changeset<T: Into<CellContentChangeset>>(
|
||||
changeset: T,
|
||||
pub fn apply_cell_data_changeset<C: Into<CellContentChangeset>, T: AsRef<FieldRevision>>(
|
||||
changeset: C,
|
||||
cell_rev: Option<CellRevision>,
|
||||
field_rev: &FieldRevision,
|
||||
field_rev: T,
|
||||
) -> Result<String, FlowyError> {
|
||||
let s = match field_rev.field_type {
|
||||
let field_rev = field_rev.as_ref();
|
||||
let field_type = field_rev.field_type_rev.into();
|
||||
let s = match field_type {
|
||||
FieldType::RichText => RichTextTypeOption::from(field_rev).apply_changeset(changeset, cell_rev),
|
||||
FieldType::Number => NumberTypeOption::from(field_rev).apply_changeset(changeset, cell_rev),
|
||||
FieldType::DateTime => DateTypeOption::from(field_rev).apply_changeset(changeset, cell_rev),
|
||||
@ -130,14 +133,14 @@ pub fn apply_cell_data_changeset<T: Into<CellContentChangeset>>(
|
||||
FieldType::URL => URLTypeOption::from(field_rev).apply_changeset(changeset, cell_rev),
|
||||
}?;
|
||||
|
||||
Ok(TypeOptionCellData::new(s, field_rev.field_type.clone()).json())
|
||||
Ok(TypeOptionCellData::new(s, field_type).json())
|
||||
}
|
||||
|
||||
pub fn decode_cell_data<T: TryInto<TypeOptionCellData>>(data: T, field_rev: &FieldRevision) -> DecodedCellData {
|
||||
if let Ok(type_option_cell_data) = data.try_into() {
|
||||
let TypeOptionCellData { data, field_type } = type_option_cell_data;
|
||||
let to_field_type = &field_rev.field_type;
|
||||
match try_decode_cell_data(data, field_rev, &field_type, to_field_type) {
|
||||
let to_field_type = field_rev.field_type_rev.into();
|
||||
match try_decode_cell_data(data, field_rev, &field_type, &to_field_type) {
|
||||
Ok(cell_data) => cell_data,
|
||||
Err(e) => {
|
||||
tracing::error!("Decode cell data failed, {:?}", e);
|
||||
@ -150,35 +153,34 @@ pub fn decode_cell_data<T: TryInto<TypeOptionCellData>>(data: T, field_rev: &Fie
|
||||
}
|
||||
}
|
||||
|
||||
pub fn try_decode_cell_data<T: Into<String>>(
|
||||
encoded_data: T,
|
||||
pub fn try_decode_cell_data(
|
||||
encoded_data: String,
|
||||
field_rev: &FieldRevision,
|
||||
s_field_type: &FieldType,
|
||||
t_field_type: &FieldType,
|
||||
) -> FlowyResult<DecodedCellData> {
|
||||
let encoded_data = encoded_data.into();
|
||||
let get_cell_data = || {
|
||||
let data = match t_field_type {
|
||||
FieldType::RichText => field_rev
|
||||
.get_type_option_entry::<RichTextTypeOption>(t_field_type)?
|
||||
.get_type_option_entry::<RichTextTypeOption, _>(t_field_type)?
|
||||
.decode_cell_data(encoded_data, s_field_type, field_rev),
|
||||
FieldType::Number => field_rev
|
||||
.get_type_option_entry::<NumberTypeOption>(t_field_type)?
|
||||
.get_type_option_entry::<NumberTypeOption, _>(t_field_type)?
|
||||
.decode_cell_data(encoded_data, s_field_type, field_rev),
|
||||
FieldType::DateTime => field_rev
|
||||
.get_type_option_entry::<DateTypeOption>(t_field_type)?
|
||||
.get_type_option_entry::<DateTypeOption, _>(t_field_type)?
|
||||
.decode_cell_data(encoded_data, s_field_type, field_rev),
|
||||
FieldType::SingleSelect => field_rev
|
||||
.get_type_option_entry::<SingleSelectTypeOption>(t_field_type)?
|
||||
.get_type_option_entry::<SingleSelectTypeOption, _>(t_field_type)?
|
||||
.decode_cell_data(encoded_data, s_field_type, field_rev),
|
||||
FieldType::MultiSelect => field_rev
|
||||
.get_type_option_entry::<MultiSelectTypeOption>(t_field_type)?
|
||||
.get_type_option_entry::<MultiSelectTypeOption, _>(t_field_type)?
|
||||
.decode_cell_data(encoded_data, s_field_type, field_rev),
|
||||
FieldType::Checkbox => field_rev
|
||||
.get_type_option_entry::<CheckboxTypeOption>(t_field_type)?
|
||||
.get_type_option_entry::<CheckboxTypeOption, _>(t_field_type)?
|
||||
.decode_cell_data(encoded_data, s_field_type, field_rev),
|
||||
FieldType::URL => field_rev
|
||||
.get_type_option_entry::<URLTypeOption>(t_field_type)?
|
||||
.get_type_option_entry::<URLTypeOption, _>(t_field_type)?
|
||||
.decode_cell_data(encoded_data, s_field_type, field_rev),
|
||||
};
|
||||
Some(data)
|
||||
|
@ -1,6 +1,5 @@
|
||||
mod cell_data_operation;
|
||||
mod row_builder;
|
||||
pub mod row_entities;
|
||||
mod row_loader;
|
||||
|
||||
pub use cell_data_operation::*;
|
||||
|
@ -4,18 +4,19 @@ use flowy_error::{FlowyError, FlowyResult};
|
||||
use flowy_grid_data_model::revision::{gen_row_id, CellRevision, FieldRevision, RowRevision, DEFAULT_ROW_HEIGHT};
|
||||
use indexmap::IndexMap;
|
||||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
|
||||
pub struct CreateRowRevisionBuilder<'a> {
|
||||
field_rev_map: HashMap<&'a String, &'a FieldRevision>,
|
||||
field_rev_map: HashMap<&'a String, &'a Arc<FieldRevision>>,
|
||||
payload: CreateRowRevisionPayload,
|
||||
}
|
||||
|
||||
impl<'a> CreateRowRevisionBuilder<'a> {
|
||||
pub fn new(fields: &'a [FieldRevision]) -> Self {
|
||||
pub fn new(fields: &'a [Arc<FieldRevision>]) -> Self {
|
||||
let field_rev_map = fields
|
||||
.iter()
|
||||
.map(|field| (&field.id, field))
|
||||
.collect::<HashMap<&String, &FieldRevision>>();
|
||||
.collect::<HashMap<&String, &Arc<FieldRevision>>>();
|
||||
|
||||
let payload = CreateRowRevisionPayload {
|
||||
row_id: gen_row_id(),
|
||||
|
@ -1,31 +0,0 @@
|
||||
use flowy_derive::ProtoBuf;
|
||||
use flowy_error::ErrorCode;
|
||||
use flowy_grid_data_model::parser::NotEmptyStr;
|
||||
|
||||
#[derive(ProtoBuf, Default)]
|
||||
pub struct RowIdentifierPayload {
|
||||
#[pb(index = 1)]
|
||||
pub grid_id: String,
|
||||
|
||||
#[pb(index = 3)]
|
||||
pub row_id: String,
|
||||
}
|
||||
|
||||
pub struct RowIdentifier {
|
||||
pub grid_id: String,
|
||||
pub row_id: String,
|
||||
}
|
||||
|
||||
impl TryInto<RowIdentifier> for RowIdentifierPayload {
|
||||
type Error = ErrorCode;
|
||||
|
||||
fn try_into(self) -> Result<RowIdentifier, Self::Error> {
|
||||
let grid_id = NotEmptyStr::parse(self.grid_id).map_err(|_| ErrorCode::GridIdIsEmpty)?;
|
||||
let row_id = NotEmptyStr::parse(self.row_id).map_err(|_| ErrorCode::RowIdIsEmpty)?;
|
||||
|
||||
Ok(RowIdentifier {
|
||||
grid_id: grid_id.0,
|
||||
row_id: row_id.0,
|
||||
})
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
use crate::entities::{BlockRowInfo, GridBlock, RepeatedGridBlock, Row};
|
||||
use flowy_error::FlowyResult;
|
||||
use flowy_grid_data_model::entities::{GridBlock, RepeatedGridBlock, Row, RowOrder};
|
||||
use flowy_grid_data_model::revision::{FieldRevision, RowRevision};
|
||||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
@ -9,15 +9,16 @@ pub struct GridBlockSnapshot {
|
||||
pub row_revs: Vec<Arc<RowRevision>>,
|
||||
}
|
||||
|
||||
pub(crate) fn block_from_row_orders(row_orders: Vec<RowOrder>) -> Vec<GridBlock> {
|
||||
pub(crate) fn block_from_row_orders(row_orders: Vec<BlockRowInfo>) -> Vec<GridBlock> {
|
||||
let mut map: HashMap<String, GridBlock> = HashMap::new();
|
||||
row_orders.into_iter().for_each(|row_order| {
|
||||
row_orders.into_iter().for_each(|row_info| {
|
||||
// Memory Optimization: escape clone block_id
|
||||
let block_id = row_order.block_id.clone();
|
||||
let block_id = row_info.block_id().to_owned();
|
||||
let cloned_block_id = block_id.clone();
|
||||
map.entry(block_id)
|
||||
.or_insert_with(|| GridBlock::new(&row_order.block_id, vec![]))
|
||||
.row_orders
|
||||
.push(row_order);
|
||||
.or_insert_with(|| GridBlock::new(&cloned_block_id, vec![]))
|
||||
.row_infos
|
||||
.push(row_info);
|
||||
});
|
||||
map.into_values().collect::<Vec<_>>()
|
||||
}
|
||||
@ -34,15 +35,15 @@ pub(crate) fn block_from_row_orders(row_orders: Vec<RowOrder>) -> Vec<GridBlock>
|
||||
// Some((field_id, cell))
|
||||
// }
|
||||
|
||||
pub(crate) fn make_row_orders_from_row_revs(row_revs: &[Arc<RowRevision>]) -> Vec<RowOrder> {
|
||||
row_revs.iter().map(RowOrder::from).collect::<Vec<_>>()
|
||||
pub(crate) fn make_row_orders_from_row_revs(row_revs: &[Arc<RowRevision>]) -> Vec<BlockRowInfo> {
|
||||
row_revs.iter().map(BlockRowInfo::from).collect::<Vec<_>>()
|
||||
}
|
||||
|
||||
pub(crate) fn make_row_from_row_rev(fields: &[FieldRevision], row_rev: Arc<RowRevision>) -> Option<Row> {
|
||||
pub(crate) fn make_row_from_row_rev(fields: &[Arc<FieldRevision>], row_rev: Arc<RowRevision>) -> Option<Row> {
|
||||
make_rows_from_row_revs(fields, &[row_rev]).pop()
|
||||
}
|
||||
|
||||
pub(crate) fn make_rows_from_row_revs(_fields: &[FieldRevision], row_revs: &[Arc<RowRevision>]) -> Vec<Row> {
|
||||
pub(crate) fn make_rows_from_row_revs(_fields: &[Arc<FieldRevision>], row_revs: &[Arc<RowRevision>]) -> Vec<Row> {
|
||||
// let field_rev_map = fields
|
||||
// .iter()
|
||||
// .map(|field_rev| (&field_rev.id, field_rev))
|
||||
|
@ -1,4 +1,5 @@
|
||||
use flowy_grid_data_model::entities::{CreateGridFilterParams, GridLayoutType, GridSettingChangesetParams};
|
||||
use crate::entities::GridLayoutType;
|
||||
use flowy_sync::entities::grid::{CreateGridFilterParams, DeleteFilterParams, GridSettingChangesetParams};
|
||||
|
||||
pub struct GridSettingChangesetBuilder {
|
||||
params: GridSettingChangesetParams,
|
||||
@ -8,7 +9,7 @@ impl GridSettingChangesetBuilder {
|
||||
pub fn new(grid_id: &str, layout_type: &GridLayoutType) -> Self {
|
||||
let params = GridSettingChangesetParams {
|
||||
grid_id: grid_id.to_string(),
|
||||
layout_type: layout_type.clone(),
|
||||
layout_type: layout_type.clone().into(),
|
||||
insert_filter: None,
|
||||
delete_filter: None,
|
||||
insert_group: None,
|
||||
@ -24,8 +25,8 @@ impl GridSettingChangesetBuilder {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn delete_filter(mut self, filter_id: &str) -> Self {
|
||||
self.params.delete_filter = Some(filter_id.to_string());
|
||||
pub fn delete_filter(mut self, params: DeleteFilterParams) -> Self {
|
||||
self.params.delete_filter = Some(params);
|
||||
self
|
||||
}
|
||||
|
||||
|
@ -21,8 +21,8 @@ impl GridTaskQueue {
|
||||
|
||||
pub(crate) fn push(&mut self, task: &Task) {
|
||||
let task_type = match task.content {
|
||||
TaskContent::Snapshot { .. } => TaskType::Snapshot,
|
||||
TaskContent::Filter => TaskType::Filter,
|
||||
TaskContent::Snapshot => TaskType::Snapshot,
|
||||
TaskContent::Filter { .. } => TaskType::Filter,
|
||||
};
|
||||
let pending_task = PendingTask {
|
||||
ty: task_type,
|
||||
|
@ -3,6 +3,7 @@ use crate::services::tasks::runner::GridTaskRunner;
|
||||
use crate::services::tasks::store::GridTaskStore;
|
||||
use crate::services::tasks::task::Task;
|
||||
|
||||
use crate::services::tasks::TaskId;
|
||||
use flowy_error::{FlowyError, FlowyResult};
|
||||
use lib_infra::future::BoxResultFuture;
|
||||
use std::collections::HashMap;
|
||||
@ -10,7 +11,7 @@ use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use tokio::sync::{watch, RwLock};
|
||||
|
||||
pub trait GridTaskHandler: Send + Sync + 'static {
|
||||
pub(crate) trait GridTaskHandler: Send + Sync + 'static {
|
||||
fn handler_id(&self) -> &TaskHandlerId;
|
||||
|
||||
fn process_task(&self, task: Task) -> BoxResultFuture<(), FlowyError>;
|
||||
@ -24,7 +25,7 @@ pub struct GridTaskScheduler {
|
||||
}
|
||||
|
||||
impl GridTaskScheduler {
|
||||
pub fn new() -> Arc<RwLock<Self>> {
|
||||
pub(crate) fn new() -> Arc<RwLock<Self>> {
|
||||
let (notifier, rx) = watch::channel(());
|
||||
|
||||
let scheduler = Self {
|
||||
@ -44,7 +45,7 @@ impl GridTaskScheduler {
|
||||
scheduler
|
||||
}
|
||||
|
||||
pub fn register_handler<T>(&mut self, handler: Arc<T>)
|
||||
pub(crate) fn register_handler<T>(&mut self, handler: Arc<T>)
|
||||
where
|
||||
T: GridTaskHandler,
|
||||
{
|
||||
@ -52,11 +53,11 @@ impl GridTaskScheduler {
|
||||
self.handlers.insert(handler_id, handler);
|
||||
}
|
||||
|
||||
pub fn unregister_handler<T: AsRef<str>>(&mut self, handler_id: T) {
|
||||
pub(crate) fn unregister_handler<T: AsRef<str>>(&mut self, handler_id: T) {
|
||||
let _ = self.handlers.remove(handler_id.as_ref());
|
||||
}
|
||||
|
||||
pub async fn process_next_task(&mut self) -> FlowyResult<()> {
|
||||
pub(crate) async fn process_next_task(&mut self) -> FlowyResult<()> {
|
||||
let mut get_next_task = || {
|
||||
let pending_task = self.queue.mut_head(|list| list.pop())?;
|
||||
let task = self.store.remove_task(&pending_task.id)?;
|
||||
@ -64,7 +65,7 @@ impl GridTaskScheduler {
|
||||
};
|
||||
|
||||
if let Some(task) = get_next_task() {
|
||||
match self.handlers.get(&task.hid) {
|
||||
match self.handlers.get(&task.handler_id) {
|
||||
None => {}
|
||||
Some(handler) => {
|
||||
let _ = handler.process_task(task).await;
|
||||
@ -74,14 +75,18 @@ impl GridTaskScheduler {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn register_task(&mut self, task: Task) {
|
||||
pub(crate) fn register_task(&mut self, task: Task) {
|
||||
assert!(!task.is_finished());
|
||||
self.queue.push(&task);
|
||||
self.store.insert_task(task);
|
||||
self.notify();
|
||||
}
|
||||
|
||||
pub fn notify(&self) {
|
||||
pub(crate) fn next_task_id(&self) -> TaskId {
|
||||
self.store.next_task_id()
|
||||
}
|
||||
|
||||
pub(crate) fn notify(&self) {
|
||||
let _ = self.notifier.send(());
|
||||
}
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ use std::collections::HashMap;
|
||||
use std::sync::atomic::AtomicU32;
|
||||
use std::sync::atomic::Ordering::SeqCst;
|
||||
|
||||
pub struct GridTaskStore {
|
||||
pub(crate) struct GridTaskStore {
|
||||
tasks: HashMap<TaskId, Task>,
|
||||
task_id_counter: AtomicU32,
|
||||
}
|
||||
@ -17,15 +17,15 @@ impl GridTaskStore {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn insert_task(&mut self, task: Task) {
|
||||
pub(crate) fn insert_task(&mut self, task: Task) {
|
||||
self.tasks.insert(task.id, task);
|
||||
}
|
||||
|
||||
pub fn remove_task(&mut self, task_id: &TaskId) -> Option<Task> {
|
||||
pub(crate) fn remove_task(&mut self, task_id: &TaskId) -> Option<Task> {
|
||||
self.tasks.remove(task_id)
|
||||
}
|
||||
#[allow(dead_code)]
|
||||
pub fn next_task_id(&self) -> TaskId {
|
||||
|
||||
pub(crate) fn next_task_id(&self) -> TaskId {
|
||||
let _ = self.task_id_counter.fetch_add(1, SeqCst);
|
||||
self.task_id_counter.load(SeqCst)
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
use crate::services::row::GridBlockSnapshot;
|
||||
use crate::services::tasks::queue::TaskHandlerId;
|
||||
use std::cmp::Ordering;
|
||||
|
||||
@ -44,20 +45,23 @@ impl Ord for PendingTask {
|
||||
(TaskType::Snapshot, TaskType::Snapshot) => Ordering::Equal,
|
||||
(TaskType::Snapshot, _) => Ordering::Greater,
|
||||
(_, TaskType::Snapshot) => Ordering::Less,
|
||||
(TaskType::Filter, TaskType::Filter) => self.id.cmp(&other.id),
|
||||
(TaskType::Filter, TaskType::Filter) => self.id.cmp(&other.id).reverse(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub type ContentId = String;
|
||||
|
||||
pub enum TaskContent {
|
||||
Snapshot { content_id: ContentId },
|
||||
Filter,
|
||||
pub(crate) struct FilterTaskContext {
|
||||
pub blocks: Vec<GridBlockSnapshot>,
|
||||
}
|
||||
|
||||
pub struct Task {
|
||||
pub hid: TaskHandlerId,
|
||||
pub(crate) enum TaskContent {
|
||||
#[allow(dead_code)]
|
||||
Snapshot,
|
||||
Filter(FilterTaskContext),
|
||||
}
|
||||
|
||||
pub(crate) struct Task {
|
||||
pub handler_id: TaskHandlerId,
|
||||
pub id: TaskId,
|
||||
pub content: TaskContent,
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
use crate::entities::FieldType;
|
||||
use crate::services::field::*;
|
||||
use flowy_grid_data_model::entities::FieldType;
|
||||
use flowy_grid_data_model::revision::BuildGridContext;
|
||||
use flowy_sync::client_grid::GridBuilder;
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
use crate::grid::field_util::make_date_cell_string;
|
||||
use crate::grid::script::EditorScript::*;
|
||||
use crate::grid::script::*;
|
||||
use flowy_grid::entities::{CellChangeset, FieldType};
|
||||
use flowy_grid::services::field::{MultiSelectTypeOption, SelectOptionCellContentChangeset, SingleSelectTypeOption};
|
||||
use flowy_grid_data_model::entities::{CellChangeset, FieldType};
|
||||
|
||||
#[tokio::test]
|
||||
async fn grid_cell_update() {
|
||||
@ -17,7 +17,8 @@ async fn grid_cell_update() {
|
||||
let mut scripts = vec![];
|
||||
for (_, row_rev) in row_revs.iter().enumerate() {
|
||||
for field_rev in field_revs {
|
||||
let data = match field_rev.field_type {
|
||||
let field_type: FieldType = field_rev.field_type_rev.into();
|
||||
let data = match field_type {
|
||||
FieldType::RichText => "".to_string(),
|
||||
FieldType::Number => "123".to_string(),
|
||||
FieldType::DateTime => make_date_cell_string("123"),
|
||||
|
@ -2,8 +2,8 @@ use crate::grid::field_util::*;
|
||||
use crate::grid::script::EditorScript::*;
|
||||
use crate::grid::script::*;
|
||||
use flowy_grid::services::field::{SelectOption, SingleSelectTypeOption};
|
||||
use flowy_grid_data_model::entities::FieldChangesetParams;
|
||||
use flowy_grid_data_model::revision::TypeOptionDataEntry;
|
||||
use flowy_sync::entities::grid::FieldChangesetParams;
|
||||
|
||||
#[tokio::test]
|
||||
async fn grid_create_field() {
|
||||
|
@ -1,6 +1,6 @@
|
||||
use flowy_grid::services::field::*;
|
||||
|
||||
use flowy_grid_data_model::entities::*;
|
||||
use flowy_grid::entities::*;
|
||||
use flowy_grid_data_model::revision::*;
|
||||
|
||||
pub fn create_text_field(grid_id: &str) -> (InsertFieldParams, FieldRevision) {
|
||||
@ -12,7 +12,7 @@ pub fn create_text_field(grid_id: &str) -> (InsertFieldParams, FieldRevision) {
|
||||
let cloned_field_rev = field_rev.clone();
|
||||
|
||||
let type_option_data = field_rev
|
||||
.get_type_option_entry::<RichTextTypeOption>(&field_rev.field_type)
|
||||
.get_type_option_entry::<RichTextTypeOption, _>(field_rev.field_type_rev)
|
||||
.unwrap()
|
||||
.protobuf_bytes()
|
||||
.to_vec();
|
||||
@ -21,7 +21,7 @@ pub fn create_text_field(grid_id: &str) -> (InsertFieldParams, FieldRevision) {
|
||||
id: field_rev.id,
|
||||
name: field_rev.name,
|
||||
desc: field_rev.desc,
|
||||
field_type: field_rev.field_type,
|
||||
field_type: field_rev.field_type_rev.into(),
|
||||
frozen: field_rev.frozen,
|
||||
visibility: field_rev.visibility,
|
||||
width: field_rev.width,
|
||||
@ -44,8 +44,9 @@ pub fn create_single_select_field(grid_id: &str) -> (InsertFieldParams, FieldRev
|
||||
|
||||
let field_rev = FieldBuilder::new(single_select).name("Name").visibility(true).build();
|
||||
let cloned_field_rev = field_rev.clone();
|
||||
let field_type: FieldType = field_rev.field_type_rev.into();
|
||||
let type_option_data = field_rev
|
||||
.get_type_option_entry::<SingleSelectTypeOption>(&field_rev.field_type)
|
||||
.get_type_option_entry::<SingleSelectTypeOption, _>(&field_type)
|
||||
.unwrap()
|
||||
.protobuf_bytes()
|
||||
.to_vec();
|
||||
@ -54,7 +55,7 @@ pub fn create_single_select_field(grid_id: &str) -> (InsertFieldParams, FieldRev
|
||||
id: field_rev.id,
|
||||
name: field_rev.name,
|
||||
desc: field_rev.desc,
|
||||
field_type: field_rev.field_type,
|
||||
field_type,
|
||||
frozen: field_rev.frozen,
|
||||
visibility: field_rev.visibility,
|
||||
width: field_rev.width,
|
||||
|
@ -1,6 +1,6 @@
|
||||
use crate::grid::script::EditorScript::*;
|
||||
use crate::grid::script::*;
|
||||
use flowy_grid_data_model::entities::{CreateGridFilterPayload, TextFilterCondition};
|
||||
use flowy_grid::entities::CreateGridFilterPayload;
|
||||
|
||||
#[tokio::test]
|
||||
async fn grid_filter_create_test() {
|
||||
@ -26,14 +26,17 @@ async fn grid_filter_invalid_condition_panic_test() {
|
||||
#[tokio::test]
|
||||
async fn grid_filter_delete_test() {
|
||||
let mut test = GridEditorTest::new().await;
|
||||
let field_rev = test.text_field();
|
||||
let payload = CreateGridFilterPayload::new(field_rev, TextFilterCondition::TextIsEmpty, Some("abc".to_owned()));
|
||||
let field_rev = test.text_field().clone();
|
||||
let payload = CreateGridFilterPayload::new(&field_rev, TextFilterCondition::TextIsEmpty, Some("abc".to_owned()));
|
||||
let scripts = vec![InsertGridTableFilter { payload }, AssertTableFilterCount { count: 1 }];
|
||||
test.run_scripts(scripts).await;
|
||||
|
||||
let filter = test.grid_filters().await.pop().unwrap();
|
||||
test.run_scripts(vec![
|
||||
DeleteGridTableFilter { filter_id: filter.id },
|
||||
DeleteGridTableFilter {
|
||||
filter_id: filter.id,
|
||||
field_type: field_rev.field_type.clone(),
|
||||
},
|
||||
AssertTableFilterCount { count: 0 },
|
||||
])
|
||||
.await;
|
||||
|
@ -2,7 +2,7 @@ mod block_test;
|
||||
mod cell_test;
|
||||
mod field_test;
|
||||
mod field_util;
|
||||
mod filter_test;
|
||||
// mod filter_test;
|
||||
mod row_test;
|
||||
mod row_util;
|
||||
mod script;
|
||||
|
@ -3,11 +3,11 @@ use crate::grid::row_util::GridRowTestBuilder;
|
||||
use crate::grid::script::EditorScript::*;
|
||||
use crate::grid::script::*;
|
||||
use chrono::NaiveDateTime;
|
||||
use flowy_grid::entities::FieldType;
|
||||
use flowy_grid::services::field::{
|
||||
DateCellData, MultiSelectTypeOption, SingleSelectTypeOption, SELECTION_IDS_SEPARATOR,
|
||||
};
|
||||
use flowy_grid::services::row::{decode_cell_data, CreateRowRevisionBuilder};
|
||||
use flowy_grid_data_model::entities::FieldType;
|
||||
use flowy_grid_data_model::revision::RowMetaChangeset;
|
||||
|
||||
#[tokio::test]
|
||||
@ -75,7 +75,8 @@ async fn grid_row_add_cells_test() {
|
||||
let mut test = GridEditorTest::new().await;
|
||||
let mut builder = CreateRowRevisionBuilder::new(&test.field_revs);
|
||||
for field in &test.field_revs {
|
||||
match field.field_type {
|
||||
let field_type: FieldType = field.field_type_rev.into();
|
||||
match field_type {
|
||||
FieldType::RichText => {
|
||||
builder.add_cell(&field.id, "hello world".to_owned()).unwrap();
|
||||
}
|
||||
@ -122,7 +123,8 @@ async fn grid_row_add_date_cell_test() {
|
||||
let mut date_field = None;
|
||||
let timestamp = 1647390674;
|
||||
for field in &test.field_revs {
|
||||
if field.field_type == FieldType::DateTime {
|
||||
let field_type: FieldType = field.field_type_rev.into();
|
||||
if field_type == FieldType::DateTime {
|
||||
date_field = Some(field.clone());
|
||||
NaiveDateTime::from_timestamp(123, 0);
|
||||
// The data should not be empty
|
||||
|
@ -1,7 +1,7 @@
|
||||
use crate::grid::script::GridEditorTest;
|
||||
use flowy_grid::entities::FieldType;
|
||||
use flowy_grid::services::field::DateCellContentChangeset;
|
||||
use flowy_grid::services::row::{CreateRowRevisionBuilder, CreateRowRevisionPayload};
|
||||
use flowy_grid_data_model::entities::FieldType;
|
||||
use flowy_grid_data_model::revision::FieldRevision;
|
||||
use strum::EnumCount;
|
||||
|
||||
@ -61,8 +61,12 @@ impl<'a> GridRowTestBuilder<'a> {
|
||||
self.test
|
||||
.field_revs
|
||||
.iter()
|
||||
.find(|field_rev| &field_rev.field_type == field_type)
|
||||
.find(|field_rev| {
|
||||
let t_field_type: FieldType = field_rev.field_type_rev.into();
|
||||
&t_field_type == field_type
|
||||
})
|
||||
.unwrap()
|
||||
.as_ref()
|
||||
.clone()
|
||||
}
|
||||
|
||||
|
@ -1,10 +1,13 @@
|
||||
#![cfg_attr(rustfmt, rustfmt::skip)]
|
||||
#![allow(clippy::all)]
|
||||
#![allow(dead_code)]
|
||||
#![allow(unused_imports)]
|
||||
use bytes::Bytes;
|
||||
use flowy_grid::services::field::*;
|
||||
use flowy_grid::services::grid_editor::{GridPadBuilder, GridRevisionEditor};
|
||||
use flowy_grid::services::row::CreateRowRevisionPayload;
|
||||
use flowy_grid::services::setting::GridSettingChangesetBuilder;
|
||||
use flowy_grid_data_model::entities::*;
|
||||
use flowy_grid::entities::*;
|
||||
use flowy_grid_data_model::revision::*;
|
||||
use flowy_revision::REVISION_WRITE_INTERVAL_IN_MILLIS;
|
||||
use flowy_sync::client_grid::GridBuilder;
|
||||
@ -15,6 +18,7 @@ use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use strum::EnumCount;
|
||||
use tokio::time::sleep;
|
||||
use flowy_sync::entities::grid::{CreateGridFilterParams, DeleteFilterParams, FieldChangesetParams, GridSettingChangesetParams};
|
||||
|
||||
pub enum EditorScript {
|
||||
CreateField {
|
||||
@ -77,6 +81,7 @@ pub enum EditorScript {
|
||||
},
|
||||
DeleteGridTableFilter {
|
||||
filter_id: String,
|
||||
field_type: FieldType,
|
||||
},
|
||||
#[allow(dead_code)]
|
||||
AssertGridSetting {
|
||||
@ -89,12 +94,12 @@ pub struct GridEditorTest {
|
||||
pub sdk: FlowySDKTest,
|
||||
pub grid_id: String,
|
||||
pub editor: Arc<GridRevisionEditor>,
|
||||
pub field_revs: Vec<FieldRevision>,
|
||||
pub field_revs: Vec<Arc<FieldRevision>>,
|
||||
pub block_meta_revs: Vec<Arc<GridBlockMetaRevision>>,
|
||||
pub row_revs: Vec<Arc<RowRevision>>,
|
||||
pub field_count: usize,
|
||||
|
||||
pub row_order_by_row_id: HashMap<String, RowOrder>,
|
||||
pub row_order_by_row_id: HashMap<String, BlockRowInfo>,
|
||||
}
|
||||
|
||||
impl GridEditorTest {
|
||||
@ -105,7 +110,7 @@ impl GridEditorTest {
|
||||
let view_data: Bytes = build_context.into();
|
||||
let test = ViewTest::new_grid_view(&sdk, view_data.to_vec()).await;
|
||||
let editor = sdk.grid_manager.open_grid(&test.view.id).await.unwrap();
|
||||
let field_revs = editor.get_field_revs::<FieldOrder>(None).await.unwrap();
|
||||
let field_revs = editor.get_field_revs(None).await.unwrap();
|
||||
let block_meta_revs = editor.get_block_meta_revs().await.unwrap();
|
||||
let row_revs = editor.grid_block_snapshots(None).await.unwrap().pop().unwrap().row_revs;
|
||||
assert_eq!(row_revs.len(), 3);
|
||||
@ -147,12 +152,12 @@ impl GridEditorTest {
|
||||
}
|
||||
|
||||
self.editor.insert_field(params).await.unwrap();
|
||||
self.field_revs = self.editor.get_field_revs::<FieldOrder>(None).await.unwrap();
|
||||
self.field_revs = self.editor.get_field_revs(None).await.unwrap();
|
||||
assert_eq!(self.field_count, self.field_revs.len());
|
||||
}
|
||||
EditorScript::UpdateField { changeset: change } => {
|
||||
self.editor.update_field(change).await.unwrap();
|
||||
self.field_revs = self.editor.get_field_revs::<FieldOrder>(None).await.unwrap();
|
||||
self.field_revs = self.editor.get_field_revs(None).await.unwrap();
|
||||
}
|
||||
EditorScript::DeleteField { field_rev } => {
|
||||
if self.editor.contain_field(&field_rev.id).await {
|
||||
@ -160,18 +165,18 @@ impl GridEditorTest {
|
||||
}
|
||||
|
||||
self.editor.delete_field(&field_rev.id).await.unwrap();
|
||||
self.field_revs = self.editor.get_field_revs::<FieldOrder>(None).await.unwrap();
|
||||
self.field_revs = self.editor.get_field_revs(None).await.unwrap();
|
||||
assert_eq!(self.field_count, self.field_revs.len());
|
||||
}
|
||||
EditorScript::AssertFieldCount(count) => {
|
||||
assert_eq!(
|
||||
self.editor.get_field_revs::<FieldOrder>(None).await.unwrap().len(),
|
||||
self.editor.get_field_revs(None).await.unwrap().len(),
|
||||
count
|
||||
);
|
||||
}
|
||||
EditorScript::AssertFieldEqual { field_index, field_rev } => {
|
||||
let field_revs = self.editor.get_field_revs::<FieldOrder>(None).await.unwrap();
|
||||
assert_eq!(field_revs[field_index].clone(), field_rev);
|
||||
let field_revs = self.editor.get_field_revs(None).await.unwrap();
|
||||
assert_eq!(field_revs[field_index].as_ref(), &field_rev);
|
||||
}
|
||||
EditorScript::CreateBlock { block } => {
|
||||
self.editor.create_block(block).await.unwrap();
|
||||
@ -198,14 +203,14 @@ impl GridEditorTest {
|
||||
}
|
||||
EditorScript::CreateEmptyRow => {
|
||||
let row_order = self.editor.create_row(None).await.unwrap();
|
||||
self.row_order_by_row_id.insert(row_order.row_id.clone(), row_order);
|
||||
self.row_order_by_row_id.insert(row_order.row_id().to_owned(), row_order);
|
||||
self.row_revs = self.get_row_revs().await;
|
||||
self.block_meta_revs = self.editor.get_block_meta_revs().await.unwrap();
|
||||
}
|
||||
EditorScript::CreateRow { payload: context } => {
|
||||
let row_orders = self.editor.insert_rows(vec![context]).await.unwrap();
|
||||
for row_order in row_orders {
|
||||
self.row_order_by_row_id.insert(row_order.row_id.clone(), row_order);
|
||||
self.row_order_by_row_id.insert(row_order.row_id().to_owned(), row_order);
|
||||
}
|
||||
self.row_revs = self.get_row_revs().await;
|
||||
self.block_meta_revs = self.editor.get_block_meta_revs().await.unwrap();
|
||||
@ -215,7 +220,7 @@ impl GridEditorTest {
|
||||
let row_orders = row_ids
|
||||
.into_iter()
|
||||
.map(|row_id| self.row_order_by_row_id.get(&row_id).unwrap().clone())
|
||||
.collect::<Vec<RowOrder>>();
|
||||
.collect::<Vec<BlockRowInfo>>();
|
||||
|
||||
self.editor.delete_rows(row_orders).await.unwrap();
|
||||
self.row_revs = self.get_row_revs().await;
|
||||
@ -265,10 +270,10 @@ impl GridEditorTest {
|
||||
let filters = self.editor.get_grid_filter(&layout_type).await.unwrap();
|
||||
assert_eq!(count as usize, filters.len());
|
||||
}
|
||||
EditorScript::DeleteGridTableFilter { filter_id } => {
|
||||
EditorScript::DeleteGridTableFilter { filter_id ,field_type} => {
|
||||
let layout_type = GridLayoutType::Table;
|
||||
let params = GridSettingChangesetBuilder::new(&self.grid_id, &layout_type)
|
||||
.delete_filter(&filter_id)
|
||||
.delete_filter(DeleteFilterParams { filter_id, field_type_rev: field_type.into() })
|
||||
.build();
|
||||
let _ = self.editor.update_grid_setting(params).await.unwrap();
|
||||
}
|
||||
@ -303,7 +308,10 @@ impl GridEditorTest {
|
||||
pub fn text_field(&self) -> &FieldRevision {
|
||||
self.field_revs
|
||||
.iter()
|
||||
.filter(|field_rev| field_rev.field_type == FieldType::RichText)
|
||||
.filter(|field_rev| {
|
||||
let t_field_type: FieldType = field_rev.field_type_rev.into();
|
||||
t_field_type == FieldType::RichText
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
.pop()
|
||||
.unwrap()
|
||||
|
@ -3,7 +3,7 @@ use crate::{
|
||||
request::{HttpRequestBuilder, ResponseMiddleware},
|
||||
};
|
||||
use flowy_error::FlowyError;
|
||||
use flowy_sync::entities::text_block_info::{CreateTextBlockParams, ResetTextBlockParams, TextBlockId, TextBlockInfo};
|
||||
use flowy_sync::entities::text_block::{CreateTextBlockParams, ResetTextBlockParams, TextBlockId, TextBlockInfo};
|
||||
use flowy_text_block::BlockCloudService;
|
||||
use http_flowy::response::FlowyResponse;
|
||||
use lazy_static::lazy_static;
|
||||
|
@ -1,5 +1,5 @@
|
||||
use flowy_sync::{
|
||||
entities::{folder_info::FolderInfo, text_block_info::TextBlockInfo},
|
||||
entities::{folder::FolderInfo, text_block::TextBlockInfo},
|
||||
errors::CollaborateError,
|
||||
protobuf::{RepeatedRevision as RepeatedRevisionPB, Revision as RevisionPB},
|
||||
server_document::*,
|
||||
|
@ -6,7 +6,7 @@ use flowy_folder::event_map::FolderCouldServiceV1;
|
||||
use flowy_sync::{
|
||||
client_document::default::initial_quill_delta_string,
|
||||
entities::{
|
||||
text_block_info::{CreateTextBlockParams, ResetTextBlockParams, TextBlockId, TextBlockInfo},
|
||||
text_block::{CreateTextBlockParams, ResetTextBlockParams, TextBlockId, TextBlockInfo},
|
||||
ws_data::{ClientRevisionWSData, ClientRevisionWSDataType},
|
||||
},
|
||||
errors::CollaborateError,
|
||||
|
@ -9,7 +9,7 @@ use flowy_error::{internal_error, FlowyResult};
|
||||
use flowy_revision::{RevisionCloudService, RevisionManager, RevisionObjectBuilder, RevisionWebSocket};
|
||||
use flowy_sync::entities::ws_data::ServerRevisionWSData;
|
||||
use flowy_sync::{
|
||||
entities::{revision::Revision, text_block_info::TextBlockInfo},
|
||||
entities::{revision::Revision, text_block::TextBlockInfo},
|
||||
errors::CollaborateResult,
|
||||
util::make_delta_from_revisions,
|
||||
};
|
||||
|
@ -1,7 +1,7 @@
|
||||
use crate::entities::{ExportData, ExportParams, ExportPayload};
|
||||
use crate::TextBlockManager;
|
||||
use flowy_error::FlowyError;
|
||||
use flowy_sync::entities::text_block_info::{TextBlockDelta, TextBlockId};
|
||||
use flowy_sync::entities::text_block::{TextBlockDelta, TextBlockId};
|
||||
use lib_dispatch::prelude::{data_result, AppData, Data, DataResult};
|
||||
use std::convert::TryInto;
|
||||
use std::sync::Arc;
|
||||
|
@ -15,7 +15,7 @@ pub mod errors {
|
||||
pub const TEXT_BLOCK_SYNC_INTERVAL_IN_MILLIS: u64 = 1000;
|
||||
|
||||
use crate::errors::FlowyError;
|
||||
use flowy_sync::entities::text_block_info::{CreateTextBlockParams, ResetTextBlockParams, TextBlockId, TextBlockInfo};
|
||||
use flowy_sync::entities::text_block::{CreateTextBlockParams, ResetTextBlockParams, TextBlockId, TextBlockInfo};
|
||||
use lib_infra::future::FutureResult;
|
||||
|
||||
pub trait BlockCloudService: Send + Sync {
|
||||
|
@ -7,7 +7,7 @@ use flowy_revision::disk::SQLiteTextBlockRevisionPersistence;
|
||||
use flowy_revision::{RevisionCloudService, RevisionManager, RevisionPersistence, RevisionWebSocket};
|
||||
use flowy_sync::entities::{
|
||||
revision::{md5, RepeatedRevision, Revision},
|
||||
text_block_info::{TextBlockDelta, TextBlockId},
|
||||
text_block::{TextBlockDelta, TextBlockId},
|
||||
ws_data::ServerRevisionWSData,
|
||||
};
|
||||
use lib_infra::future::FutureResult;
|
||||
|
4
shared-lib/Cargo.lock
generated
4
shared-lib/Cargo.lock
generated
@ -447,17 +447,13 @@ name = "flowy-grid-data-model"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"flowy-derive",
|
||||
"flowy-error-code",
|
||||
"indexmap",
|
||||
"lib-infra",
|
||||
"nanoid",
|
||||
"protobuf",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_repr",
|
||||
"strum",
|
||||
"strum_macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -6,17 +6,14 @@ edition = "2021"
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
flowy-derive = { path = "../flowy-derive" }
|
||||
protobuf = {version = "2.18.0"}
|
||||
bytes = "1.0"
|
||||
strum = "0.21"
|
||||
strum_macros = "0.21"
|
||||
serde = { version = "1.0", features = ["derive", "rc"] }
|
||||
serde_json = {version = "1.0"}
|
||||
serde_repr = "0.1"
|
||||
nanoid = "0.4.0"
|
||||
flowy-error-code = { path = "../flowy-error-code"}
|
||||
indexmap = {version = "1.8.1", features = ["serde"]}
|
||||
|
||||
[build-dependencies]
|
||||
lib-infra = { path = "../lib-infra", features = ["protobuf_file_gen"] }
|
||||
|
||||
|
@ -1,2 +0,0 @@
|
||||
# Check out the FlowyConfig (located in flowy_toml.rs) for more details.
|
||||
proto_input = ["src/entities/",]
|
@ -1,5 +0,0 @@
|
||||
use lib_infra::code_gen;
|
||||
|
||||
fn main() {
|
||||
code_gen::protobuf_file::gen(env!("CARGO_PKG_NAME"));
|
||||
}
|
@ -1,523 +0,0 @@
|
||||
use crate::parser::NotEmptyStr;
|
||||
use crate::revision::FieldRevision;
|
||||
use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
|
||||
use flowy_error_code::ErrorCode;
|
||||
use serde_repr::*;
|
||||
use strum_macros::{Display, EnumCount as EnumCountMacro, EnumIter, EnumString};
|
||||
|
||||
#[derive(Debug, Clone, Default, ProtoBuf)]
|
||||
pub struct Field {
|
||||
#[pb(index = 1)]
|
||||
pub id: String,
|
||||
|
||||
#[pb(index = 2)]
|
||||
pub name: String,
|
||||
|
||||
#[pb(index = 3)]
|
||||
pub desc: String,
|
||||
|
||||
#[pb(index = 4)]
|
||||
pub field_type: FieldType,
|
||||
|
||||
#[pb(index = 5)]
|
||||
pub frozen: bool,
|
||||
|
||||
#[pb(index = 6)]
|
||||
pub visibility: bool,
|
||||
|
||||
#[pb(index = 7)]
|
||||
pub width: i32,
|
||||
|
||||
#[pb(index = 8)]
|
||||
pub is_primary: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, ProtoBuf)]
|
||||
pub struct FieldOrder {
|
||||
#[pb(index = 1)]
|
||||
pub field_id: String,
|
||||
}
|
||||
|
||||
impl std::convert::From<&str> for FieldOrder {
|
||||
fn from(s: &str) -> Self {
|
||||
FieldOrder { field_id: s.to_owned() }
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::From<String> for FieldOrder {
|
||||
fn from(s: String) -> Self {
|
||||
FieldOrder { field_id: s }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, ProtoBuf)]
|
||||
pub struct GridFieldChangeset {
|
||||
#[pb(index = 1)]
|
||||
pub grid_id: String,
|
||||
|
||||
#[pb(index = 2)]
|
||||
pub inserted_fields: Vec<IndexField>,
|
||||
|
||||
#[pb(index = 3)]
|
||||
pub deleted_fields: Vec<FieldOrder>,
|
||||
|
||||
#[pb(index = 4)]
|
||||
pub updated_fields: Vec<Field>,
|
||||
}
|
||||
|
||||
impl GridFieldChangeset {
|
||||
pub fn insert(grid_id: &str, inserted_fields: Vec<IndexField>) -> Self {
|
||||
Self {
|
||||
grid_id: grid_id.to_owned(),
|
||||
inserted_fields,
|
||||
deleted_fields: vec![],
|
||||
updated_fields: vec![],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn delete(grid_id: &str, deleted_fields: Vec<FieldOrder>) -> Self {
|
||||
Self {
|
||||
grid_id: grid_id.to_string(),
|
||||
inserted_fields: vec![],
|
||||
deleted_fields,
|
||||
updated_fields: vec![],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update(grid_id: &str, updated_fields: Vec<Field>) -> Self {
|
||||
Self {
|
||||
grid_id: grid_id.to_string(),
|
||||
inserted_fields: vec![],
|
||||
deleted_fields: vec![],
|
||||
updated_fields,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, ProtoBuf)]
|
||||
pub struct IndexField {
|
||||
#[pb(index = 1)]
|
||||
pub field: Field,
|
||||
|
||||
#[pb(index = 2)]
|
||||
pub index: i32,
|
||||
}
|
||||
|
||||
impl IndexField {
|
||||
pub fn from_field_rev(field_rev: &FieldRevision, index: usize) -> Self {
|
||||
Self {
|
||||
field: Field::from(field_rev.clone()),
|
||||
index: index as i32,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, ProtoBuf)]
|
||||
pub struct GetEditFieldContextPayload {
|
||||
#[pb(index = 1)]
|
||||
pub grid_id: String,
|
||||
|
||||
#[pb(index = 2, one_of)]
|
||||
pub field_id: Option<String>,
|
||||
|
||||
#[pb(index = 3)]
|
||||
pub field_type: FieldType,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, ProtoBuf)]
|
||||
pub struct EditFieldPayload {
|
||||
#[pb(index = 1)]
|
||||
pub grid_id: String,
|
||||
|
||||
#[pb(index = 2)]
|
||||
pub field_id: String,
|
||||
|
||||
#[pb(index = 3)]
|
||||
pub field_type: FieldType,
|
||||
|
||||
#[pb(index = 4)]
|
||||
pub create_if_not_exist: bool,
|
||||
}
|
||||
|
||||
pub struct EditFieldParams {
|
||||
pub grid_id: String,
|
||||
pub field_id: String,
|
||||
pub field_type: FieldType,
|
||||
}
|
||||
|
||||
impl TryInto<EditFieldParams> for EditFieldPayload {
|
||||
type Error = ErrorCode;
|
||||
|
||||
fn try_into(self) -> Result<EditFieldParams, Self::Error> {
|
||||
let grid_id = NotEmptyStr::parse(self.grid_id).map_err(|_| ErrorCode::GridIdIsEmpty)?;
|
||||
let field_id = NotEmptyStr::parse(self.field_id).map_err(|_| ErrorCode::FieldIdIsEmpty)?;
|
||||
Ok(EditFieldParams {
|
||||
grid_id: grid_id.0,
|
||||
field_id: field_id.0,
|
||||
field_type: self.field_type,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub struct CreateFieldParams {
|
||||
pub grid_id: String,
|
||||
pub field_type: FieldType,
|
||||
}
|
||||
|
||||
impl TryInto<CreateFieldParams> for EditFieldPayload {
|
||||
type Error = ErrorCode;
|
||||
|
||||
fn try_into(self) -> Result<CreateFieldParams, Self::Error> {
|
||||
let grid_id = NotEmptyStr::parse(self.grid_id).map_err(|_| ErrorCode::GridIdIsEmpty)?;
|
||||
|
||||
Ok(CreateFieldParams {
|
||||
grid_id: grid_id.0,
|
||||
field_type: self.field_type,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, ProtoBuf)]
|
||||
pub struct FieldTypeOptionContext {
|
||||
#[pb(index = 1)]
|
||||
pub grid_id: String,
|
||||
|
||||
#[pb(index = 2)]
|
||||
pub grid_field: Field,
|
||||
|
||||
#[pb(index = 3)]
|
||||
pub type_option_data: Vec<u8>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, ProtoBuf)]
|
||||
pub struct FieldTypeOptionData {
|
||||
#[pb(index = 1)]
|
||||
pub grid_id: String,
|
||||
|
||||
#[pb(index = 2)]
|
||||
pub field: Field,
|
||||
|
||||
#[pb(index = 3)]
|
||||
pub type_option_data: Vec<u8>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, ProtoBuf)]
|
||||
pub struct RepeatedField {
|
||||
#[pb(index = 1)]
|
||||
pub items: Vec<Field>,
|
||||
}
|
||||
impl std::ops::Deref for RepeatedField {
|
||||
type Target = Vec<Field>;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.items
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::DerefMut for RepeatedField {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.items
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::From<Vec<Field>> for RepeatedField {
|
||||
fn from(items: Vec<Field>) -> Self {
|
||||
Self { items }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, ProtoBuf)]
|
||||
pub struct RepeatedFieldOrder {
|
||||
#[pb(index = 1)]
|
||||
pub items: Vec<FieldOrder>,
|
||||
}
|
||||
|
||||
impl std::ops::Deref for RepeatedFieldOrder {
|
||||
type Target = Vec<FieldOrder>;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.items
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::From<Vec<FieldOrder>> for RepeatedFieldOrder {
|
||||
fn from(field_orders: Vec<FieldOrder>) -> Self {
|
||||
RepeatedFieldOrder { items: field_orders }
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::From<String> for RepeatedFieldOrder {
|
||||
fn from(s: String) -> Self {
|
||||
RepeatedFieldOrder {
|
||||
items: vec![FieldOrder::from(s)],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(ProtoBuf, Default)]
|
||||
pub struct InsertFieldPayload {
|
||||
#[pb(index = 1)]
|
||||
pub grid_id: String,
|
||||
|
||||
#[pb(index = 2)]
|
||||
pub field: Field,
|
||||
|
||||
#[pb(index = 3)]
|
||||
pub type_option_data: Vec<u8>,
|
||||
|
||||
#[pb(index = 4, one_of)]
|
||||
pub start_field_id: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct InsertFieldParams {
|
||||
pub grid_id: String,
|
||||
pub field: Field,
|
||||
pub type_option_data: Vec<u8>,
|
||||
pub start_field_id: Option<String>,
|
||||
}
|
||||
|
||||
impl TryInto<InsertFieldParams> for InsertFieldPayload {
|
||||
type Error = ErrorCode;
|
||||
|
||||
fn try_into(self) -> Result<InsertFieldParams, Self::Error> {
|
||||
let grid_id = NotEmptyStr::parse(self.grid_id).map_err(|_| ErrorCode::GridIdIsEmpty)?;
|
||||
let _ = NotEmptyStr::parse(self.field.id.clone()).map_err(|_| ErrorCode::FieldIdIsEmpty)?;
|
||||
|
||||
let start_field_id = match self.start_field_id {
|
||||
None => None,
|
||||
Some(id) => Some(NotEmptyStr::parse(id).map_err(|_| ErrorCode::FieldIdIsEmpty)?.0),
|
||||
};
|
||||
|
||||
Ok(InsertFieldParams {
|
||||
grid_id: grid_id.0,
|
||||
field: self.field,
|
||||
type_option_data: self.type_option_data,
|
||||
start_field_id,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(ProtoBuf, Default)]
|
||||
pub struct UpdateFieldTypeOptionPayload {
|
||||
#[pb(index = 1)]
|
||||
pub grid_id: String,
|
||||
|
||||
#[pb(index = 2)]
|
||||
pub field_id: String,
|
||||
|
||||
#[pb(index = 3)]
|
||||
pub type_option_data: Vec<u8>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct UpdateFieldTypeOptionParams {
|
||||
pub grid_id: String,
|
||||
pub field_id: String,
|
||||
pub type_option_data: Vec<u8>,
|
||||
}
|
||||
|
||||
impl TryInto<UpdateFieldTypeOptionParams> for UpdateFieldTypeOptionPayload {
|
||||
type Error = ErrorCode;
|
||||
|
||||
fn try_into(self) -> Result<UpdateFieldTypeOptionParams, Self::Error> {
|
||||
let grid_id = NotEmptyStr::parse(self.grid_id).map_err(|_| ErrorCode::GridIdIsEmpty)?;
|
||||
let _ = NotEmptyStr::parse(self.field_id.clone()).map_err(|_| ErrorCode::FieldIdIsEmpty)?;
|
||||
|
||||
Ok(UpdateFieldTypeOptionParams {
|
||||
grid_id: grid_id.0,
|
||||
field_id: self.field_id,
|
||||
type_option_data: self.type_option_data,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(ProtoBuf, Default)]
|
||||
pub struct QueryFieldPayload {
|
||||
#[pb(index = 1)]
|
||||
pub grid_id: String,
|
||||
|
||||
#[pb(index = 2)]
|
||||
pub field_orders: RepeatedFieldOrder,
|
||||
}
|
||||
|
||||
pub struct QueryFieldParams {
|
||||
pub grid_id: String,
|
||||
pub field_orders: RepeatedFieldOrder,
|
||||
}
|
||||
|
||||
impl TryInto<QueryFieldParams> for QueryFieldPayload {
|
||||
type Error = ErrorCode;
|
||||
|
||||
fn try_into(self) -> Result<QueryFieldParams, Self::Error> {
|
||||
let grid_id = NotEmptyStr::parse(self.grid_id).map_err(|_| ErrorCode::GridIdIsEmpty)?;
|
||||
Ok(QueryFieldParams {
|
||||
grid_id: grid_id.0,
|
||||
field_orders: self.field_orders,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, ProtoBuf)]
|
||||
pub struct FieldChangesetPayload {
|
||||
#[pb(index = 1)]
|
||||
pub field_id: String,
|
||||
|
||||
#[pb(index = 2)]
|
||||
pub grid_id: String,
|
||||
|
||||
#[pb(index = 3, one_of)]
|
||||
pub name: Option<String>,
|
||||
|
||||
#[pb(index = 4, one_of)]
|
||||
pub desc: Option<String>,
|
||||
|
||||
#[pb(index = 5, one_of)]
|
||||
pub field_type: Option<FieldType>,
|
||||
|
||||
#[pb(index = 6, one_of)]
|
||||
pub frozen: Option<bool>,
|
||||
|
||||
#[pb(index = 7, one_of)]
|
||||
pub visibility: Option<bool>,
|
||||
|
||||
#[pb(index = 8, one_of)]
|
||||
pub width: Option<i32>,
|
||||
|
||||
#[pb(index = 9, one_of)]
|
||||
pub type_option_data: Option<Vec<u8>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct FieldChangesetParams {
|
||||
pub field_id: String,
|
||||
|
||||
pub grid_id: String,
|
||||
|
||||
pub name: Option<String>,
|
||||
|
||||
pub desc: Option<String>,
|
||||
|
||||
pub field_type: Option<FieldType>,
|
||||
|
||||
pub frozen: Option<bool>,
|
||||
|
||||
pub visibility: Option<bool>,
|
||||
|
||||
pub width: Option<i32>,
|
||||
|
||||
pub type_option_data: Option<Vec<u8>>,
|
||||
}
|
||||
|
||||
impl TryInto<FieldChangesetParams> for FieldChangesetPayload {
|
||||
type Error = ErrorCode;
|
||||
|
||||
fn try_into(self) -> Result<FieldChangesetParams, Self::Error> {
|
||||
let grid_id = NotEmptyStr::parse(self.grid_id).map_err(|_| ErrorCode::GridIdIsEmpty)?;
|
||||
let field_id = NotEmptyStr::parse(self.field_id).map_err(|_| ErrorCode::FieldIdIsEmpty)?;
|
||||
|
||||
if let Some(type_option_data) = self.type_option_data.as_ref() {
|
||||
if type_option_data.is_empty() {
|
||||
return Err(ErrorCode::TypeOptionDataIsEmpty);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(FieldChangesetParams {
|
||||
field_id: field_id.0,
|
||||
grid_id: grid_id.0,
|
||||
name: self.name,
|
||||
desc: self.desc,
|
||||
field_type: self.field_type,
|
||||
frozen: self.frozen,
|
||||
visibility: self.visibility,
|
||||
width: self.width,
|
||||
type_option_data: self.type_option_data,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
Clone,
|
||||
PartialEq,
|
||||
Eq,
|
||||
ProtoBuf_Enum,
|
||||
EnumCountMacro,
|
||||
EnumString,
|
||||
EnumIter,
|
||||
Display,
|
||||
Serialize_repr,
|
||||
Deserialize_repr,
|
||||
)]
|
||||
#[repr(u8)]
|
||||
pub enum FieldType {
|
||||
RichText = 0,
|
||||
Number = 1,
|
||||
DateTime = 2,
|
||||
SingleSelect = 3,
|
||||
MultiSelect = 4,
|
||||
Checkbox = 5,
|
||||
URL = 6,
|
||||
}
|
||||
|
||||
impl std::default::Default for FieldType {
|
||||
fn default() -> Self {
|
||||
FieldType::RichText
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<FieldType> for FieldType {
|
||||
fn as_ref(&self) -> &FieldType {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&FieldType> for FieldType {
|
||||
fn from(field_type: &FieldType) -> Self {
|
||||
field_type.clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl FieldType {
|
||||
pub fn type_id(&self) -> String {
|
||||
let ty = self.clone() as u8;
|
||||
ty.to_string()
|
||||
}
|
||||
|
||||
pub fn default_cell_width(&self) -> i32 {
|
||||
match self {
|
||||
FieldType::DateTime => 180,
|
||||
_ => 150,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_number(&self) -> bool {
|
||||
self == &FieldType::Number
|
||||
}
|
||||
|
||||
pub fn is_text(&self) -> bool {
|
||||
self == &FieldType::RichText
|
||||
}
|
||||
|
||||
pub fn is_checkbox(&self) -> bool {
|
||||
self == &FieldType::Checkbox
|
||||
}
|
||||
|
||||
pub fn is_date(&self) -> bool {
|
||||
self == &FieldType::DateTime
|
||||
}
|
||||
|
||||
pub fn is_single_select(&self) -> bool {
|
||||
self == &FieldType::SingleSelect
|
||||
}
|
||||
|
||||
pub fn is_multi_select(&self) -> bool {
|
||||
self == &FieldType::MultiSelect
|
||||
}
|
||||
|
||||
pub fn is_url(&self) -> bool {
|
||||
self == &FieldType::URL
|
||||
}
|
||||
|
||||
pub fn is_select_option(&self) -> bool {
|
||||
self == &FieldType::MultiSelect || self == &FieldType::SingleSelect
|
||||
}
|
||||
}
|
@ -1,379 +0,0 @@
|
||||
use crate::entities::FieldOrder;
|
||||
use crate::parser::NotEmptyStr;
|
||||
use crate::revision::RowRevision;
|
||||
use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
|
||||
use flowy_error_code::ErrorCode;
|
||||
|
||||
#[derive(Debug, Clone, Default, ProtoBuf)]
|
||||
pub struct Grid {
|
||||
#[pb(index = 1)]
|
||||
pub id: String,
|
||||
|
||||
#[pb(index = 2)]
|
||||
pub field_orders: Vec<FieldOrder>,
|
||||
|
||||
#[pb(index = 3)]
|
||||
pub blocks: Vec<GridBlock>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone, ProtoBuf)]
|
||||
pub struct RowOrder {
|
||||
#[pb(index = 1)]
|
||||
pub row_id: String,
|
||||
|
||||
#[pb(index = 2)]
|
||||
pub block_id: String,
|
||||
|
||||
#[pb(index = 3)]
|
||||
pub height: i32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, ProtoBuf)]
|
||||
pub struct Row {
|
||||
#[pb(index = 1)]
|
||||
pub id: String,
|
||||
|
||||
#[pb(index = 2)]
|
||||
pub height: i32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, ProtoBuf)]
|
||||
pub struct OptionalRow {
|
||||
#[pb(index = 1, one_of)]
|
||||
pub row: Option<Row>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, ProtoBuf)]
|
||||
pub struct RepeatedRow {
|
||||
#[pb(index = 1)]
|
||||
pub items: Vec<Row>,
|
||||
}
|
||||
|
||||
impl std::convert::From<Vec<Row>> for RepeatedRow {
|
||||
fn from(items: Vec<Row>) -> Self {
|
||||
Self { items }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, ProtoBuf)]
|
||||
pub struct RepeatedGridBlock {
|
||||
#[pb(index = 1)]
|
||||
pub items: Vec<GridBlock>,
|
||||
}
|
||||
|
||||
impl std::convert::From<Vec<GridBlock>> for RepeatedGridBlock {
|
||||
fn from(items: Vec<GridBlock>) -> Self {
|
||||
Self { items }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, ProtoBuf)]
|
||||
pub struct IndexRowOrder {
|
||||
#[pb(index = 1)]
|
||||
pub row_order: RowOrder,
|
||||
|
||||
#[pb(index = 2, one_of)]
|
||||
pub index: Option<i32>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, ProtoBuf)]
|
||||
pub struct UpdatedRowOrder {
|
||||
#[pb(index = 1)]
|
||||
pub row_order: RowOrder,
|
||||
|
||||
#[pb(index = 2)]
|
||||
pub row: Row,
|
||||
}
|
||||
|
||||
impl UpdatedRowOrder {
|
||||
pub fn new(row_rev: &RowRevision, row: Row) -> Self {
|
||||
Self {
|
||||
row_order: RowOrder::from(row_rev),
|
||||
row,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, ProtoBuf)]
|
||||
pub struct GridRowsChangeset {
|
||||
#[pb(index = 1)]
|
||||
pub block_id: String,
|
||||
|
||||
#[pb(index = 2)]
|
||||
pub inserted_rows: Vec<IndexRowOrder>,
|
||||
|
||||
#[pb(index = 3)]
|
||||
pub deleted_rows: Vec<RowOrder>,
|
||||
|
||||
#[pb(index = 4)]
|
||||
pub updated_rows: Vec<UpdatedRowOrder>,
|
||||
}
|
||||
|
||||
impl std::convert::From<RowOrder> for IndexRowOrder {
|
||||
fn from(row_order: RowOrder) -> Self {
|
||||
Self { row_order, index: None }
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::From<&RowRevision> for IndexRowOrder {
|
||||
fn from(row: &RowRevision) -> Self {
|
||||
let row_order = RowOrder::from(row);
|
||||
Self::from(row_order)
|
||||
}
|
||||
}
|
||||
|
||||
impl GridRowsChangeset {
|
||||
pub fn insert(block_id: &str, inserted_rows: Vec<IndexRowOrder>) -> Self {
|
||||
Self {
|
||||
block_id: block_id.to_owned(),
|
||||
inserted_rows,
|
||||
deleted_rows: vec![],
|
||||
updated_rows: vec![],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn delete(block_id: &str, deleted_rows: Vec<RowOrder>) -> Self {
|
||||
Self {
|
||||
block_id: block_id.to_owned(),
|
||||
inserted_rows: vec![],
|
||||
deleted_rows,
|
||||
updated_rows: vec![],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update(block_id: &str, updated_rows: Vec<UpdatedRowOrder>) -> Self {
|
||||
Self {
|
||||
block_id: block_id.to_owned(),
|
||||
inserted_rows: vec![],
|
||||
deleted_rows: vec![],
|
||||
updated_rows,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, ProtoBuf)]
|
||||
pub struct GridBlock {
|
||||
#[pb(index = 1)]
|
||||
pub id: String,
|
||||
|
||||
#[pb(index = 2)]
|
||||
pub row_orders: Vec<RowOrder>,
|
||||
}
|
||||
|
||||
impl GridBlock {
|
||||
pub fn new(block_id: &str, row_orders: Vec<RowOrder>) -> Self {
|
||||
Self {
|
||||
id: block_id.to_owned(),
|
||||
row_orders,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, ProtoBuf)]
|
||||
pub struct Cell {
|
||||
#[pb(index = 1)]
|
||||
pub field_id: String,
|
||||
|
||||
#[pb(index = 2)]
|
||||
pub data: Vec<u8>,
|
||||
}
|
||||
|
||||
impl Cell {
|
||||
pub fn new(field_id: &str, data: Vec<u8>) -> Self {
|
||||
Self {
|
||||
field_id: field_id.to_owned(),
|
||||
data,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn empty(field_id: &str) -> Self {
|
||||
Self {
|
||||
field_id: field_id.to_owned(),
|
||||
data: vec![],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, ProtoBuf)]
|
||||
pub struct RepeatedCell {
|
||||
#[pb(index = 1)]
|
||||
pub items: Vec<Cell>,
|
||||
}
|
||||
|
||||
impl std::ops::Deref for RepeatedCell {
|
||||
type Target = Vec<Cell>;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.items
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::DerefMut for RepeatedCell {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.items
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::From<Vec<Cell>> for RepeatedCell {
|
||||
fn from(items: Vec<Cell>) -> Self {
|
||||
Self { items }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(ProtoBuf, Default)]
|
||||
pub struct CreateGridPayload {
|
||||
#[pb(index = 1)]
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, ProtoBuf, Default, Debug)]
|
||||
pub struct GridId {
|
||||
#[pb(index = 1)]
|
||||
pub value: String,
|
||||
}
|
||||
|
||||
impl AsRef<str> for GridId {
|
||||
fn as_ref(&self) -> &str {
|
||||
&self.value
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, ProtoBuf, Default, Debug)]
|
||||
pub struct GridBlockId {
|
||||
#[pb(index = 1)]
|
||||
pub value: String,
|
||||
}
|
||||
|
||||
impl AsRef<str> for GridBlockId {
|
||||
fn as_ref(&self) -> &str {
|
||||
&self.value
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::From<&str> for GridBlockId {
|
||||
fn from(s: &str) -> Self {
|
||||
GridBlockId { value: s.to_owned() }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(ProtoBuf, Default)]
|
||||
pub struct CreateRowPayload {
|
||||
#[pb(index = 1)]
|
||||
pub grid_id: String,
|
||||
|
||||
#[pb(index = 2, one_of)]
|
||||
pub start_row_id: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct CreateRowParams {
|
||||
pub grid_id: String,
|
||||
pub start_row_id: Option<String>,
|
||||
}
|
||||
|
||||
impl TryInto<CreateRowParams> for CreateRowPayload {
|
||||
type Error = ErrorCode;
|
||||
|
||||
fn try_into(self) -> Result<CreateRowParams, Self::Error> {
|
||||
let grid_id = NotEmptyStr::parse(self.grid_id).map_err(|_| ErrorCode::GridIdIsEmpty)?;
|
||||
Ok(CreateRowParams {
|
||||
grid_id: grid_id.0,
|
||||
start_row_id: self.start_row_id,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(ProtoBuf, Default)]
|
||||
pub struct QueryGridBlocksPayload {
|
||||
#[pb(index = 1)]
|
||||
pub grid_id: String,
|
||||
|
||||
#[pb(index = 2)]
|
||||
pub block_ids: Vec<String>,
|
||||
}
|
||||
|
||||
pub struct QueryGridBlocksParams {
|
||||
pub grid_id: String,
|
||||
pub block_ids: Vec<String>,
|
||||
}
|
||||
|
||||
impl TryInto<QueryGridBlocksParams> for QueryGridBlocksPayload {
|
||||
type Error = ErrorCode;
|
||||
|
||||
fn try_into(self) -> Result<QueryGridBlocksParams, Self::Error> {
|
||||
let grid_id = NotEmptyStr::parse(self.grid_id).map_err(|_| ErrorCode::GridIdIsEmpty)?;
|
||||
Ok(QueryGridBlocksParams {
|
||||
grid_id: grid_id.0,
|
||||
block_ids: self.block_ids,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, ProtoBuf_Enum)]
|
||||
pub enum MoveItemType {
|
||||
MoveField = 0,
|
||||
MoveRow = 1,
|
||||
}
|
||||
|
||||
impl std::default::Default for MoveItemType {
|
||||
fn default() -> Self {
|
||||
MoveItemType::MoveField
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, ProtoBuf)]
|
||||
pub struct MoveItemPayload {
|
||||
#[pb(index = 1)]
|
||||
pub grid_id: String,
|
||||
|
||||
#[pb(index = 2)]
|
||||
pub item_id: String,
|
||||
|
||||
#[pb(index = 3)]
|
||||
pub from_index: i32,
|
||||
|
||||
#[pb(index = 4)]
|
||||
pub to_index: i32,
|
||||
|
||||
#[pb(index = 5)]
|
||||
pub ty: MoveItemType,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct MoveItemParams {
|
||||
pub grid_id: String,
|
||||
pub item_id: String,
|
||||
pub from_index: i32,
|
||||
pub to_index: i32,
|
||||
pub ty: MoveItemType,
|
||||
}
|
||||
|
||||
impl TryInto<MoveItemParams> for MoveItemPayload {
|
||||
type Error = ErrorCode;
|
||||
|
||||
fn try_into(self) -> Result<MoveItemParams, Self::Error> {
|
||||
let grid_id = NotEmptyStr::parse(self.grid_id).map_err(|_| ErrorCode::GridIdIsEmpty)?;
|
||||
let item_id = NotEmptyStr::parse(self.item_id).map_err(|_| ErrorCode::InvalidData)?;
|
||||
Ok(MoveItemParams {
|
||||
grid_id: grid_id.0,
|
||||
item_id: item_id.0,
|
||||
from_index: self.from_index,
|
||||
to_index: self.to_index,
|
||||
ty: self.ty,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, ProtoBuf)]
|
||||
pub struct CellChangeset {
|
||||
#[pb(index = 1)]
|
||||
pub grid_id: String,
|
||||
|
||||
#[pb(index = 2)]
|
||||
pub row_id: String,
|
||||
|
||||
#[pb(index = 3)]
|
||||
pub field_id: String,
|
||||
|
||||
#[pb(index = 4, one_of)]
|
||||
pub cell_content_changeset: Option<String>,
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
mod field;
|
||||
mod grid;
|
||||
mod grid_filter;
|
||||
mod grid_group;
|
||||
mod grid_setting;
|
||||
mod grid_sort;
|
||||
|
||||
pub use field::*;
|
||||
pub use grid::*;
|
||||
pub use grid_filter::*;
|
||||
pub use grid_group::*;
|
||||
pub use grid_setting::*;
|
||||
pub use grid_sort::*;
|
@ -1,4 +1,2 @@
|
||||
pub mod entities;
|
||||
pub mod parser;
|
||||
pub mod protobuf;
|
||||
pub mod revision;
|
||||
|
@ -1,4 +1,3 @@
|
||||
use crate::entities::{CellChangeset, Field, FieldOrder, FieldType, RowOrder};
|
||||
use crate::revision::GridSettingRevision;
|
||||
use bytes::Bytes;
|
||||
use indexmap::IndexMap;
|
||||
@ -29,7 +28,7 @@ pub fn gen_field_id() -> String {
|
||||
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
|
||||
pub struct GridRevision {
|
||||
pub grid_id: String,
|
||||
pub fields: Vec<FieldRevision>,
|
||||
pub fields: Vec<Arc<FieldRevision>>,
|
||||
pub blocks: Vec<Arc<GridBlockMetaRevision>>,
|
||||
|
||||
#[serde(default, skip)]
|
||||
@ -49,7 +48,7 @@ impl GridRevision {
|
||||
pub fn from_build_context(grid_id: &str, context: BuildGridContext) -> Self {
|
||||
Self {
|
||||
grid_id: grid_id.to_owned(),
|
||||
fields: context.field_revs,
|
||||
fields: context.field_revs.into_iter().map(Arc::new).collect(),
|
||||
blocks: context.blocks.into_iter().map(Arc::new).collect(),
|
||||
setting: Default::default(),
|
||||
}
|
||||
@ -112,7 +111,8 @@ pub struct FieldRevision {
|
||||
|
||||
pub desc: String,
|
||||
|
||||
pub field_type: FieldType,
|
||||
#[serde(rename = "field_type")]
|
||||
pub field_type_rev: FieldTypeRevision,
|
||||
|
||||
pub frozen: bool,
|
||||
|
||||
@ -131,16 +131,27 @@ pub struct FieldRevision {
|
||||
pub is_primary: bool,
|
||||
}
|
||||
|
||||
impl AsRef<FieldRevision> for FieldRevision {
|
||||
fn as_ref(&self) -> &FieldRevision {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
const DEFAULT_IS_PRIMARY: fn() -> bool = || false;
|
||||
|
||||
impl FieldRevision {
|
||||
pub fn new(name: &str, desc: &str, field_type: FieldType, is_primary: bool) -> Self {
|
||||
let width = field_type.default_cell_width();
|
||||
pub fn new<T: Into<FieldTypeRevision>>(
|
||||
name: &str,
|
||||
desc: &str,
|
||||
field_type: T,
|
||||
width: i32,
|
||||
is_primary: bool,
|
||||
) -> Self {
|
||||
Self {
|
||||
id: gen_field_id(),
|
||||
name: name.to_string(),
|
||||
desc: desc.to_string(),
|
||||
field_type,
|
||||
field_type_rev: field_type.into(),
|
||||
frozen: false,
|
||||
visibility: true,
|
||||
width,
|
||||
@ -153,49 +164,32 @@ impl FieldRevision {
|
||||
where
|
||||
T: TypeOptionDataEntry + ?Sized,
|
||||
{
|
||||
self.type_options.insert(entry.field_type().type_id(), entry.json_str());
|
||||
let id = self.field_type_rev.to_string();
|
||||
self.type_options.insert(id, entry.json_str());
|
||||
}
|
||||
|
||||
pub fn get_type_option_entry<T: TypeOptionDataDeserializer>(&self, field_type: &FieldType) -> Option<T> {
|
||||
self.type_options
|
||||
.get(&field_type.type_id())
|
||||
.map(|s| T::from_json_str(s))
|
||||
pub fn get_type_option_entry<T1: TypeOptionDataDeserializer, T2: Into<FieldTypeRevision>>(
|
||||
&self,
|
||||
field_type: T2,
|
||||
) -> Option<T1> {
|
||||
let field_type_rev = field_type.into();
|
||||
let id = field_type_rev.to_string();
|
||||
self.type_options.get(&id).map(|s| T1::from_json_str(s))
|
||||
}
|
||||
|
||||
pub fn insert_type_option_str(&mut self, field_type: &FieldType, json_str: String) {
|
||||
self.type_options.insert(field_type.type_id(), json_str);
|
||||
pub fn insert_type_option_str(&mut self, field_type: &FieldTypeRevision, json_str: String) {
|
||||
let id = field_type.to_string();
|
||||
self.type_options.insert(id, json_str);
|
||||
}
|
||||
|
||||
pub fn get_type_option_str(&self, field_type: &FieldType) -> Option<String> {
|
||||
self.type_options.get(&field_type.type_id()).map(|s| s.to_owned())
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::From<FieldRevision> for Field {
|
||||
fn from(field_rev: FieldRevision) -> Self {
|
||||
Self {
|
||||
id: field_rev.id,
|
||||
name: field_rev.name,
|
||||
desc: field_rev.desc,
|
||||
field_type: field_rev.field_type,
|
||||
frozen: field_rev.frozen,
|
||||
visibility: field_rev.visibility,
|
||||
width: field_rev.width,
|
||||
is_primary: field_rev.is_primary,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::From<&FieldRevision> for FieldOrder {
|
||||
fn from(field_rev: &FieldRevision) -> Self {
|
||||
Self {
|
||||
field_id: field_rev.id.clone(),
|
||||
}
|
||||
pub fn get_type_option_str<T: Into<FieldTypeRevision>>(&self, field_type: T) -> Option<String> {
|
||||
let field_type_rev = field_type.into();
|
||||
let id = field_type_rev.to_string();
|
||||
self.type_options.get(&id).map(|s| s.to_owned())
|
||||
}
|
||||
}
|
||||
|
||||
pub trait TypeOptionDataEntry {
|
||||
fn field_type(&self) -> FieldType;
|
||||
fn json_str(&self) -> String;
|
||||
fn protobuf_bytes(&self) -> Bytes;
|
||||
}
|
||||
@ -204,7 +198,7 @@ pub trait TypeOptionDataDeserializer {
|
||||
fn from_json_str(s: &str) -> Self;
|
||||
fn from_protobuf_bytes(bytes: Bytes) -> Self;
|
||||
}
|
||||
|
||||
pub type FieldId = String;
|
||||
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct RowRevision {
|
||||
pub id: String,
|
||||
@ -213,7 +207,7 @@ pub struct RowRevision {
|
||||
/// key: field id,
|
||||
/// value: CellMeta
|
||||
#[serde(with = "indexmap::serde_seq")]
|
||||
pub cells: IndexMap<String, CellRevision>,
|
||||
pub cells: IndexMap<FieldId, CellRevision>,
|
||||
pub height: i32,
|
||||
pub visibility: bool,
|
||||
}
|
||||
@ -229,51 +223,12 @@ impl RowRevision {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::From<&RowRevision> for RowOrder {
|
||||
fn from(row: &RowRevision) -> Self {
|
||||
Self {
|
||||
row_id: row.id.clone(),
|
||||
block_id: row.block_id.clone(),
|
||||
height: row.height,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::From<&Arc<RowRevision>> for RowOrder {
|
||||
fn from(row: &Arc<RowRevision>) -> Self {
|
||||
Self {
|
||||
row_id: row.id.clone(),
|
||||
block_id: row.block_id.clone(),
|
||||
height: row.height,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct RowMetaChangeset {
|
||||
pub row_id: String,
|
||||
pub height: Option<i32>,
|
||||
pub visibility: Option<bool>,
|
||||
pub cell_by_field_id: HashMap<String, CellRevision>,
|
||||
}
|
||||
|
||||
impl std::convert::From<CellChangeset> for RowMetaChangeset {
|
||||
fn from(changeset: CellChangeset) -> Self {
|
||||
let mut cell_by_field_id = HashMap::with_capacity(1);
|
||||
let field_id = changeset.field_id;
|
||||
let cell_rev = CellRevision {
|
||||
data: changeset.cell_content_changeset.unwrap_or_else(|| "".to_owned()),
|
||||
};
|
||||
cell_by_field_id.insert(field_id, cell_rev);
|
||||
|
||||
RowMetaChangeset {
|
||||
row_id: changeset.row_id,
|
||||
height: None,
|
||||
visibility: None,
|
||||
cell_by_field_id,
|
||||
}
|
||||
}
|
||||
pub cell_by_field_id: HashMap<FieldId, CellRevision>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Default, Serialize, Deserialize)]
|
||||
@ -315,3 +270,5 @@ impl std::convert::TryFrom<Bytes> for BuildGridContext {
|
||||
Ok(ctx)
|
||||
}
|
||||
}
|
||||
|
||||
pub type FieldTypeRevision = u8;
|
||||
|
@ -1,7 +1,9 @@
|
||||
use crate::revision::FieldTypeRevision;
|
||||
use indexmap::IndexMap;
|
||||
use nanoid::nanoid;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_repr::*;
|
||||
use std::sync::Arc;
|
||||
|
||||
pub fn gen_grid_filter_id() -> String {
|
||||
nanoid!(6)
|
||||
@ -18,9 +20,17 @@ pub fn gen_grid_sort_id() -> String {
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Default, Eq, PartialEq)]
|
||||
pub struct GridSettingRevision {
|
||||
pub layout: GridLayoutRevision,
|
||||
|
||||
// layout:
|
||||
// field_id:
|
||||
// FieldType: GridFilterRevision
|
||||
// FieldType: GridFilterRevision
|
||||
// layout:
|
||||
// field_id:
|
||||
// FieldType: GridFilterRevision
|
||||
// field_id:
|
||||
// FieldType: GridFilterRevision
|
||||
#[serde(with = "indexmap::serde_seq")]
|
||||
pub filters: IndexMap<GridLayoutRevision, Vec<GridFilterRevision>>,
|
||||
pub filters: IndexMap<GridLayoutRevision, IndexMap<String, GridFilterRevisionMap>>,
|
||||
|
||||
#[serde(skip, with = "indexmap::serde_seq")]
|
||||
pub groups: IndexMap<GridLayoutRevision, Vec<GridGroupRevision>>,
|
||||
@ -29,6 +39,78 @@ pub struct GridSettingRevision {
|
||||
pub sorts: IndexMap<GridLayoutRevision, Vec<GridSortRevision>>,
|
||||
}
|
||||
|
||||
impl GridSettingRevision {
|
||||
pub fn get_mut_filters(
|
||||
&mut self,
|
||||
layout: &GridLayoutRevision,
|
||||
field_id: &str,
|
||||
field_type: &FieldTypeRevision,
|
||||
) -> Option<&mut Vec<Arc<GridFilterRevision>>> {
|
||||
self.filters
|
||||
.get_mut(layout)
|
||||
.and_then(|filter_rev_map_by_field_id| filter_rev_map_by_field_id.get_mut(field_id))
|
||||
.and_then(|filter_rev_map| filter_rev_map.get_mut(field_type))
|
||||
}
|
||||
|
||||
pub fn get_filters(
|
||||
&self,
|
||||
layout: &GridLayoutRevision,
|
||||
field_id: &str,
|
||||
field_type: &FieldTypeRevision,
|
||||
) -> Option<Vec<Arc<GridFilterRevision>>> {
|
||||
self.filters
|
||||
.get(layout)
|
||||
.and_then(|filter_rev_map_by_field_id| filter_rev_map_by_field_id.get(field_id))
|
||||
.and_then(|filter_rev_map| filter_rev_map.get(field_type))
|
||||
.cloned()
|
||||
}
|
||||
|
||||
pub fn insert_filter(
|
||||
&mut self,
|
||||
layout: &GridLayoutRevision,
|
||||
field_id: &str,
|
||||
field_type: &FieldTypeRevision,
|
||||
filter_rev: GridFilterRevision,
|
||||
) {
|
||||
let filter_rev_map_by_field_id = self.filters.entry(layout.clone()).or_insert_with(IndexMap::new);
|
||||
let filter_rev_map = filter_rev_map_by_field_id
|
||||
.entry(field_id.to_string())
|
||||
.or_insert_with(GridFilterRevisionMap::new);
|
||||
|
||||
filter_rev_map
|
||||
.entry(field_type.to_owned())
|
||||
.or_insert_with(Vec::new)
|
||||
.push(Arc::new(filter_rev))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Default, Eq, PartialEq)]
|
||||
#[serde(transparent)]
|
||||
pub struct GridFilterRevisionMap {
|
||||
#[serde(with = "indexmap::serde_seq")]
|
||||
pub filter_by_field_type: IndexMap<FieldTypeRevision, Vec<Arc<GridFilterRevision>>>,
|
||||
}
|
||||
|
||||
impl GridFilterRevisionMap {
|
||||
pub fn new() -> Self {
|
||||
GridFilterRevisionMap::default()
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::Deref for GridFilterRevisionMap {
|
||||
type Target = IndexMap<FieldTypeRevision, Vec<Arc<GridFilterRevision>>>;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.filter_by_field_type
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::DerefMut for GridFilterRevisionMap {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.filter_by_field_type
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Hash, Clone, Serialize_repr, Deserialize_repr)]
|
||||
#[repr(u8)]
|
||||
pub enum GridLayoutRevision {
|
||||
@ -49,7 +131,7 @@ impl std::default::Default for GridLayoutRevision {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq, Hash)]
|
||||
pub struct GridFilterRevision {
|
||||
pub id: String,
|
||||
pub field_id: String,
|
||||
|
@ -1,4 +1,4 @@
|
||||
use crate::entities::folder_info::FolderDelta;
|
||||
use crate::entities::folder::FolderDelta;
|
||||
use crate::util::make_delta_from_revisions;
|
||||
use crate::{
|
||||
client_folder::{default_folder_delta, FolderPad},
|
||||
|
@ -3,7 +3,7 @@ use crate::util::cal_diff;
|
||||
use crate::{
|
||||
client_folder::builder::FolderPadBuilder,
|
||||
entities::{
|
||||
folder_info::FolderDelta,
|
||||
folder::FolderDelta,
|
||||
revision::{md5, Revision},
|
||||
},
|
||||
errors::{CollaborateError, CollaborateResult},
|
||||
@ -431,7 +431,7 @@ pub struct FolderChange {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
#![allow(clippy::all)]
|
||||
use crate::{client_folder::folder_pad::FolderPad, entities::folder_info::FolderDelta};
|
||||
use crate::{client_folder::folder_pad::FolderPad, entities::folder::FolderDelta};
|
||||
use chrono::Utc;
|
||||
|
||||
use flowy_folder_data_model::revision::{AppRevision, TrashRevision, ViewRevision, WorkspaceRevision};
|
||||
|
@ -57,36 +57,3 @@ fn check_rows(fields: &[FieldRevision], rows: &[RowRevision]) -> CollaborateResu
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::client_grid::{make_block_meta_delta, make_grid_delta, GridBuilder};
|
||||
use flowy_grid_data_model::entities::FieldType;
|
||||
use flowy_grid_data_model::revision::{FieldRevision, GridBlockRevision, GridRevision};
|
||||
use std::sync::Arc;
|
||||
|
||||
#[test]
|
||||
fn create_default_grid_test() {
|
||||
let grid_id = "1".to_owned();
|
||||
let build_context = GridBuilder::default()
|
||||
.add_field(FieldRevision::new("Name", "", FieldType::RichText, true))
|
||||
.add_field(FieldRevision::new("Tags", "", FieldType::SingleSelect, false))
|
||||
.add_empty_row()
|
||||
.add_empty_row()
|
||||
.add_empty_row()
|
||||
.build();
|
||||
|
||||
let grid_rev = GridRevision {
|
||||
grid_id,
|
||||
fields: build_context.field_revs,
|
||||
blocks: build_context.blocks.into_iter().map(Arc::new).collect(),
|
||||
setting: Default::default(),
|
||||
};
|
||||
|
||||
let grid_meta_delta = make_grid_delta(&grid_rev);
|
||||
let _: GridRevision = serde_json::from_str(&grid_meta_delta.to_str().unwrap()).unwrap();
|
||||
|
||||
let grid_block_meta_delta = make_block_meta_delta(build_context.blocks_meta_data.first().unwrap());
|
||||
let _: GridBlockRevision = serde_json::from_str(&grid_block_meta_delta.to_str().unwrap()).unwrap();
|
||||
}
|
||||
}
|
||||
|
@ -1,13 +1,12 @@
|
||||
use crate::entities::grid::{FieldChangesetParams, GridSettingChangesetParams};
|
||||
use crate::entities::revision::{md5, RepeatedRevision, Revision};
|
||||
use crate::errors::{internal_error, CollaborateError, CollaborateResult};
|
||||
use crate::util::{cal_diff, make_delta_from_revisions};
|
||||
use bytes::Bytes;
|
||||
use flowy_grid_data_model::entities::{FieldChangesetParams, FieldOrder};
|
||||
use flowy_grid_data_model::entities::{FieldType, GridSettingChangesetParams};
|
||||
use flowy_grid_data_model::revision::{
|
||||
gen_block_id, gen_grid_filter_id, gen_grid_group_id, gen_grid_id, gen_grid_sort_id, FieldRevision,
|
||||
GridBlockMetaRevision, GridBlockMetaRevisionChangeset, GridFilterRevision, GridGroupRevision, GridLayoutRevision,
|
||||
GridRevision, GridSettingRevision, GridSortRevision,
|
||||
FieldTypeRevision, GridBlockMetaRevision, GridBlockMetaRevisionChangeset, GridFilterRevision, GridGroupRevision,
|
||||
GridLayoutRevision, GridRevision, GridSettingRevision, GridSortRevision,
|
||||
};
|
||||
use lib_infra::util::move_vec_element;
|
||||
use lib_ot::core::{OperationTransformable, PlainTextAttributes, PlainTextDelta, PlainTextDeltaBuilder};
|
||||
@ -27,8 +26,16 @@ pub trait JsonDeserializer {
|
||||
}
|
||||
|
||||
impl GridRevisionPad {
|
||||
pub fn grid_id(&self) -> String {
|
||||
self.grid_rev.grid_id.clone()
|
||||
}
|
||||
pub async fn duplicate_grid_block_meta(&self) -> (Vec<FieldRevision>, Vec<GridBlockMetaRevision>) {
|
||||
let fields = self.grid_rev.fields.to_vec();
|
||||
let fields = self
|
||||
.grid_rev
|
||||
.fields
|
||||
.iter()
|
||||
.map(|field_rev| field_rev.as_ref().clone())
|
||||
.collect();
|
||||
|
||||
let blocks = self
|
||||
.grid_rev
|
||||
@ -81,7 +88,7 @@ impl GridRevisionPad {
|
||||
None => None,
|
||||
Some(start_field_id) => grid_meta.fields.iter().position(|field| field.id == start_field_id),
|
||||
};
|
||||
|
||||
let new_field_rev = Arc::new(new_field_rev);
|
||||
match insert_index {
|
||||
None => grid_meta.fields.push(new_field_rev),
|
||||
Some(index) => grid_meta.fields.insert(index, new_field_rev),
|
||||
@ -111,25 +118,27 @@ impl GridRevisionPad {
|
||||
|grid_meta| match grid_meta.fields.iter().position(|field| field.id == field_id) {
|
||||
None => Ok(None),
|
||||
Some(index) => {
|
||||
let mut duplicate_field_rev = grid_meta.fields[index].clone();
|
||||
let mut duplicate_field_rev = grid_meta.fields[index].as_ref().clone();
|
||||
duplicate_field_rev.id = duplicated_field_id.to_string();
|
||||
duplicate_field_rev.name = format!("{} (copy)", duplicate_field_rev.name);
|
||||
grid_meta.fields.insert(index + 1, duplicate_field_rev);
|
||||
grid_meta.fields.insert(index + 1, Arc::new(duplicate_field_rev));
|
||||
Ok(Some(()))
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
pub fn switch_to_field<B>(
|
||||
pub fn switch_to_field<B, T>(
|
||||
&mut self,
|
||||
field_id: &str,
|
||||
field_type: FieldType,
|
||||
field_type: T,
|
||||
type_option_json_builder: B,
|
||||
) -> CollaborateResult<Option<GridChangeset>>
|
||||
where
|
||||
B: FnOnce(&FieldType) -> String,
|
||||
B: FnOnce(&FieldTypeRevision) -> String,
|
||||
T: Into<FieldTypeRevision>,
|
||||
{
|
||||
let field_type = field_type.into();
|
||||
self.modify_grid(|grid_meta| {
|
||||
//
|
||||
match grid_meta.fields.iter_mut().find(|field_rev| field_rev.id == field_id) {
|
||||
@ -138,12 +147,13 @@ impl GridRevisionPad {
|
||||
Ok(None)
|
||||
}
|
||||
Some(field_rev) => {
|
||||
if field_rev.get_type_option_str(&field_type).is_none() {
|
||||
let mut_field_rev = Arc::make_mut(field_rev);
|
||||
if mut_field_rev.get_type_option_str(field_type).is_none() {
|
||||
let type_option_json = type_option_json_builder(&field_type);
|
||||
field_rev.insert_type_option_str(&field_type, type_option_json);
|
||||
mut_field_rev.insert_type_option_str(&field_type, type_option_json);
|
||||
}
|
||||
|
||||
field_rev.field_type = field_type;
|
||||
mut_field_rev.field_type_rev = field_type;
|
||||
Ok(Some(()))
|
||||
}
|
||||
}
|
||||
@ -169,7 +179,7 @@ impl GridRevisionPad {
|
||||
}
|
||||
|
||||
if let Some(field_type) = changeset.field_type {
|
||||
field.field_type = field_type;
|
||||
field.field_type_rev = field_type;
|
||||
is_changed = Some(())
|
||||
}
|
||||
|
||||
@ -191,7 +201,7 @@ impl GridRevisionPad {
|
||||
if let Some(type_option_data) = changeset.type_option_data {
|
||||
match deserializer.deserialize(type_option_data) {
|
||||
Ok(json_str) => {
|
||||
let field_type = field.field_type.clone();
|
||||
let field_type = field.field_type_rev;
|
||||
field.insert_type_option_str(&field_type, json_str);
|
||||
is_changed = Some(())
|
||||
}
|
||||
@ -205,7 +215,7 @@ impl GridRevisionPad {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn get_field_rev(&self, field_id: &str) -> Option<(usize, &FieldRevision)> {
|
||||
pub fn get_field_rev(&self, field_id: &str) -> Option<(usize, &Arc<FieldRevision>)> {
|
||||
self.grid_rev
|
||||
.fields
|
||||
.iter()
|
||||
@ -213,7 +223,7 @@ impl GridRevisionPad {
|
||||
.find(|(_, field)| field.id == field_id)
|
||||
}
|
||||
|
||||
pub fn replace_field_rev(&mut self, field_rev: FieldRevision) -> CollaborateResult<Option<GridChangeset>> {
|
||||
pub fn replace_field_rev(&mut self, field_rev: Arc<FieldRevision>) -> CollaborateResult<Option<GridChangeset>> {
|
||||
self.modify_grid(
|
||||
|grid_meta| match grid_meta.fields.iter().position(|field| field.id == field_rev.id) {
|
||||
None => Ok(None),
|
||||
@ -251,31 +261,27 @@ impl GridRevisionPad {
|
||||
self.grid_rev.fields.iter().any(|field| field.id == field_id)
|
||||
}
|
||||
|
||||
pub fn get_field_orders(&self) -> Vec<FieldOrder> {
|
||||
self.grid_rev.fields.iter().map(FieldOrder::from).collect()
|
||||
}
|
||||
|
||||
pub fn get_field_revs(&self, field_orders: Option<Vec<FieldOrder>>) -> CollaborateResult<Vec<FieldRevision>> {
|
||||
match field_orders {
|
||||
pub fn get_field_revs(&self, field_ids: Option<Vec<String>>) -> CollaborateResult<Vec<Arc<FieldRevision>>> {
|
||||
match field_ids {
|
||||
None => Ok(self.grid_rev.fields.clone()),
|
||||
Some(field_orders) => {
|
||||
Some(field_ids) => {
|
||||
let field_by_field_id = self
|
||||
.grid_rev
|
||||
.fields
|
||||
.iter()
|
||||
.map(|field| (&field.id, field))
|
||||
.collect::<HashMap<&String, &FieldRevision>>();
|
||||
.collect::<HashMap<&String, &Arc<FieldRevision>>>();
|
||||
|
||||
let fields = field_orders
|
||||
let fields = field_ids
|
||||
.iter()
|
||||
.flat_map(|field_order| match field_by_field_id.get(&field_order.field_id) {
|
||||
.flat_map(|field_id| match field_by_field_id.get(&field_id) {
|
||||
None => {
|
||||
tracing::error!("Can't find the field with id: {}", field_order.field_id);
|
||||
tracing::error!("Can't find the field with id: {}", field_id);
|
||||
None
|
||||
}
|
||||
Some(field) => Some((*field).clone()),
|
||||
})
|
||||
.collect::<Vec<FieldRevision>>();
|
||||
.collect::<Vec<Arc<FieldRevision>>>();
|
||||
Ok(fields)
|
||||
}
|
||||
}
|
||||
@ -334,9 +340,35 @@ impl GridRevisionPad {
|
||||
&self.grid_rev.setting
|
||||
}
|
||||
|
||||
pub fn get_filters(&self, layout: Option<&GridLayoutRevision>) -> Option<&Vec<GridFilterRevision>> {
|
||||
/// If layout is None, then the default layout will be the read from GridSettingRevision
|
||||
pub fn get_filters(
|
||||
&self,
|
||||
layout: Option<&GridLayoutRevision>,
|
||||
field_ids: Option<Vec<String>>,
|
||||
) -> Option<Vec<Arc<GridFilterRevision>>> {
|
||||
let mut filter_revs = vec![];
|
||||
let layout_ty = layout.unwrap_or(&self.grid_rev.setting.layout);
|
||||
self.grid_rev.setting.filters.get(layout_ty)
|
||||
let field_revs = self.get_field_revs(None).ok()?;
|
||||
|
||||
field_revs.iter().for_each(|field_rev| {
|
||||
let mut is_contain = true;
|
||||
if let Some(field_ids) = &field_ids {
|
||||
is_contain = field_ids.contains(&field_rev.id);
|
||||
}
|
||||
|
||||
if is_contain {
|
||||
// Only return the filters for the current fields' type.
|
||||
if let Some(mut t_filter_revs) =
|
||||
self.grid_rev
|
||||
.setting
|
||||
.get_filters(layout_ty, &field_rev.id, &field_rev.field_type_rev)
|
||||
{
|
||||
filter_revs.append(&mut t_filter_revs);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Some(filter_revs)
|
||||
}
|
||||
|
||||
pub fn update_grid_setting_rev(
|
||||
@ -345,28 +377,30 @@ impl GridRevisionPad {
|
||||
) -> CollaborateResult<Option<GridChangeset>> {
|
||||
self.modify_grid(|grid_rev| {
|
||||
let mut is_changed = None;
|
||||
let layout_rev: GridLayoutRevision = changeset.layout_type.into();
|
||||
let layout_rev = changeset.layout_type;
|
||||
|
||||
if let Some(params) = changeset.insert_filter {
|
||||
let rev = GridFilterRevision {
|
||||
let filter_rev = GridFilterRevision {
|
||||
id: gen_grid_filter_id(),
|
||||
field_id: params.field_id,
|
||||
field_id: params.field_id.clone(),
|
||||
condition: params.condition,
|
||||
content: params.content,
|
||||
};
|
||||
|
||||
grid_rev
|
||||
.setting
|
||||
.filters
|
||||
.entry(layout_rev.clone())
|
||||
.or_insert_with(std::vec::Vec::new)
|
||||
.push(rev);
|
||||
.insert_filter(&layout_rev, ¶ms.field_id, ¶ms.field_type_rev, filter_rev);
|
||||
|
||||
is_changed = Some(())
|
||||
}
|
||||
if let Some(delete_filter_id) = changeset.delete_filter {
|
||||
match grid_rev.setting.filters.get_mut(&layout_rev) {
|
||||
Some(filters) => filters.retain(|filter| filter.id != delete_filter_id),
|
||||
if let Some(params) = changeset.delete_filter {
|
||||
match grid_rev
|
||||
.setting
|
||||
.get_mut_filters(&layout_rev, ¶ms.filter_id, ¶ms.field_type_rev)
|
||||
{
|
||||
Some(filters) => {
|
||||
filters.retain(|filter| filter.id != params.filter_id);
|
||||
}
|
||||
None => {
|
||||
tracing::warn!("Can't find the filter with {:?}", layout_rev);
|
||||
}
|
||||
@ -435,7 +469,7 @@ impl GridRevisionPad {
|
||||
self.delta.to_delta_bytes()
|
||||
}
|
||||
|
||||
pub fn fields(&self) -> &[FieldRevision] {
|
||||
pub fn fields(&self) -> &[Arc<FieldRevision>] {
|
||||
&self.grid_rev.fields
|
||||
}
|
||||
|
||||
@ -488,7 +522,10 @@ impl GridRevisionPad {
|
||||
tracing::warn!("[GridMetaPad]: Can't find any field with id: {}", field_id);
|
||||
Ok(None)
|
||||
}
|
||||
Some(index) => f(&mut grid_rev.fields[index]),
|
||||
Some(index) => {
|
||||
let mut_field_rev = Arc::make_mut(&mut grid_rev.fields[index]);
|
||||
f(mut_field_rev)
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user