diff --git a/frontend/app_flowy/lib/plugins/board/application/board_bloc.dart b/frontend/app_flowy/lib/plugins/board/application/board_bloc.dart index de177e47a4..ed3af090de 100644 --- a/frontend/app_flowy/lib/plugins/board/application/board_bloc.dart +++ b/frontend/app_flowy/lib/plugins/board/application/board_bloc.dart @@ -1,7 +1,6 @@ import 'dart:async'; import 'dart:collection'; -import 'package:app_flowy/plugins/grid/application/block/block_cache.dart'; import 'package:app_flowy/plugins/grid/application/field/field_controller.dart'; import 'package:app_flowy/plugins/grid/application/row/row_cache.dart'; import 'package:app_flowy/plugins/grid/application/row/row_service.dart'; @@ -229,8 +228,7 @@ class BoardBloc extends Bloc { } GridRowCache? getRowCache(String blockId) { - final GridBlockCache? blockCache = _gridDataController.blocks[blockId]; - return blockCache?.rowCache; + return _gridDataController.rowCache; } void _startListening() { diff --git a/frontend/app_flowy/lib/plugins/board/application/board_data_controller.dart b/frontend/app_flowy/lib/plugins/board/application/board_data_controller.dart index c3669948b9..73ea620b20 100644 --- a/frontend/app_flowy/lib/plugins/board/application/board_data_controller.dart +++ b/frontend/app_flowy/lib/plugins/board/application/board_data_controller.dart @@ -1,6 +1,6 @@ import 'dart:collection'; -import 'package:app_flowy/plugins/grid/application/block/block_cache.dart'; +import 'package:app_flowy/plugins/grid/application/view/grid_view_cache.dart'; import 'package:app_flowy/plugins/grid/application/field/field_controller.dart'; import 'package:app_flowy/plugins/grid/application/grid_service.dart'; import 'package:app_flowy/plugins/grid/application/row/row_cache.dart'; @@ -31,11 +31,7 @@ class BoardDataController { final GridFFIService _gridFFIService; final GridFieldController fieldController; final BoardListener _listener; - - // key: the block id - final LinkedHashMap _blocks; - UnmodifiableMapView get blocks => - UnmodifiableMapView(_blocks); + late GridViewCache _viewCache; OnFieldsChanged? _onFieldsChanged; OnGridChanged? _onGridChanged; @@ -43,21 +39,23 @@ class BoardDataController { OnRowsChanged? _onRowsChanged; OnError? _onError; - List get rowInfos { - final List rows = []; - for (var block in _blocks.values) { - rows.addAll(block.rows); - } - return rows; - } + List get rowInfos => _viewCache.rowInfos; + GridRowCache get rowCache => _viewCache.rowCache; BoardDataController({required ViewPB view}) : gridId = view.id, _listener = BoardListener(view.id), - // ignore: prefer_collection_literals - _blocks = LinkedHashMap(), _gridFFIService = GridFFIService(gridId: view.id), - fieldController = GridFieldController(gridId: view.id); + fieldController = GridFieldController(gridId: view.id) { + // + _viewCache = GridViewCache( + gridId: view.id, + fieldController: fieldController, + ); + _viewCache.addListener(onRowsChanged: (reason) { + _onRowsChanged?.call(rowInfos, reason); + }); + } void addListener({ required OnGridChanged onGridChanged, @@ -110,23 +108,21 @@ class BoardDataController { Future> openGrid() async { final result = await _gridFFIService.openGrid(); - return Future( - () => result.fold( - (grid) async { - _onGridChanged?.call(grid); - final result = await fieldController.loadFields( - fieldIds: grid.fields, - ); - return result.fold( - (l) { - _loadGroups(grid.blocks); - return left(l); - }, - (err) => right(err), - ); - }, - (err) => right(err), - ), + + return result.fold( + (grid) async { + _onGridChanged?.call(grid); + final result = await fieldController.loadFields(fieldIds: grid.fields); + return result.fold( + (l) { + _loadGroups(); + _viewCache.rowCache.initializeRows(grid.rows); + return left(l); + }, + (err) => right(err), + ); + }, + (err) => right(err), ); } @@ -138,26 +134,9 @@ class BoardDataController { Future dispose() async { await _gridFFIService.closeGrid(); await fieldController.dispose(); - - for (final blockCache in _blocks.values) { - blockCache.dispose(); - } } - Future _loadGroups(List blocks) async { - for (final block in blocks) { - final cache = GridBlockCache( - gridId: gridId, - block: block, - fieldController: fieldController, - ); - - cache.addListener(onRowsChanged: (reason) { - _onRowsChanged?.call(rowInfos, reason); - }); - _blocks[block.id] = cache; - } - + Future _loadGroups() async { final result = await _gridFFIService.loadGroups(); return Future( () => result.fold( diff --git a/frontend/app_flowy/lib/plugins/board/application/card/card_bloc.dart b/frontend/app_flowy/lib/plugins/board/application/card/card_bloc.dart index 4902e77555..8f4a5504ee 100644 --- a/frontend/app_flowy/lib/plugins/board/application/card/card_bloc.dart +++ b/frontend/app_flowy/lib/plugins/board/application/card/card_bloc.dart @@ -3,7 +3,7 @@ import 'package:app_flowy/plugins/grid/application/cell/cell_service/cell_servic import 'package:app_flowy/plugins/grid/application/row/row_cache.dart'; import 'package:app_flowy/plugins/grid/application/row/row_service.dart'; import 'package:equatable/equatable.dart'; -import 'package:flowy_sdk/protobuf/flowy-grid/block_entities.pb.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid/row_entities.pb.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; import 'dart:async'; @@ -23,7 +23,6 @@ class BoardCardBloc extends Bloc { required bool isEditing, }) : _rowService = RowFFIService( gridId: gridId, - blockId: dataController.rowPB.blockId, ), _dataController = dataController, super( diff --git a/frontend/app_flowy/lib/plugins/board/application/card/card_data_controller.dart b/frontend/app_flowy/lib/plugins/board/application/card/card_data_controller.dart index 0e7cf6c153..38f75ff159 100644 --- a/frontend/app_flowy/lib/plugins/board/application/card/card_data_controller.dart +++ b/frontend/app_flowy/lib/plugins/board/application/card/card_data_controller.dart @@ -3,7 +3,7 @@ import 'package:app_flowy/plugins/grid/application/cell/cell_service/cell_servic import 'package:app_flowy/plugins/grid/application/cell/cell_service/cell_field_notifier.dart'; import 'package:app_flowy/plugins/grid/application/field/field_controller.dart'; import 'package:app_flowy/plugins/grid/application/row/row_cache.dart'; -import 'package:flowy_sdk/protobuf/flowy-grid/block_entities.pb.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid/row_entities.pb.dart'; import 'package:flutter/foundation.dart'; typedef OnCardChanged = void Function(GridCellMap, RowsChangedReason); diff --git a/frontend/app_flowy/lib/plugins/board/presentation/board_page.dart b/frontend/app_flowy/lib/plugins/board/presentation/board_page.dart index 0d736975ed..f1bd518733 100644 --- a/frontend/app_flowy/lib/plugins/board/presentation/board_page.dart +++ b/frontend/app_flowy/lib/plugins/board/presentation/board_page.dart @@ -16,8 +16,8 @@ import 'package:flowy_infra_ui/style_widget/text.dart'; import 'package:flowy_infra_ui/flowy_infra_ui_web.dart'; import 'package:flowy_infra_ui/widget/error_page.dart'; import 'package:flowy_sdk/protobuf/flowy-folder/view.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/row_entities.pb.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import '../../grid/application/row/row_cache.dart'; diff --git a/frontend/app_flowy/lib/plugins/grid/application/block/block_listener.dart b/frontend/app_flowy/lib/plugins/grid/application/block/block_listener.dart deleted file mode 100644 index c4770462b3..0000000000 --- a/frontend/app_flowy/lib/plugins/grid/application/block/block_listener.dart +++ /dev/null @@ -1,53 +0,0 @@ -import 'dart:async'; -import 'dart:typed_data'; -import 'package:app_flowy/core/grid_notification.dart'; -import 'package:dartz/dartz.dart'; -import 'package:flowy_infra/notifier.dart'; -import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart'; -import 'package:flowy_sdk/protobuf/flowy-grid/block_entities.pb.dart'; -import 'package:flowy_sdk/protobuf/flowy-grid/dart_notification.pb.dart'; - -typedef GridBlockUpdateNotifierValue = Either; - -class GridBlockListener { - final String blockId; - PublishNotifier? _rowsUpdateNotifier = - PublishNotifier(); - GridNotificationListener? _listener; - - GridBlockListener({required this.blockId}); - - void start(void Function(GridBlockUpdateNotifierValue) onBlockChanged) { - if (_listener != null) { - _listener?.stop(); - } - - _listener = GridNotificationListener( - objectId: blockId, - handler: _handler, - ); - - _rowsUpdateNotifier?.addPublishListener(onBlockChanged); - } - - void _handler(GridDartNotification ty, Either result) { - switch (ty) { - case GridDartNotification.DidUpdateGridBlock: - result.fold( - (payload) => _rowsUpdateNotifier?.value = - left(GridBlockChangesetPB.fromBuffer(payload)), - (error) => _rowsUpdateNotifier?.value = right(error), - ); - break; - - default: - break; - } - } - - Future stop() async { - await _listener?.stop(); - _rowsUpdateNotifier?.dispose(); - _rowsUpdateNotifier = null; - } -} diff --git a/frontend/app_flowy/lib/plugins/grid/application/field/grid_listener.dart b/frontend/app_flowy/lib/plugins/grid/application/field/grid_listener.dart index fd26cd3dd8..acc50e2cc3 100644 --- a/frontend/app_flowy/lib/plugins/grid/application/field/grid_listener.dart +++ b/frontend/app_flowy/lib/plugins/grid/application/field/grid_listener.dart @@ -27,7 +27,7 @@ class GridFieldsListener { void _handler(GridDartNotification ty, Either result) { switch (ty) { - case GridDartNotification.DidUpdateGridField: + case GridDartNotification.DidUpdateGridFields: result.fold( (payload) => updateFieldsNotifier?.value = left(GridFieldChangesetPB.fromBuffer(payload)), diff --git a/frontend/app_flowy/lib/plugins/grid/application/filter/checkbox_filter_editor_bloc.dart b/frontend/app_flowy/lib/plugins/grid/application/filter/checkbox_filter_editor_bloc.dart index 399f233361..ed17b3b55b 100644 --- a/frontend/app_flowy/lib/plugins/grid/application/filter/checkbox_filter_editor_bloc.dart +++ b/frontend/app_flowy/lib/plugins/grid/application/filter/checkbox_filter_editor_bloc.dart @@ -28,7 +28,7 @@ class CheckboxFilterEditorBloc initial: () async { _startListening(); }, - updateCondition: (CheckboxFilterCondition condition) { + updateCondition: (CheckboxFilterConditionPB condition) { _ffiService.insertCheckboxFilter( filterId: filterInfo.filter.id, fieldId: filterInfo.fieldInfo.id, @@ -79,7 +79,7 @@ class CheckboxFilterEditorEvent with _$CheckboxFilterEditorEvent { const factory CheckboxFilterEditorEvent.didReceiveFilter(FilterPB filter) = _DidReceiveFilter; const factory CheckboxFilterEditorEvent.updateCondition( - CheckboxFilterCondition condition) = _UpdateCondition; + CheckboxFilterConditionPB condition) = _UpdateCondition; const factory CheckboxFilterEditorEvent.delete() = _Delete; } diff --git a/frontend/app_flowy/lib/plugins/grid/application/filter/checklist_filter_bloc.dart b/frontend/app_flowy/lib/plugins/grid/application/filter/checklist_filter_bloc.dart index 05e801081a..8050e3bccb 100644 --- a/frontend/app_flowy/lib/plugins/grid/application/filter/checklist_filter_bloc.dart +++ b/frontend/app_flowy/lib/plugins/grid/application/filter/checklist_filter_bloc.dart @@ -32,7 +32,7 @@ class ChecklistFilterEditorBloc initial: () async { _startListening(); }, - updateCondition: (ChecklistFilterCondition condition) { + updateCondition: (ChecklistFilterConditionPB condition) { _ffiService.insertChecklistFilter( filterId: filterInfo.filter.id, fieldId: filterInfo.fieldInfo.id, @@ -85,7 +85,7 @@ class ChecklistFilterEditorEvent with _$ChecklistFilterEditorEvent { const factory ChecklistFilterEditorEvent.didReceiveFilter(FilterPB filter) = _DidReceiveFilter; const factory ChecklistFilterEditorEvent.updateCondition( - ChecklistFilterCondition condition) = _UpdateCondition; + ChecklistFilterConditionPB condition) = _UpdateCondition; const factory ChecklistFilterEditorEvent.delete() = _Delete; } diff --git a/frontend/app_flowy/lib/plugins/grid/application/filter/filter_create_bloc.dart b/frontend/app_flowy/lib/plugins/grid/application/filter/filter_create_bloc.dart index ff933a1da3..65835c2f81 100644 --- a/frontend/app_flowy/lib/plugins/grid/application/filter/filter_create_bloc.dart +++ b/frontend/app_flowy/lib/plugins/grid/application/filter/filter_create_bloc.dart @@ -90,48 +90,48 @@ class GridCreateFilterBloc case FieldType.Checkbox: return _ffiService.insertCheckboxFilter( fieldId: fieldId, - condition: CheckboxFilterCondition.IsChecked, + condition: CheckboxFilterConditionPB.IsChecked, ); case FieldType.DateTime: final timestamp = DateTime.now().millisecondsSinceEpoch ~/ 1000; return _ffiService.insertDateFilter( fieldId: fieldId, - condition: DateFilterCondition.DateIs, + condition: DateFilterConditionPB.DateIs, timestamp: timestamp, ); case FieldType.MultiSelect: return _ffiService.insertSelectOptionFilter( fieldId: fieldId, - condition: SelectOptionCondition.OptionIs, + condition: SelectOptionConditionPB.OptionIs, fieldType: FieldType.MultiSelect, ); case FieldType.Checklist: return _ffiService.insertChecklistFilter( fieldId: fieldId, - condition: ChecklistFilterCondition.IsIncomplete, + condition: ChecklistFilterConditionPB.IsIncomplete, ); case FieldType.Number: return _ffiService.insertNumberFilter( fieldId: fieldId, - condition: NumberFilterCondition.Equal, + condition: NumberFilterConditionPB.Equal, content: "", ); case FieldType.RichText: return _ffiService.insertTextFilter( fieldId: fieldId, - condition: TextFilterCondition.Contains, + condition: TextFilterConditionPB.Contains, content: '', ); case FieldType.SingleSelect: return _ffiService.insertSelectOptionFilter( fieldId: fieldId, - condition: SelectOptionCondition.OptionIs, + condition: SelectOptionConditionPB.OptionIs, fieldType: FieldType.SingleSelect, ); case FieldType.URL: return _ffiService.insertURLFilter( fieldId: fieldId, - condition: TextFilterCondition.Contains, + condition: TextFilterConditionPB.Contains, ); } diff --git a/frontend/app_flowy/lib/plugins/grid/application/filter/filter_service.dart b/frontend/app_flowy/lib/plugins/grid/application/filter/filter_service.dart index f30a9dc263..406b9073af 100644 --- a/frontend/app_flowy/lib/plugins/grid/application/filter/filter_service.dart +++ b/frontend/app_flowy/lib/plugins/grid/application/filter/filter_service.dart @@ -32,7 +32,7 @@ class FilterFFIService { Future> insertTextFilter({ required String fieldId, String? filterId, - required TextFilterCondition condition, + required TextFilterConditionPB condition, required String content, }) { final filter = TextFilterPB() @@ -50,7 +50,7 @@ class FilterFFIService { Future> insertCheckboxFilter({ required String fieldId, String? filterId, - required CheckboxFilterCondition condition, + required CheckboxFilterConditionPB condition, }) { final filter = CheckboxFilterPB()..condition = condition; @@ -65,7 +65,7 @@ class FilterFFIService { Future> insertNumberFilter({ required String fieldId, String? filterId, - required NumberFilterCondition condition, + required NumberFilterConditionPB condition, String content = "", }) { final filter = NumberFilterPB() @@ -83,7 +83,7 @@ class FilterFFIService { Future> insertDateFilter({ required String fieldId, String? filterId, - required DateFilterCondition condition, + required DateFilterConditionPB condition, int? start, int? end, int? timestamp, @@ -112,7 +112,7 @@ class FilterFFIService { Future> insertURLFilter({ required String fieldId, String? filterId, - required TextFilterCondition condition, + required TextFilterConditionPB condition, String content = "", }) { final filter = TextFilterPB() @@ -130,7 +130,7 @@ class FilterFFIService { Future> insertSelectOptionFilter({ required String fieldId, required FieldType fieldType, - required SelectOptionCondition condition, + required SelectOptionConditionPB condition, String? filterId, List optionIds = const [], }) { @@ -148,7 +148,7 @@ class FilterFFIService { Future> insertChecklistFilter({ required String fieldId, - required ChecklistFilterCondition condition, + required ChecklistFilterConditionPB condition, String? filterId, List optionIds = const [], }) { @@ -171,6 +171,7 @@ class FilterFFIService { var insertFilterPayload = AlterFilterPayloadPB.create() ..fieldId = fieldId ..fieldType = fieldType + ..viewId = viewId ..data = data; if (filterId != null) { @@ -179,7 +180,7 @@ class FilterFFIService { final payload = GridSettingChangesetPB.create() ..gridId = viewId - ..insertFilter = insertFilterPayload; + ..alterFilter = insertFilterPayload; return GridEventUpdateGridSetting(payload).send().then((result) { return result.fold( (l) => left(l), @@ -196,11 +197,12 @@ class FilterFFIService { required String filterId, required FieldType fieldType, }) { - TextFilterCondition.DoesNotContain.value; + TextFilterConditionPB.DoesNotContain.value; final deleteFilterPayload = DeleteFilterPayloadPB.create() ..fieldId = fieldId ..filterId = filterId + ..viewId = viewId ..fieldType = fieldType; final payload = GridSettingChangesetPB.create() diff --git a/frontend/app_flowy/lib/plugins/grid/application/filter/select_option_filter_bloc.dart b/frontend/app_flowy/lib/plugins/grid/application/filter/select_option_filter_bloc.dart index 4cf76e7cac..54852bb53e 100644 --- a/frontend/app_flowy/lib/plugins/grid/application/filter/select_option_filter_bloc.dart +++ b/frontend/app_flowy/lib/plugins/grid/application/filter/select_option_filter_bloc.dart @@ -33,7 +33,7 @@ class SelectOptionFilterEditorBloc _startListening(); _loadOptions(); }, - updateCondition: (SelectOptionCondition condition) { + updateCondition: (SelectOptionConditionPB condition) { _ffiService.insertSelectOptionFilter( filterId: filterInfo.filter.id, fieldId: filterInfo.fieldInfo.id, @@ -114,7 +114,7 @@ class SelectOptionFilterEditorEvent with _$SelectOptionFilterEditorEvent { const factory SelectOptionFilterEditorEvent.didReceiveFilter( FilterPB filter) = _DidReceiveFilter; const factory SelectOptionFilterEditorEvent.updateCondition( - SelectOptionCondition condition) = _UpdateCondition; + SelectOptionConditionPB condition) = _UpdateCondition; const factory SelectOptionFilterEditorEvent.updateContent( List optionIds) = _UpdateContent; const factory SelectOptionFilterEditorEvent.updateFilterDescription( diff --git a/frontend/app_flowy/lib/plugins/grid/application/filter/text_filter_editor_bloc.dart b/frontend/app_flowy/lib/plugins/grid/application/filter/text_filter_editor_bloc.dart index e556d04d9e..724d44e093 100644 --- a/frontend/app_flowy/lib/plugins/grid/application/filter/text_filter_editor_bloc.dart +++ b/frontend/app_flowy/lib/plugins/grid/application/filter/text_filter_editor_bloc.dart @@ -28,7 +28,7 @@ class TextFilterEditorBloc initial: () async { _startListening(); }, - updateCondition: (TextFilterCondition condition) { + updateCondition: (TextFilterConditionPB condition) { _ffiService.insertTextFilter( filterId: filterInfo.filter.id, fieldId: filterInfo.fieldInfo.id, @@ -88,7 +88,7 @@ class TextFilterEditorEvent with _$TextFilterEditorEvent { const factory TextFilterEditorEvent.didReceiveFilter(FilterPB filter) = _DidReceiveFilter; const factory TextFilterEditorEvent.updateCondition( - TextFilterCondition condition) = _UpdateCondition; + TextFilterConditionPB condition) = _UpdateCondition; const factory TextFilterEditorEvent.updateContent(String content) = _UpdateContent; const factory TextFilterEditorEvent.delete() = _Delete; diff --git a/frontend/app_flowy/lib/plugins/grid/application/grid_bloc.dart b/frontend/app_flowy/lib/plugins/grid/application/grid_bloc.dart index ec35a05eef..06c8074772 100644 --- a/frontend/app_flowy/lib/plugins/grid/application/grid_bloc.dart +++ b/frontend/app_flowy/lib/plugins/grid/application/grid_bloc.dart @@ -6,7 +6,6 @@ import 'package:flowy_sdk/protobuf/flowy-folder/view.pb.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_cache.dart'; import 'field/field_controller.dart'; import 'grid_data_controller.dart'; import 'row/row_cache.dart'; @@ -38,7 +37,6 @@ class GridBloc extends Bloc { }, deleteRow: (rowInfo) async { final rowService = RowFFIService( - blockId: rowInfo.rowPB.blockId, gridId: rowInfo.gridId, ); await rowService.deleteRow(rowInfo.rowPB.id); @@ -70,8 +68,7 @@ class GridBloc extends Bloc { } GridRowCache? getRowCache(String blockId, String rowId) { - final GridBlockCache? blockCache = gridController.blocks[blockId]; - return blockCache?.rowCache; + return gridController.rowCache; } void _startListening() { diff --git a/frontend/app_flowy/lib/plugins/grid/application/grid_data_controller.dart b/frontend/app_flowy/lib/plugins/grid/application/grid_data_controller.dart index af25cc1007..36685ab30b 100644 --- a/frontend/app_flowy/lib/plugins/grid/application/grid_data_controller.dart +++ b/frontend/app_flowy/lib/plugins/grid/application/grid_data_controller.dart @@ -1,14 +1,10 @@ -import 'dart:collection'; - import 'package:app_flowy/plugins/grid/presentation/widgets/filter/filter_info.dart'; -import 'package:flowy_sdk/log.dart'; import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-folder/view.pb.dart'; -import 'package:flowy_sdk/protobuf/flowy-grid/block_entities.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-grid/grid_entities.pb.dart'; import 'dart:async'; import 'package:dartz/dartz.dart'; -import 'block/block_cache.dart'; +import 'view/grid_view_cache.dart'; import 'field/field_controller.dart'; import 'prelude.dart'; import 'row/row_cache.dart'; @@ -27,29 +23,25 @@ class GridController { final String gridId; final GridFFIService _gridFFIService; final GridFieldController fieldController; + late GridViewCache _viewCache; + OnRowsChanged? _onRowChanged; OnGridChanged? _onGridChanged; - - // Getters - // key: the block id - final LinkedHashMap _blocks; - UnmodifiableMapView get blocks => - UnmodifiableMapView(_blocks); - - List get rowInfos { - final List rows = []; - for (var block in _blocks.values) { - rows.addAll(block.rows); - } - return rows; - } + List get rowInfos => _viewCache.rowInfos; + GridRowCache get rowCache => _viewCache.rowCache; GridController({required ViewPB view}) : gridId = view.id, - // ignore: prefer_collection_literals - _blocks = LinkedHashMap(), _gridFFIService = GridFFIService(gridId: view.id), - fieldController = GridFieldController(gridId: view.id); + fieldController = GridFieldController(gridId: view.id) { + _viewCache = GridViewCache( + gridId: gridId, + fieldController: fieldController, + ); + _viewCache.addListener(onRowsChanged: (reason) { + _onRowChanged?.call(rowInfos, reason); + }); + } void addListener({ OnGridChanged? onGridChanged, @@ -71,9 +63,8 @@ class GridController { return _gridFFIService.openGrid().then((result) { return result.fold( (grid) async { - _initialBlocks(grid.blocks); _onGridChanged?.call(grid); - + _viewCache.rowCache.initializeRows(grid.rows); final result = await fieldController.loadFields( fieldIds: grid.fields, ); @@ -91,30 +82,5 @@ class GridController { Future dispose() async { await _gridFFIService.closeGrid(); await fieldController.dispose(); - - for (final blockCache in _blocks.values) { - blockCache.dispose(); - } - } - - void _initialBlocks(List blocks) { - for (final block in blocks) { - if (_blocks[block.id] != null) { - Log.warn("Initial duplicate block's cache: ${block.id}"); - return; - } - - final cache = GridBlockCache( - gridId: gridId, - block: block, - fieldController: fieldController, - ); - - cache.addListener(onRowsChanged: (reason) { - _onRowChanged?.call(rowInfos, reason); - }); - - _blocks[block.id] = cache; - } } } diff --git a/frontend/app_flowy/lib/plugins/grid/application/grid_service.dart b/frontend/app_flowy/lib/plugins/grid/application/grid_service.dart index 2f3d437f8b..0b07fbfe58 100644 --- a/frontend/app_flowy/lib/plugins/grid/application/grid_service.dart +++ b/frontend/app_flowy/lib/plugins/grid/application/grid_service.dart @@ -2,7 +2,6 @@ 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-folder/view.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/group.pb.dart'; diff --git a/frontend/app_flowy/lib/plugins/grid/application/row/row_action_sheet_bloc.dart b/frontend/app_flowy/lib/plugins/grid/application/row/row_action_sheet_bloc.dart index fa81e6cb23..1d21d0e181 100644 --- a/frontend/app_flowy/lib/plugins/grid/application/row/row_action_sheet_bloc.dart +++ b/frontend/app_flowy/lib/plugins/grid/application/row/row_action_sheet_bloc.dart @@ -15,10 +15,7 @@ class RowActionSheetBloc final RowFFIService _rowService; RowActionSheetBloc({required RowInfo rowInfo}) - : _rowService = RowFFIService( - gridId: rowInfo.gridId, - blockId: rowInfo.rowPB.blockId, - ), + : _rowService = RowFFIService(gridId: rowInfo.gridId), super(RowActionSheetState.initial(rowInfo)) { on( (event, emit) async { diff --git a/frontend/app_flowy/lib/plugins/grid/application/row/row_bloc.dart b/frontend/app_flowy/lib/plugins/grid/application/row/row_bloc.dart index 385319d878..98d80960bc 100644 --- a/frontend/app_flowy/lib/plugins/grid/application/row/row_bloc.dart +++ b/frontend/app_flowy/lib/plugins/grid/application/row/row_bloc.dart @@ -18,10 +18,7 @@ class RowBloc extends Bloc { RowBloc({ required RowInfo rowInfo, required GridRowDataController dataController, - }) : _rowService = RowFFIService( - gridId: rowInfo.gridId, - blockId: rowInfo.rowPB.blockId, - ), + }) : _rowService = RowFFIService(gridId: rowInfo.gridId), _dataController = dataController, super(RowState.initial(rowInfo, dataController.loadData())) { on( diff --git a/frontend/app_flowy/lib/plugins/grid/application/row/row_cache.dart b/frontend/app_flowy/lib/plugins/grid/application/row/row_cache.dart index 0a920639a9..f2421b7e10 100644 --- a/frontend/app_flowy/lib/plugins/grid/application/row/row_cache.dart +++ b/frontend/app_flowy/lib/plugins/grid/application/row/row_cache.dart @@ -3,8 +3,7 @@ import 'package:app_flowy/plugins/grid/application/cell/cell_service/cell_servic import 'package:app_flowy/plugins/grid/application/field/field_controller.dart'; import 'package:flowy_sdk/dispatch/dispatch.dart'; import 'package:flowy_sdk/log.dart'; -import 'package:flowy_sdk/protobuf/flowy-grid/block_entities.pb.dart'; -import 'package:flowy_sdk/protobuf/flowy-grid/row_entities.pb.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid/protobuf.dart'; import 'package:flutter/foundation.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; @@ -27,7 +26,7 @@ abstract class IGridRowFieldNotifier { class GridRowCache { final String gridId; - final BlockPB block; + final List rows; /// _rows containers the current block's rows /// Use List to reverse the order of the GridRow. @@ -46,7 +45,7 @@ class GridRowCache { GridRowCache({ required this.gridId, - required this.block, + required this.rows, required IGridRowFieldNotifier notifier, }) : _cellCache = GridCellCache(gridId: gridId), _rowChangeReasonNotifier = _RowChangesetNotifier(), @@ -56,8 +55,10 @@ class GridRowCache { .receive(const RowsChangedReason.fieldDidChange())); notifier.onRowFieldChanged( (field) => _cellCache.removeCellWithFieldId(field.id)); + } - for (final row in block.rows) { + void initializeRows(List rows) { + for (final row in rows) { final rowInfo = buildGridRow(row); _rowList.add(rowInfo); } @@ -69,10 +70,13 @@ class GridRowCache { await _cellCache.dispose(); } - void applyChangesets(GridBlockChangesetPB changeset) { + void applyRowsChanged(GridViewRowsChangesetPB changeset) { _deleteRows(changeset.deletedRows); _insertRows(changeset.insertedRows); _updateRows(changeset.updatedRows); + } + + void applyRowsVisibility(GridRowsVisibilityChangesetPB changeset) { _hideRows(changeset.invisibleRows); _showRows(changeset.visibleRows); } @@ -192,7 +196,6 @@ class GridRowCache { Future _loadRow(String rowId) async { final payload = RowIdPB.create() ..gridId = gridId - ..blockId = block.id ..rowId = rowId; final result = await GridEventGetRow(payload).send(); diff --git a/frontend/app_flowy/lib/plugins/grid/application/row/row_list.dart b/frontend/app_flowy/lib/plugins/grid/application/row/row_list.dart index 6e2d5d64f0..450650041f 100644 --- a/frontend/app_flowy/lib/plugins/grid/application/row/row_list.dart +++ b/frontend/app_flowy/lib/plugins/grid/application/row/row_list.dart @@ -1,6 +1,6 @@ import 'dart:collection'; -import 'package:flowy_sdk/protobuf/flowy-grid/block_entities.pb.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid/row_entities.pb.dart'; import 'row_cache.dart'; diff --git a/frontend/app_flowy/lib/plugins/grid/application/row/row_listener.dart b/frontend/app_flowy/lib/plugins/grid/application/row/row_listener.dart index 76ee622a41..c904a7cc1d 100644 --- a/frontend/app_flowy/lib/plugins/grid/application/row/row_listener.dart +++ b/frontend/app_flowy/lib/plugins/grid/application/row/row_listener.dart @@ -1,12 +1,12 @@ import 'package:app_flowy/core/grid_notification.dart'; import 'package:flowy_sdk/protobuf/flowy-error/errors.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:dartz/dartz.dart'; import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid/row_entities.pb.dart'; typedef UpdateRowNotifiedValue = Either; typedef UpdateFieldNotifiedValue = Either, FlowyError>; diff --git a/frontend/app_flowy/lib/plugins/grid/application/row/row_service.dart b/frontend/app_flowy/lib/plugins/grid/application/row/row_service.dart index 2612f5975c..147cc44793 100644 --- a/frontend/app_flowy/lib/plugins/grid/application/row/row_service.dart +++ b/frontend/app_flowy/lib/plugins/grid/application/row/row_service.dart @@ -1,18 +1,15 @@ 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/block_entities.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-grid/grid_entities.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-grid/group_changeset.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-grid/row_entities.pb.dart'; class RowFFIService { final String gridId; - final String blockId; RowFFIService({ required this.gridId, - required this.blockId, }); Future> createRow(String rowId) { @@ -26,7 +23,6 @@ class RowFFIService { Future> getRow(String rowId) { final payload = RowIdPB.create() ..gridId = gridId - ..blockId = blockId ..rowId = rowId; return GridEventGetRow(payload).send(); @@ -35,7 +31,6 @@ class RowFFIService { Future> deleteRow(String rowId) { final payload = RowIdPB.create() ..gridId = gridId - ..blockId = blockId ..rowId = rowId; return GridEventDeleteRow(payload).send(); @@ -44,7 +39,6 @@ class RowFFIService { Future> duplicateRow(String rowId) { final payload = RowIdPB.create() ..gridId = gridId - ..blockId = blockId ..rowId = rowId; return GridEventDuplicateRow(payload).send(); diff --git a/frontend/app_flowy/lib/plugins/grid/application/block/block_cache.dart b/frontend/app_flowy/lib/plugins/grid/application/view/grid_view_cache.dart similarity index 55% rename from frontend/app_flowy/lib/plugins/grid/application/block/block_cache.dart rename to frontend/app_flowy/lib/plugins/grid/application/view/grid_view_cache.dart index 34bd1ba3dd..fea8f46f46 100644 --- a/frontend/app_flowy/lib/plugins/grid/application/block/block_cache.dart +++ b/frontend/app_flowy/lib/plugins/grid/application/view/grid_view_cache.dart @@ -1,43 +1,47 @@ import 'dart:async'; +import 'package:app_flowy/plugins/grid/application/view/grid_view_listener.dart'; import 'package:flowy_sdk/log.dart'; -import 'package:flowy_sdk/protobuf/flowy-grid/block_entities.pb.dart'; import '../field/field_controller.dart'; import '../row/row_cache.dart'; -import 'block_listener.dart'; /// Read https://appflowy.gitbook.io/docs/essential-documentation/contribute-to-appflowy/architecture/frontend/grid for more information -class GridBlockCache { +class GridViewCache { final String gridId; - final BlockPB block; late GridRowCache _rowCache; - late GridBlockListener _listener; + final GridViewListener _gridViewListener; - List get rows => _rowCache.visibleRows; + List get rowInfos => _rowCache.visibleRows; GridRowCache get rowCache => _rowCache; - GridBlockCache({ + GridViewCache({ required this.gridId, - required this.block, required GridFieldController fieldController, - }) { + }) : _gridViewListener = GridViewListener(viewId: gridId) { _rowCache = GridRowCache( gridId: gridId, - block: block, + rows: [], notifier: GridRowFieldNotifierImpl(fieldController), ); - _listener = GridBlockListener(blockId: block.id); - _listener.start((result) { - result.fold( - (changeset) => _rowCache.applyChangesets(changeset), - (err) => Log.error(err), - ); - }); + _gridViewListener.start( + onRowsChanged: (result) { + result.fold( + (changeset) => _rowCache.applyRowsChanged(changeset), + (err) => Log.error(err), + ); + }, + onRowsVisibilityChanged: (result) { + result.fold( + (changeset) => _rowCache.applyRowsVisibility(changeset), + (err) => Log.error(err), + ); + }, + ); } Future dispose() async { - await _listener.stop(); + await _gridViewListener.stop(); await _rowCache.dispose(); } diff --git a/frontend/app_flowy/lib/plugins/grid/application/view/grid_view_listener.dart b/frontend/app_flowy/lib/plugins/grid/application/view/grid_view_listener.dart new file mode 100644 index 0000000000..47b1cb9ee7 --- /dev/null +++ b/frontend/app_flowy/lib/plugins/grid/application/view/grid_view_listener.dart @@ -0,0 +1,72 @@ +import 'dart:async'; +import 'dart:typed_data'; +import 'package:app_flowy/core/grid_notification.dart'; +import 'package:dartz/dartz.dart'; +import 'package:flowy_infra/notifier.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_sdk/protobuf/flowy-grid/view_entities.pb.dart'; + +typedef GridRowsVisibilityNotifierValue + = Either; + +typedef GridViewRowsNotifierValue = Either; + +class GridViewListener { + final String viewId; + PublishNotifier? _rowsNotifier = PublishNotifier(); + PublishNotifier? _rowsVisibilityNotifier = + PublishNotifier(); + + GridNotificationListener? _listener; + GridViewListener({required this.viewId}); + + void start({ + required void Function(GridViewRowsNotifierValue) onRowsChanged, + required void Function(GridRowsVisibilityNotifierValue) + onRowsVisibilityChanged, + }) { + if (_listener != null) { + _listener?.stop(); + } + + _listener = GridNotificationListener( + objectId: viewId, + handler: _handler, + ); + + _rowsNotifier?.addPublishListener(onRowsChanged); + _rowsVisibilityNotifier?.addPublishListener(onRowsVisibilityChanged); + } + + void _handler(GridDartNotification ty, Either result) { + switch (ty) { + case GridDartNotification.DidUpdateGridViewRowsVisibility: + result.fold( + (payload) => _rowsVisibilityNotifier?.value = + left(GridRowsVisibilityChangesetPB.fromBuffer(payload)), + (error) => _rowsVisibilityNotifier?.value = right(error), + ); + break; + case GridDartNotification.DidUpdateGridViewRows: + result.fold( + (payload) => _rowsNotifier?.value = + left(GridViewRowsChangesetPB.fromBuffer(payload)), + (error) => _rowsNotifier?.value = right(error), + ); + break; + + default: + break; + } + } + + Future stop() async { + await _listener?.stop(); + _rowsVisibilityNotifier?.dispose(); + _rowsVisibilityNotifier = null; + + _rowsNotifier?.dispose(); + _rowsNotifier = null; + } +} diff --git a/frontend/app_flowy/lib/plugins/grid/presentation/widgets/filter/choicechip/checkbox.dart b/frontend/app_flowy/lib/plugins/grid/presentation/widgets/filter/choicechip/checkbox.dart index 6f8edaa656..717be3d0a2 100644 --- a/frontend/app_flowy/lib/plugins/grid/presentation/widgets/filter/choicechip/checkbox.dart +++ b/frontend/app_flowy/lib/plugins/grid/presentation/widgets/filter/choicechip/checkbox.dart @@ -108,7 +108,7 @@ class _CheckboxFilterEditorState extends State { children: [ FlowyText(state.filterInfo.fieldInfo.name), const HSpace(4), - CheckboxFilterConditionList( + CheckboxFilterConditionPBList( filterInfo: state.filterInfo, popoverMutex: popoverMutex, onCondition: (condition) { @@ -136,11 +136,11 @@ class _CheckboxFilterEditorState extends State { } } -class CheckboxFilterConditionList extends StatelessWidget { +class CheckboxFilterConditionPBList extends StatelessWidget { final FilterInfo filterInfo; final PopoverMutex popoverMutex; - final Function(CheckboxFilterCondition) onCondition; - const CheckboxFilterConditionList({ + final Function(CheckboxFilterConditionPB) onCondition; + const CheckboxFilterConditionPBList({ required this.filterInfo, required this.popoverMutex, required this.onCondition, @@ -154,7 +154,7 @@ class CheckboxFilterConditionList extends StatelessWidget { asBarrier: true, mutex: popoverMutex, direction: PopoverDirection.bottomWithCenterAligned, - actions: CheckboxFilterCondition.values + actions: CheckboxFilterConditionPB.values .map( (action) => ConditionWrapper( action, @@ -177,7 +177,7 @@ class CheckboxFilterConditionList extends StatelessWidget { } class ConditionWrapper extends ActionCell { - final CheckboxFilterCondition inner; + final CheckboxFilterConditionPB inner; final bool isSelected; ConditionWrapper(this.inner, this.isSelected); @@ -195,12 +195,12 @@ class ConditionWrapper extends ActionCell { String get name => inner.filterName; } -extension TextFilterConditionExtension on CheckboxFilterCondition { +extension TextFilterConditionPBExtension on CheckboxFilterConditionPB { String get filterName { switch (this) { - case CheckboxFilterCondition.IsChecked: + case CheckboxFilterConditionPB.IsChecked: return LocaleKeys.grid_checkboxFilter_isChecked.tr(); - case CheckboxFilterCondition.IsUnChecked: + case CheckboxFilterConditionPB.IsUnChecked: return LocaleKeys.grid_checkboxFilter_isUnchecked.tr(); default: return ""; diff --git a/frontend/app_flowy/lib/plugins/grid/presentation/widgets/filter/choicechip/checklist/checklist.dart b/frontend/app_flowy/lib/plugins/grid/presentation/widgets/filter/choicechip/checklist/checklist.dart index 114ececac7..aba0c5d2c8 100644 --- a/frontend/app_flowy/lib/plugins/grid/presentation/widgets/filter/choicechip/checklist/checklist.dart +++ b/frontend/app_flowy/lib/plugins/grid/presentation/widgets/filter/choicechip/checklist/checklist.dart @@ -92,7 +92,7 @@ class ChecklistState extends State { children: [ FlowyText(state.filterInfo.fieldInfo.name), const HSpace(4), - ChecklistFilterConditionList( + ChecklistFilterConditionPBList( filterInfo: state.filterInfo, ), const Spacer(), @@ -117,9 +117,9 @@ class ChecklistState extends State { } } -class ChecklistFilterConditionList extends StatelessWidget { +class ChecklistFilterConditionPBList extends StatelessWidget { final FilterInfo filterInfo; - const ChecklistFilterConditionList({ + const ChecklistFilterConditionPBList({ required this.filterInfo, Key? key, }) : super(key: key); @@ -130,7 +130,7 @@ class ChecklistFilterConditionList extends StatelessWidget { return PopoverActionList( asBarrier: true, direction: PopoverDirection.bottomWithCenterAligned, - actions: ChecklistFilterCondition.values + actions: ChecklistFilterConditionPB.values .map((action) => ConditionWrapper(action)) .toList(), buildChild: (controller) { @@ -150,7 +150,7 @@ class ChecklistFilterConditionList extends StatelessWidget { } class ConditionWrapper extends ActionCell { - final ChecklistFilterCondition inner; + final ChecklistFilterConditionPB inner; ConditionWrapper(this.inner); @@ -158,12 +158,12 @@ class ConditionWrapper extends ActionCell { String get name => inner.filterName; } -extension ChecklistFilterConditionExtension on ChecklistFilterCondition { +extension ChecklistFilterConditionPBExtension on ChecklistFilterConditionPB { String get filterName { switch (this) { - case ChecklistFilterCondition.IsComplete: + case ChecklistFilterConditionPB.IsComplete: return LocaleKeys.grid_checklistFilter_isComplete.tr(); - case ChecklistFilterCondition.IsIncomplete: + case ChecklistFilterConditionPB.IsIncomplete: return LocaleKeys.grid_checklistFilter_isIncomplted.tr(); default: return ""; diff --git a/frontend/app_flowy/lib/plugins/grid/presentation/widgets/filter/choicechip/select_option/condition_list.dart b/frontend/app_flowy/lib/plugins/grid/presentation/widgets/filter/choicechip/select_option/condition_list.dart index 2ece1ce0d7..e8cc4a9ae6 100644 --- a/frontend/app_flowy/lib/plugins/grid/presentation/widgets/filter/choicechip/select_option/condition_list.dart +++ b/frontend/app_flowy/lib/plugins/grid/presentation/widgets/filter/choicechip/select_option/condition_list.dart @@ -12,7 +12,7 @@ import 'package:flutter/material.dart'; class SelectOptionFilterConditionList extends StatelessWidget { final FilterInfo filterInfo; final PopoverMutex popoverMutex; - final Function(SelectOptionCondition) onCondition; + final Function(SelectOptionConditionPB) onCondition; const SelectOptionFilterConditionList({ required this.filterInfo, required this.popoverMutex, @@ -27,7 +27,7 @@ class SelectOptionFilterConditionList extends StatelessWidget { asBarrier: true, mutex: popoverMutex, direction: PopoverDirection.bottomWithCenterAligned, - actions: SelectOptionCondition.values + actions: SelectOptionConditionPB.values .map( (action) => ConditionWrapper( action, @@ -59,7 +59,7 @@ class SelectOptionFilterConditionList extends StatelessWidget { } class ConditionWrapper extends ActionCell { - final SelectOptionCondition inner; + final SelectOptionConditionPB inner; final bool isSelected; final FieldType fieldType; @@ -84,16 +84,16 @@ class ConditionWrapper extends ActionCell { } } -extension SelectOptionConditionExtension on SelectOptionCondition { +extension SelectOptionConditionPBExtension on SelectOptionConditionPB { String get singleSelectFilterName { switch (this) { - case SelectOptionCondition.OptionIs: + case SelectOptionConditionPB.OptionIs: return LocaleKeys.grid_singleSelectOptionFilter_is.tr(); - case SelectOptionCondition.OptionIsEmpty: + case SelectOptionConditionPB.OptionIsEmpty: return LocaleKeys.grid_singleSelectOptionFilter_isEmpty.tr(); - case SelectOptionCondition.OptionIsNot: + case SelectOptionConditionPB.OptionIsNot: return LocaleKeys.grid_singleSelectOptionFilter_isNot.tr(); - case SelectOptionCondition.OptionIsNotEmpty: + case SelectOptionConditionPB.OptionIsNotEmpty: return LocaleKeys.grid_singleSelectOptionFilter_isNotEmpty.tr(); default: return ""; @@ -102,13 +102,13 @@ extension SelectOptionConditionExtension on SelectOptionCondition { String get multiSelectFilterName { switch (this) { - case SelectOptionCondition.OptionIs: + case SelectOptionConditionPB.OptionIs: return LocaleKeys.grid_multiSelectOptionFilter_contains.tr(); - case SelectOptionCondition.OptionIsEmpty: + case SelectOptionConditionPB.OptionIsEmpty: return LocaleKeys.grid_multiSelectOptionFilter_isEmpty.tr(); - case SelectOptionCondition.OptionIsNot: + case SelectOptionConditionPB.OptionIsNot: return LocaleKeys.grid_multiSelectOptionFilter_doesNotContain.tr(); - case SelectOptionCondition.OptionIsNotEmpty: + case SelectOptionConditionPB.OptionIsNotEmpty: return LocaleKeys.grid_multiSelectOptionFilter_isNotEmpty.tr(); default: return ""; diff --git a/frontend/app_flowy/lib/plugins/grid/presentation/widgets/filter/choicechip/select_option/select_option.dart b/frontend/app_flowy/lib/plugins/grid/presentation/widgets/filter/choicechip/select_option/select_option.dart index 8f835a032d..3f0fe9a0b1 100644 --- a/frontend/app_flowy/lib/plugins/grid/presentation/widgets/filter/choicechip/select_option/select_option.dart +++ b/frontend/app_flowy/lib/plugins/grid/presentation/widgets/filter/choicechip/select_option/select_option.dart @@ -101,9 +101,9 @@ class _SelectOptionFilterEditorState extends State { SliverToBoxAdapter(child: _buildFilterPannel(context, state)), ]; - if (state.filter.condition != SelectOptionCondition.OptionIsEmpty && + if (state.filter.condition != SelectOptionConditionPB.OptionIsEmpty && state.filter.condition != - SelectOptionCondition.OptionIsNotEmpty) { + SelectOptionConditionPB.OptionIsNotEmpty) { slivers.add(const SliverToBoxAdapter(child: VSpace(4))); slivers.add( SliverToBoxAdapter( diff --git a/frontend/app_flowy/lib/plugins/grid/presentation/widgets/filter/choicechip/text.dart b/frontend/app_flowy/lib/plugins/grid/presentation/widgets/filter/choicechip/text.dart index 1c51eba0ff..4c7ead3d81 100644 --- a/frontend/app_flowy/lib/plugins/grid/presentation/widgets/filter/choicechip/text.dart +++ b/frontend/app_flowy/lib/plugins/grid/presentation/widgets/filter/choicechip/text.dart @@ -64,8 +64,8 @@ class _TextFilterChoicechipState extends State { String _makeFilterDesc(TextFilterEditorState state) { String filterDesc = state.filter.condition.choicechipPrefix; - if (state.filter.condition == TextFilterCondition.TextIsEmpty || - state.filter.condition == TextFilterCondition.TextIsNotEmpty) { + if (state.filter.condition == TextFilterConditionPB.TextIsEmpty || + state.filter.condition == TextFilterConditionPB.TextIsNotEmpty) { return filterDesc; } @@ -98,8 +98,8 @@ class _TextFilterEditorState extends State { _buildFilterPannel(context, state), ]; - if (state.filter.condition != TextFilterCondition.TextIsEmpty && - state.filter.condition != TextFilterCondition.TextIsNotEmpty) { + if (state.filter.condition != TextFilterConditionPB.TextIsEmpty && + state.filter.condition != TextFilterConditionPB.TextIsNotEmpty) { children.add(const VSpace(4)); children.add(_buildFilterTextField(context, state)); } @@ -120,7 +120,7 @@ class _TextFilterEditorState extends State { children: [ FlowyText(state.filterInfo.fieldInfo.name), const HSpace(4), - TextFilterConditionList( + TextFilterConditionPBList( filterInfo: state.filterInfo, popoverMutex: popoverMutex, onCondition: (condition) { @@ -163,11 +163,11 @@ class _TextFilterEditorState extends State { } } -class TextFilterConditionList extends StatelessWidget { +class TextFilterConditionPBList extends StatelessWidget { final FilterInfo filterInfo; final PopoverMutex popoverMutex; - final Function(TextFilterCondition) onCondition; - const TextFilterConditionList({ + final Function(TextFilterConditionPB) onCondition; + const TextFilterConditionPBList({ required this.filterInfo, required this.popoverMutex, required this.onCondition, @@ -181,7 +181,7 @@ class TextFilterConditionList extends StatelessWidget { asBarrier: true, mutex: popoverMutex, direction: PopoverDirection.bottomWithCenterAligned, - actions: TextFilterCondition.values + actions: TextFilterConditionPB.values .map( (action) => ConditionWrapper( action, @@ -204,7 +204,7 @@ class TextFilterConditionList extends StatelessWidget { } class ConditionWrapper extends ActionCell { - final TextFilterCondition inner; + final TextFilterConditionPB inner; final bool isSelected; ConditionWrapper(this.inner, this.isSelected); @@ -222,24 +222,24 @@ class ConditionWrapper extends ActionCell { String get name => inner.filterName; } -extension TextFilterConditionExtension on TextFilterCondition { +extension TextFilterConditionPBExtension on TextFilterConditionPB { String get filterName { switch (this) { - case TextFilterCondition.Contains: + case TextFilterConditionPB.Contains: return LocaleKeys.grid_textFilter_contains.tr(); - case TextFilterCondition.DoesNotContain: + case TextFilterConditionPB.DoesNotContain: return LocaleKeys.grid_textFilter_doesNotContain.tr(); - case TextFilterCondition.EndsWith: + case TextFilterConditionPB.EndsWith: return LocaleKeys.grid_textFilter_endsWith.tr(); - case TextFilterCondition.Is: + case TextFilterConditionPB.Is: return LocaleKeys.grid_textFilter_is.tr(); - case TextFilterCondition.IsNot: + case TextFilterConditionPB.IsNot: return LocaleKeys.grid_textFilter_isNot.tr(); - case TextFilterCondition.StartsWith: + case TextFilterConditionPB.StartsWith: return LocaleKeys.grid_textFilter_startWith.tr(); - case TextFilterCondition.TextIsEmpty: + case TextFilterConditionPB.TextIsEmpty: return LocaleKeys.grid_textFilter_isEmpty.tr(); - case TextFilterCondition.TextIsNotEmpty: + case TextFilterConditionPB.TextIsNotEmpty: return LocaleKeys.grid_textFilter_isNotEmpty.tr(); default: return ""; @@ -248,17 +248,17 @@ extension TextFilterConditionExtension on TextFilterCondition { String get choicechipPrefix { switch (this) { - case TextFilterCondition.DoesNotContain: + case TextFilterConditionPB.DoesNotContain: return LocaleKeys.grid_textFilter_choicechipPrefix_isNot.tr(); - case TextFilterCondition.EndsWith: + case TextFilterConditionPB.EndsWith: return LocaleKeys.grid_textFilter_choicechipPrefix_endWith.tr(); - case TextFilterCondition.IsNot: + case TextFilterConditionPB.IsNot: return LocaleKeys.grid_textFilter_choicechipPrefix_isNot.tr(); - case TextFilterCondition.StartsWith: + case TextFilterConditionPB.StartsWith: return LocaleKeys.grid_textFilter_choicechipPrefix_startWith.tr(); - case TextFilterCondition.TextIsEmpty: + case TextFilterConditionPB.TextIsEmpty: return LocaleKeys.grid_textFilter_choicechipPrefix_isEmpty.tr(); - case TextFilterCondition.TextIsNotEmpty: + case TextFilterConditionPB.TextIsNotEmpty: return LocaleKeys.grid_textFilter_choicechipPrefix_isNotEmpty.tr(); default: return ""; diff --git a/frontend/app_flowy/test/bloc_test/board_test/util.dart b/frontend/app_flowy/test/bloc_test/board_test/util.dart index 1a198b9538..7cf0ea583f 100644 --- a/frontend/app_flowy/test/bloc_test/board_test/util.dart +++ b/frontend/app_flowy/test/bloc_test/board_test/util.dart @@ -1,8 +1,5 @@ -import 'dart:collection'; - import 'package:app_flowy/plugins/board/application/board_data_controller.dart'; import 'package:app_flowy/plugins/board/board.dart'; -import 'package:app_flowy/plugins/grid/application/block/block_cache.dart'; import 'package:app_flowy/plugins/grid/application/cell/cell_service/cell_service.dart'; import 'package:app_flowy/plugins/grid/application/field/field_controller.dart'; import 'package:app_flowy/plugins/grid/application/field/field_editor_bloc.dart'; @@ -74,10 +71,6 @@ class BoardTestContext { return _boardDataController.rowInfos; } - UnmodifiableMapView get blocks { - return _boardDataController.blocks; - } - List get fieldContexts => fieldController.fieldInfos; GridFieldController get fieldController { @@ -113,15 +106,13 @@ class BoardTestContext { String fieldId, ) async { final RowInfo rowInfo = rowInfos.last; - final blockCache = blocks[rowInfo.rowPB.blockId]; - final rowCache = blockCache?.rowCache; - + final rowCache = _boardDataController.rowCache; final fieldController = _boardDataController.fieldController; final rowDataController = GridRowDataController( rowInfo: rowInfo, fieldController: fieldController, - rowCache: rowCache!, + rowCache: rowCache, ); final rowBloc = RowBloc( diff --git a/frontend/app_flowy/test/bloc_test/grid_test/filter/create_filter_test.dart b/frontend/app_flowy/test/bloc_test/grid_test/filter/create_filter_test.dart index db9dfdccab..292c17be1b 100644 --- a/frontend/app_flowy/test/bloc_test/grid_test/filter/create_filter_test.dart +++ b/frontend/app_flowy/test/bloc_test/grid_test/filter/create_filter_test.dart @@ -19,7 +19,7 @@ void main() { final textField = context.textFieldContext(); await service.insertTextFilter( fieldId: textField.id, - condition: TextFilterCondition.TextIsEmpty, + condition: TextFilterConditionPB.TextIsEmpty, content: ""); await gridResponseFuture(); @@ -32,7 +32,7 @@ void main() { final textField = context.textFieldContext(); await service.insertTextFilter( fieldId: textField.id, - condition: TextFilterCondition.TextIsEmpty, + condition: TextFilterConditionPB.TextIsEmpty, content: ""); await gridResponseFuture(); @@ -60,7 +60,7 @@ void main() { final textField = context.textFieldContext(); service.insertTextFilter( fieldId: textField.id, - condition: TextFilterCondition.TextIsEmpty, + condition: TextFilterConditionPB.TextIsEmpty, content: ""); await gridResponseFuture(); @@ -81,7 +81,7 @@ void main() { final textField = context.textFieldContext(); await service.insertTextFilter( fieldId: textField.id, - condition: TextFilterCondition.TextIsEmpty, + condition: TextFilterConditionPB.TextIsEmpty, content: ""); await gridResponseFuture(); @@ -102,7 +102,7 @@ void main() { await gridResponseFuture(); await service.insertTextFilter( fieldId: textField.id, - condition: TextFilterCondition.TextIsNotEmpty, + condition: TextFilterConditionPB.TextIsNotEmpty, content: ""); await gridResponseFuture(); assert(context.rowInfos.isEmpty); @@ -121,7 +121,7 @@ void main() { await gridResponseFuture(); await service.insertCheckboxFilter( fieldId: checkboxField.id, - condition: CheckboxFilterCondition.IsUnChecked, + condition: CheckboxFilterConditionPB.IsUnChecked, ); await gridResponseFuture(); assert(gridBloc.state.rowInfos.length == 3); @@ -140,7 +140,7 @@ void main() { await gridResponseFuture(); await service.insertCheckboxFilter( fieldId: checkboxField.id, - condition: CheckboxFilterCondition.IsChecked, + condition: CheckboxFilterConditionPB.IsChecked, ); await gridResponseFuture(); assert(gridBloc.state.rowInfos.isEmpty); diff --git a/frontend/app_flowy/test/bloc_test/grid_test/filter/edit_filter_field_test.dart b/frontend/app_flowy/test/bloc_test/grid_test/filter/edit_filter_field_test.dart index d1e6263b24..2171ab948c 100644 --- a/frontend/app_flowy/test/bloc_test/grid_test/filter/edit_filter_field_test.dart +++ b/frontend/app_flowy/test/bloc_test/grid_test/filter/edit_filter_field_test.dart @@ -28,7 +28,7 @@ void main() { // Insert filter for the text field await service.insertTextFilter( fieldId: textField.id, - condition: TextFilterCondition.TextIsEmpty, + condition: TextFilterConditionPB.TextIsEmpty, content: ""); await gridResponseFuture(); assert(menuBloc.state.filters.length == 1); diff --git a/frontend/app_flowy/test/bloc_test/grid_test/filter/filter_menu_test.dart b/frontend/app_flowy/test/bloc_test/grid_test/filter/filter_menu_test.dart index 46a52fc834..d345ff4b2a 100644 --- a/frontend/app_flowy/test/bloc_test/grid_test/filter/filter_menu_test.dart +++ b/frontend/app_flowy/test/bloc_test/grid_test/filter/filter_menu_test.dart @@ -23,7 +23,7 @@ void main() { final textField = context.textFieldContext(); await service.insertTextFilter( fieldId: textField.id, - condition: TextFilterCondition.TextIsEmpty, + condition: TextFilterConditionPB.TextIsEmpty, content: ""); await gridResponseFuture(); assert(menuBloc.state.creatableFields.length == 2); @@ -42,7 +42,7 @@ void main() { // Create filter await service.insertTextFilter( fieldId: textField.id, - condition: TextFilterCondition.TextIsEmpty, + condition: TextFilterConditionPB.TextIsEmpty, content: ""); await gridResponseFuture(); @@ -51,11 +51,11 @@ void main() { await service.insertTextFilter( fieldId: textField.id, filterId: textFilter.filter.id, - condition: TextFilterCondition.Is, + condition: TextFilterConditionPB.Is, content: "ABC"); await gridResponseFuture(); assert(menuBloc.state.filters.first.textFilter()!.condition == - TextFilterCondition.Is); + TextFilterConditionPB.Is); assert(menuBloc.state.filters.first.textFilter()!.content == "ABC"); }); } diff --git a/frontend/app_flowy/test/bloc_test/grid_test/filter/filter_rows_by_checkbox_test.dart b/frontend/app_flowy/test/bloc_test/grid_test/filter/filter_rows_by_checkbox_test.dart index 60ba6580fe..9551c7a16c 100644 --- a/frontend/app_flowy/test/bloc_test/grid_test/filter/filter_rows_by_checkbox_test.dart +++ b/frontend/app_flowy/test/bloc_test/grid_test/filter/filter_rows_by_checkbox_test.dart @@ -23,7 +23,7 @@ void main() { final checkboxField = context.checkboxFieldContext(); await service.insertCheckboxFilter( fieldId: checkboxField.id, - condition: CheckboxFilterCondition.IsChecked, + condition: CheckboxFilterConditionPB.IsChecked, ); await gridResponseFuture(); assert(context.rowInfos.length == 1, @@ -42,7 +42,7 @@ void main() { final checkboxField = context.checkboxFieldContext(); await service.insertCheckboxFilter( fieldId: checkboxField.id, - condition: CheckboxFilterCondition.IsUnChecked, + condition: CheckboxFilterConditionPB.IsUnChecked, ); await gridResponseFuture(); assert(context.rowInfos.length == 2, diff --git a/frontend/app_flowy/test/bloc_test/grid_test/filter/filter_rows_by_text_test.dart b/frontend/app_flowy/test/bloc_test/grid_test/filter/filter_rows_by_text_test.dart index bea99b55e9..6192633d57 100644 --- a/frontend/app_flowy/test/bloc_test/grid_test/filter/filter_rows_by_text_test.dart +++ b/frontend/app_flowy/test/bloc_test/grid_test/filter/filter_rows_by_text_test.dart @@ -19,7 +19,7 @@ void main() { // create a new filter await service.insertTextFilter( fieldId: textField.id, - condition: TextFilterCondition.TextIsEmpty, + condition: TextFilterConditionPB.TextIsEmpty, content: ""); await gridResponseFuture(); assert(context.fieldController.filterInfos.length == 1, @@ -46,7 +46,7 @@ void main() { // create a new filter await service.insertTextFilter( fieldId: textField.id, - condition: TextFilterCondition.TextIsNotEmpty, + condition: TextFilterConditionPB.TextIsNotEmpty, content: ""); await gridResponseFuture(); assert(context.rowInfos.length == 2, @@ -71,7 +71,7 @@ void main() { // create a new filter await service.insertTextFilter( fieldId: textField.id, - condition: TextFilterCondition.TextIsEmpty, + condition: TextFilterConditionPB.TextIsEmpty, content: ""); await gridResponseFuture(); assert(context.fieldController.filterInfos.length == 1, @@ -84,7 +84,7 @@ void main() { await service.insertTextFilter( fieldId: textField.id, filterId: textFilter.filter.id, - condition: TextFilterCondition.TextIsNotEmpty, + condition: TextFilterConditionPB.TextIsNotEmpty, content: ""); await gridResponseFuture(); assert(context.rowInfos.length == 2); @@ -106,7 +106,9 @@ void main() { final textField = context.textFieldContext(); // create a new filter await service.insertTextFilter( - fieldId: textField.id, condition: TextFilterCondition.Is, content: "A"); + fieldId: textField.id, + condition: TextFilterConditionPB.Is, + content: "A"); await gridResponseFuture(); assert(context.rowInfos.length == 1, "expect 1 but receive ${context.rowInfos.length}"); @@ -116,7 +118,7 @@ void main() { await service.insertTextFilter( fieldId: textField.id, filterId: textFilter.filter.id, - condition: TextFilterCondition.Is, + condition: TextFilterConditionPB.Is, content: "B"); await gridResponseFuture(); assert(context.rowInfos.length == 1); @@ -125,7 +127,7 @@ void main() { await service.insertTextFilter( fieldId: textField.id, filterId: textFilter.filter.id, - condition: TextFilterCondition.Is, + condition: TextFilterConditionPB.Is, content: "b"); await gridResponseFuture(); assert(context.rowInfos.length == 1); @@ -134,7 +136,7 @@ void main() { await service.insertTextFilter( fieldId: textField.id, filterId: textFilter.filter.id, - condition: TextFilterCondition.Is, + condition: TextFilterConditionPB.Is, content: "C"); await gridResponseFuture(); assert(context.rowInfos.isEmpty); diff --git a/frontend/app_flowy/test/bloc_test/grid_test/util.dart b/frontend/app_flowy/test/bloc_test/grid_test/util.dart index 657120488e..0b011de245 100644 --- a/frontend/app_flowy/test/bloc_test/grid_test/util.dart +++ b/frontend/app_flowy/test/bloc_test/grid_test/util.dart @@ -1,5 +1,3 @@ -import 'dart:collection'; -import 'package:app_flowy/plugins/grid/application/block/block_cache.dart'; import 'package:app_flowy/plugins/grid/application/cell/cell_service/cell_service.dart'; import 'package:app_flowy/plugins/grid/application/field/field_controller.dart'; import 'package:app_flowy/plugins/grid/application/field/field_editor_bloc.dart'; @@ -26,10 +24,6 @@ class GridTestContext { return gridController.rowInfos; } - UnmodifiableMapView get blocks { - return gridController.blocks; - } - List get fieldContexts => fieldController.fieldInfos; GridFieldController get fieldController { @@ -71,14 +65,13 @@ class GridTestContext { int rowIndex, ) async { final RowInfo rowInfo = rowInfos[rowIndex]; - final blockCache = blocks[rowInfo.rowPB.blockId]; - final rowCache = blockCache?.rowCache; + final rowCache = gridController.rowCache; final fieldController = gridController.fieldController; final rowDataController = GridRowDataController( rowInfo: rowInfo, fieldController: fieldController, - rowCache: rowCache!, + rowCache: rowCache, ); final rowBloc = RowBloc( diff --git a/frontend/rust-lib/flowy-grid/src/dart_notification.rs b/frontend/rust-lib/flowy-grid/src/dart_notification.rs index bfa1636002..ba5ab22ae1 100644 --- a/frontend/rust-lib/flowy-grid/src/dart_notification.rs +++ b/frontend/rust-lib/flowy-grid/src/dart_notification.rs @@ -6,8 +6,9 @@ const OBSERVABLE_CATEGORY: &str = "Grid"; pub enum GridDartNotification { Unknown = 0, DidCreateBlock = 11, - DidUpdateGridBlock = 20, - DidUpdateGridField = 21, + DidUpdateGridViewRows = 20, + DidUpdateGridViewRowsVisibility = 21, + DidUpdateGridFields = 22, DidUpdateRow = 30, DidUpdateCell = 40, DidUpdateField = 50, @@ -15,6 +16,7 @@ pub enum GridDartNotification { DidUpdateGroup = 61, DidGroupByNewField = 62, DidUpdateFilter = 63, + DidUpdateSort = 64, DidUpdateGridSetting = 70, } diff --git a/frontend/rust-lib/flowy-grid/src/entities/block_entities.rs b/frontend/rust-lib/flowy-grid/src/entities/block_entities.rs deleted file mode 100644 index 25d2fb79ad..0000000000 --- a/frontend/rust-lib/flowy-grid/src/entities/block_entities.rs +++ /dev/null @@ -1,245 +0,0 @@ -use crate::entities::parser::NotEmptyStr; -use flowy_derive::ProtoBuf; -use flowy_error::ErrorCode; -use grid_rev_model::RowRevision; -use std::sync::Arc; - -/// [BlockPB] contains list of row ids. The rows here does not contain any data, just the id -/// of the row. Check out [RowPB] for more details. -/// -/// -/// A grid can have many rows. Rows are therefore grouped into Blocks in order to make -/// things more efficient. -/// | -#[derive(Debug, Clone, Default, ProtoBuf)] -pub struct BlockPB { - #[pb(index = 1)] - pub id: String, - - #[pb(index = 2)] - pub rows: Vec, -} - -impl BlockPB { - pub fn new(block_id: &str, rows: Vec) -> Self { - Self { - id: block_id.to_owned(), - rows, - } - } -} - -/// [RowPB] Describes a row. Has the id of the parent Block. Has the metadata of the row. -#[derive(Debug, Default, Clone, ProtoBuf, Eq, PartialEq)] -pub struct RowPB { - #[pb(index = 1)] - pub block_id: String, - - #[pb(index = 2)] - pub id: String, - - #[pb(index = 3)] - pub height: i32, -} - -impl RowPB { - pub fn row_id(&self) -> &str { - &self.id - } - - pub fn block_id(&self) -> &str { - &self.block_id - } -} - -impl std::convert::From<&RowRevision> for RowPB { - fn from(rev: &RowRevision) -> Self { - Self { - block_id: rev.block_id.clone(), - id: rev.id.clone(), - height: rev.height, - } - } -} - -impl std::convert::From<&mut RowRevision> for RowPB { - fn from(rev: &mut RowRevision) -> Self { - Self { - block_id: rev.block_id.clone(), - id: rev.id.clone(), - height: rev.height, - } - } -} - -impl std::convert::From<&Arc> for RowPB { - fn from(rev: &Arc) -> Self { - Self { - block_id: rev.block_id.clone(), - id: rev.id.clone(), - height: rev.height, - } - } -} - -#[derive(Debug, Default, ProtoBuf)] -pub struct OptionalRowPB { - #[pb(index = 1, one_of)] - pub row: Option, -} - -#[derive(Debug, Default, ProtoBuf)] -pub struct RepeatedRowPB { - #[pb(index = 1)] - pub items: Vec, -} - -impl std::convert::From> for RepeatedRowPB { - fn from(items: Vec) -> Self { - Self { items } - } -} - -/// [RepeatedBlockPB] contains list of [BlockPB] -#[derive(Debug, Default, ProtoBuf)] -pub struct RepeatedBlockPB { - #[pb(index = 1)] - pub items: Vec, -} - -impl std::convert::From> for RepeatedBlockPB { - fn from(items: Vec) -> Self { - Self { items } - } -} - -#[derive(Debug, Clone, Default, ProtoBuf)] -pub struct InsertedRowPB { - #[pb(index = 1)] - pub row: RowPB, - - #[pb(index = 2, one_of)] - pub index: Option, - - #[pb(index = 3)] - pub is_new: bool, -} - -impl InsertedRowPB { - pub fn new(row: RowPB) -> Self { - Self { - row, - index: None, - is_new: false, - } - } - - pub fn with_index(row: RowPB, index: i32) -> Self { - Self { - row, - index: Some(index), - is_new: false, - } - } -} - -impl std::convert::From for InsertedRowPB { - fn from(row: RowPB) -> Self { - Self { - row, - index: None, - is_new: false, - } - } -} - -impl std::convert::From<&RowRevision> for InsertedRowPB { - fn from(row: &RowRevision) -> Self { - let row_order = RowPB::from(row); - Self::from(row_order) - } -} - -#[derive(Debug, Clone, Default, ProtoBuf)] -pub struct UpdatedRowPB { - #[pb(index = 1)] - pub row: RowPB, - - // represents as the cells that were updated in this row. - #[pb(index = 2)] - pub field_ids: Vec, -} - -#[derive(Debug, Default, Clone, ProtoBuf)] -pub struct GridBlockChangesetPB { - #[pb(index = 1)] - pub block_id: String, - - #[pb(index = 2)] - pub inserted_rows: Vec, - - #[pb(index = 3)] - pub deleted_rows: Vec, - - #[pb(index = 4)] - pub updated_rows: Vec, - - #[pb(index = 5)] - pub visible_rows: Vec, - - #[pb(index = 6)] - pub invisible_rows: Vec, -} -impl GridBlockChangesetPB { - pub fn insert(block_id: String, inserted_rows: Vec) -> Self { - Self { - block_id, - inserted_rows, - ..Default::default() - } - } - - pub fn delete(block_id: &str, deleted_rows: Vec) -> Self { - Self { - block_id: block_id.to_owned(), - deleted_rows, - ..Default::default() - } - } - - pub fn update(block_id: &str, updated_rows: Vec) -> Self { - Self { - block_id: block_id.to_owned(), - updated_rows, - ..Default::default() - } - } -} - -/// [QueryBlocksPayloadPB] is used to query the data of the block that belongs to the grid whose -/// id is grid_id. -#[derive(ProtoBuf, Default)] -pub struct QueryBlocksPayloadPB { - #[pb(index = 1)] - pub grid_id: String, - - #[pb(index = 2)] - pub block_ids: Vec, -} - -pub struct QueryGridBlocksParams { - pub grid_id: String, - pub block_ids: Vec, -} - -impl TryInto for QueryBlocksPayloadPB { - type Error = ErrorCode; - - fn try_into(self) -> Result { - let grid_id = NotEmptyStr::parse(self.grid_id).map_err(|_| ErrorCode::GridIdIsEmpty)?; - Ok(QueryGridBlocksParams { - grid_id: grid_id.0, - block_ids: self.block_ids, - }) - } -} diff --git a/frontend/rust-lib/flowy-grid/src/entities/filter_entities/checkbox_filter.rs b/frontend/rust-lib/flowy-grid/src/entities/filter_entities/checkbox_filter.rs index 6476926b39..81d659f4e6 100644 --- a/frontend/rust-lib/flowy-grid/src/entities/filter_entities/checkbox_filter.rs +++ b/frontend/rust-lib/flowy-grid/src/entities/filter_entities/checkbox_filter.rs @@ -5,35 +5,35 @@ use grid_rev_model::FilterRevision; #[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)] pub struct CheckboxFilterPB { #[pb(index = 1)] - pub condition: CheckboxFilterCondition, + pub condition: CheckboxFilterConditionPB, } #[derive(Debug, Clone, PartialEq, Eq, ProtoBuf_Enum)] #[repr(u8)] -pub enum CheckboxFilterCondition { +pub enum CheckboxFilterConditionPB { IsChecked = 0, IsUnChecked = 1, } -impl std::convert::From for u32 { - fn from(value: CheckboxFilterCondition) -> Self { +impl std::convert::From for u32 { + fn from(value: CheckboxFilterConditionPB) -> Self { value as u32 } } -impl std::default::Default for CheckboxFilterCondition { +impl std::default::Default for CheckboxFilterConditionPB { fn default() -> Self { - CheckboxFilterCondition::IsChecked + CheckboxFilterConditionPB::IsChecked } } -impl std::convert::TryFrom for CheckboxFilterCondition { +impl std::convert::TryFrom for CheckboxFilterConditionPB { type Error = ErrorCode; fn try_from(value: u8) -> Result { match value { - 0 => Ok(CheckboxFilterCondition::IsChecked), - 1 => Ok(CheckboxFilterCondition::IsUnChecked), + 0 => Ok(CheckboxFilterConditionPB::IsChecked), + 1 => Ok(CheckboxFilterConditionPB::IsUnChecked), _ => Err(ErrorCode::InvalidData), } } @@ -42,7 +42,8 @@ impl std::convert::TryFrom for CheckboxFilterCondition { impl std::convert::From<&FilterRevision> for CheckboxFilterPB { fn from(rev: &FilterRevision) -> Self { CheckboxFilterPB { - condition: CheckboxFilterCondition::try_from(rev.condition).unwrap_or(CheckboxFilterCondition::IsChecked), + condition: CheckboxFilterConditionPB::try_from(rev.condition) + .unwrap_or(CheckboxFilterConditionPB::IsChecked), } } } diff --git a/frontend/rust-lib/flowy-grid/src/entities/filter_entities/checklist_filter.rs b/frontend/rust-lib/flowy-grid/src/entities/filter_entities/checklist_filter.rs index a697ebbe11..bbd2480836 100644 --- a/frontend/rust-lib/flowy-grid/src/entities/filter_entities/checklist_filter.rs +++ b/frontend/rust-lib/flowy-grid/src/entities/filter_entities/checklist_filter.rs @@ -5,35 +5,35 @@ use grid_rev_model::FilterRevision; #[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)] pub struct ChecklistFilterPB { #[pb(index = 1)] - pub condition: ChecklistFilterCondition, + pub condition: ChecklistFilterConditionPB, } #[derive(Debug, Clone, PartialEq, Eq, ProtoBuf_Enum)] #[repr(u8)] -pub enum ChecklistFilterCondition { +pub enum ChecklistFilterConditionPB { IsComplete = 0, IsIncomplete = 1, } -impl std::convert::From for u32 { - fn from(value: ChecklistFilterCondition) -> Self { +impl std::convert::From for u32 { + fn from(value: ChecklistFilterConditionPB) -> Self { value as u32 } } -impl std::default::Default for ChecklistFilterCondition { +impl std::default::Default for ChecklistFilterConditionPB { fn default() -> Self { - ChecklistFilterCondition::IsIncomplete + ChecklistFilterConditionPB::IsIncomplete } } -impl std::convert::TryFrom for ChecklistFilterCondition { +impl std::convert::TryFrom for ChecklistFilterConditionPB { type Error = ErrorCode; fn try_from(value: u8) -> Result { match value { - 0 => Ok(ChecklistFilterCondition::IsComplete), - 1 => Ok(ChecklistFilterCondition::IsIncomplete), + 0 => Ok(ChecklistFilterConditionPB::IsComplete), + 1 => Ok(ChecklistFilterConditionPB::IsIncomplete), _ => Err(ErrorCode::InvalidData), } } @@ -42,8 +42,8 @@ impl std::convert::TryFrom for ChecklistFilterCondition { impl std::convert::From<&FilterRevision> for ChecklistFilterPB { fn from(rev: &FilterRevision) -> Self { ChecklistFilterPB { - condition: ChecklistFilterCondition::try_from(rev.condition) - .unwrap_or(ChecklistFilterCondition::IsIncomplete), + condition: ChecklistFilterConditionPB::try_from(rev.condition) + .unwrap_or(ChecklistFilterConditionPB::IsIncomplete), } } } diff --git a/frontend/rust-lib/flowy-grid/src/entities/filter_entities/date_filter.rs b/frontend/rust-lib/flowy-grid/src/entities/filter_entities/date_filter.rs index 84fa43471f..b70b1b0944 100644 --- a/frontend/rust-lib/flowy-grid/src/entities/filter_entities/date_filter.rs +++ b/frontend/rust-lib/flowy-grid/src/entities/filter_entities/date_filter.rs @@ -7,7 +7,7 @@ use std::str::FromStr; #[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)] pub struct DateFilterPB { #[pb(index = 1)] - pub condition: DateFilterCondition, + pub condition: DateFilterConditionPB, #[pb(index = 2, one_of)] pub start: Option, @@ -20,19 +20,19 @@ pub struct DateFilterPB { } #[derive(Deserialize, Serialize, Default, Clone, Debug)] -pub struct DateFilterContent { +pub struct DateFilterContentPB { pub start: Option, pub end: Option, pub timestamp: Option, } -impl ToString for DateFilterContent { +impl ToString for DateFilterContentPB { fn to_string(&self) -> String { serde_json::to_string(self).unwrap() } } -impl FromStr for DateFilterContent { +impl FromStr for DateFilterContentPB { type Err = serde_json::Error; fn from_str(s: &str) -> Result { @@ -42,7 +42,7 @@ impl FromStr for DateFilterContent { #[derive(Debug, Clone, PartialEq, Eq, ProtoBuf_Enum)] #[repr(u8)] -pub enum DateFilterCondition { +pub enum DateFilterConditionPB { DateIs = 0, DateBefore = 1, DateAfter = 2, @@ -53,42 +53,42 @@ pub enum DateFilterCondition { DateIsNotEmpty = 7, } -impl std::convert::From for u32 { - fn from(value: DateFilterCondition) -> Self { +impl std::convert::From for u32 { + fn from(value: DateFilterConditionPB) -> Self { value as u32 } } -impl std::default::Default for DateFilterCondition { +impl std::default::Default for DateFilterConditionPB { fn default() -> Self { - DateFilterCondition::DateIs + DateFilterConditionPB::DateIs } } -impl std::convert::TryFrom for DateFilterCondition { +impl std::convert::TryFrom for DateFilterConditionPB { type Error = ErrorCode; fn try_from(value: u8) -> Result { match value { - 0 => Ok(DateFilterCondition::DateIs), - 1 => Ok(DateFilterCondition::DateBefore), - 2 => Ok(DateFilterCondition::DateAfter), - 3 => Ok(DateFilterCondition::DateOnOrBefore), - 4 => Ok(DateFilterCondition::DateOnOrAfter), - 5 => Ok(DateFilterCondition::DateWithIn), - 6 => Ok(DateFilterCondition::DateIsEmpty), + 0 => Ok(DateFilterConditionPB::DateIs), + 1 => Ok(DateFilterConditionPB::DateBefore), + 2 => Ok(DateFilterConditionPB::DateAfter), + 3 => Ok(DateFilterConditionPB::DateOnOrBefore), + 4 => Ok(DateFilterConditionPB::DateOnOrAfter), + 5 => Ok(DateFilterConditionPB::DateWithIn), + 6 => Ok(DateFilterConditionPB::DateIsEmpty), _ => Err(ErrorCode::InvalidData), } } } impl std::convert::From<&FilterRevision> for DateFilterPB { fn from(rev: &FilterRevision) -> Self { - let condition = DateFilterCondition::try_from(rev.condition).unwrap_or(DateFilterCondition::DateIs); + let condition = DateFilterConditionPB::try_from(rev.condition).unwrap_or(DateFilterConditionPB::DateIs); let mut filter = DateFilterPB { condition, ..Default::default() }; - if let Ok(content) = DateFilterContent::from_str(&rev.content) { + if let Ok(content) = DateFilterContentPB::from_str(&rev.content) { filter.start = content.start; filter.end = content.end; filter.timestamp = content.timestamp; diff --git a/frontend/rust-lib/flowy-grid/src/entities/filter_entities/number_filter.rs b/frontend/rust-lib/flowy-grid/src/entities/filter_entities/number_filter.rs index 0eed1a9e1c..900059ccab 100644 --- a/frontend/rust-lib/flowy-grid/src/entities/filter_entities/number_filter.rs +++ b/frontend/rust-lib/flowy-grid/src/entities/filter_entities/number_filter.rs @@ -5,7 +5,7 @@ use grid_rev_model::FilterRevision; #[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)] pub struct NumberFilterPB { #[pb(index = 1)] - pub condition: NumberFilterCondition, + pub condition: NumberFilterConditionPB, #[pb(index = 2)] pub content: String, @@ -13,7 +13,7 @@ pub struct NumberFilterPB { #[derive(Debug, Clone, PartialEq, Eq, ProtoBuf_Enum)] #[repr(u8)] -pub enum NumberFilterCondition { +pub enum NumberFilterConditionPB { Equal = 0, NotEqual = 1, GreaterThan = 2, @@ -24,30 +24,30 @@ pub enum NumberFilterCondition { NumberIsNotEmpty = 7, } -impl std::default::Default for NumberFilterCondition { +impl std::default::Default for NumberFilterConditionPB { fn default() -> Self { - NumberFilterCondition::Equal + NumberFilterConditionPB::Equal } } -impl std::convert::From for u32 { - fn from(value: NumberFilterCondition) -> Self { +impl std::convert::From for u32 { + fn from(value: NumberFilterConditionPB) -> Self { value as u32 } } -impl std::convert::TryFrom for NumberFilterCondition { +impl std::convert::TryFrom for NumberFilterConditionPB { type Error = ErrorCode; fn try_from(n: u8) -> Result { match n { - 0 => Ok(NumberFilterCondition::Equal), - 1 => Ok(NumberFilterCondition::NotEqual), - 2 => Ok(NumberFilterCondition::GreaterThan), - 3 => Ok(NumberFilterCondition::LessThan), - 4 => Ok(NumberFilterCondition::GreaterThanOrEqualTo), - 5 => Ok(NumberFilterCondition::LessThanOrEqualTo), - 6 => Ok(NumberFilterCondition::NumberIsEmpty), - 7 => Ok(NumberFilterCondition::NumberIsNotEmpty), + 0 => Ok(NumberFilterConditionPB::Equal), + 1 => Ok(NumberFilterConditionPB::NotEqual), + 2 => Ok(NumberFilterConditionPB::GreaterThan), + 3 => Ok(NumberFilterConditionPB::LessThan), + 4 => Ok(NumberFilterConditionPB::GreaterThanOrEqualTo), + 5 => Ok(NumberFilterConditionPB::LessThanOrEqualTo), + 6 => Ok(NumberFilterConditionPB::NumberIsEmpty), + 7 => Ok(NumberFilterConditionPB::NumberIsNotEmpty), _ => Err(ErrorCode::InvalidData), } } @@ -56,7 +56,7 @@ impl std::convert::TryFrom for NumberFilterCondition { impl std::convert::From<&FilterRevision> for NumberFilterPB { fn from(rev: &FilterRevision) -> Self { NumberFilterPB { - condition: NumberFilterCondition::try_from(rev.condition).unwrap_or(NumberFilterCondition::Equal), + condition: NumberFilterConditionPB::try_from(rev.condition).unwrap_or(NumberFilterConditionPB::Equal), content: rev.content.clone(), } } diff --git a/frontend/rust-lib/flowy-grid/src/entities/filter_entities/select_option_filter.rs b/frontend/rust-lib/flowy-grid/src/entities/filter_entities/select_option_filter.rs index d73ef933a1..9b182f9378 100644 --- a/frontend/rust-lib/flowy-grid/src/entities/filter_entities/select_option_filter.rs +++ b/frontend/rust-lib/flowy-grid/src/entities/filter_entities/select_option_filter.rs @@ -6,7 +6,7 @@ use grid_rev_model::FilterRevision; #[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)] pub struct SelectOptionFilterPB { #[pb(index = 1)] - pub condition: SelectOptionCondition, + pub condition: SelectOptionConditionPB, #[pb(index = 2)] pub option_ids: Vec, @@ -14,34 +14,34 @@ pub struct SelectOptionFilterPB { #[derive(Debug, Clone, PartialEq, Eq, ProtoBuf_Enum)] #[repr(u8)] -pub enum SelectOptionCondition { +pub enum SelectOptionConditionPB { OptionIs = 0, OptionIsNot = 1, OptionIsEmpty = 2, OptionIsNotEmpty = 3, } -impl std::convert::From for u32 { - fn from(value: SelectOptionCondition) -> Self { +impl std::convert::From for u32 { + fn from(value: SelectOptionConditionPB) -> Self { value as u32 } } -impl std::default::Default for SelectOptionCondition { +impl std::default::Default for SelectOptionConditionPB { fn default() -> Self { - SelectOptionCondition::OptionIs + SelectOptionConditionPB::OptionIs } } -impl std::convert::TryFrom for SelectOptionCondition { +impl std::convert::TryFrom for SelectOptionConditionPB { type Error = ErrorCode; fn try_from(value: u8) -> Result { match value { - 0 => Ok(SelectOptionCondition::OptionIs), - 1 => Ok(SelectOptionCondition::OptionIsNot), - 2 => Ok(SelectOptionCondition::OptionIsEmpty), - 3 => Ok(SelectOptionCondition::OptionIsNotEmpty), + 0 => Ok(SelectOptionConditionPB::OptionIs), + 1 => Ok(SelectOptionConditionPB::OptionIsNot), + 2 => Ok(SelectOptionConditionPB::OptionIsEmpty), + 3 => Ok(SelectOptionConditionPB::OptionIsNotEmpty), _ => Err(ErrorCode::InvalidData), } } @@ -51,7 +51,7 @@ impl std::convert::From<&FilterRevision> for SelectOptionFilterPB { fn from(rev: &FilterRevision) -> Self { let ids = SelectOptionIds::from(rev.content.clone()); SelectOptionFilterPB { - condition: SelectOptionCondition::try_from(rev.condition).unwrap_or(SelectOptionCondition::OptionIs), + condition: SelectOptionConditionPB::try_from(rev.condition).unwrap_or(SelectOptionConditionPB::OptionIs), option_ids: ids.into_inner(), } } diff --git a/frontend/rust-lib/flowy-grid/src/entities/filter_entities/text_filter.rs b/frontend/rust-lib/flowy-grid/src/entities/filter_entities/text_filter.rs index 57f1fcfdf5..f7a5770f2c 100644 --- a/frontend/rust-lib/flowy-grid/src/entities/filter_entities/text_filter.rs +++ b/frontend/rust-lib/flowy-grid/src/entities/filter_entities/text_filter.rs @@ -5,7 +5,7 @@ use grid_rev_model::FilterRevision; #[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)] pub struct TextFilterPB { #[pb(index = 1)] - pub condition: TextFilterCondition, + pub condition: TextFilterConditionPB, #[pb(index = 2)] pub content: String, @@ -13,7 +13,7 @@ pub struct TextFilterPB { #[derive(Debug, Clone, PartialEq, Eq, ProtoBuf_Enum)] #[repr(u8)] -pub enum TextFilterCondition { +pub enum TextFilterConditionPB { Is = 0, IsNot = 1, Contains = 2, @@ -24,31 +24,31 @@ pub enum TextFilterCondition { TextIsNotEmpty = 7, } -impl std::convert::From for u32 { - fn from(value: TextFilterCondition) -> Self { +impl std::convert::From for u32 { + fn from(value: TextFilterConditionPB) -> Self { value as u32 } } -impl std::default::Default for TextFilterCondition { +impl std::default::Default for TextFilterConditionPB { fn default() -> Self { - TextFilterCondition::Is + TextFilterConditionPB::Is } } -impl std::convert::TryFrom for TextFilterCondition { +impl std::convert::TryFrom for TextFilterConditionPB { type Error = ErrorCode; fn try_from(value: u8) -> Result { match value { - 0 => Ok(TextFilterCondition::Is), - 1 => Ok(TextFilterCondition::IsNot), - 2 => Ok(TextFilterCondition::Contains), - 3 => Ok(TextFilterCondition::DoesNotContain), - 4 => Ok(TextFilterCondition::StartsWith), - 5 => Ok(TextFilterCondition::EndsWith), - 6 => Ok(TextFilterCondition::TextIsEmpty), - 7 => Ok(TextFilterCondition::TextIsNotEmpty), + 0 => Ok(TextFilterConditionPB::Is), + 1 => Ok(TextFilterConditionPB::IsNot), + 2 => Ok(TextFilterConditionPB::Contains), + 3 => Ok(TextFilterConditionPB::DoesNotContain), + 4 => Ok(TextFilterConditionPB::StartsWith), + 5 => Ok(TextFilterConditionPB::EndsWith), + 6 => Ok(TextFilterConditionPB::TextIsEmpty), + 7 => Ok(TextFilterConditionPB::TextIsNotEmpty), _ => Err(ErrorCode::InvalidData), } } @@ -57,7 +57,7 @@ impl std::convert::TryFrom for TextFilterCondition { impl std::convert::From<&FilterRevision> for TextFilterPB { fn from(rev: &FilterRevision) -> Self { TextFilterPB { - condition: TextFilterCondition::try_from(rev.condition).unwrap_or(TextFilterCondition::Is), + condition: TextFilterConditionPB::try_from(rev.condition).unwrap_or(TextFilterConditionPB::Is), content: rev.content.clone(), } } diff --git a/frontend/rust-lib/flowy-grid/src/entities/filter_entities/util.rs b/frontend/rust-lib/flowy-grid/src/entities/filter_entities/util.rs index 57c8db310e..fcd3c4fca6 100644 --- a/frontend/rust-lib/flowy-grid/src/entities/filter_entities/util.rs +++ b/frontend/rust-lib/flowy-grid/src/entities/filter_entities/util.rs @@ -1,6 +1,6 @@ use crate::entities::parser::NotEmptyStr; use crate::entities::{ - CheckboxFilterPB, ChecklistFilterPB, DateFilterContent, DateFilterPB, FieldType, NumberFilterPB, + CheckboxFilterPB, ChecklistFilterPB, DateFilterContentPB, DateFilterPB, FieldType, NumberFilterPB, SelectOptionFilterPB, TextFilterPB, }; use crate::services::field::SelectOptionIds; @@ -79,12 +79,18 @@ pub struct DeleteFilterPayloadPB { #[pb(index = 3)] pub filter_id: String, + + #[pb(index = 4)] + pub view_id: String, } impl TryInto for DeleteFilterPayloadPB { type Error = ErrorCode; fn try_into(self) -> Result { + let view_id = NotEmptyStr::parse(self.view_id) + .map_err(|_| ErrorCode::GridViewIdIsEmpty)? + .0; let field_id = NotEmptyStr::parse(self.field_id) .map_err(|_| ErrorCode::FieldIdIsEmpty)? .0; @@ -98,12 +104,17 @@ impl TryInto for DeleteFilterPayloadPB { field_type: self.field_type, }; - Ok(DeleteFilterParams { filter_id, filter_type }) + Ok(DeleteFilterParams { + view_id, + filter_id, + filter_type, + }) } } #[derive(Debug)] pub struct DeleteFilterParams { + pub view_id: String, pub filter_type: FilterType, pub filter_id: String, } @@ -116,18 +127,27 @@ pub struct AlterFilterPayloadPB { #[pb(index = 2)] pub field_type: FieldType, + /// Create a new filter if the filter_id is None #[pb(index = 3, one_of)] pub filter_id: Option, #[pb(index = 4)] pub data: Vec, + + #[pb(index = 5)] + pub view_id: String, } impl AlterFilterPayloadPB { #[allow(dead_code)] - pub fn new>(field_rev: &FieldRevision, data: T) -> Self { + pub fn new>( + view_id: &str, + field_rev: &FieldRevision, + data: T, + ) -> Self { let data = data.try_into().unwrap_or_else(|_| Bytes::new()); Self { + view_id: view_id.to_owned(), field_id: field_rev.id.clone(), field_type: field_rev.ty.into(), filter_id: None, @@ -140,6 +160,10 @@ impl TryInto for AlterFilterPayloadPB { type Error = ErrorCode; fn try_into(self) -> Result { + let view_id = NotEmptyStr::parse(self.view_id) + .map_err(|_| ErrorCode::GridViewIdIsEmpty)? + .0; + let field_id = NotEmptyStr::parse(self.field_id) .map_err(|_| ErrorCode::FieldIdIsEmpty)? .0; @@ -169,7 +193,7 @@ impl TryInto for AlterFilterPayloadPB { FieldType::DateTime => { let filter = DateFilterPB::try_from(bytes).map_err(|_| ErrorCode::ProtobufSerde)?; condition = filter.condition as u8; - content = DateFilterContent { + content = DateFilterContentPB { start: filter.start, end: filter.end, timestamp: filter.timestamp, @@ -184,6 +208,7 @@ impl TryInto for AlterFilterPayloadPB { } Ok(AlterFilterParams { + view_id, field_id, filter_id, field_type: self.field_type.into(), @@ -195,7 +220,9 @@ impl TryInto for AlterFilterPayloadPB { #[derive(Debug)] pub struct AlterFilterParams { + pub view_id: String, pub field_id: String, + /// Create a new filter if the filter_id is None pub filter_id: Option, pub field_type: FieldTypeRevision, pub condition: u8, diff --git a/frontend/rust-lib/flowy-grid/src/entities/grid_entities.rs b/frontend/rust-lib/flowy-grid/src/entities/grid_entities.rs index f5af76b331..a543787d28 100644 --- a/frontend/rust-lib/flowy-grid/src/entities/grid_entities.rs +++ b/frontend/rust-lib/flowy-grid/src/entities/grid_entities.rs @@ -1,5 +1,5 @@ use crate::entities::parser::NotEmptyStr; -use crate::entities::{BlockPB, FieldIdPB}; +use crate::entities::{FieldIdPB, RowPB}; use flowy_derive::ProtoBuf; use flowy_error::ErrorCode; @@ -13,7 +13,7 @@ pub struct GridPB { pub fields: Vec, #[pb(index = 3)] - pub blocks: Vec, + pub rows: Vec, } #[derive(ProtoBuf, Default)] diff --git a/frontend/rust-lib/flowy-grid/src/entities/mod.rs b/frontend/rust-lib/flowy-grid/src/entities/mod.rs index 44daf6bedc..9f83360346 100644 --- a/frontend/rust-lib/flowy-grid/src/entities/mod.rs +++ b/frontend/rust-lib/flowy-grid/src/entities/mod.rs @@ -1,4 +1,3 @@ -pub mod block_entities; mod cell_entities; mod field_entities; pub mod filter_entities; @@ -7,8 +6,9 @@ mod group_entities; pub mod parser; mod row_entities; pub mod setting_entities; +mod sort_entities; +mod view_entities; -pub use block_entities::*; pub use cell_entities::*; pub use field_entities::*; pub use filter_entities::*; @@ -16,3 +16,5 @@ pub use grid_entities::*; pub use group_entities::*; pub use row_entities::*; pub use setting_entities::*; +pub use sort_entities::*; +pub use view_entities::*; diff --git a/frontend/rust-lib/flowy-grid/src/entities/row_entities.rs b/frontend/rust-lib/flowy-grid/src/entities/row_entities.rs index af6a9a54f5..9b52aad506 100644 --- a/frontend/rust-lib/flowy-grid/src/entities/row_entities.rs +++ b/frontend/rust-lib/flowy-grid/src/entities/row_entities.rs @@ -2,6 +2,136 @@ use crate::entities::parser::NotEmptyStr; use crate::entities::GridLayout; use flowy_derive::ProtoBuf; use flowy_error::ErrorCode; +use grid_rev_model::RowRevision; +use std::sync::Arc; + +/// [RowPB] Describes a row. Has the id of the parent Block. Has the metadata of the row. +#[derive(Debug, Default, Clone, ProtoBuf, Eq, PartialEq)] +pub struct RowPB { + #[pb(index = 1)] + pub block_id: String, + + #[pb(index = 2)] + pub id: String, + + #[pb(index = 3)] + pub height: i32, +} + +impl RowPB { + pub fn row_id(&self) -> &str { + &self.id + } + + pub fn block_id(&self) -> &str { + &self.block_id + } +} + +impl std::convert::From<&RowRevision> for RowPB { + fn from(rev: &RowRevision) -> Self { + Self { + block_id: rev.block_id.clone(), + id: rev.id.clone(), + height: rev.height, + } + } +} + +impl std::convert::From<&mut RowRevision> for RowPB { + fn from(rev: &mut RowRevision) -> Self { + Self { + block_id: rev.block_id.clone(), + id: rev.id.clone(), + height: rev.height, + } + } +} + +impl std::convert::From<&Arc> for RowPB { + fn from(rev: &Arc) -> Self { + Self { + block_id: rev.block_id.clone(), + id: rev.id.clone(), + height: rev.height, + } + } +} + +#[derive(Debug, Default, ProtoBuf)] +pub struct OptionalRowPB { + #[pb(index = 1, one_of)] + pub row: Option, +} + +#[derive(Debug, Default, ProtoBuf)] +pub struct RepeatedRowPB { + #[pb(index = 1)] + pub items: Vec, +} + +impl std::convert::From> for RepeatedRowPB { + fn from(items: Vec) -> Self { + Self { items } + } +} + +#[derive(Debug, Clone, Default, ProtoBuf)] +pub struct InsertedRowPB { + #[pb(index = 1)] + pub row: RowPB, + + #[pb(index = 2, one_of)] + pub index: Option, + + #[pb(index = 3)] + pub is_new: bool, +} + +impl InsertedRowPB { + pub fn new(row: RowPB) -> Self { + Self { + row, + index: None, + is_new: false, + } + } + + pub fn with_index(row: RowPB, index: i32) -> Self { + Self { + row, + index: Some(index), + is_new: false, + } + } +} + +impl std::convert::From for InsertedRowPB { + fn from(row: RowPB) -> Self { + Self { + row, + index: None, + is_new: false, + } + } +} + +impl std::convert::From<&RowRevision> for InsertedRowPB { + fn from(row: &RowRevision) -> Self { + let row_order = RowPB::from(row); + Self::from(row_order) + } +} + +#[derive(Debug, Clone, Default, ProtoBuf)] +pub struct UpdatedRowPB { + #[pb(index = 1)] + pub row: RowPB, + + // represents as the cells that were updated in this row. + #[pb(index = 2)] + pub field_ids: Vec, +} #[derive(Debug, Default, Clone, ProtoBuf)] pub struct RowIdPB { @@ -9,15 +139,11 @@ pub struct RowIdPB { pub grid_id: String, #[pb(index = 2)] - pub block_id: String, - - #[pb(index = 3)] pub row_id: String, } pub struct RowIdParams { pub grid_id: String, - pub block_id: String, pub row_id: String, } @@ -26,12 +152,10 @@ impl TryInto for RowIdPB { fn try_into(self) -> Result { 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(RowIdParams { grid_id: grid_id.0, - block_id: block_id.0, row_id: row_id.0, }) } diff --git a/frontend/rust-lib/flowy-grid/src/entities/setting_entities.rs b/frontend/rust-lib/flowy-grid/src/entities/setting_entities.rs index 7e33acc0b7..6f7b73b5a8 100644 --- a/frontend/rust-lib/flowy-grid/src/entities/setting_entities.rs +++ b/frontend/rust-lib/flowy-grid/src/entities/setting_entities.rs @@ -1,7 +1,8 @@ use crate::entities::parser::NotEmptyStr; use crate::entities::{ - AlterFilterParams, AlterFilterPayloadPB, DeleteFilterParams, DeleteFilterPayloadPB, DeleteGroupParams, - DeleteGroupPayloadPB, InsertGroupParams, InsertGroupPayloadPB, RepeatedFilterPB, RepeatedGroupConfigurationPB, + AlterFilterParams, AlterFilterPayloadPB, AlterSortParams, AlterSortPayloadPB, DeleteFilterParams, + DeleteFilterPayloadPB, DeleteGroupParams, DeleteGroupPayloadPB, DeleteSortParams, DeleteSortPayloadPB, + InsertGroupParams, InsertGroupPayloadPB, RepeatedFilterPB, RepeatedGroupConfigurationPB, }; use flowy_derive::{ProtoBuf, ProtoBuf_Enum}; use flowy_error::ErrorCode; @@ -83,7 +84,7 @@ pub struct GridSettingChangesetPB { pub layout_type: GridLayout, #[pb(index = 3, one_of)] - pub insert_filter: Option, + pub alter_filter: Option, #[pb(index = 4, one_of)] pub delete_filter: Option, @@ -93,6 +94,12 @@ pub struct GridSettingChangesetPB { #[pb(index = 6, one_of)] pub delete_group: Option, + + #[pb(index = 7, one_of)] + pub alter_sort: Option, + + #[pb(index = 8, one_of)] + pub delete_sort: Option, } impl TryInto for GridSettingChangesetPB { @@ -103,7 +110,7 @@ impl TryInto for GridSettingChangesetPB { .map_err(|_| ErrorCode::ViewIdInvalid)? .0; - let insert_filter = match self.insert_filter { + let insert_filter = match self.alter_filter { None => None, Some(payload) => Some(payload.try_into()?), }; @@ -123,6 +130,16 @@ impl TryInto for GridSettingChangesetPB { None => None, }; + let alert_sort = match self.alter_sort { + None => None, + Some(payload) => Some(payload.try_into()?), + }; + + let delete_sort = match self.delete_sort { + None => None, + Some(payload) => Some(payload.try_into()?), + }; + Ok(GridSettingChangesetParams { grid_id: view_id, layout_type: self.layout_type.into(), @@ -130,6 +147,8 @@ impl TryInto for GridSettingChangesetPB { delete_filter, insert_group, delete_group, + alert_sort, + delete_sort, }) } } @@ -141,6 +160,8 @@ pub struct GridSettingChangesetParams { pub delete_filter: Option, pub insert_group: Option, pub delete_group: Option, + pub alert_sort: Option, + pub delete_sort: Option, } impl GridSettingChangesetParams { diff --git a/frontend/rust-lib/flowy-grid/src/entities/sort_entities.rs b/frontend/rust-lib/flowy-grid/src/entities/sort_entities.rs new file mode 100644 index 0000000000..5e84201acc --- /dev/null +++ b/frontend/rust-lib/flowy-grid/src/entities/sort_entities.rs @@ -0,0 +1,153 @@ +use crate::entities::parser::NotEmptyStr; +use crate::entities::FieldType; +use crate::services::sort::SortType; + +use flowy_derive::{ProtoBuf, ProtoBuf_Enum}; +use flowy_error::ErrorCode; +use grid_rev_model::FieldTypeRevision; + +#[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)] +pub struct GridSortPB { + #[pb(index = 1)] + pub id: String, + + #[pb(index = 2)] + pub field_id: String, + + #[pb(index = 3)] + pub field_type: FieldType, + + #[pb(index = 4)] + pub condition: GridSortConditionPB, +} + +#[derive(Debug, Clone, PartialEq, Eq, ProtoBuf_Enum)] +#[repr(u8)] +pub enum GridSortConditionPB { + Ascending = 0, + Descending = 1, +} +impl std::default::Default for GridSortConditionPB { + fn default() -> Self { + Self::Ascending + } +} +#[derive(ProtoBuf, Debug, Default, Clone)] +pub struct AlterSortPayloadPB { + #[pb(index = 1)] + pub view_id: String, + + #[pb(index = 2)] + pub field_id: String, + + #[pb(index = 3)] + pub field_type: FieldType, + + /// Create a new filter if the filter_id is None + #[pb(index = 4, one_of)] + pub sort_id: Option, + + #[pb(index = 5)] + pub condition: GridSortConditionPB, +} + +impl TryInto for AlterSortPayloadPB { + type Error = ErrorCode; + + fn try_into(self) -> Result { + let view_id = NotEmptyStr::parse(self.view_id) + .map_err(|_| ErrorCode::GridViewIdIsEmpty)? + .0; + + let field_id = NotEmptyStr::parse(self.field_id) + .map_err(|_| ErrorCode::FieldIdIsEmpty)? + .0; + let sort_id = match self.sort_id { + None => None, + Some(filter_id) => Some(NotEmptyStr::parse(filter_id).map_err(|_| ErrorCode::FilterIdIsEmpty)?.0), + }; + + Ok(AlterSortParams { + view_id, + field_id, + sort_id, + field_type: self.field_type.into(), + condition: self.condition as u8, + }) + } +} + +#[derive(Debug)] +pub struct AlterSortParams { + pub view_id: String, + pub field_id: String, + /// Create a new sort if the sort is None + pub sort_id: Option, + pub field_type: FieldTypeRevision, + pub condition: u8, +} + +#[derive(ProtoBuf, Debug, Default, Clone)] +pub struct DeleteSortPayloadPB { + #[pb(index = 1)] + pub view_id: String, + + #[pb(index = 2)] + pub field_id: String, + + #[pb(index = 3)] + pub field_type: FieldType, + + #[pb(index = 4)] + pub sort_id: String, +} + +impl TryInto for DeleteSortPayloadPB { + type Error = ErrorCode; + + fn try_into(self) -> Result { + let view_id = NotEmptyStr::parse(self.view_id) + .map_err(|_| ErrorCode::GridViewIdIsEmpty)? + .0; + let field_id = NotEmptyStr::parse(self.field_id) + .map_err(|_| ErrorCode::FieldIdIsEmpty)? + .0; + + let sort_id = NotEmptyStr::parse(self.sort_id) + .map_err(|_| ErrorCode::UnexpectedEmptyString)? + .0; + + let sort_type = SortType { + field_id, + field_type: self.field_type, + }; + + Ok(DeleteSortParams { + view_id, + sort_type, + sort_id, + }) + } +} + +#[derive(Debug)] +pub struct DeleteSortParams { + pub view_id: String, + pub sort_type: SortType, + pub sort_id: String, +} + +#[derive(Debug, Default, ProtoBuf)] +pub struct SortChangesetNotificationPB { + #[pb(index = 1)] + pub view_id: String, + + #[pb(index = 2)] + pub insert_sorts: Vec, + + #[pb(index = 3)] + pub delete_sorts: Vec, + + #[pb(index = 4)] + pub update_sorts: Vec, +} diff --git a/frontend/rust-lib/flowy-grid/src/entities/view_entities.rs b/frontend/rust-lib/flowy-grid/src/entities/view_entities.rs new file mode 100644 index 0000000000..de8de7bc15 --- /dev/null +++ b/frontend/rust-lib/flowy-grid/src/entities/view_entities.rs @@ -0,0 +1,64 @@ +use crate::entities::{InsertedRowPB, UpdatedRowPB}; +use flowy_derive::ProtoBuf; + +#[derive(Debug, Default, Clone, ProtoBuf)] +pub struct GridRowsVisibilityChangesetPB { + #[pb(index = 1)] + pub view_id: String, + + #[pb(index = 5)] + pub visible_rows: Vec, + + #[pb(index = 6)] + pub invisible_rows: Vec, +} + +#[derive(Debug, Default, Clone, ProtoBuf)] +pub struct GridViewRowsChangesetPB { + #[pb(index = 1)] + pub view_id: String, + + #[pb(index = 2)] + pub inserted_rows: Vec, + + #[pb(index = 3)] + pub deleted_rows: Vec, + + #[pb(index = 4)] + pub updated_rows: Vec, +} + +impl GridViewRowsChangesetPB { + pub fn from_insert(view_id: String, inserted_rows: Vec) -> Self { + Self { + view_id, + inserted_rows, + ..Default::default() + } + } + + pub fn from_delete(view_id: String, deleted_rows: Vec) -> Self { + Self { + view_id, + deleted_rows, + ..Default::default() + } + } + + pub fn from_update(view_id: String, updated_rows: Vec) -> Self { + Self { + view_id, + updated_rows, + ..Default::default() + } + } + + pub fn from_move(view_id: String, deleted_rows: Vec, inserted_rows: Vec) -> Self { + Self { + view_id, + inserted_rows, + deleted_rows, + ..Default::default() + } + } +} diff --git a/frontend/rust-lib/flowy-grid/src/event_handler.rs b/frontend/rust-lib/flowy-grid/src/event_handler.rs index 8a1aadb8a4..e4f966c6dc 100644 --- a/frontend/rust-lib/flowy-grid/src/event_handler.rs +++ b/frontend/rust-lib/flowy-grid/src/event_handler.rs @@ -7,7 +7,7 @@ use crate::services::field::{ SelectOptionCellChangesetParams, SelectOptionCellDataPB, SelectOptionChangeset, SelectOptionChangesetPB, SelectOptionPB, }; -use crate::services::row::{make_block_pbs, make_row_from_row_rev}; +use crate::services::row::make_row_from_row_rev; use flowy_error::{ErrorCode, FlowyError, FlowyResult}; use grid_rev_model::FieldRevision; use lib_dispatch::prelude::{data_result, AFPluginData, AFPluginState, DataResult}; @@ -19,8 +19,8 @@ pub(crate) async fn get_grid_handler( manager: AFPluginState>, ) -> DataResult { let grid_id: GridIdPB = data.into_inner(); - let editor = manager.open_grid(grid_id).await?; - let grid = editor.get_grid().await?; + let editor = manager.open_grid(grid_id.as_ref()).await?; + let grid = editor.get_grid(grid_id.as_ref()).await?; data_result(grid) } @@ -58,6 +58,13 @@ pub(crate) async fn update_grid_setting_handler( if let Some(delete_filter) = params.delete_filter { let _ = editor.delete_filter(delete_filter).await?; } + + if let Some(alter_sort) = params.alert_sort { + let _ = editor.create_or_update_sort(alter_sort).await?; + } + if let Some(delete_sort) = params.delete_sort { + let _ = editor.delete_sort(delete_sort).await?; + } Ok(()) } @@ -74,17 +81,6 @@ pub(crate) async fn get_all_filters_handler( data_result(filters) } -#[tracing::instrument(level = "debug", skip(data, manager), err)] -pub(crate) async fn get_grid_blocks_handler( - data: AFPluginData, - manager: AFPluginState>, -) -> DataResult { - let params: QueryGridBlocksParams = data.into_inner().try_into()?; - let editor = manager.get_grid_editor(¶ms.grid_id).await?; - let blocks = editor.get_blocks(Some(params.block_ids)).await?; - data_result(make_block_pbs(blocks)) -} - #[tracing::instrument(level = "trace", skip(data, manager), err)] pub(crate) async fn get_fields_handler( data: AFPluginData, @@ -415,14 +411,14 @@ pub(crate) async fn get_select_option_handler( // let cell_rev = editor.get_cell_rev(¶ms.row_id, ¶ms.field_id).await?; let type_option = select_type_option_from_field_rev(&field_rev)?; - let any_cell_data: TypeCellData = match cell_rev { + let type_cell_data: TypeCellData = match cell_rev { None => TypeCellData { data: "".to_string(), field_type: field_rev.ty.into(), }, Some(cell_rev) => cell_rev.try_into()?, }; - let selected_options = type_option.get_selected_options(any_cell_data.into()); + let selected_options = type_option.get_selected_options(type_cell_data.into()); data_result(selected_options) } } diff --git a/frontend/rust-lib/flowy-grid/src/event_map.rs b/frontend/rust-lib/flowy-grid/src/event_map.rs index b4fb1c1d55..654580766b 100644 --- a/frontend/rust-lib/flowy-grid/src/event_map.rs +++ b/frontend/rust-lib/flowy-grid/src/event_map.rs @@ -9,7 +9,7 @@ pub fn init(grid_manager: Arc) -> AFPlugin { let mut plugin = AFPlugin::new().name(env!("CARGO_PKG_NAME")).state(grid_manager); plugin = plugin .event(GridEvent::GetGrid, get_grid_handler) - .event(GridEvent::GetGridBlocks, get_grid_blocks_handler) + // .event(GridEvent::GetGridBlocks, get_grid_blocks_handler) .event(GridEvent::GetGridSetting, get_grid_setting_handler) .event(GridEvent::UpdateGridSetting, update_grid_setting_handler) .event(GridEvent::GetAllFilters, get_all_filters_handler) @@ -59,13 +59,6 @@ pub enum GridEvent { #[event(input = "GridIdPB", output = "GridPB")] GetGrid = 0, - /// [GetGridBlocks] event is used to get the grid's block. - /// - /// The event handler accepts a [QueryBlocksPayloadPB] and returns a [RepeatedBlockPB] - /// if there are no errors. - #[event(input = "QueryBlocksPayloadPB", output = "RepeatedBlockPB")] - GetGridBlocks = 1, - /// [GetGridSetting] event is used to get the grid's settings. /// /// The event handler accepts [GridIdPB] and return [GridSettingPB] diff --git a/frontend/rust-lib/flowy-grid/src/services/block_editor.rs b/frontend/rust-lib/flowy-grid/src/services/block_editor.rs index 969fec5d8c..07bc1ffdaf 100644 --- a/frontend/rust-lib/flowy-grid/src/services/block_editor.rs +++ b/frontend/rust-lib/flowy-grid/src/services/block_editor.rs @@ -1,4 +1,3 @@ -use crate::entities::RowPB; use bytes::Bytes; use flowy_error::{FlowyError, FlowyResult}; use flowy_http_model::revision::Revision; @@ -114,6 +113,10 @@ impl GridBlockRevisionEditor { self.pad.read().await.index_of_row(row_id) } + pub async fn number_of_rows(&self) -> i32 { + self.pad.read().await.rows.len() as i32 + } + pub async fn get_row_rev(&self, row_id: &str) -> FlowyResult)>> { let row_rev = self.pad.read().await.get_row_rev(row_id); Ok(row_rev) @@ -136,26 +139,6 @@ impl GridBlockRevisionEditor { Ok(cell_revs) } - pub async fn get_row_pb(&self, row_id: &str) -> FlowyResult> { - let row_ids = Some(vec![Cow::Borrowed(row_id)]); - Ok(self.get_row_pbs(row_ids).await?.pop()) - } - - pub async fn get_row_pbs(&self, row_ids: Option>>) -> FlowyResult> - where - T: AsRef + ToOwned + ?Sized, - { - let row_infos = self - .pad - .read() - .await - .get_row_revs(row_ids)? - .iter() - .map(RowPB::from) - .collect::>(); - Ok(row_infos) - } - async fn modify(&self, f: F) -> FlowyResult<()> where F: for<'a> FnOnce(&'a mut GridBlockRevisionPad) -> FlowyResult>, diff --git a/frontend/rust-lib/flowy-grid/src/services/block_manager.rs b/frontend/rust-lib/flowy-grid/src/services/block_manager.rs index 909ac9e75d..46f5719b57 100644 --- a/frontend/rust-lib/flowy-grid/src/services/block_manager.rs +++ b/frontend/rust-lib/flowy-grid/src/services/block_manager.rs @@ -1,12 +1,12 @@ use crate::dart_notification::{send_dart_notification, GridDartNotification}; -use crate::entities::{CellChangesetPB, GridBlockChangesetPB, InsertedRowPB, RowPB, UpdatedRowPB}; +use crate::entities::{CellChangesetPB, InsertedRowPB, UpdatedRowPB}; use crate::manager::GridUser; use crate::services::block_editor::{GridBlockRevisionEditor, GridBlockRevisionMergeable}; use crate::services::persistence::block_index::BlockIndexCache; use crate::services::persistence::rev_sqlite::{ SQLiteGridBlockRevisionPersistence, SQLiteGridRevisionSnapshotPersistence, }; -use crate::services::row::{block_from_row_orders, make_row_from_row_rev, GridBlock}; +use crate::services::row::{make_row_from_row_rev, GridBlockRow, GridBlockRowRevision}; use dashmap::DashMap; use flowy_database::ConnectionPool; use flowy_error::FlowyResult; @@ -15,12 +15,35 @@ use grid_rev_model::{GridBlockMetaRevision, GridBlockMetaRevisionChangeset, RowC use std::borrow::Cow; use std::collections::HashMap; use std::sync::Arc; +use tokio::sync::broadcast; + +#[derive(Debug, Clone)] +pub enum GridBlockEvent { + InsertRow { + block_id: String, + row: InsertedRowPB, + }, + UpdateRow { + block_id: String, + row: UpdatedRowPB, + }, + DeleteRow { + block_id: String, + row_id: String, + }, + Move { + block_id: String, + deleted_row_id: String, + inserted_row: InsertedRowPB, + }, +} type BlockId = String; pub(crate) struct GridBlockManager { user: Arc, persistence: Arc, block_editors: DashMap>, + event_notifier: broadcast::Sender, } impl GridBlockManager { @@ -28,6 +51,7 @@ impl GridBlockManager { user: &Arc, block_meta_revs: Vec>, persistence: Arc, + event_notifier: broadcast::Sender, ) -> FlowyResult { let block_editors = make_block_editors(user, block_meta_revs).await?; let user = user.clone(); @@ -35,6 +59,7 @@ impl GridBlockManager { user, block_editors, persistence, + event_notifier, }; Ok(manager) } @@ -70,12 +95,12 @@ impl GridBlockManager { let _ = self.persistence.insert(&row_rev.block_id, &row_rev.id)?; let editor = self.get_block_editor(&row_rev.block_id).await?; - let mut index_row_order = InsertedRowPB::from(&row_rev); - let (row_count, row_index) = editor.create_row(row_rev, start_row_id).await?; - index_row_order.index = row_index; - let changeset = GridBlockChangesetPB::insert(block_id.clone(), vec![index_row_order]); - let _ = self.notify_did_update_block(&block_id, changeset).await?; - Ok(row_count) + let mut row = InsertedRowPB::from(&row_rev); + let (number_of_rows, index) = editor.create_row(row_rev, start_row_id).await?; + row.index = index; + + let _ = self.event_notifier.send(GridBlockEvent::InsertRow { block_id, row }); + Ok(number_of_rows) } pub(crate) async fn insert_row( @@ -84,28 +109,20 @@ impl GridBlockManager { ) -> FlowyResult> { let mut changesets = vec![]; for (block_id, row_revs) in rows_by_block_id { - let mut inserted_row_orders = vec![]; let editor = self.get_block_editor(&block_id).await?; - let mut row_count = 0; - for row in row_revs { - let _ = self.persistence.insert(&row.block_id, &row.id)?; - let mut row_order = InsertedRowPB::from(&row); - let (count, index) = editor.create_row(row, None).await?; - row_count = count; - row_order.index = index; - inserted_row_orders.push(row_order); + for row_rev in row_revs { + let _ = self.persistence.insert(&row_rev.block_id, &row_rev.id)?; + let mut row = InsertedRowPB::from(&row_rev); + row.index = editor.create_row(row_rev, None).await?.1; + let _ = self.event_notifier.send(GridBlockEvent::InsertRow { + block_id: block_id.clone(), + row, + }); } changesets.push(GridBlockMetaRevisionChangeset::from_row_count( block_id.clone(), - row_count, + editor.number_of_rows().await, )); - - let _ = self - .notify_did_update_block( - &block_id, - GridBlockChangesetPB::insert(block_id.clone(), inserted_row_orders), - ) - .await?; } Ok(changesets) @@ -118,14 +135,15 @@ impl GridBlockManager { None => tracing::error!("Update row failed, can't find the row with id: {}", changeset.row_id), Some((_, row_rev)) => { let changed_field_ids = changeset.cell_by_field_id.keys().cloned().collect::>(); - let updated_row = UpdatedRowPB { + let row = UpdatedRowPB { row: make_row_from_row_rev(row_rev), field_ids: changed_field_ids, }; - let block_order_changeset = GridBlockChangesetPB::update(&editor.block_id, vec![updated_row]); - let _ = self - .notify_did_update_block(&editor.block_id, block_order_changeset) - .await?; + + let _ = self.event_notifier.send(GridBlockEvent::UpdateRow { + block_id: editor.block_id.clone(), + row, + }); } } Ok(()) @@ -140,28 +158,30 @@ impl GridBlockManager { None => Ok(None), Some((_, row_rev)) => { let _ = editor.delete_rows(vec![Cow::Borrowed(&row_id)]).await?; - let _ = self - .notify_did_update_block( - &block_id, - GridBlockChangesetPB::delete(&block_id, vec![row_rev.id.clone()]), - ) - .await?; + let _ = self.event_notifier.send(GridBlockEvent::DeleteRow { + block_id: editor.block_id.clone(), + row_id: row_rev.id.clone(), + }); + Ok(Some(row_rev)) } } } - pub(crate) async fn delete_rows(&self, row_orders: Vec) -> FlowyResult> { + pub(crate) async fn delete_rows( + &self, + block_rows: Vec, + ) -> FlowyResult> { let mut changesets = vec![]; - for grid_block in block_from_row_orders(row_orders) { - let editor = self.get_block_editor(&grid_block.id).await?; - let row_ids = grid_block - .rows + for block_row in block_rows { + let editor = self.get_block_editor(&block_row.block_id).await?; + let row_ids = block_row + .row_ids .into_iter() - .map(|row_info| Cow::Owned(row_info.row_id().to_owned())) + .map(Cow::Owned) .collect::>>(); let row_count = editor.delete_rows(row_ids).await?; - let changeset = GridBlockMetaRevisionChangeset::from_row_count(grid_block.id.clone(), row_count); + let changeset = GridBlockMetaRevisionChangeset::from_row_count(block_row.block_id, row_count); changesets.push(changeset); } @@ -179,16 +199,11 @@ impl GridBlockManager { is_new: false, }; - let notified_changeset = GridBlockChangesetPB { + let _ = self.event_notifier.send(GridBlockEvent::Move { block_id: editor.block_id.clone(), - inserted_rows: vec![insert_row], - deleted_rows: vec![delete_row_id], - ..Default::default() - }; - - let _ = self - .notify_did_update_block(&editor.block_id, notified_changeset) - .await?; + deleted_row_id: delete_row_id, + inserted_row: insert_row, + }); Ok(()) } @@ -213,12 +228,13 @@ impl GridBlockManager { editor.get_row_rev(row_id).await } + #[allow(dead_code)] pub async fn get_row_revs(&self, block_id: &str) -> FlowyResult>> { let editor = self.get_block_editor(block_id).await?; editor.get_row_revs::<&str>(None).await } - pub(crate) async fn get_blocks(&self, block_ids: Option>) -> FlowyResult> { + pub(crate) async fn get_blocks(&self, block_ids: Option>) -> FlowyResult> { let mut blocks = vec![]; match block_ids { None => { @@ -226,27 +242,20 @@ impl GridBlockManager { let editor = iter.value(); let block_id = editor.block_id.clone(); let row_revs = editor.get_row_revs::<&str>(None).await?; - blocks.push(GridBlock { block_id, row_revs }); + blocks.push(GridBlockRowRevision { block_id, row_revs }); } } Some(block_ids) => { for block_id in block_ids { let editor = self.get_block_editor(&block_id).await?; let row_revs = editor.get_row_revs::<&str>(None).await?; - blocks.push(GridBlock { block_id, row_revs }); + blocks.push(GridBlockRowRevision { block_id, row_revs }); } } } Ok(blocks) } - async fn notify_did_update_block(&self, block_id: &str, changeset: GridBlockChangesetPB) -> FlowyResult<()> { - send_dart_notification(block_id, GridDartNotification::DidUpdateGridBlock) - .payload(changeset) - .send(); - Ok(()) - } - async fn notify_did_update_cell(&self, changeset: CellChangesetPB) -> FlowyResult<()> { let id = format!("{}:{}", changeset.row_id, changeset.field_id); send_dart_notification(&id, GridDartNotification::DidUpdateCell).send(); diff --git a/frontend/rust-lib/flowy-grid/src/services/cell/cell_operation.rs b/frontend/rust-lib/flowy-grid/src/services/cell/cell_operation.rs index 52c47f56ea..0811918685 100644 --- a/frontend/rust-lib/flowy-grid/src/services/cell/cell_operation.rs +++ b/frontend/rust-lib/flowy-grid/src/services/cell/cell_operation.rs @@ -1,25 +1,32 @@ use crate::entities::FieldType; use crate::services::cell::{CellBytes, TypeCellData}; use crate::services::field::*; +use std::cmp::Ordering; use std::fmt::Debug; use flowy_error::{ErrorCode, FlowyError, FlowyResult}; use grid_rev_model::{CellRevision, FieldRevision, FieldTypeRevision}; /// This trait is used when doing filter/search on the grid. -pub trait CellFilterOperation { - /// Return true if any_cell_data match the filter condition. - fn apply_filter(&self, any_cell_data: TypeCellData, filter: &T) -> FlowyResult; +pub trait CellFilterable { + /// Return true if type_cell_data match the filter condition. + fn apply_filter(&self, type_cell_data: TypeCellData, filter: &T) -> FlowyResult; } -pub trait CellGroupOperation { - fn apply_group(&self, any_cell_data: TypeCellData, group_content: &str) -> FlowyResult; +pub trait CellComparable { + fn apply_cmp(&self, type_cell_data: &TypeCellData, other_type_cell_data: &TypeCellData) -> FlowyResult; } -/// Return object that describes the cell. -pub trait CellDisplayable { +/// Serialize the cell data in Protobuf/String format. +/// +/// Each cell data is a opaque data, it needs to deserialized to a concrete data struct. +/// Essentially when the field type is SingleSelect/Multi-Select, the cell data contains a +/// list of option ids. So it need to be decoded including convert the option's id to +/// option's name +/// +pub trait CellDataSerialize { /// Serialize the cell data into `CellBytes` that will be posted to the `Dart` side. Using the - /// corresponding protobuf struct implement in `Dart` to deserialize the data. + /// corresponding protobuf struct implemented in `Dart` to deserialize the data. /// /// Using `utf8` to encode the cell data if the cell data use `String` as its data container. /// Using `protobuf` to encode the cell data if the cell data use `Protobuf struct` as its data container. @@ -43,9 +50,9 @@ pub trait CellDisplayable { /// /// returns: Result /// - fn displayed_cell_bytes( + fn serialize_cell_data_to_bytes( &self, - cell_data: CellData, + cell_data: IntoCellData, decoded_field_type: &FieldType, field_rev: &FieldRevision, ) -> FlowyResult; @@ -55,14 +62,14 @@ pub trait CellDisplayable { /// The cell data is not readable which means it can't display the cell data directly to user. /// For example, /// 1. the cell data is timestamp if its field type is FieldType::Date that is not readable. - /// It needs to be parsed as the date string. + /// So it needs to be parsed as the date string with custom format setting. /// /// 2. the cell data is a commas separated id if its field type if FieldType::MultiSelect that is not readable. - /// It needs to be parsed as a commas separated option name. + /// So it needs to be parsed as a commas separated option name. /// - fn displayed_cell_string( + fn serialize_cell_data_to_str( &self, - cell_data: CellData, + cell_data: IntoCellData, decoded_field_type: &FieldType, field_rev: &FieldRevision, ) -> FlowyResult; @@ -76,7 +83,10 @@ pub trait CellDataOperation { /// FieldType::URL => URLCellData /// FieldType::Date=> DateCellData /// - /// Each cell data is a opaque data, it needs to deserialized to a concrete data struct + /// Each cell data is a opaque data, it needs to deserialized to a concrete data struct. + /// Essentially when the field type is SingleSelect/Multi-Select, the cell data contains a + /// list of option ids. So it need to be decoded including convert the option's id to + /// option's name /// /// `cell_data`: the opaque data of the cell. /// `decoded_field_type`: the field type of the cell data when doing serialization @@ -86,7 +96,7 @@ pub trait CellDataOperation { /// fn decode_cell_data( &self, - cell_data: CellData, + cell_data: IntoCellData, decoded_field_type: &FieldType, field_rev: &FieldRevision, ) -> FlowyResult; @@ -130,14 +140,14 @@ pub fn apply_cell_data_changeset>( Ok(TypeCellData::new(s, field_type).to_json()) } -pub fn decode_any_cell_data + Debug>( +pub fn decode_type_cell_data + Debug>( data: T, field_rev: &FieldRevision, ) -> (FieldType, CellBytes) { let to_field_type = field_rev.ty.into(); match data.try_into() { - Ok(any_cell_data) => { - let TypeCellData { data, field_type } = any_cell_data; + Ok(type_cell_data) => { + let TypeCellData { data, field_type } = type_cell_data; match try_decode_cell_data(data.into(), &field_type, &to_field_type, field_rev) { Ok(cell_bytes) => (field_type, cell_bytes), Err(e) => { @@ -156,40 +166,40 @@ pub fn decode_any_cell_data + Debug } } -pub fn decode_cell_data_to_string( - cell_data: CellData, +pub fn decode_cell_data_to_string>>( + cell_data: C, from_field_type: &FieldType, to_field_type: &FieldType, field_rev: &FieldRevision, ) -> FlowyResult { - let cell_data = cell_data.try_into_inner()?; + let cell_data = cell_data.into().try_into_inner()?; let get_cell_display_str = || { let field_type: FieldTypeRevision = to_field_type.into(); let result = match to_field_type { FieldType::RichText => field_rev .get_type_option::(field_type)? - .displayed_cell_string(cell_data.into(), from_field_type, field_rev), + .serialize_cell_data_to_str(cell_data.into(), from_field_type, field_rev), FieldType::Number => field_rev .get_type_option::(field_type)? - .displayed_cell_string(cell_data.into(), from_field_type, field_rev), + .serialize_cell_data_to_str(cell_data.into(), from_field_type, field_rev), FieldType::DateTime => field_rev .get_type_option::(field_type)? - .displayed_cell_string(cell_data.into(), from_field_type, field_rev), + .serialize_cell_data_to_str(cell_data.into(), from_field_type, field_rev), FieldType::SingleSelect => field_rev .get_type_option::(field_type)? - .displayed_cell_string(cell_data.into(), from_field_type, field_rev), + .serialize_cell_data_to_str(cell_data.into(), from_field_type, field_rev), FieldType::MultiSelect => field_rev .get_type_option::(field_type)? - .displayed_cell_string(cell_data.into(), from_field_type, field_rev), + .serialize_cell_data_to_str(cell_data.into(), from_field_type, field_rev), FieldType::Checklist => field_rev .get_type_option::(field_type)? - .displayed_cell_string(cell_data.into(), from_field_type, field_rev), + .serialize_cell_data_to_str(cell_data.into(), from_field_type, field_rev), FieldType::Checkbox => field_rev .get_type_option::(field_type)? - .displayed_cell_string(cell_data.into(), from_field_type, field_rev), + .serialize_cell_data_to_str(cell_data.into(), from_field_type, field_rev), FieldType::URL => field_rev .get_type_option::(field_type)? - .displayed_cell_string(cell_data.into(), from_field_type, field_rev), + .serialize_cell_data_to_str(cell_data.into(), from_field_type, field_rev), }; Some(result) }; @@ -210,7 +220,7 @@ pub fn decode_cell_data_to_string( /// and `CellDataOperation` traits. /// pub fn try_decode_cell_data( - cell_data: CellData, + cell_data: IntoCellData, from_field_type: &FieldType, to_field_type: &FieldType, field_rev: &FieldRevision, @@ -312,9 +322,10 @@ pub trait FromCellString { Self: Sized; } -/// CellData is a helper struct. String will be parser into Option only if the T impl the FromCellString trait. -pub struct CellData(pub Option); -impl CellData { +/// IntoCellData is a helper struct. String will be parser into Option only if the T impl the FromCellString trait. +/// +pub struct IntoCellData(pub Option); +impl IntoCellData { pub fn try_into_inner(self) -> FlowyResult { match self.0 { None => Err(ErrorCode::InvalidData.into()), @@ -323,35 +334,35 @@ impl CellData { } } -impl std::convert::From for CellData +impl std::convert::From for IntoCellData where T: FromCellString, { fn from(s: String) -> Self { match T::from_cell_str(&s) { - Ok(inner) => CellData(Some(inner)), + Ok(inner) => IntoCellData(Some(inner)), Err(e) => { tracing::error!("Deserialize Cell Data failed: {}", e); - CellData(None) + IntoCellData(None) } } } } -impl std::convert::From for CellData { +impl std::convert::From for IntoCellData { fn from(n: usize) -> Self { - CellData(Some(n.to_string())) + IntoCellData(Some(n.to_string())) } } -impl std::convert::From for CellData { +impl std::convert::From for IntoCellData { fn from(val: T) -> Self { - CellData(Some(val)) + IntoCellData(Some(val)) } } -impl std::convert::From> for String { - fn from(p: CellData) -> Self { +impl std::convert::From> for String { + fn from(p: IntoCellData) -> Self { p.try_into_inner().unwrap_or_else(|_| String::new()) } } diff --git a/frontend/rust-lib/flowy-grid/src/services/cell/mod.rs b/frontend/rust-lib/flowy-grid/src/services/cell/mod.rs index bc8ada929c..0df4561559 100644 --- a/frontend/rust-lib/flowy-grid/src/services/cell/mod.rs +++ b/frontend/rust-lib/flowy-grid/src/services/cell/mod.rs @@ -1,5 +1,5 @@ -mod any_cell_data; mod cell_operation; +mod type_cell_data; -pub use any_cell_data::*; pub use cell_operation::*; +pub use type_cell_data::*; diff --git a/frontend/rust-lib/flowy-grid/src/services/cell/any_cell_data.rs b/frontend/rust-lib/flowy-grid/src/services/cell/type_cell_data.rs similarity index 94% rename from frontend/rust-lib/flowy-grid/src/services/cell/any_cell_data.rs rename to frontend/rust-lib/flowy-grid/src/services/cell/type_cell_data.rs index b623d784e0..26d666169e 100644 --- a/frontend/rust-lib/flowy-grid/src/services/cell/any_cell_data.rs +++ b/frontend/rust-lib/flowy-grid/src/services/cell/type_cell_data.rs @@ -1,13 +1,13 @@ use crate::entities::FieldType; -use crate::services::cell::{CellData, FromCellString}; +use crate::services::cell::{FromCellString, IntoCellData}; use bytes::Bytes; use flowy_error::{internal_error, FlowyError, FlowyResult}; use grid_rev_model::CellRevision; use serde::{Deserialize, Serialize}; use std::str::FromStr; -/// TypeCellData is a generic CellData, you can parse the cell_data according to the field_type. -/// When the type of field is changed, it's different from the field_type of AnyCellData. +/// TypeCellData is a generic CellData, you can parse the type_cell_data according to the field_type. +/// When the type of field is changed, it's different from the field_type of TypeCellData. /// So it will return an empty data. You could check the CellDataOperation trait for more information. #[derive(Debug, Serialize, Deserialize)] pub struct TypeCellData { @@ -60,12 +60,12 @@ impl std::convert::TryFrom for TypeCellData { } } -impl std::convert::From for CellData +impl std::convert::From for IntoCellData where T: FromCellString, { fn from(any_call_data: TypeCellData) -> Self { - CellData::from(any_call_data.data) + IntoCellData::from(any_call_data.data) } } diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option/checkbox_filter.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option/checkbox_filter.rs index c6b6c4c138..616a572092 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option/checkbox_filter.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option/checkbox_filter.rs @@ -1,5 +1,5 @@ -use crate::entities::{CheckboxFilterCondition, CheckboxFilterPB}; -use crate::services::cell::{CellData, CellFilterOperation, TypeCellData}; +use crate::entities::{CheckboxFilterConditionPB, CheckboxFilterPB}; +use crate::services::cell::{CellFilterable, IntoCellData, TypeCellData}; use crate::services::field::{CheckboxCellData, CheckboxTypeOptionPB}; use flowy_error::FlowyResult; @@ -7,18 +7,18 @@ impl CheckboxFilterPB { pub fn is_visible(&self, cell_data: &CheckboxCellData) -> bool { let is_check = cell_data.is_check(); match self.condition { - CheckboxFilterCondition::IsChecked => is_check, - CheckboxFilterCondition::IsUnChecked => !is_check, + CheckboxFilterConditionPB::IsChecked => is_check, + CheckboxFilterConditionPB::IsUnChecked => !is_check, } } } -impl CellFilterOperation for CheckboxTypeOptionPB { - fn apply_filter(&self, any_cell_data: TypeCellData, filter: &CheckboxFilterPB) -> FlowyResult { - if !any_cell_data.is_checkbox() { +impl CellFilterable for CheckboxTypeOptionPB { + fn apply_filter(&self, type_cell_data: TypeCellData, filter: &CheckboxFilterPB) -> FlowyResult { + if !type_cell_data.is_checkbox() { return Ok(true); } - let cell_data: CellData = any_cell_data.into(); + let cell_data: IntoCellData = type_cell_data.into(); let checkbox_cell_data = cell_data.try_into_inner()?; Ok(filter.is_visible(&checkbox_cell_data)) } @@ -26,14 +26,14 @@ impl CellFilterOperation for CheckboxTypeOptionPB { #[cfg(test)] mod tests { - use crate::entities::{CheckboxFilterCondition, CheckboxFilterPB}; + use crate::entities::{CheckboxFilterConditionPB, CheckboxFilterPB}; use crate::services::field::CheckboxCellData; use std::str::FromStr; #[test] fn checkbox_filter_is_check_test() { let checkbox_filter = CheckboxFilterPB { - condition: CheckboxFilterCondition::IsChecked, + condition: CheckboxFilterConditionPB::IsChecked, }; for (value, visible) in [("true", true), ("yes", true), ("false", false), ("no", false)] { let data = CheckboxCellData::from_str(value).unwrap(); @@ -44,7 +44,7 @@ mod tests { #[test] fn checkbox_filter_is_uncheck_test() { let checkbox_filter = CheckboxFilterPB { - condition: CheckboxFilterCondition::IsUnChecked, + condition: CheckboxFilterConditionPB::IsUnChecked, }; for (value, visible) in [("false", true), ("no", true), ("true", false), ("yes", false)] { let data = CheckboxCellData::from_str(value).unwrap(); diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option/checkbox_type_option.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option/checkbox_type_option.rs index c4ee0dd3db..aaa157a61c 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option/checkbox_type_option.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option/checkbox_type_option.rs @@ -1,6 +1,6 @@ use crate::entities::FieldType; use crate::impl_type_option; -use crate::services::cell::{AnyCellChangeset, CellBytes, CellData, CellDataOperation, CellDisplayable}; +use crate::services::cell::{AnyCellChangeset, CellBytes, CellDataOperation, CellDataSerialize, IntoCellData}; use crate::services::field::{BoxTypeOptionBuilder, CheckboxCellData, TypeOptionBuilder}; use bytes::Bytes; use flowy_derive::ProtoBuf; @@ -42,10 +42,10 @@ pub struct CheckboxTypeOptionPB { } impl_type_option!(CheckboxTypeOptionPB, FieldType::Checkbox); -impl CellDisplayable for CheckboxTypeOptionPB { - fn displayed_cell_bytes( +impl CellDataSerialize for CheckboxTypeOptionPB { + fn serialize_cell_data_to_bytes( &self, - cell_data: CellData, + cell_data: IntoCellData, _decoded_field_type: &FieldType, _field_rev: &FieldRevision, ) -> FlowyResult { @@ -53,9 +53,9 @@ impl CellDisplayable for CheckboxTypeOptionPB { Ok(CellBytes::new(cell_data)) } - fn displayed_cell_string( + fn serialize_cell_data_to_str( &self, - cell_data: CellData, + cell_data: IntoCellData, _decoded_field_type: &FieldType, _field_rev: &FieldRevision, ) -> FlowyResult { @@ -69,7 +69,7 @@ pub type CheckboxCellChangeset = String; impl CellDataOperation for CheckboxTypeOptionPB { fn decode_cell_data( &self, - cell_data: CellData, + cell_data: IntoCellData, decoded_field_type: &FieldType, field_rev: &FieldRevision, ) -> FlowyResult { @@ -77,7 +77,7 @@ impl CellDataOperation for CheckboxType return Ok(CellBytes::default()); } - self.displayed_cell_bytes(cell_data, decoded_field_type, field_rev) + self.serialize_cell_data_to_bytes(cell_data, decoded_field_type, field_rev) } fn apply_changeset( diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option/checkbox_type_option_entities.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option/checkbox_type_option_entities.rs index 1cd64e3f4c..d3ba95d32f 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option/checkbox_type_option_entities.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option/checkbox_type_option_entities.rs @@ -73,7 +73,7 @@ impl CellBytesParser for CheckboxCellDataParser { type Object = CheckboxCellData; fn parser(bytes: &Bytes) -> FlowyResult { match String::from_utf8(bytes.to_vec()) { - Ok(s) => CheckboxCellData::from_str(&s), + Ok(s) => CheckboxCellData::from_cell_str(&s), Err(_) => Ok(CheckboxCellData("".to_string())), } } diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/date_filter.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/date_filter.rs index 4785fcc5ae..e3f4f4ac38 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/date_filter.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/date_filter.rs @@ -1,5 +1,5 @@ -use crate::entities::{DateFilterCondition, DateFilterPB}; -use crate::services::cell::{CellData, CellFilterOperation, TypeCellData}; +use crate::entities::{DateFilterConditionPB, DateFilterPB}; +use crate::services::cell::{CellFilterable, IntoCellData, TypeCellData}; use crate::services::field::{DateTimestamp, DateTypeOptionPB}; use chrono::NaiveDateTime; use flowy_error::FlowyResult; @@ -7,13 +7,13 @@ use flowy_error::FlowyResult; impl DateFilterPB { pub fn is_visible>>(&self, cell_timestamp: T) -> bool { match cell_timestamp.into() { - None => DateFilterCondition::DateIsEmpty == self.condition, + None => DateFilterConditionPB::DateIsEmpty == self.condition, Some(timestamp) => { match self.condition { - DateFilterCondition::DateIsNotEmpty => { + DateFilterConditionPB::DateIsNotEmpty => { return true; } - DateFilterCondition::DateIsEmpty => { + DateFilterConditionPB::DateIsEmpty => { return false; } _ => {} @@ -45,11 +45,11 @@ impl DateFilterPB { // We assume that the cell_timestamp doesn't contain hours, just day. match self.condition { - DateFilterCondition::DateIs => cell_date == expected_date, - DateFilterCondition::DateBefore => cell_date < expected_date, - DateFilterCondition::DateAfter => cell_date > expected_date, - DateFilterCondition::DateOnOrBefore => cell_date <= expected_date, - DateFilterCondition::DateOnOrAfter => cell_date >= expected_date, + DateFilterConditionPB::DateIs => cell_date == expected_date, + DateFilterConditionPB::DateBefore => cell_date < expected_date, + DateFilterConditionPB::DateAfter => cell_date > expected_date, + DateFilterConditionPB::DateOnOrBefore => cell_date <= expected_date, + DateFilterConditionPB::DateOnOrAfter => cell_date >= expected_date, _ => true, } } @@ -59,12 +59,12 @@ impl DateFilterPB { } } -impl CellFilterOperation for DateTypeOptionPB { - fn apply_filter(&self, any_cell_data: TypeCellData, filter: &DateFilterPB) -> FlowyResult { - if !any_cell_data.is_date() { +impl CellFilterable for DateTypeOptionPB { + fn apply_filter(&self, type_cell_data: TypeCellData, filter: &DateFilterPB) -> FlowyResult { + if !type_cell_data.is_date() { return Ok(true); } - let cell_data: CellData = any_cell_data.into(); + let cell_data: IntoCellData = type_cell_data.into(); let timestamp = cell_data.try_into_inner()?; Ok(filter.is_visible(timestamp)) } @@ -73,12 +73,12 @@ impl CellFilterOperation for DateTypeOptionPB { #[cfg(test)] mod tests { #![allow(clippy::all)] - use crate::entities::{DateFilterCondition, DateFilterPB}; + use crate::entities::{DateFilterConditionPB, DateFilterPB}; #[test] fn date_filter_is_test() { let filter = DateFilterPB { - condition: DateFilterCondition::DateIs, + condition: DateFilterConditionPB::DateIs, timestamp: Some(1668387885), end: None, start: None, @@ -91,7 +91,7 @@ mod tests { #[test] fn date_filter_before_test() { let filter = DateFilterPB { - condition: DateFilterCondition::DateBefore, + condition: DateFilterConditionPB::DateBefore, timestamp: Some(1668387885), start: None, end: None, @@ -105,7 +105,7 @@ mod tests { #[test] fn date_filter_before_or_on_test() { let filter = DateFilterPB { - condition: DateFilterCondition::DateOnOrBefore, + condition: DateFilterConditionPB::DateOnOrBefore, timestamp: Some(1668387885), start: None, end: None, @@ -118,7 +118,7 @@ mod tests { #[test] fn date_filter_after_test() { let filter = DateFilterPB { - condition: DateFilterCondition::DateAfter, + condition: DateFilterConditionPB::DateAfter, timestamp: Some(1668387885), start: None, end: None, @@ -132,7 +132,7 @@ mod tests { #[test] fn date_filter_within_test() { let filter = DateFilterPB { - condition: DateFilterCondition::DateWithIn, + condition: DateFilterConditionPB::DateWithIn, start: Some(1668272685), // 11/13 end: Some(1668618285), // 11/17 timestamp: None, @@ -150,7 +150,7 @@ mod tests { #[test] fn date_filter_is_empty_test() { let filter = DateFilterPB { - condition: DateFilterCondition::DateIsEmpty, + condition: DateFilterConditionPB::DateIsEmpty, start: None, end: None, timestamp: None, diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/date_type_option.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/date_type_option.rs index 18b5a894cf..0341a7e520 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/date_type_option.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/date_type_option.rs @@ -1,6 +1,6 @@ use crate::entities::FieldType; use crate::impl_type_option; -use crate::services::cell::{AnyCellChangeset, CellBytes, CellData, CellDataOperation, CellDisplayable}; +use crate::services::cell::{AnyCellChangeset, CellBytes, CellDataOperation, CellDataSerialize, IntoCellData}; use crate::services::field::{ BoxTypeOptionBuilder, DateCellChangeset, DateCellDataPB, DateFormat, DateTimestamp, TimeFormat, TypeOptionBuilder, }; @@ -107,21 +107,21 @@ impl DateTypeOptionPB { } } -impl CellDisplayable for DateTypeOptionPB { - fn displayed_cell_bytes( +impl CellDataSerialize for DateTypeOptionPB { + fn serialize_cell_data_to_bytes( &self, - cell_data: CellData, + cell_data: IntoCellData, _decoded_field_type: &FieldType, _field_rev: &FieldRevision, ) -> FlowyResult { let timestamp = cell_data.try_into_inner()?; - let date_cell_data = self.today_desc_from_timestamp(timestamp); - CellBytes::from(date_cell_data) + let cell_data_pb = self.today_desc_from_timestamp(timestamp); + CellBytes::from(cell_data_pb) } - fn displayed_cell_string( + fn serialize_cell_data_to_str( &self, - cell_data: CellData, + cell_data: IntoCellData, _decoded_field_type: &FieldType, _field_rev: &FieldRevision, ) -> FlowyResult { @@ -134,7 +134,7 @@ impl CellDisplayable for DateTypeOptionPB { impl CellDataOperation for DateTypeOptionPB { fn decode_cell_data( &self, - cell_data: CellData, + cell_data: IntoCellData, decoded_field_type: &FieldType, field_rev: &FieldRevision, ) -> FlowyResult { @@ -145,7 +145,7 @@ impl CellDataOperation for DateTypeOptionPB { if !decoded_field_type.is_date() { return Ok(CellBytes::default()); } - self.displayed_cell_bytes(cell_data, decoded_field_type, field_rev) + self.serialize_cell_data_to_bytes(cell_data, decoded_field_type, field_rev) } fn apply_changeset( diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option/number_filter.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option/number_filter.rs index 2fdf4bab97..6629da1078 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option/number_filter.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option/number_filter.rs @@ -1,5 +1,5 @@ -use crate::entities::{NumberFilterCondition, NumberFilterPB}; -use crate::services::cell::{CellFilterOperation, TypeCellData}; +use crate::entities::{NumberFilterConditionPB, NumberFilterPB}; +use crate::services::cell::{CellFilterable, TypeCellData}; use crate::services::field::{NumberCellData, NumberTypeOptionPB}; use flowy_error::FlowyResult; use rust_decimal::prelude::Zero; @@ -10,10 +10,10 @@ impl NumberFilterPB { pub fn is_visible(&self, num_cell_data: &NumberCellData) -> bool { if self.content.is_empty() { match self.condition { - NumberFilterCondition::NumberIsEmpty => { + NumberFilterConditionPB::NumberIsEmpty => { return num_cell_data.is_empty(); } - NumberFilterCondition::NumberIsNotEmpty => { + NumberFilterConditionPB::NumberIsNotEmpty => { return !num_cell_data.is_empty(); } _ => {} @@ -24,12 +24,12 @@ impl NumberFilterPB { Some(cell_decimal) => { let decimal = Decimal::from_str(&self.content).unwrap_or_else(|_| Decimal::zero()); match self.condition { - NumberFilterCondition::Equal => cell_decimal == &decimal, - NumberFilterCondition::NotEqual => cell_decimal != &decimal, - NumberFilterCondition::GreaterThan => cell_decimal > &decimal, - NumberFilterCondition::LessThan => cell_decimal < &decimal, - NumberFilterCondition::GreaterThanOrEqualTo => cell_decimal >= &decimal, - NumberFilterCondition::LessThanOrEqualTo => cell_decimal <= &decimal, + NumberFilterConditionPB::Equal => cell_decimal == &decimal, + NumberFilterConditionPB::NotEqual => cell_decimal != &decimal, + NumberFilterConditionPB::GreaterThan => cell_decimal > &decimal, + NumberFilterConditionPB::LessThan => cell_decimal < &decimal, + NumberFilterConditionPB::GreaterThanOrEqualTo => cell_decimal >= &decimal, + NumberFilterConditionPB::LessThanOrEqualTo => cell_decimal <= &decimal, _ => true, } } @@ -37,13 +37,13 @@ impl NumberFilterPB { } } -impl CellFilterOperation for NumberTypeOptionPB { - fn apply_filter(&self, any_cell_data: TypeCellData, filter: &NumberFilterPB) -> FlowyResult { - if !any_cell_data.is_number() { +impl CellFilterable for NumberTypeOptionPB { + fn apply_filter(&self, type_cell_data: TypeCellData, filter: &NumberFilterPB) -> FlowyResult { + if !type_cell_data.is_number() { return Ok(true); } - let cell_data = any_cell_data.data; + let cell_data = type_cell_data.data; let num_cell_data = self.format_cell_data(&cell_data)?; Ok(filter.is_visible(&num_cell_data)) @@ -52,12 +52,12 @@ impl CellFilterOperation for NumberTypeOptionPB { #[cfg(test)] mod tests { - use crate::entities::{NumberFilterCondition, NumberFilterPB}; + use crate::entities::{NumberFilterConditionPB, NumberFilterPB}; use crate::services::field::{NumberCellData, NumberFormat}; #[test] fn number_filter_equal_test() { let number_filter = NumberFilterPB { - condition: NumberFilterCondition::Equal, + condition: NumberFilterConditionPB::Equal, content: "123".to_owned(), }; @@ -75,7 +75,7 @@ mod tests { #[test] fn number_filter_greater_than_test() { let number_filter = NumberFilterPB { - condition: NumberFilterCondition::GreaterThan, + condition: NumberFilterConditionPB::GreaterThan, content: "12".to_owned(), }; for (num_str, visible) in [("123", true), ("10", false), ("30", true), ("", false)] { @@ -87,7 +87,7 @@ mod tests { #[test] fn number_filter_less_than_test() { let number_filter = NumberFilterPB { - condition: NumberFilterCondition::LessThan, + condition: NumberFilterConditionPB::LessThan, content: "100".to_owned(), }; for (num_str, visible) in [("12", true), ("1234", false), ("30", true), ("", false)] { diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option/number_type_option.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option/number_type_option.rs index 2cefab11f9..656d5f123b 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option/number_type_option.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option/number_type_option.rs @@ -1,15 +1,13 @@ use crate::entities::FieldType; use crate::impl_type_option; -use crate::services::cell::{AnyCellChangeset, CellBytes, CellData, CellDataOperation, CellDisplayable}; +use crate::services::cell::{AnyCellChangeset, CellBytes, CellDataOperation, CellDataSerialize, IntoCellData}; use crate::services::field::type_options::number_type_option::format::*; use crate::services::field::{BoxTypeOptionBuilder, NumberCellData, TypeOptionBuilder}; use bytes::Bytes; use flowy_derive::ProtoBuf; use flowy_error::{FlowyError, FlowyResult}; use grid_rev_model::{CellRevision, FieldRevision, TypeOptionDataDeserializer, TypeOptionDataSerializer}; - use rust_decimal::Decimal; - use serde::{Deserialize, Serialize}; use std::str::FromStr; @@ -105,10 +103,10 @@ pub(crate) fn strip_currency_symbol(s: T) -> String { s } -impl CellDisplayable for NumberTypeOptionPB { - fn displayed_cell_bytes( +impl CellDataSerialize for NumberTypeOptionPB { + fn serialize_cell_data_to_bytes( &self, - cell_data: CellData, + cell_data: IntoCellData, _decoded_field_type: &FieldType, _field_rev: &FieldRevision, ) -> FlowyResult { @@ -119,9 +117,9 @@ impl CellDisplayable for NumberTypeOptionPB { } } - fn displayed_cell_string( + fn serialize_cell_data_to_str( &self, - cell_data: CellData, + cell_data: IntoCellData, _decoded_field_type: &FieldType, _field_rev: &FieldRevision, ) -> FlowyResult { @@ -135,7 +133,7 @@ pub type NumberCellChangeset = String; impl CellDataOperation for NumberTypeOptionPB { fn decode_cell_data( &self, - cell_data: CellData, + cell_data: IntoCellData, decoded_field_type: &FieldType, field_rev: &FieldRevision, ) -> FlowyResult { @@ -143,7 +141,7 @@ impl CellDataOperation for NumberTypeOptionPB { return Ok(CellBytes::default()); } - self.displayed_cell_bytes(cell_data, decoded_field_type, field_rev) + self.serialize_cell_data_to_bytes(cell_data, decoded_field_type, field_rev) } fn apply_changeset( diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option/number_type_option_entities.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option/number_type_option_entities.rs index bdb227ad37..439bfda6c7 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option/number_type_option_entities.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option/number_type_option_entities.rs @@ -99,6 +99,7 @@ impl CellDataIsEmpty for NumberCellData { self.decimal.is_none() } } + pub struct NumberCellDataParser(); impl CellBytesParser for NumberCellDataParser { type Object = NumberCellData; diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/checklist_filter.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/checklist_filter.rs index 913d1e353a..2f10547a81 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/checklist_filter.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/checklist_filter.rs @@ -1,4 +1,4 @@ -use crate::entities::{ChecklistFilterCondition, ChecklistFilterPB}; +use crate::entities::{ChecklistFilterConditionPB, ChecklistFilterPB}; use crate::services::field::{SelectOptionPB, SelectedSelectOptions}; impl ChecklistFilterPB { @@ -15,7 +15,7 @@ impl ChecklistFilterPB { .collect::>(); match self.condition { - ChecklistFilterCondition::IsComplete => { + ChecklistFilterConditionPB::IsComplete => { if selected_option_ids.is_empty() { return false; } @@ -23,7 +23,7 @@ impl ChecklistFilterPB { all_option_ids.retain(|option_id| !selected_option_ids.contains(option_id)); all_option_ids.is_empty() } - ChecklistFilterCondition::IsIncomplete => { + ChecklistFilterConditionPB::IsIncomplete => { if selected_option_ids.is_empty() { return true; } diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/checklist_type_option.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/checklist_type_option.rs index ded054112d..ff15f71f1a 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/checklist_type_option.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/checklist_type_option.rs @@ -1,6 +1,6 @@ use crate::entities::FieldType; use crate::impl_type_option; -use crate::services::cell::{AnyCellChangeset, CellBytes, CellData, CellDataOperation, CellDisplayable}; +use crate::services::cell::{AnyCellChangeset, CellBytes, CellDataOperation, CellDataSerialize, IntoCellData}; use crate::services::field::selection_type_option::type_option_transform::SelectOptionTypeOptionTransformer; use crate::services::field::type_options::util::get_cell_data; use crate::services::field::{ @@ -41,11 +41,11 @@ impl SelectTypeOptionSharedAction for ChecklistTypeOptionPB { impl CellDataOperation for ChecklistTypeOptionPB { fn decode_cell_data( &self, - cell_data: CellData, + cell_data: IntoCellData, decoded_field_type: &FieldType, field_rev: &FieldRevision, ) -> FlowyResult { - self.displayed_cell_bytes(cell_data, decoded_field_type, field_rev) + self.serialize_cell_data_to_bytes(cell_data, decoded_field_type, field_rev) } fn apply_changeset( diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/multi_select_type_option.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/multi_select_type_option.rs index 71c8c1e39b..c639581c6b 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/multi_select_type_option.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/multi_select_type_option.rs @@ -1,6 +1,6 @@ use crate::entities::FieldType; use crate::impl_type_option; -use crate::services::cell::{AnyCellChangeset, CellBytes, CellData, CellDataOperation, CellDisplayable}; +use crate::services::cell::{AnyCellChangeset, CellBytes, CellDataOperation, CellDataSerialize, IntoCellData}; use crate::services::field::selection_type_option::type_option_transform::SelectOptionTypeOptionTransformer; use crate::services::field::type_options::util::get_cell_data; use crate::services::field::{ @@ -41,11 +41,11 @@ impl SelectTypeOptionSharedAction for MultiSelectTypeOptionPB { impl CellDataOperation for MultiSelectTypeOptionPB { fn decode_cell_data( &self, - cell_data: CellData, + cell_data: IntoCellData, decoded_field_type: &FieldType, field_rev: &FieldRevision, ) -> FlowyResult { - self.displayed_cell_bytes(cell_data, decoded_field_type, field_rev) + self.serialize_cell_data_to_bytes(cell_data, decoded_field_type, field_rev) } fn apply_changeset( diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/select_filter.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/select_filter.rs index a9c0bdde93..f4d4a40244 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/select_filter.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/select_filter.rs @@ -1,7 +1,7 @@ #![allow(clippy::needless_collect)] -use crate::entities::{ChecklistFilterPB, FieldType, SelectOptionCondition, SelectOptionFilterPB}; -use crate::services::cell::{CellFilterOperation, TypeCellData}; +use crate::entities::{ChecklistFilterPB, FieldType, SelectOptionConditionPB, SelectOptionFilterPB}; +use crate::services::cell::{CellFilterable, TypeCellData}; use crate::services::field::{ChecklistTypeOptionPB, MultiSelectTypeOptionPB, SingleSelectTypeOptionPB}; use crate::services::field::{SelectTypeOptionSharedAction, SelectedSelectOptions}; use flowy_error::FlowyResult; @@ -10,7 +10,7 @@ impl SelectOptionFilterPB { pub fn is_visible(&self, selected_options: &SelectedSelectOptions, field_type: FieldType) -> bool { let selected_option_ids: Vec<&String> = selected_options.options.iter().map(|option| &option.id).collect(); match self.condition { - SelectOptionCondition::OptionIs => match field_type { + SelectOptionConditionPB::OptionIs => match field_type { FieldType::SingleSelect => { if self.option_ids.is_empty() { return true; @@ -43,7 +43,7 @@ impl SelectOptionFilterPB { } _ => false, }, - SelectOptionCondition::OptionIsNot => match field_type { + SelectOptionConditionPB::OptionIsNot => match field_type { FieldType::SingleSelect => { if self.option_ids.is_empty() { return true; @@ -72,39 +72,39 @@ impl SelectOptionFilterPB { } _ => false, }, - SelectOptionCondition::OptionIsEmpty => selected_option_ids.is_empty(), - SelectOptionCondition::OptionIsNotEmpty => !selected_option_ids.is_empty(), + SelectOptionConditionPB::OptionIsEmpty => selected_option_ids.is_empty(), + SelectOptionConditionPB::OptionIsNotEmpty => !selected_option_ids.is_empty(), } } } -impl CellFilterOperation for MultiSelectTypeOptionPB { - fn apply_filter(&self, any_cell_data: TypeCellData, filter: &SelectOptionFilterPB) -> FlowyResult { - if !any_cell_data.is_multi_select() { +impl CellFilterable for MultiSelectTypeOptionPB { + fn apply_filter(&self, type_cell_data: TypeCellData, filter: &SelectOptionFilterPB) -> FlowyResult { + if !type_cell_data.is_multi_select() { return Ok(true); } - let selected_options = SelectedSelectOptions::from(self.get_selected_options(any_cell_data.into())); + let selected_options = SelectedSelectOptions::from(self.get_selected_options(type_cell_data.into())); Ok(filter.is_visible(&selected_options, FieldType::MultiSelect)) } } -impl CellFilterOperation for SingleSelectTypeOptionPB { - fn apply_filter(&self, any_cell_data: TypeCellData, filter: &SelectOptionFilterPB) -> FlowyResult { - if !any_cell_data.is_single_select() { +impl CellFilterable for SingleSelectTypeOptionPB { + fn apply_filter(&self, type_cell_data: TypeCellData, filter: &SelectOptionFilterPB) -> FlowyResult { + if !type_cell_data.is_single_select() { return Ok(true); } - let selected_options = SelectedSelectOptions::from(self.get_selected_options(any_cell_data.into())); + let selected_options = SelectedSelectOptions::from(self.get_selected_options(type_cell_data.into())); Ok(filter.is_visible(&selected_options, FieldType::SingleSelect)) } } -impl CellFilterOperation for ChecklistTypeOptionPB { - fn apply_filter(&self, any_cell_data: TypeCellData, filter: &ChecklistFilterPB) -> FlowyResult { - if !any_cell_data.is_checklist() { +impl CellFilterable for ChecklistTypeOptionPB { + fn apply_filter(&self, type_cell_data: TypeCellData, filter: &ChecklistFilterPB) -> FlowyResult { + if !type_cell_data.is_checklist() { return Ok(true); } - let selected_options = SelectedSelectOptions::from(self.get_selected_options(any_cell_data.into())); + let selected_options = SelectedSelectOptions::from(self.get_selected_options(type_cell_data.into())); Ok(filter.is_visible(&self.options, &selected_options)) } } @@ -112,14 +112,14 @@ impl CellFilterOperation for ChecklistTypeOptionPB { #[cfg(test)] mod tests { #![allow(clippy::all)] - use crate::entities::{FieldType, SelectOptionCondition, SelectOptionFilterPB}; + use crate::entities::{FieldType, SelectOptionConditionPB, SelectOptionFilterPB}; use crate::services::field::selection_type_option::{SelectOptionPB, SelectedSelectOptions}; #[test] fn select_option_filter_is_empty_test() { let option = SelectOptionPB::new("A"); let filter = SelectOptionFilterPB { - condition: SelectOptionCondition::OptionIsEmpty, + condition: SelectOptionConditionPB::OptionIsEmpty, option_ids: vec![], }; @@ -152,7 +152,7 @@ mod tests { let option_1 = SelectOptionPB::new("A"); let option_2 = SelectOptionPB::new("B"); let filter = SelectOptionFilterPB { - condition: SelectOptionCondition::OptionIsNotEmpty, + condition: SelectOptionConditionPB::OptionIsNotEmpty, option_ids: vec![option_1.id.clone(), option_2.id.clone()], }; @@ -191,7 +191,7 @@ mod tests { let option_2 = SelectOptionPB::new("B"); let option_3 = SelectOptionPB::new("C"); let filter = SelectOptionFilterPB { - condition: SelectOptionCondition::OptionIsNot, + condition: SelectOptionConditionPB::OptionIsNot, option_ids: vec![option_1.id.clone(), option_2.id.clone()], }; @@ -215,7 +215,7 @@ mod tests { let option_3 = SelectOptionPB::new("c"); let filter = SelectOptionFilterPB { - condition: SelectOptionCondition::OptionIs, + condition: SelectOptionConditionPB::OptionIs, option_ids: vec![option_1.id.clone()], }; for (options, is_visible) in vec![ @@ -237,7 +237,7 @@ mod tests { let option_2 = SelectOptionPB::new("B"); let filter = SelectOptionFilterPB { - condition: SelectOptionCondition::OptionIs, + condition: SelectOptionConditionPB::OptionIs, option_ids: vec![], }; for (options, is_visible) in vec![ @@ -258,7 +258,7 @@ mod tests { let option_2 = SelectOptionPB::new("B"); let option_3 = SelectOptionPB::new("C"); let filter = SelectOptionFilterPB { - condition: SelectOptionCondition::OptionIsNot, + condition: SelectOptionConditionPB::OptionIsNot, option_ids: vec![option_1.id.clone(), option_2.id.clone()], }; @@ -283,7 +283,7 @@ mod tests { let option_3 = SelectOptionPB::new("C"); let filter = SelectOptionFilterPB { - condition: SelectOptionCondition::OptionIs, + condition: SelectOptionConditionPB::OptionIs, option_ids: vec![option_1.id.clone(), option_2.id.clone()], }; for (options, is_visible) in vec![ @@ -305,7 +305,7 @@ mod tests { let option_1 = SelectOptionPB::new("A"); let filter = SelectOptionFilterPB { - condition: SelectOptionCondition::OptionIs, + condition: SelectOptionConditionPB::OptionIs, option_ids: vec![], }; for (options, is_visible) in vec![(vec![option_1.clone()], true), (vec![], true)] { diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/select_type_option.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/select_type_option.rs index 1f961b868a..b889dfbc78 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/select_type_option.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/select_type_option.rs @@ -1,7 +1,7 @@ use crate::entities::parser::NotEmptyStr; use crate::entities::{CellChangesetPB, CellPathPB, CellPathParams, FieldType}; use crate::services::cell::{ - CellBytes, CellBytesParser, CellData, CellDataIsEmpty, CellDisplayable, FromCellChangeset, FromCellString, + CellBytes, CellBytesParser, CellDataIsEmpty, CellDataSerialize, FromCellChangeset, FromCellString, IntoCellData, }; use crate::services::field::selection_type_option::type_option_transform::SelectOptionTypeOptionTransformer; use crate::services::field::{ChecklistTypeOptionPB, MultiSelectTypeOptionPB, SingleSelectTypeOptionPB}; @@ -69,7 +69,10 @@ impl std::default::Default for SelectOptionColorPB { } } -pub fn make_selected_options(cell_data: CellData, options: &[SelectOptionPB]) -> Vec { +pub fn make_selected_options( + cell_data: IntoCellData, + options: &[SelectOptionPB], +) -> Vec { if let Ok(ids) = cell_data.try_into_inner() { ids.iter() .flat_map(|option_id| options.iter().find(|option| &option.id == option_id).cloned()) @@ -110,7 +113,7 @@ pub trait SelectTypeOptionSharedAction: TypeOptionDataSerializer + Send + Sync { } /// Return a list of options that are selected by user - fn get_selected_options(&self, cell_data: CellData) -> SelectOptionCellDataPB { + fn get_selected_options(&self, cell_data: IntoCellData) -> SelectOptionCellDataPB { let mut select_options = make_selected_options(cell_data, self.options()); match self.number_of_max_options() { None => {} @@ -126,7 +129,7 @@ pub trait SelectTypeOptionSharedAction: TypeOptionDataSerializer + Send + Sync { fn transform_cell_data( &self, - cell_data: CellData, + cell_data: IntoCellData, decoded_field_type: &FieldType, _field_rev: &FieldRevision, ) -> FlowyResult { @@ -150,7 +153,9 @@ pub trait SelectTypeOptionSharedAction: TypeOptionDataSerializer + Send + Sync { }) }); - return CellBytes::from(self.get_selected_options(CellData(Some(SelectOptionIds(transformed_ids))))); + return CellBytes::from( + self.get_selected_options(IntoCellData(Some(SelectOptionIds(transformed_ids)))), + ); } _ => { return Ok(CellBytes::default()); @@ -165,13 +170,13 @@ pub trait SelectTypeOptionSharedAction: TypeOptionDataSerializer + Send + Sync { fn mut_options(&mut self) -> &mut Vec; } -impl CellDisplayable for T +impl CellDataSerialize for T where T: SelectTypeOptionSharedAction, { - fn displayed_cell_bytes( + fn serialize_cell_data_to_bytes( &self, - cell_data: CellData, + cell_data: IntoCellData, decoded_field_type: &FieldType, field_rev: &FieldRevision, ) -> FlowyResult { @@ -183,9 +188,9 @@ where ) } - fn displayed_cell_string( + fn serialize_cell_data_to_str( &self, - cell_data: CellData, + cell_data: IntoCellData, _decoded_field_type: &FieldType, _field_rev: &FieldRevision, ) -> FlowyResult { diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/single_select_type_option.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/single_select_type_option.rs index 5d51a68c83..5efcde1aea 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/single_select_type_option.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/single_select_type_option.rs @@ -1,6 +1,6 @@ use crate::entities::FieldType; use crate::impl_type_option; -use crate::services::cell::{AnyCellChangeset, CellBytes, CellData, CellDataOperation, CellDisplayable}; +use crate::services::cell::{AnyCellChangeset, CellBytes, CellDataOperation, CellDataSerialize, IntoCellData}; use crate::services::field::selection_type_option::type_option_transform::SelectOptionTypeOptionTransformer; use crate::services::field::{BoxTypeOptionBuilder, TypeOptionBuilder}; use crate::services::field::{ @@ -40,11 +40,11 @@ impl SelectTypeOptionSharedAction for SingleSelectTypeOptionPB { impl CellDataOperation for SingleSelectTypeOptionPB { fn decode_cell_data( &self, - cell_data: CellData, + cell_data: IntoCellData, decoded_field_type: &FieldType, field_rev: &FieldRevision, ) -> FlowyResult { - self.displayed_cell_bytes(cell_data, decoded_field_type, field_rev) + self.serialize_cell_data_to_bytes(cell_data, decoded_field_type, field_rev) } fn apply_changeset( diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/type_option_transform.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/type_option_transform.rs index ed673e56b3..91a2241f34 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/type_option_transform.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/type_option_transform.rs @@ -1,5 +1,5 @@ use crate::entities::FieldType; -use crate::services::cell::{CellBytes, CellData}; +use crate::services::cell::{CellBytes, IntoCellData}; use crate::services::field::{ MultiSelectTypeOptionPB, SelectOptionColorPB, SelectOptionIds, SelectOptionPB, SelectTypeOptionSharedAction, SingleSelectTypeOptionPB, CHECK, UNCHECK, @@ -57,7 +57,7 @@ impl SelectOptionTypeOptionTransformer { pub fn transform_type_option_cell_data( shared: &T, - cell_data: CellData, + cell_data: IntoCellData, decoded_field_type: &FieldType, _field_rev: &FieldRevision, ) -> FlowyResult @@ -78,7 +78,7 @@ impl SelectOptionTypeOptionTransformer { transformed_ids.push(option.id.clone()); } }); - let transformed_cell_data = CellData::from(SelectOptionIds::from(transformed_ids)); + let transformed_cell_data = IntoCellData::from(SelectOptionIds::from(transformed_ids)); CellBytes::from(shared.get_selected_options(transformed_cell_data)) } _ => Ok(CellBytes::default()), diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/text_type_option/text_filter.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/text_type_option/text_filter.rs index 7e6ca21474..55866f734a 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/text_type_option/text_filter.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/text_type_option/text_filter.rs @@ -1,5 +1,5 @@ -use crate::entities::{TextFilterCondition, TextFilterPB}; -use crate::services::cell::{CellData, CellFilterOperation, TypeCellData}; +use crate::entities::{TextFilterConditionPB, TextFilterPB}; +use crate::services::cell::{CellFilterable, IntoCellData, TypeCellData}; use crate::services::field::{RichTextTypeOptionPB, TextCellData}; use flowy_error::FlowyResult; @@ -8,25 +8,25 @@ impl TextFilterPB { let cell_data = cell_data.as_ref().to_lowercase(); let content = &self.content.to_lowercase(); match self.condition { - TextFilterCondition::Is => &cell_data == content, - TextFilterCondition::IsNot => &cell_data != content, - TextFilterCondition::Contains => cell_data.contains(content), - TextFilterCondition::DoesNotContain => !cell_data.contains(content), - TextFilterCondition::StartsWith => cell_data.starts_with(content), - TextFilterCondition::EndsWith => cell_data.ends_with(content), - TextFilterCondition::TextIsEmpty => cell_data.is_empty(), - TextFilterCondition::TextIsNotEmpty => !cell_data.is_empty(), + TextFilterConditionPB::Is => &cell_data == content, + TextFilterConditionPB::IsNot => &cell_data != content, + TextFilterConditionPB::Contains => cell_data.contains(content), + TextFilterConditionPB::DoesNotContain => !cell_data.contains(content), + TextFilterConditionPB::StartsWith => cell_data.starts_with(content), + TextFilterConditionPB::EndsWith => cell_data.ends_with(content), + TextFilterConditionPB::TextIsEmpty => cell_data.is_empty(), + TextFilterConditionPB::TextIsNotEmpty => !cell_data.is_empty(), } } } -impl CellFilterOperation for RichTextTypeOptionPB { - fn apply_filter(&self, any_cell_data: TypeCellData, filter: &TextFilterPB) -> FlowyResult { - if !any_cell_data.is_text() { +impl CellFilterable for RichTextTypeOptionPB { + fn apply_filter(&self, type_cell_data: TypeCellData, filter: &TextFilterPB) -> FlowyResult { + if !type_cell_data.is_text() { return Ok(false); } - let cell_data: CellData = any_cell_data.into(); + let cell_data: IntoCellData = type_cell_data.into(); let text_cell_data = cell_data.try_into_inner()?; Ok(filter.is_visible(text_cell_data)) } @@ -34,12 +34,12 @@ impl CellFilterOperation for RichTextTypeOptionPB { #[cfg(test)] mod tests { #![allow(clippy::all)] - use crate::entities::{TextFilterCondition, TextFilterPB}; + use crate::entities::{TextFilterConditionPB, TextFilterPB}; #[test] fn text_filter_equal_test() { let text_filter = TextFilterPB { - condition: TextFilterCondition::Is, + condition: TextFilterConditionPB::Is, content: "appflowy".to_owned(), }; @@ -51,7 +51,7 @@ mod tests { #[test] fn text_filter_start_with_test() { let text_filter = TextFilterPB { - condition: TextFilterCondition::StartsWith, + condition: TextFilterConditionPB::StartsWith, content: "appflowy".to_owned(), }; @@ -63,7 +63,7 @@ mod tests { #[test] fn text_filter_end_with_test() { let text_filter = TextFilterPB { - condition: TextFilterCondition::EndsWith, + condition: TextFilterConditionPB::EndsWith, content: "appflowy".to_owned(), }; @@ -74,7 +74,7 @@ mod tests { #[test] fn text_filter_empty_test() { let text_filter = TextFilterPB { - condition: TextFilterCondition::TextIsEmpty, + condition: TextFilterConditionPB::TextIsEmpty, content: "appflowy".to_owned(), }; @@ -84,7 +84,7 @@ mod tests { #[test] fn text_filter_contain_test() { let text_filter = TextFilterPB { - condition: TextFilterCondition::Contains, + condition: TextFilterConditionPB::Contains, content: "appflowy".to_owned(), }; diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/text_type_option/text_type_option.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/text_type_option/text_type_option.rs index d9d4216f8b..eedba039a6 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/text_type_option/text_type_option.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/text_type_option/text_type_option.rs @@ -1,8 +1,8 @@ use crate::entities::FieldType; use crate::impl_type_option; use crate::services::cell::{ - decode_cell_data_to_string, AnyCellChangeset, CellBytes, CellBytesParser, CellData, CellDataIsEmpty, - CellDataOperation, CellDisplayable, FromCellString, + decode_cell_data_to_string, AnyCellChangeset, CellBytes, CellBytesParser, CellDataIsEmpty, CellDataOperation, + CellDataSerialize, FromCellString, IntoCellData, }; use crate::services::field::{BoxTypeOptionBuilder, TypeOptionBuilder}; use bytes::Bytes; @@ -39,32 +39,32 @@ pub struct RichTextTypeOptionPB { } impl_type_option!(RichTextTypeOptionPB, FieldType::RichText); -impl CellDisplayable for RichTextTypeOptionPB { - fn displayed_cell_bytes( +impl CellDataSerialize for RichTextTypeOptionPB { + fn serialize_cell_data_to_bytes( &self, - cell_data: CellData, + cell_data: IntoCellData, _decoded_field_type: &FieldType, _field_rev: &FieldRevision, ) -> FlowyResult { - let cell_str: String = cell_data.try_into_inner()?; + let cell_str: RichTextCellData = cell_data.try_into_inner()?; Ok(CellBytes::new(cell_str)) } - fn displayed_cell_string( + fn serialize_cell_data_to_str( &self, - cell_data: CellData, + cell_data: IntoCellData, _decoded_field_type: &FieldType, _field_rev: &FieldRevision, ) -> FlowyResult { - let cell_str: String = cell_data.try_into_inner()?; + let cell_str: RichTextCellData = cell_data.try_into_inner()?; Ok(cell_str) } } -impl CellDataOperation for RichTextTypeOptionPB { +impl CellDataOperation for RichTextTypeOptionPB { fn decode_cell_data( &self, - cell_data: CellData, + cell_data: IntoCellData, decoded_field_type: &FieldType, field_rev: &FieldRevision, ) -> FlowyResult { @@ -77,7 +77,7 @@ impl CellDataOperation for RichTextTypeOptionPB { let s = decode_cell_data_to_string(cell_data, decoded_field_type, decoded_field_type, field_rev); Ok(CellBytes::new(s.unwrap_or_else(|_| "".to_owned()))) } else { - self.displayed_cell_bytes(cell_data, decoded_field_type, field_rev) + self.serialize_cell_data_to_bytes(cell_data, decoded_field_type, field_rev) } } @@ -141,3 +141,5 @@ impl CellBytesParser for TextCellDataParser { } } } + +pub type RichTextCellData = String; diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option/url_filter.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option/url_filter.rs index ae2baa5cb8..86ec058d48 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option/url_filter.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option/url_filter.rs @@ -1,15 +1,15 @@ use crate::entities::TextFilterPB; -use crate::services::cell::{CellData, CellFilterOperation, TypeCellData}; +use crate::services::cell::{CellFilterable, IntoCellData, TypeCellData}; use crate::services::field::{TextCellData, URLTypeOptionPB}; use flowy_error::FlowyResult; -impl CellFilterOperation for URLTypeOptionPB { - fn apply_filter(&self, any_cell_data: TypeCellData, filter: &TextFilterPB) -> FlowyResult { - if !any_cell_data.is_url() { +impl CellFilterable for URLTypeOptionPB { + fn apply_filter(&self, type_cell_data: TypeCellData, filter: &TextFilterPB) -> FlowyResult { + if !type_cell_data.is_url() { return Ok(true); } - let cell_data: CellData = any_cell_data.into(); + let cell_data: IntoCellData = type_cell_data.into(); let text_cell_data = cell_data.try_into_inner()?; Ok(filter.is_visible(&text_cell_data)) } diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option/url_tests.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option/url_tests.rs index b66badcf5b..4ca2a99626 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option/url_tests.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option/url_tests.rs @@ -1,9 +1,9 @@ #[cfg(test)] mod tests { use crate::entities::FieldType; - use crate::services::cell::{CellData, CellDataOperation}; + use crate::services::cell::{CellDataOperation, IntoCellData}; use crate::services::field::{FieldBuilder, URLCellDataParser}; - use crate::services::field::{URLCellDataPB, URLTypeOptionPB}; + use crate::services::field::{URLCellData, URLTypeOptionPB}; use grid_rev_model::FieldRevision; /// The expected_str will equal to the input string, but the expected_url will be empty if there's no @@ -175,12 +175,12 @@ mod tests { assert_eq!(expected_url.to_owned(), decode_cell_data.url); } - fn decode_cell_data>>( + fn decode_cell_data>>( encoded_data: T, type_option: &URLTypeOptionPB, field_rev: &FieldRevision, field_type: &FieldType, - ) -> URLCellDataPB { + ) -> URLCellData { type_option .decode_cell_data(encoded_data.into(), field_type, field_rev) .unwrap() diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option/url_type_option.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option/url_type_option.rs index bac3516135..bfaee28a1a 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option/url_type_option.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option/url_type_option.rs @@ -1,7 +1,7 @@ use crate::entities::FieldType; use crate::impl_type_option; -use crate::services::cell::{AnyCellChangeset, CellBytes, CellData, CellDataOperation, CellDisplayable}; -use crate::services::field::{BoxTypeOptionBuilder, TypeOptionBuilder, URLCellDataPB}; +use crate::services::cell::{AnyCellChangeset, CellBytes, CellDataOperation, CellDataSerialize, IntoCellData}; +use crate::services::field::{BoxTypeOptionBuilder, TypeOptionBuilder, URLCellData, URLCellDataPB}; use bytes::Bytes; use fancy_regex::Regex; use flowy_derive::ProtoBuf; @@ -36,41 +36,42 @@ pub struct URLTypeOptionPB { } impl_type_option!(URLTypeOptionPB, FieldType::URL); -impl CellDisplayable for URLTypeOptionPB { - fn displayed_cell_bytes( +impl CellDataSerialize for URLTypeOptionPB { + fn serialize_cell_data_to_bytes( &self, - cell_data: CellData, + cell_data: IntoCellData, _decoded_field_type: &FieldType, _field_rev: &FieldRevision, ) -> FlowyResult { - let cell_data: URLCellDataPB = cell_data.try_into_inner()?; - CellBytes::from(cell_data) + let cell_data_pb: URLCellDataPB = cell_data.try_into_inner()?.into(); + CellBytes::from(cell_data_pb) } - fn displayed_cell_string( + fn serialize_cell_data_to_str( &self, - cell_data: CellData, + cell_data: IntoCellData, _decoded_field_type: &FieldType, _field_rev: &FieldRevision, ) -> FlowyResult { - let cell_data: URLCellDataPB = cell_data.try_into_inner()?; + let cell_data: URLCellData = cell_data.try_into_inner()?; Ok(cell_data.content) } } pub type URLCellChangeset = String; -impl CellDataOperation for URLTypeOptionPB { +impl CellDataOperation for URLTypeOptionPB { fn decode_cell_data( &self, - cell_data: CellData, + cell_data: IntoCellData, decoded_field_type: &FieldType, - field_rev: &FieldRevision, + _field_rev: &FieldRevision, ) -> FlowyResult { if !decoded_field_type.is_url() { return Ok(CellBytes::default()); } - self.displayed_cell_bytes(cell_data, decoded_field_type, field_rev) + let cell_data = cell_data.try_into_inner()?.to_json()?; + Ok(CellBytes::new(cell_data)) } fn apply_changeset( @@ -83,7 +84,7 @@ impl CellDataOperation for URLTypeOptionPB { if let Ok(Some(m)) = URL_REGEX.find(&content) { url = auto_append_scheme(m.as_str()); } - URLCellDataPB { url, content }.to_json() + URLCellData { url, content }.to_json() } } diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option/url_type_option_entities.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option/url_type_option_entities.rs index a368f48fd2..4239ba707b 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option/url_type_option_entities.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option/url_type_option_entities.rs @@ -4,7 +4,7 @@ use flowy_derive::ProtoBuf; use flowy_error::{internal_error, FlowyResult}; use serde::{Deserialize, Serialize}; -#[derive(Clone, Debug, Default, Serialize, Deserialize, ProtoBuf)] +#[derive(Clone, Debug, Default, ProtoBuf)] pub struct URLCellDataPB { #[pb(index = 1)] pub url: String, @@ -13,7 +13,22 @@ pub struct URLCellDataPB { pub content: String, } -impl URLCellDataPB { +impl From for URLCellDataPB { + fn from(data: URLCellData) -> Self { + Self { + url: data.url, + content: data.content, + } + } +} + +#[derive(Clone, Default, Serialize, Deserialize)] +pub struct URLCellData { + pub url: String, + pub content: String, +} + +impl URLCellData { pub fn new(s: &str) -> Self { Self { url: "".to_string(), @@ -26,7 +41,7 @@ impl URLCellDataPB { } } -impl CellDataIsEmpty for URLCellDataPB { +impl CellDataIsEmpty for URLCellData { fn is_empty(&self) -> bool { self.content.is_empty() } @@ -34,15 +49,18 @@ impl CellDataIsEmpty for URLCellDataPB { pub struct URLCellDataParser(); impl CellBytesParser for URLCellDataParser { - type Object = URLCellDataPB; + type Object = URLCellData; fn parser(bytes: &Bytes) -> FlowyResult { - URLCellDataPB::try_from(bytes.as_ref()).map_err(internal_error) + match String::from_utf8(bytes.to_vec()) { + Ok(s) => URLCellData::from_cell_str(&s), + Err(_) => Ok(URLCellData::default()), + } } } -impl FromCellString for URLCellDataPB { +impl FromCellString for URLCellData { fn from_cell_str(s: &str) -> FlowyResult { - serde_json::from_str::(s).map_err(internal_error) + serde_json::from_str::(s).map_err(internal_error) } } diff --git a/frontend/rust-lib/flowy-grid/src/services/filter/controller.rs b/frontend/rust-lib/flowy-grid/src/services/filter/controller.rs index 5fe2f1e189..028de3a06a 100644 --- a/frontend/rust-lib/flowy-grid/src/services/filter/controller.rs +++ b/frontend/rust-lib/flowy-grid/src/services/filter/controller.rs @@ -1,9 +1,9 @@ use crate::entities::filter_entities::*; use crate::entities::{FieldType, InsertedRowPB, RowPB}; -use crate::services::cell::{CellFilterOperation, TypeCellData}; +use crate::services::cell::{CellFilterable, TypeCellData}; use crate::services::field::*; use crate::services::filter::{FilterChangeset, FilterMap, FilterResult, FilterResultNotification, FilterType}; -use crate::services::row::GridBlock; +use crate::services::row::GridBlockRowRevision; use crate::services::view_editor::{GridViewChanged, GridViewChangedNotifier}; use flowy_error::FlowyResult; use flowy_task::{QualityOfService, Task, TaskContent, TaskDispatcher}; @@ -20,7 +20,7 @@ pub trait FilterDelegate: Send + Sync + 'static { fn get_filter_rev(&self, filter_type: FilterType) -> Fut>>; fn get_field_rev(&self, field_id: &str) -> Fut>>; fn get_field_revs(&self, field_ids: Option>) -> Fut>>; - fn get_blocks(&self) -> Fut>; + fn get_blocks(&self) -> Fut>; fn get_row_rev(&self, rows_id: &str) -> Fut)>>; } @@ -44,7 +44,7 @@ impl FilterController { notifier: GridViewChangedNotifier, ) -> Self where - T: FilterDelegate, + T: FilterDelegate + 'static, { let mut this = Self { view_id: view_id.to_string(), @@ -55,7 +55,7 @@ impl FilterController { task_scheduler, notifier, }; - this.cache_filters(filter_revs).await; + this.refresh_filters(filter_revs).await; this } @@ -191,17 +191,14 @@ impl FilterController { } #[tracing::instrument(level = "trace", skip(self))] - pub async fn did_receive_filter_changed( - &mut self, - changeset: FilterChangeset, - ) -> Option { + pub async fn did_receive_changes(&mut self, changeset: FilterChangeset) -> Option { let mut notification: Option = None; if let Some(filter_type) = &changeset.insert_filter { if let Some(filter) = self.filter_from_filter_type(filter_type).await { notification = Some(FilterChangesetNotificationPB::from_insert(&self.view_id, vec![filter])); } if let Some(filter_rev) = self.delegate.get_filter_rev(filter_type.clone()).await { - let _ = self.cache_filters(vec![filter_rev]).await; + let _ = self.refresh_filters(vec![filter_rev]).await; } } @@ -218,7 +215,7 @@ impl FilterController { // Update the corresponding filter in the cache if let Some(filter_rev) = self.delegate.get_filter_rev(updated_filter_type.new.clone()).await { - let _ = self.cache_filters(vec![filter_rev]).await; + let _ = self.refresh_filters(vec![filter_rev]).await; } if let Some(filter_id) = filter_id { @@ -253,7 +250,7 @@ impl FilterController { } #[tracing::instrument(level = "trace", skip_all)] - async fn cache_filters(&mut self, filter_revs: Vec>) { + async fn refresh_filters(&mut self, filter_revs: Vec>) { for filter_rev in filter_revs { if let Some(field_rev) = self.delegate.get_field_rev(&filter_rev.field_id).await { let filter_type = FilterType::from(&field_rev); @@ -355,7 +352,7 @@ fn filter_cell( filter_map: &FilterMap, cell_rev: Option<&CellRevision>, ) -> Option { - let any_cell_data = match cell_rev { + let type_cell_data = match cell_rev { None => TypeCellData::from_field_type(&filter_id.field_type), Some(cell_rev) => match TypeCellData::try_from(cell_rev) { Ok(cell_data) => cell_data, @@ -365,13 +362,13 @@ fn filter_cell( } }, }; - let cloned_cell_data = any_cell_data.data.clone(); + let cloned_type_cell_data = type_cell_data.data.clone(); let is_visible = match &filter_id.field_type { FieldType::RichText => filter_map.text_filter.get(filter_id).and_then(|filter| { Some( field_rev .get_type_option::(field_rev.ty)? - .apply_filter(any_cell_data, filter) + .apply_filter(type_cell_data, filter) .ok(), ) }), @@ -379,7 +376,7 @@ fn filter_cell( Some( field_rev .get_type_option::(field_rev.ty)? - .apply_filter(any_cell_data, filter) + .apply_filter(type_cell_data, filter) .ok(), ) }), @@ -387,7 +384,7 @@ fn filter_cell( Some( field_rev .get_type_option::(field_rev.ty)? - .apply_filter(any_cell_data, filter) + .apply_filter(type_cell_data, filter) .ok(), ) }), @@ -395,7 +392,7 @@ fn filter_cell( Some( field_rev .get_type_option::(field_rev.ty)? - .apply_filter(any_cell_data, filter) + .apply_filter(type_cell_data, filter) .ok(), ) }), @@ -403,7 +400,7 @@ fn filter_cell( Some( field_rev .get_type_option::(field_rev.ty)? - .apply_filter(any_cell_data, filter) + .apply_filter(type_cell_data, filter) .ok(), ) }), @@ -411,7 +408,7 @@ fn filter_cell( Some( field_rev .get_type_option::(field_rev.ty)? - .apply_filter(any_cell_data, filter) + .apply_filter(type_cell_data, filter) .ok(), ) }), @@ -419,7 +416,7 @@ fn filter_cell( Some( field_rev .get_type_option::(field_rev.ty)? - .apply_filter(any_cell_data, filter) + .apply_filter(type_cell_data, filter) .ok(), ) }), @@ -427,14 +424,14 @@ fn filter_cell( Some( field_rev .get_type_option::(field_rev.ty)? - .apply_filter(any_cell_data, filter) + .apply_filter(type_cell_data, filter) .ok(), ) }), }?; tracing::Span::current().record( "cell_content", - &format!("{} => {:?}", cloned_cell_data, is_visible.unwrap()).as_str(), + &format!("{} => {:?}", cloned_type_cell_data, is_visible.unwrap()).as_str(), ); is_visible } diff --git a/frontend/rust-lib/flowy-grid/src/services/filter/entities.rs b/frontend/rust-lib/flowy-grid/src/services/filter/entities.rs index bfc7e666bb..973238ea38 100644 --- a/frontend/rust-lib/flowy-grid/src/services/filter/entities.rs +++ b/frontend/rust-lib/flowy-grid/src/services/filter/entities.rs @@ -71,12 +71,11 @@ pub struct FilterType { pub field_type: FieldType, } -impl FilterType { - pub fn field_type_rev(&self) -> FieldTypeRevision { - self.field_type.clone().into() +impl From for FieldTypeRevision { + fn from(filter_type: FilterType) -> Self { + filter_type.field_type.into() } } - impl std::convert::From<&Arc> for FilterType { fn from(rev: &Arc) -> Self { Self { diff --git a/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs b/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs index a9d5df547e..1224004259 100644 --- a/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs +++ b/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs @@ -3,7 +3,7 @@ use crate::entities::CellPathParams; use crate::entities::*; use crate::manager::GridUser; use crate::services::block_manager::GridBlockManager; -use crate::services::cell::{apply_cell_data_changeset, decode_any_cell_data, CellBytes}; +use crate::services::cell::{apply_cell_data_changeset, decode_type_cell_data, CellBytes}; use crate::services::field::{ default_type_option_builder_from_type, type_option_builder_from_bytes, type_option_builder_from_json_str, FieldBuilder, @@ -12,7 +12,7 @@ use crate::services::field::{ use crate::services::filter::FilterType; use crate::services::grid_editor_trait_impl::GridViewEditorDelegateImpl; use crate::services::persistence::block_index::BlockIndexCache; -use crate::services::row::{GridBlock, RowRevisionBuilder}; +use crate::services::row::{GridBlockRow, GridBlockRowRevision, RowRevisionBuilder}; use crate::services::view_editor::{GridViewChanged, GridViewManager}; use bytes::Bytes; use flowy_database::ConnectionPool; @@ -63,8 +63,9 @@ impl GridRevisionEditor { let grid_pad = Arc::new(RwLock::new(grid_pad)); // Block manager + let (block_event_tx, block_event_rx) = broadcast::channel(100); let block_meta_revs = grid_pad.read().await.get_block_meta_revs(); - let block_manager = Arc::new(GridBlockManager::new(&user, block_meta_revs, persistence).await?); + let block_manager = Arc::new(GridBlockManager::new(&user, block_meta_revs, persistence, block_event_tx).await?); let delegate = Arc::new(GridViewEditorDelegateImpl { pad: grid_pad.clone(), block_manager: block_manager.clone(), @@ -72,7 +73,8 @@ impl GridRevisionEditor { }); // View manager - let view_manager = Arc::new(GridViewManager::new(grid_id.to_owned(), user.clone(), delegate).await?); + let view_manager = + Arc::new(GridViewManager::new(grid_id.to_owned(), user.clone(), delegate, block_event_rx).await?); let editor = Arc::new(Self { grid_id: grid_id.to_owned(), @@ -391,11 +393,12 @@ impl GridRevisionEditor { Ok(()) } - pub async fn get_row_pbs(&self, block_id: &str) -> FlowyResult> { - let rows = self.block_manager.get_row_revs(block_id).await?; + /// Returns all the rows in this block. + pub async fn get_row_pbs(&self, view_id: &str, block_id: &str) -> FlowyResult> { + let rows = self.view_manager.get_row_revs(view_id, block_id).await?; let rows = self .view_manager - .filter_rows(block_id, rows) + .filter_rows(view_id, block_id, rows) .await? .into_iter() .map(|row_rev| RowPB::from(&row_rev)) @@ -428,20 +431,20 @@ impl GridRevisionEditor { } pub async fn get_cell(&self, params: &CellPathParams) -> Option { - let (field_type, cell_bytes) = self.decode_any_cell_data(params).await?; + let (field_type, cell_bytes) = self.decode_cell_data_from(params).await?; Some(CellPB::new(¶ms.field_id, field_type, cell_bytes.to_vec())) } pub async fn get_cell_bytes(&self, params: &CellPathParams) -> Option { - let (_, cell_data) = self.decode_any_cell_data(params).await?; + let (_, cell_data) = self.decode_cell_data_from(params).await?; Some(cell_data) } - async fn decode_any_cell_data(&self, params: &CellPathParams) -> Option<(FieldType, CellBytes)> { + async fn decode_cell_data_from(&self, params: &CellPathParams) -> Option<(FieldType, CellBytes)> { let field_rev = self.get_field_rev(¶ms.field_id).await?; let (_, row_rev) = self.block_manager.get_row_rev(¶ms.row_id).await.ok()??; let cell_rev = row_rev.cells.get(¶ms.field_id)?.clone(); - Some(decode_any_cell_data(cell_rev.data, &field_rev)) + Some(decode_type_cell_data(cell_rev.data, &field_rev)) } pub async fn get_cell_rev(&self, row_id: &str, field_id: &str) -> FlowyResult> { @@ -508,7 +511,7 @@ impl GridRevisionEditor { Ok(block_meta_revs) } - pub async fn get_blocks(&self, block_ids: Option>) -> FlowyResult> { + pub async fn get_blocks(&self, block_ids: Option>) -> FlowyResult> { let block_ids = match block_ids { None => self .grid_pad @@ -524,32 +527,28 @@ impl GridRevisionEditor { Ok(blocks) } - pub async fn delete_rows(&self, row_orders: Vec) -> FlowyResult<()> { - let changesets = self.block_manager.delete_rows(row_orders).await?; + pub async fn delete_rows(&self, block_rows: Vec) -> FlowyResult<()> { + let changesets = self.block_manager.delete_rows(block_rows).await?; for changeset in changesets { let _ = self.update_block(changeset).await?; } Ok(()) } - pub async fn get_grid(&self) -> FlowyResult { + pub async fn get_grid(&self, view_id: &str) -> FlowyResult { let pad = self.grid_pad.read().await; let fields = pad.get_field_revs(None)?.iter().map(FieldIdPB::from).collect(); - - let mut blocks = vec![]; + let mut all_rows = vec![]; for block_rev in pad.get_block_meta_revs() { - let rows = self.get_row_pbs(&block_rev.block_id).await?; - let block = BlockPB { - id: block_rev.block_id.clone(), - rows, - }; - blocks.push(block); + if let Ok(rows) = self.get_row_pbs(view_id, &block_rev.block_id).await { + all_rows.extend(rows); + } } Ok(GridPB { id: self.grid_id.clone(), fields, - blocks, + rows: all_rows, }) } @@ -589,6 +588,16 @@ impl GridRevisionEditor { Ok(()) } + pub async fn delete_sort(&self, params: DeleteSortParams) -> FlowyResult<()> { + let _ = self.view_manager.delete_sort(params).await?; + Ok(()) + } + + pub async fn create_or_update_sort(&self, params: AlterSortParams) -> FlowyResult<()> { + let _ = self.view_manager.create_or_update_sort(params).await?; + Ok(()) + } + pub async fn move_row(&self, params: MoveRowParams) -> FlowyResult<()> { let MoveRowParams { view_id: _, @@ -801,7 +810,7 @@ impl GridRevisionEditor { } async fn notify_did_update_grid(&self, changeset: GridFieldChangesetPB) -> FlowyResult<()> { - send_dart_notification(&self.grid_id, GridDartNotification::DidUpdateGridField) + send_dart_notification(&self.grid_id, GridDartNotification::DidUpdateGridFields) .payload(changeset) .send(); Ok(()) diff --git a/frontend/rust-lib/flowy-grid/src/services/grid_editor_trait_impl.rs b/frontend/rust-lib/flowy-grid/src/services/grid_editor_trait_impl.rs index b4208843eb..3a56b0c5d0 100644 --- a/frontend/rust-lib/flowy-grid/src/services/grid_editor_trait_impl.rs +++ b/frontend/rust-lib/flowy-grid/src/services/grid_editor_trait_impl.rs @@ -1,5 +1,5 @@ use crate::services::block_manager::GridBlockManager; -use crate::services::row::GridBlock; +use crate::services::row::GridBlockRowRevision; use crate::services::view_editor::GridViewEditorDelegate; use flowy_sync::client_grid::GridRevisionPad; use flowy_task::TaskDispatcher; @@ -51,11 +51,11 @@ impl GridViewEditorDelegate for GridViewEditorDelegateImpl { }) } - fn get_row_revs(&self) -> Fut>> { + fn get_row_revs(&self, block_id: Option>) -> Fut>> { let block_manager = self.block_manager.clone(); to_fut(async move { - let blocks = block_manager.get_blocks(None).await.unwrap(); + let blocks = block_manager.get_blocks(block_id).await.unwrap(); blocks .into_iter() .flat_map(|block| block.row_revs) @@ -63,7 +63,7 @@ impl GridViewEditorDelegate for GridViewEditorDelegateImpl { }) } - fn get_blocks(&self) -> Fut> { + fn get_blocks(&self) -> Fut> { let block_manager = self.block_manager.clone(); to_fut(async move { block_manager.get_blocks(None).await.unwrap_or_default() }) } diff --git a/frontend/rust-lib/flowy-grid/src/services/group/controller.rs b/frontend/rust-lib/flowy-grid/src/services/group/controller.rs index 00624c0651..950098bdb6 100644 --- a/frontend/rust-lib/flowy-grid/src/services/group/controller.rs +++ b/frontend/rust-lib/flowy-grid/src/services/group/controller.rs @@ -1,5 +1,5 @@ use crate::entities::{GroupRowsNotificationPB, GroupViewChangesetPB, InsertedRowPB, RowPB}; -use crate::services::cell::{decode_any_cell_data, CellBytesParser, CellDataIsEmpty}; +use crate::services::cell::{decode_type_cell_data, CellBytesParser, CellDataIsEmpty}; use crate::services::group::action::{GroupControllerCustomActions, GroupControllerSharedActions}; use crate::services::group::configuration::GroupContext; use crate::services::group::entities::Group; @@ -184,7 +184,7 @@ where if let Some(cell_rev) = cell_rev { let mut grouped_rows: Vec = vec![]; - let cell_bytes = decode_any_cell_data(cell_rev.data, field_rev).1; + let cell_bytes = decode_type_cell_data(cell_rev.data, field_rev).1; let cell_data = cell_bytes.parser::

()?; for group in self.group_ctx.groups() { if self.can_group(&group.filter_content, &cell_data) { @@ -224,7 +224,7 @@ where field_rev: &FieldRevision, ) -> FlowyResult> { if let Some(cell_rev) = row_rev.cells.get(&self.field_id) { - let cell_bytes = decode_any_cell_data(cell_rev.data.clone(), field_rev).1; + let cell_bytes = decode_type_cell_data(cell_rev.data.clone(), field_rev).1; let cell_data = cell_bytes.parser::

()?; let mut changesets = self.add_or_remove_row_in_groups_if_match(row_rev, &cell_data); @@ -247,7 +247,7 @@ where ) -> FlowyResult> { // if the cell_rev is none, then the row must in the default group. if let Some(cell_rev) = row_rev.cells.get(&self.field_id) { - let cell_bytes = decode_any_cell_data(cell_rev.data.clone(), field_rev).1; + let cell_bytes = decode_type_cell_data(cell_rev.data.clone(), field_rev).1; let cell_data = cell_bytes.parser::

()?; if !cell_data.is_empty() { tracing::error!("did_delete_delete_row {:?}", cell_rev.data); @@ -280,7 +280,7 @@ where }; if let Some(cell_rev) = cell_rev { - let cell_bytes = decode_any_cell_data(cell_rev.data, context.field_rev).1; + let cell_bytes = decode_type_cell_data(cell_rev.data, context.field_rev).1; let cell_data = cell_bytes.parser::

()?; Ok(self.move_row(&cell_data, context)) } else { diff --git a/frontend/rust-lib/flowy-grid/src/services/mod.rs b/frontend/rust-lib/flowy-grid/src/services/mod.rs index f69805e802..d9dd4a5592 100644 --- a/frontend/rust-lib/flowy-grid/src/services/mod.rs +++ b/frontend/rust-lib/flowy-grid/src/services/mod.rs @@ -11,4 +11,5 @@ pub mod group; pub mod persistence; pub mod row; pub mod setting; +pub mod sort; pub mod view_editor; diff --git a/frontend/rust-lib/flowy-grid/src/services/row/mod.rs b/frontend/rust-lib/flowy-grid/src/services/row/mod.rs index 60c8421d15..8af63cc54a 100644 --- a/frontend/rust-lib/flowy-grid/src/services/row/mod.rs +++ b/frontend/rust-lib/flowy-grid/src/services/row/mod.rs @@ -2,4 +2,4 @@ mod row_builder; mod row_loader; pub use row_builder::*; -pub(crate) use row_loader::*; +pub use row_loader::*; diff --git a/frontend/rust-lib/flowy-grid/src/services/row/row_loader.rs b/frontend/rust-lib/flowy-grid/src/services/row/row_loader.rs index 0b92889fca..4071fc50a6 100644 --- a/frontend/rust-lib/flowy-grid/src/services/row/row_loader.rs +++ b/frontend/rust-lib/flowy-grid/src/services/row/row_loader.rs @@ -1,42 +1,22 @@ -use crate::entities::{BlockPB, RepeatedBlockPB, RowPB}; - +use crate::entities::RowPB; use grid_rev_model::RowRevision; -use std::collections::HashMap; + use std::sync::Arc; -pub struct GridBlock { +pub struct GridBlockRowRevision { pub(crate) block_id: String, pub row_revs: Vec>, } -pub(crate) fn block_from_row_orders(row_orders: Vec) -> Vec { - let mut map: HashMap = HashMap::new(); - row_orders.into_iter().for_each(|row_info| { - // Memory Optimization: escape clone block_id - let block_id = row_info.block_id().to_owned(); - let cloned_block_id = block_id.clone(); - map.entry(block_id) - .or_insert_with(|| BlockPB::new(&cloned_block_id, vec![])) - .rows - .push(row_info); - }); - map.into_values().collect::>() +pub struct GridBlockRow { + pub block_id: String, + pub row_ids: Vec, } -// -// #[inline(always)] -// fn make_cell_by_field_id( -// field_map: &HashMap<&String, &FieldRevision>, -// field_id: String, -// cell_rev: CellRevision, -// ) -> Option<(String, Cell)> { -// let field_rev = field_map.get(&field_id)?; -// let data = decode_cell_data(cell_rev.data, field_rev).data; -// let cell = Cell::new(&field_id, data); -// Some((field_id, cell)) -// } -pub(crate) fn make_row_pb_from_row_rev(row_revs: &[Arc]) -> Vec { - row_revs.iter().map(RowPB::from).collect::>() +impl GridBlockRow { + pub fn new(block_id: String, row_ids: Vec) -> Self { + Self { block_id, row_ids } + } } pub(crate) fn make_row_from_row_rev(row_rev: Arc) -> RowPB { @@ -52,14 +32,3 @@ pub(crate) fn make_rows_from_row_revs(row_revs: &[Arc]) -> Vec>() } - -pub(crate) fn make_block_pbs(blocks: Vec) -> RepeatedBlockPB { - blocks - .into_iter() - .map(|block| { - let row_pbs = make_row_pb_from_row_rev(&block.row_revs); - BlockPB::new(&block.block_id, row_pbs) - }) - .collect::>() - .into() -} diff --git a/frontend/rust-lib/flowy-grid/src/services/setting/setting_builder.rs b/frontend/rust-lib/flowy-grid/src/services/setting/setting_builder.rs index 8d21427a2d..bc57dcff3b 100644 --- a/frontend/rust-lib/flowy-grid/src/services/setting/setting_builder.rs +++ b/frontend/rust-lib/flowy-grid/src/services/setting/setting_builder.rs @@ -13,6 +13,8 @@ impl GridSettingChangesetBuilder { delete_filter: None, insert_group: None, delete_group: None, + alert_sort: None, + delete_sort: None, }; Self { params } } diff --git a/frontend/rust-lib/flowy-grid/src/services/sort/controller.rs b/frontend/rust-lib/flowy-grid/src/services/sort/controller.rs new file mode 100644 index 0000000000..e7714c8d30 --- /dev/null +++ b/frontend/rust-lib/flowy-grid/src/services/sort/controller.rs @@ -0,0 +1,58 @@ +#![allow(clippy::all)] +#[allow(unused_attributes)] +use crate::entities::{GridSortPB, SortChangesetNotificationPB}; +use crate::services::sort::{SortChangeset, SortType}; +use flowy_task::TaskDispatcher; +use grid_rev_model::{FieldRevision, RowRevision, SortRevision}; +use lib_infra::future::Fut; +use std::sync::Arc; +use tokio::sync::RwLock; + +pub trait SortDelegate: Send + Sync { + fn get_sort_rev(&self, sort_type: SortType) -> Fut>>; + fn get_field_rev(&self, field_id: &str) -> Fut>>; + fn get_field_revs(&self, field_ids: Option>) -> Fut>>; +} + +pub struct SortController { + #[allow(dead_code)] + view_id: String, + #[allow(dead_code)] + handler_id: String, + #[allow(dead_code)] + delegate: Box, + task_scheduler: Arc>, + #[allow(dead_code)] + sorts: Vec, +} + +impl SortController { + pub fn new(view_id: &str, handler_id: &str, delegate: T, task_scheduler: Arc>) -> Self + where + T: SortDelegate + 'static, + { + Self { + view_id: view_id.to_string(), + handler_id: handler_id.to_string(), + delegate: Box::new(delegate), + task_scheduler, + sorts: vec![], + } + } + + pub async fn close(&self) { + self.task_scheduler + .write() + .await + .unregister_handler(&self.handler_id) + .await; + } + + pub fn sort_rows(&self, _rows: &mut Vec>) { + // + } + + pub async fn did_receive_changes(&mut self, _changeset: SortChangeset) -> Option { + None + } +} diff --git a/frontend/rust-lib/flowy-grid/src/services/sort/entities.rs b/frontend/rust-lib/flowy-grid/src/services/sort/entities.rs new file mode 100644 index 0000000000..f64160a9e6 --- /dev/null +++ b/frontend/rust-lib/flowy-grid/src/services/sort/entities.rs @@ -0,0 +1,67 @@ +use crate::entities::{AlterSortParams, FieldType}; +use grid_rev_model::{FieldRevision, FieldTypeRevision}; +use std::sync::Arc; + +#[derive(Hash, Eq, PartialEq, Debug, Clone)] +pub struct SortType { + pub field_id: String, + pub field_type: FieldType, +} + +impl From for FieldTypeRevision { + fn from(sort_type: SortType) -> Self { + sort_type.field_type.into() + } +} + +impl std::convert::From<&AlterSortParams> for SortType { + fn from(params: &AlterSortParams) -> Self { + Self { + field_id: params.field_id.clone(), + field_type: params.field_type.into(), + } + } +} + +impl std::convert::From<&Arc> for SortType { + fn from(rev: &Arc) -> Self { + Self { + field_id: rev.id.clone(), + field_type: rev.ty.into(), + } + } +} + +#[allow(dead_code)] +#[derive(Debug)] +pub struct SortChangeset { + pub(crate) insert_sort: Option, + pub(crate) update_sort: Option, + pub(crate) delete_sort: Option, +} + +impl SortChangeset { + pub fn from_insert(sort: SortType) -> Self { + Self { + insert_sort: Some(sort), + update_sort: None, + delete_sort: None, + } + } + + pub fn from_update(sort: SortType) -> Self { + Self { + insert_sort: None, + update_sort: Some(sort), + delete_sort: None, + } + } + + pub fn from_delete(sort: SortType) -> Self { + Self { + insert_sort: None, + update_sort: None, + delete_sort: Some(sort), + } + } +} diff --git a/frontend/rust-lib/flowy-grid/src/services/sort/mod.rs b/frontend/rust-lib/flowy-grid/src/services/sort/mod.rs new file mode 100644 index 0000000000..89f10043b0 --- /dev/null +++ b/frontend/rust-lib/flowy-grid/src/services/sort/mod.rs @@ -0,0 +1,7 @@ +mod controller; +mod entities; +mod task; + +pub use controller::*; +pub use entities::*; +pub use task::*; diff --git a/frontend/rust-lib/flowy-grid/src/services/sort/task.rs b/frontend/rust-lib/flowy-grid/src/services/sort/task.rs new file mode 100644 index 0000000000..66365dc8b1 --- /dev/null +++ b/frontend/rust-lib/flowy-grid/src/services/sort/task.rs @@ -0,0 +1,30 @@ +use crate::services::sort::SortController; +use flowy_task::{TaskContent, TaskHandler}; +use lib_infra::future::BoxResultFuture; +use std::sync::Arc; +use tokio::sync::RwLock; + +pub struct SortTaskHandler { + handler_id: String, + #[allow(dead_code)] + sort_controller: Arc>, +} + +impl SortTaskHandler { + pub fn new(handler_id: String, sort_controller: Arc>) -> Self { + Self { + handler_id, + sort_controller, + } + } +} + +impl TaskHandler for SortTaskHandler { + fn handler_id(&self) -> &str { + &self.handler_id + } + + fn run(&self, _content: TaskContent) -> BoxResultFuture<(), anyhow::Error> { + todo!(); + } +} diff --git a/frontend/rust-lib/flowy-grid/src/services/view_editor/changed_notifier.rs b/frontend/rust-lib/flowy-grid/src/services/view_editor/changed_notifier.rs index 3a58432918..acf8f1e52d 100644 --- a/frontend/rust-lib/flowy-grid/src/services/view_editor/changed_notifier.rs +++ b/frontend/rust-lib/flowy-grid/src/services/view_editor/changed_notifier.rs @@ -1,5 +1,5 @@ use crate::dart_notification::{send_dart_notification, GridDartNotification}; -use crate::entities::GridBlockChangesetPB; +use crate::entities::GridRowsVisibilityChangesetPB; use crate::services::filter::FilterResultNotification; use async_stream::stream; use futures::stream::StreamExt; @@ -28,16 +28,18 @@ impl GridViewChangedReceiverRunner { .for_each(|changed| async { match changed { GridViewChanged::DidReceiveFilterResult(notification) => { - let changeset = GridBlockChangesetPB { - block_id: notification.block_id, + let changeset = GridRowsVisibilityChangesetPB { + view_id: notification.view_id, visible_rows: notification.visible_rows, invisible_rows: notification.invisible_rows, - ..Default::default() }; - send_dart_notification(&changeset.block_id, GridDartNotification::DidUpdateGridBlock) - .payload(changeset) - .send() + send_dart_notification( + &changeset.view_id, + GridDartNotification::DidUpdateGridViewRowsVisibility, + ) + .payload(changeset) + .send() } } }) diff --git a/frontend/rust-lib/flowy-grid/src/services/view_editor/editor.rs b/frontend/rust-lib/flowy-grid/src/services/view_editor/editor.rs index ffdb5cc96c..753f8993b9 100644 --- a/frontend/rust-lib/flowy-grid/src/services/view_editor/editor.rs +++ b/frontend/rust-lib/flowy-grid/src/services/view_editor/editor.rs @@ -1,11 +1,13 @@ use crate::dart_notification::{send_dart_notification, GridDartNotification}; use crate::entities::*; +use crate::services::block_manager::GridBlockEvent; use crate::services::filter::{FilterChangeset, FilterController, FilterTaskHandler, FilterType, UpdatedFilterType}; use crate::services::group::{ default_group_configuration, find_group_field, make_group_controller, Group, GroupConfigurationReader, GroupController, MoveGroupRowContext, }; -use crate::services::row::GridBlock; +use crate::services::row::GridBlockRowRevision; +use crate::services::sort::{SortChangeset, SortController, SortTaskHandler, SortType}; use crate::services::view_editor::changed_notifier::GridViewChangedNotifier; use crate::services::view_editor::trait_impl::*; use crate::services::view_editor::GridViewChangedReceiverRunner; @@ -16,12 +18,14 @@ use flowy_revision::RevisionManager; use flowy_sync::client_grid::{make_grid_view_operations, GridViewRevisionChangeset, GridViewRevisionPad}; use flowy_task::TaskDispatcher; use grid_rev_model::{ - gen_grid_filter_id, FieldRevision, FieldTypeRevision, FilterRevision, LayoutRevision, RowChangeset, RowRevision, + gen_grid_filter_id, gen_grid_sort_id, FieldRevision, FieldTypeRevision, FilterRevision, LayoutRevision, + RowChangeset, RowRevision, SortRevision, }; use lib_infra::async_trait::async_trait; use lib_infra::future::Fut; use lib_infra::ref_map::RefCountValue; use nanoid::nanoid; +use std::borrow::Cow; use std::future::Future; use std::sync::Arc; use tokio::sync::{broadcast, RwLock}; @@ -29,13 +33,29 @@ use tokio::sync::{broadcast, RwLock}; pub trait GridViewEditorDelegate: Send + Sync + 'static { /// If the field_ids is None, then it will return all the field revisions fn get_field_revs(&self, field_ids: Option>) -> Fut>>; + + /// Returns the field with the field_id fn get_field_rev(&self, field_id: &str) -> Fut>>; + /// Returns the index of the row with row_id fn index_of_row(&self, row_id: &str) -> Fut>; - fn get_row_rev(&self, row_id: &str) -> Fut)>>; - fn get_row_revs(&self) -> Fut>>; - fn get_blocks(&self) -> Fut>; + /// Returns the `index` and `RowRevision` with row_id + fn get_row_rev(&self, row_id: &str) -> Fut)>>; + + /// Returns all the rows that the block has. If the passed-in block_ids is None, then will return all the rows + /// The relationship between the grid and the block is: + /// A grid has a list of blocks + /// A block has a list of rows + /// A row has a list of cells + /// + fn get_row_revs(&self, block_ids: Option>) -> Fut>>; + + /// Get all the blocks that the current Grid has. + /// One grid has a list of blocks + fn get_blocks(&self) -> Fut>; + + /// Returns a `TaskDispatcher` used to poll a `Task` fn get_task_scheduler(&self) -> Arc>; } @@ -47,6 +67,7 @@ pub struct GridViewRevisionEditor { delegate: Arc, group_controller: Arc>>, filter_controller: Arc>, + sort_controller: Arc>, pub notifier: GridViewChangedNotifier, } @@ -89,6 +110,8 @@ impl GridViewRevisionEditor { ) .await?; + let sort_controller = make_sort_controller(&view_id, delegate.clone(), view_rev_pad.clone()).await; + let user_id = user_id.to_owned(); let group_controller = Arc::new(RwLock::new(group_controller)); let filter_controller = @@ -101,6 +124,7 @@ impl GridViewRevisionEditor { delegate, group_controller, filter_controller, + sort_controller, notifier, }) } @@ -110,6 +134,40 @@ impl GridViewRevisionEditor { self.rev_manager.generate_snapshot().await; self.rev_manager.close().await; self.filter_controller.read().await.close().await; + self.sort_controller.read().await.close().await; + } + + pub async fn handle_block_event(&self, event: Cow<'_, GridBlockEvent>) { + let changeset = match event.into_owned() { + GridBlockEvent::InsertRow { block_id: _, row } => { + // + GridViewRowsChangesetPB::from_insert(self.view_id.clone(), vec![row]) + } + GridBlockEvent::UpdateRow { block_id: _, row } => { + // + GridViewRowsChangesetPB::from_update(self.view_id.clone(), vec![row]) + } + GridBlockEvent::DeleteRow { block_id: _, row_id } => { + // + GridViewRowsChangesetPB::from_delete(self.view_id.clone(), vec![row_id]) + } + GridBlockEvent::Move { + block_id: _, + deleted_row_id, + inserted_row, + } => { + // + GridViewRowsChangesetPB::from_move(self.view_id.clone(), vec![deleted_row_id], vec![inserted_row]) + } + }; + + send_dart_notification(&self.view_id, GridDartNotification::DidUpdateGridViewRows) + .payload(changeset) + .send(); + } + + pub async fn sort_rows(&self, rows: &mut Vec>) { + self.sort_controller.read().await.sort_rows(rows) } pub async fn filter_rows(&self, _block_id: &str, mut rows: Vec>) -> Vec> { @@ -316,6 +374,70 @@ impl GridViewRevisionEditor { .await } + pub async fn insert_view_sort(&self, params: AlterSortParams) -> FlowyResult<()> { + let sort_type = SortType::from(¶ms); + let is_exist = params.sort_id.is_some(); + let sort_id = match params.sort_id { + None => gen_grid_sort_id(), + Some(sort_id) => sort_id, + }; + + let sort_rev = SortRevision { + id: sort_id, + field_id: params.field_id.clone(), + field_type: params.field_type, + condition: params.condition, + }; + + let mut sort_controller = self.sort_controller.write().await; + let changeset = if is_exist { + self.modify(|pad| { + let changeset = pad.update_sort(¶ms.field_id, sort_rev)?; + Ok(changeset) + }) + .await?; + sort_controller + .did_receive_changes(SortChangeset::from_update(sort_type)) + .await + } else { + self.modify(|pad| { + let changeset = pad.insert_sort(¶ms.field_id, sort_rev)?; + Ok(changeset) + }) + .await?; + sort_controller + .did_receive_changes(SortChangeset::from_insert(sort_type)) + .await + }; + + if let Some(changeset) = changeset { + self.notify_did_update_sort(changeset).await; + } + Ok(()) + } + + pub async fn delete_view_sort(&self, params: DeleteSortParams) -> FlowyResult<()> { + let sort_type = params.sort_type; + let changeset = self + .sort_controller + .write() + .await + .did_receive_changes(SortChangeset::from_delete(sort_type.clone())) + .await; + + let _ = self + .modify(|pad| { + let changeset = pad.delete_sort(¶ms.sort_id, &sort_type.field_id, sort_type.field_type)?; + Ok(changeset) + }) + .await?; + + if changeset.is_some() { + self.notify_did_update_sort(changeset.unwrap()).await; + } + Ok(()) + } + #[tracing::instrument(level = "trace", skip(self), err)] pub async fn insert_view_filter(&self, params: AlterFilterParams) -> FlowyResult<()> { let filter_type = FilterType::from(¶ms); @@ -344,7 +466,7 @@ impl GridViewRevisionEditor { }) .await?; filter_controller - .did_receive_filter_changed(FilterChangeset::from_update(UpdatedFilterType::new( + .did_receive_changes(FilterChangeset::from_update(UpdatedFilterType::new( old_filter_type, filter_type, ))) @@ -356,7 +478,7 @@ impl GridViewRevisionEditor { }) .await?; filter_controller - .did_receive_filter_changed(FilterChangeset::from_insert(filter_type)) + .did_receive_changes(FilterChangeset::from_insert(filter_type)) .await }; @@ -369,17 +491,16 @@ impl GridViewRevisionEditor { #[tracing::instrument(level = "trace", skip(self), err)] pub async fn delete_view_filter(&self, params: DeleteFilterParams) -> FlowyResult<()> { let filter_type = params.filter_type; - let field_type_rev = filter_type.field_type_rev(); let changeset = self .filter_controller .write() .await - .did_receive_filter_changed(FilterChangeset::from_delete(filter_type.clone())) + .did_receive_changes(FilterChangeset::from_delete(filter_type.clone())) .await; let _ = self .modify(|pad| { - let changeset = pad.delete_filter(¶ms.filter_id, &filter_type.field_id, &field_type_rev)?; + let changeset = pad.delete_filter(¶ms.filter_id, &filter_type.field_id, filter_type.field_type)?; Ok(changeset) }) .await?; @@ -405,7 +526,7 @@ impl GridViewRevisionEditor { .filter_controller .write() .await - .did_receive_filter_changed(filter_changeset) + .did_receive_changes(filter_changeset) .await { self.notify_did_update_filter(changeset).await; @@ -423,7 +544,7 @@ impl GridViewRevisionEditor { #[tracing::instrument(level = "debug", skip_all, err)] pub async fn group_by_view_field(&self, field_id: &str) -> FlowyResult<()> { if let Some(field_rev) = self.delegate.get_field_rev(field_id).await { - let row_revs = self.delegate.get_row_revs().await; + let row_revs = self.delegate.get_row_revs(None).await; let new_group_controller = new_group_controller_with_field_rev( self.user_id.clone(), self.view_id.clone(), @@ -476,6 +597,12 @@ impl GridViewRevisionEditor { .send(); } + pub async fn notify_did_update_sort(&self, changeset: SortChangesetNotificationPB) { + send_dart_notification(&changeset.view_id, GridDartNotification::DidUpdateSort) + .payload(changeset) + .send(); + } + async fn notify_did_update_view(&self, changeset: GroupViewChangesetPB) { send_dart_notification(&self.view_id, GridDartNotification::DidUpdateGroupView) .payload(changeset) @@ -543,7 +670,7 @@ async fn new_group_controller( ) -> FlowyResult> { let configuration_reader = GroupConfigurationReaderImpl(view_rev_pad.clone()); let field_revs = delegate.get_field_revs(None).await; - let row_revs = delegate.get_row_revs().await; + let row_revs = delegate.get_row_revs(None).await; let layout = view_rev_pad.read().await.layout(); // Read the group field or find a new group field let field_rev = configuration_reader @@ -610,6 +737,31 @@ async fn make_filter_controller( filter_controller } +async fn make_sort_controller( + view_id: &str, + delegate: Arc, + pad: Arc>, +) -> Arc> { + let handler_id = gen_handler_id(); + let sort_delegate = GridViewSortDelegateImpl { + editor_delegate: delegate.clone(), + view_revision_pad: pad, + }; + let task_scheduler = delegate.get_task_scheduler(); + let sort_controller = Arc::new(RwLock::new(SortController::new( + view_id, + &handler_id, + sort_delegate, + task_scheduler.clone(), + ))); + task_scheduler + .write() + .await + .register_handler(SortTaskHandler::new(handler_id, sort_controller.clone())); + + sort_controller +} + fn gen_handler_id() -> String { nanoid!(10) } diff --git a/frontend/rust-lib/flowy-grid/src/services/view_editor/editor_manager.rs b/frontend/rust-lib/flowy-grid/src/services/view_editor/editor_manager.rs index 2ac564909a..3160e03bd1 100644 --- a/frontend/rust-lib/flowy-grid/src/services/view_editor/editor_manager.rs +++ b/frontend/rust-lib/flowy-grid/src/services/view_editor/editor_manager.rs @@ -1,8 +1,9 @@ use crate::entities::{ - AlterFilterParams, CreateRowParams, DeleteFilterParams, DeleteGroupParams, GridSettingPB, InsertGroupParams, - MoveGroupParams, RepeatedGroupPB, RowPB, + AlterFilterParams, AlterSortParams, CreateRowParams, DeleteFilterParams, DeleteGroupParams, DeleteSortParams, + GridSettingPB, InsertGroupParams, MoveGroupParams, RepeatedGroupPB, RowPB, }; use crate::manager::GridUser; +use crate::services::block_manager::GridBlockEvent; use crate::services::filter::FilterType; use crate::services::persistence::rev_sqlite::{ SQLiteGridRevisionSnapshotPersistence, SQLiteGridViewRevisionPersistence, @@ -16,6 +17,7 @@ use flowy_revision::{RevisionManager, RevisionPersistence, RevisionPersistenceCo use grid_rev_model::{FieldRevision, FilterRevision, RowChangeset, RowRevision}; use lib_infra::future::Fut; use lib_infra::ref_map::RefCountHashMap; +use std::borrow::Cow; use std::sync::Arc; use tokio::sync::{broadcast, RwLock}; @@ -23,7 +25,7 @@ pub struct GridViewManager { grid_id: String, user: Arc, delegate: Arc, - view_editors: RwLock>>, + view_editors: Arc>>>, } impl GridViewManager { @@ -31,8 +33,10 @@ impl GridViewManager { grid_id: String, user: Arc, delegate: Arc, + block_event_rx: broadcast::Receiver, ) -> FlowyResult { - let view_editors = RwLock::new(RefCountHashMap::default()); + let view_editors = Arc::new(RwLock::new(RefCountHashMap::default())); + listen_on_grid_block_event(block_event_rx, view_editors.clone()); Ok(Self { grid_id, user, @@ -49,9 +53,24 @@ impl GridViewManager { Ok(self.get_view_editor(view_id).await?.notifier.subscribe()) } - pub async fn filter_rows(&self, block_id: &str, rows: Vec>) -> FlowyResult>> { - let editor = self.get_default_view_editor().await?; - let rows = editor.filter_rows(block_id, rows).await; + pub async fn get_row_revs(&self, view_id: &str, block_id: &str) -> FlowyResult>> { + let mut row_revs = self.delegate.get_row_revs(Some(vec![block_id.to_owned()])).await; + if let Ok(view_editor) = self.get_view_editor(view_id).await { + view_editor.sort_rows(&mut row_revs).await; + } + Ok(row_revs) + } + + pub async fn filter_rows( + &self, + view_id: &str, + block_id: &str, + rows: Vec>, + ) -> FlowyResult>> { + let rows = match self.get_view_editor(view_id).await { + Ok(view_editor) => view_editor.filter_rows(block_id, rows).await, + Err(_) => rows, + }; Ok(rows) } @@ -117,15 +136,25 @@ impl GridViewManager { } pub async fn create_or_update_filter(&self, params: AlterFilterParams) -> FlowyResult<()> { - let view_editor = self.get_default_view_editor().await?; + let view_editor = self.get_view_editor(¶ms.view_id).await?; view_editor.insert_view_filter(params).await } pub async fn delete_filter(&self, params: DeleteFilterParams) -> FlowyResult<()> { - let view_editor = self.get_default_view_editor().await?; + let view_editor = self.get_view_editor(¶ms.view_id).await?; view_editor.delete_view_filter(params).await } + pub async fn create_or_update_sort(&self, params: AlterSortParams) -> FlowyResult<()> { + let view_editor = self.get_view_editor(¶ms.view_id).await?; + view_editor.insert_view_sort(params).await + } + + pub async fn delete_sort(&self, params: DeleteSortParams) -> FlowyResult<()> { + let view_editor = self.get_view_editor(¶ms.view_id).await?; + view_editor.delete_view_sort(params).await + } + pub async fn load_groups(&self) -> FlowyResult { let view_editor = self.get_default_view_editor().await?; let groups = view_editor.load_view_groups().await?; @@ -225,6 +254,27 @@ impl GridViewManager { } } +fn listen_on_grid_block_event( + mut block_event_rx: broadcast::Receiver, + view_editors: Arc>>>, +) { + tokio::spawn(async move { + loop { + while let Ok(event) = block_event_rx.recv().await { + let read_guard = view_editors.read().await; + let view_editors = read_guard.values(); + let event = if view_editors.len() == 1 { + Cow::Owned(event) + } else { + Cow::Borrowed(&event) + }; + for view_editor in view_editors.iter() { + view_editor.handle_block_event(event.clone()).await; + } + } + } + }); +} pub async fn make_grid_view_rev_manager( user: &Arc, view_id: &str, diff --git a/frontend/rust-lib/flowy-grid/src/services/view_editor/trait_impl.rs b/frontend/rust-lib/flowy-grid/src/services/view_editor/trait_impl.rs index 72165efc7b..8d90414b15 100644 --- a/frontend/rust-lib/flowy-grid/src/services/view_editor/trait_impl.rs +++ b/frontend/rust-lib/flowy-grid/src/services/view_editor/trait_impl.rs @@ -1,7 +1,8 @@ use crate::entities::{GridLayout, GridLayoutPB, GridSettingPB}; use crate::services::filter::{FilterDelegate, FilterType}; use crate::services::group::{GroupConfigurationReader, GroupConfigurationWriter}; -use crate::services::row::GridBlock; +use crate::services::row::GridBlockRowRevision; +use crate::services::sort::{SortDelegate, SortType}; use crate::services::view_editor::GridViewEditorDelegate; use bytes::Bytes; use flowy_database::ConnectionPool; @@ -12,7 +13,9 @@ use flowy_revision::{ }; use flowy_sync::client_grid::{GridViewRevisionChangeset, GridViewRevisionPad}; use flowy_sync::util::make_operations_from_revisions; -use grid_rev_model::{FieldRevision, FieldTypeRevision, FilterRevision, GroupConfigurationRevision, RowRevision}; +use grid_rev_model::{ + FieldRevision, FieldTypeRevision, FilterRevision, GroupConfigurationRevision, RowRevision, SortRevision, +}; use lib_infra::future::{to_fut, Fut, FutureResult}; use lib_ot::core::EmptyAttributes; use std::sync::Arc; @@ -132,11 +135,11 @@ pub(crate) struct GridViewFilterDelegateImpl { } impl FilterDelegate for GridViewFilterDelegateImpl { - fn get_filter_rev(&self, filter_id: FilterType) -> Fut>> { + fn get_filter_rev(&self, filter_type: FilterType) -> Fut>> { let pad = self.view_revision_pad.clone(); to_fut(async move { - let field_type_rev: FieldTypeRevision = filter_id.field_type.into(); - let mut filters = pad.read().await.get_filters(&filter_id.field_id, &field_type_rev); + let field_type_rev: FieldTypeRevision = filter_type.field_type.into(); + let mut filters = pad.read().await.get_filters(&filter_type.field_id, &field_type_rev); if filters.is_empty() { None } else { @@ -154,7 +157,7 @@ impl FilterDelegate for GridViewFilterDelegateImpl { self.editor_delegate.get_field_revs(field_ids) } - fn get_blocks(&self) -> Fut> { + fn get_blocks(&self) -> Fut> { self.editor_delegate.get_blocks() } @@ -162,3 +165,26 @@ impl FilterDelegate for GridViewFilterDelegateImpl { self.editor_delegate.get_row_rev(row_id) } } + +pub(crate) struct GridViewSortDelegateImpl { + pub(crate) editor_delegate: Arc, + pub(crate) view_revision_pad: Arc>, +} + +impl SortDelegate for GridViewSortDelegateImpl { + fn get_sort_rev(&self, sort_type: SortType) -> Fut>> { + let pad = self.view_revision_pad.clone(); + to_fut(async move { + let field_type_rev: FieldTypeRevision = sort_type.field_type.into(); + pad.read().await.get_sorts(&sort_type.field_id, &field_type_rev) + }) + } + + fn get_field_rev(&self, field_id: &str) -> Fut>> { + self.editor_delegate.get_field_rev(field_id) + } + + fn get_field_revs(&self, field_ids: Option>) -> Fut>> { + self.editor_delegate.get_field_revs(field_ids) + } +} diff --git a/frontend/rust-lib/flowy-grid/tests/grid/block_test/script.rs b/frontend/rust-lib/flowy-grid/tests/grid/block_test/script.rs index 2a3aa12add..3298ca965c 100644 --- a/frontend/rust-lib/flowy-grid/tests/grid/block_test/script.rs +++ b/frontend/rust-lib/flowy-grid/tests/grid/block_test/script.rs @@ -1,9 +1,9 @@ use crate::grid::block_test::script::RowScript::{AssertCell, CreateRow}; use crate::grid::block_test::util::GridRowTestBuilder; use crate::grid::grid_editor::GridEditorTest; - use flowy_grid::entities::{CellPathParams, CreateRowParams, FieldType, GridLayout, RowPB}; use flowy_grid::services::field::*; +use flowy_grid::services::row::GridBlockRow; use grid_rev_model::{GridBlockMetaRevision, GridBlockMetaRevisionChangeset, RowChangeset, RowRevision}; use std::collections::HashMap; use std::sync::Arc; @@ -82,28 +82,27 @@ impl GridRowTest { layout: GridLayout::Table, }; let row_order = self.editor.create_row(params).await.unwrap(); - self.row_order_by_row_id - .insert(row_order.row_id().to_owned(), row_order); + self.row_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(); } RowScript::CreateRow { row_rev } => { let row_orders = self.editor.insert_rows(vec![row_rev]).await.unwrap(); for row_order in row_orders { - self.row_order_by_row_id - .insert(row_order.row_id().to_owned(), row_order); + self.row_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(); } RowScript::UpdateRow { changeset: change } => self.editor.update_row(change).await.unwrap(), RowScript::DeleteRows { row_ids } => { - let row_orders = row_ids + let row_pbs = row_ids .into_iter() - .map(|row_id| self.row_order_by_row_id.get(&row_id).unwrap().clone()) + .map(|row_id| self.row_by_row_id.get(&row_id).unwrap().clone()) .collect::>(); - self.editor.delete_rows(row_orders).await.unwrap(); + let block_rows = block_from_row_pbs(row_pbs); + self.editor.delete_rows(block_rows).await.unwrap(); self.row_revs = self.get_row_revs().await; self.block_meta_revs = self.editor.get_block_meta_revs().await.unwrap(); } @@ -270,6 +269,19 @@ impl GridRowTest { } } +fn block_from_row_pbs(row_orders: Vec) -> Vec { + let mut map: HashMap = HashMap::new(); + row_orders.into_iter().for_each(|row_pb| { + let block_id = row_pb.block_id().to_owned(); + let cloned_block_id = block_id.clone(); + map.entry(block_id) + .or_insert_with(|| GridBlockRow::new(cloned_block_id, vec![])) + .row_ids + .push(row_pb.id); + }); + map.into_values().collect::>() +} + impl std::ops::Deref for GridRowTest { type Target = GridEditorTest; diff --git a/frontend/rust-lib/flowy-grid/tests/grid/filter_test/checkbox_filter_test.rs b/frontend/rust-lib/flowy-grid/tests/grid/filter_test/checkbox_filter_test.rs index 0a28bb5d15..5980c39404 100644 --- a/frontend/rust-lib/flowy-grid/tests/grid/filter_test/checkbox_filter_test.rs +++ b/frontend/rust-lib/flowy-grid/tests/grid/filter_test/checkbox_filter_test.rs @@ -1,6 +1,6 @@ use crate::grid::filter_test::script::FilterScript::*; use crate::grid::filter_test::script::GridFilterTest; -use flowy_grid::entities::CheckboxFilterCondition; +use flowy_grid::entities::CheckboxFilterConditionPB; #[tokio::test] async fn grid_filter_checkbox_is_check_test() { @@ -9,7 +9,7 @@ async fn grid_filter_checkbox_is_check_test() { // The initial number of checked is 2 let scripts = vec![ CreateCheckboxFilter { - condition: CheckboxFilterCondition::IsChecked, + condition: CheckboxFilterConditionPB::IsChecked, }, AssertFilterChanged { visible_row_len: 0, @@ -24,7 +24,7 @@ async fn grid_filter_checkbox_is_uncheck_test() { let mut test = GridFilterTest::new().await; let scripts = vec![ CreateCheckboxFilter { - condition: CheckboxFilterCondition::IsUnChecked, + condition: CheckboxFilterConditionPB::IsUnChecked, }, AssertNumberOfVisibleRows { expected: 3 }, ]; diff --git a/frontend/rust-lib/flowy-grid/tests/grid/filter_test/checklist_filter_test.rs b/frontend/rust-lib/flowy-grid/tests/grid/filter_test/checklist_filter_test.rs index a89a93cdb4..05b4754ff7 100644 --- a/frontend/rust-lib/flowy-grid/tests/grid/filter_test/checklist_filter_test.rs +++ b/frontend/rust-lib/flowy-grid/tests/grid/filter_test/checklist_filter_test.rs @@ -1,13 +1,13 @@ use crate::grid::filter_test::script::FilterScript::*; use crate::grid::filter_test::script::GridFilterTest; -use flowy_grid::entities::ChecklistFilterCondition; +use flowy_grid::entities::ChecklistFilterConditionPB; #[tokio::test] async fn grid_filter_checklist_is_incomplete_test() { let mut test = GridFilterTest::new().await; let scripts = vec![ CreateChecklistFilter { - condition: ChecklistFilterCondition::IsIncomplete, + condition: ChecklistFilterConditionPB::IsIncomplete, }, AssertNumberOfVisibleRows { expected: 4 }, ]; @@ -19,7 +19,7 @@ async fn grid_filter_checklist_is_complete_test() { let mut test = GridFilterTest::new().await; let scripts = vec![ CreateChecklistFilter { - condition: ChecklistFilterCondition::IsComplete, + condition: ChecklistFilterConditionPB::IsComplete, }, AssertNumberOfVisibleRows { expected: 1 }, ]; diff --git a/frontend/rust-lib/flowy-grid/tests/grid/filter_test/date_filter_test.rs b/frontend/rust-lib/flowy-grid/tests/grid/filter_test/date_filter_test.rs index b36aedf19f..8be96ad4f0 100644 --- a/frontend/rust-lib/flowy-grid/tests/grid/filter_test/date_filter_test.rs +++ b/frontend/rust-lib/flowy-grid/tests/grid/filter_test/date_filter_test.rs @@ -1,13 +1,13 @@ use crate::grid::filter_test::script::FilterScript::*; use crate::grid::filter_test::script::GridFilterTest; -use flowy_grid::entities::DateFilterCondition; +use flowy_grid::entities::DateFilterConditionPB; #[tokio::test] async fn grid_filter_date_is_test() { let mut test = GridFilterTest::new().await; let scripts = vec![ CreateDateFilter { - condition: DateFilterCondition::DateIs, + condition: DateFilterConditionPB::DateIs, start: None, end: None, timestamp: Some(1647251762), @@ -22,7 +22,7 @@ async fn grid_filter_date_after_test() { let mut test = GridFilterTest::new().await; let scripts = vec![ CreateDateFilter { - condition: DateFilterCondition::DateAfter, + condition: DateFilterConditionPB::DateAfter, start: None, end: None, timestamp: Some(1647251762), @@ -37,7 +37,7 @@ async fn grid_filter_date_on_or_after_test() { let mut test = GridFilterTest::new().await; let scripts = vec![ CreateDateFilter { - condition: DateFilterCondition::DateOnOrAfter, + condition: DateFilterConditionPB::DateOnOrAfter, start: None, end: None, timestamp: Some(1668359085), @@ -52,7 +52,7 @@ async fn grid_filter_date_on_or_before_test() { let mut test = GridFilterTest::new().await; let scripts = vec![ CreateDateFilter { - condition: DateFilterCondition::DateOnOrBefore, + condition: DateFilterConditionPB::DateOnOrBefore, start: None, end: None, timestamp: Some(1668359085), @@ -67,7 +67,7 @@ async fn grid_filter_date_within_test() { let mut test = GridFilterTest::new().await; let scripts = vec![ CreateDateFilter { - condition: DateFilterCondition::DateWithIn, + condition: DateFilterConditionPB::DateWithIn, start: Some(1647251762), end: Some(1668704685), timestamp: None, diff --git a/frontend/rust-lib/flowy-grid/tests/grid/filter_test/number_filter_test.rs b/frontend/rust-lib/flowy-grid/tests/grid/filter_test/number_filter_test.rs index d39649c1af..a4bb99e4e0 100644 --- a/frontend/rust-lib/flowy-grid/tests/grid/filter_test/number_filter_test.rs +++ b/frontend/rust-lib/flowy-grid/tests/grid/filter_test/number_filter_test.rs @@ -1,13 +1,13 @@ use crate::grid::filter_test::script::FilterScript::*; use crate::grid::filter_test::script::GridFilterTest; -use flowy_grid::entities::NumberFilterCondition; +use flowy_grid::entities::NumberFilterConditionPB; #[tokio::test] async fn grid_filter_number_is_equal_test() { let mut test = GridFilterTest::new().await; let scripts = vec![ CreateNumberFilter { - condition: NumberFilterCondition::Equal, + condition: NumberFilterConditionPB::Equal, content: "1".to_string(), }, AssertNumberOfVisibleRows { expected: 1 }, @@ -20,7 +20,7 @@ async fn grid_filter_number_is_less_than_test() { let mut test = GridFilterTest::new().await; let scripts = vec![ CreateNumberFilter { - condition: NumberFilterCondition::LessThan, + condition: NumberFilterConditionPB::LessThan, content: "3".to_string(), }, AssertNumberOfVisibleRows { expected: 2 }, @@ -34,7 +34,7 @@ async fn grid_filter_number_is_less_than_test2() { let mut test = GridFilterTest::new().await; let scripts = vec![ CreateNumberFilter { - condition: NumberFilterCondition::LessThan, + condition: NumberFilterConditionPB::LessThan, content: "$3".to_string(), }, AssertNumberOfVisibleRows { expected: 2 }, @@ -47,7 +47,7 @@ async fn grid_filter_number_is_less_than_or_equal_test() { let mut test = GridFilterTest::new().await; let scripts = vec![ CreateNumberFilter { - condition: NumberFilterCondition::LessThanOrEqualTo, + condition: NumberFilterConditionPB::LessThanOrEqualTo, content: "3".to_string(), }, AssertNumberOfVisibleRows { expected: 3 }, @@ -60,7 +60,7 @@ async fn grid_filter_number_is_empty_test() { let mut test = GridFilterTest::new().await; let scripts = vec![ CreateNumberFilter { - condition: NumberFilterCondition::NumberIsEmpty, + condition: NumberFilterConditionPB::NumberIsEmpty, content: "".to_string(), }, AssertNumberOfVisibleRows { expected: 1 }, @@ -73,7 +73,7 @@ async fn grid_filter_number_is_not_empty_test() { let mut test = GridFilterTest::new().await; let scripts = vec![ CreateNumberFilter { - condition: NumberFilterCondition::NumberIsNotEmpty, + condition: NumberFilterConditionPB::NumberIsNotEmpty, content: "".to_string(), }, AssertNumberOfVisibleRows { expected: 4 }, diff --git a/frontend/rust-lib/flowy-grid/tests/grid/filter_test/script.rs b/frontend/rust-lib/flowy-grid/tests/grid/filter_test/script.rs index d09c910d19..30d5187faa 100644 --- a/frontend/rust-lib/flowy-grid/tests/grid/filter_test/script.rs +++ b/frontend/rust-lib/flowy-grid/tests/grid/filter_test/script.rs @@ -6,10 +6,11 @@ use std::time::Duration; use bytes::Bytes; use futures::TryFutureExt; -use flowy_grid::entities::{AlterFilterParams, AlterFilterPayloadPB, DeleteFilterParams, GridLayout, GridSettingChangesetParams, GridSettingPB, RowPB, TextFilterCondition, FieldType, NumberFilterCondition, CheckboxFilterCondition, DateFilterCondition, DateFilterContent, SelectOptionCondition, TextFilterPB, NumberFilterPB, CheckboxFilterPB, DateFilterPB, SelectOptionFilterPB, CellChangesetPB, FilterPB, ChecklistFilterCondition, ChecklistFilterPB}; +use flowy_grid::entities::{AlterFilterParams, AlterFilterPayloadPB, DeleteFilterParams, GridLayout, GridSettingChangesetParams, GridSettingPB, RowPB, TextFilterConditionPB, FieldType, NumberFilterConditionPB, CheckboxFilterConditionPB, DateFilterConditionPB, DateFilterContentPB, SelectOptionConditionPB, TextFilterPB, NumberFilterPB, CheckboxFilterPB, DateFilterPB, SelectOptionFilterPB, CellChangesetPB, FilterPB, ChecklistFilterConditionPB, ChecklistFilterPB}; use flowy_grid::services::field::{SelectOptionCellChangeset, SelectOptionIds}; use flowy_grid::services::setting::GridSettingChangesetBuilder; use grid_rev_model::{FieldRevision, FieldTypeRevision}; +use flowy_database::schema::view_table::dsl::view_table; use flowy_grid::services::cell::insert_select_option_cell; use flowy_grid::services::filter::FilterType; use flowy_grid::services::view_editor::GridViewChanged; @@ -28,37 +29,37 @@ pub enum FilterScript { payload: AlterFilterPayloadPB, }, CreateTextFilter { - condition: TextFilterCondition, + condition: TextFilterConditionPB, content: String, }, UpdateTextFilter { filter: FilterPB, - condition: TextFilterCondition, + condition: TextFilterConditionPB, content: String, }, CreateNumberFilter { - condition: NumberFilterCondition, + condition: NumberFilterConditionPB, content: String, }, CreateCheckboxFilter { - condition: CheckboxFilterCondition, + condition: CheckboxFilterConditionPB, }, CreateDateFilter{ - condition: DateFilterCondition, + condition: DateFilterConditionPB, start: Option, end: Option, timestamp: Option, }, CreateMultiSelectFilter { - condition: SelectOptionCondition, + condition: SelectOptionConditionPB, option_ids: Vec, }, CreateSingleSelectFilter { - condition: SelectOptionCondition, + condition: SelectOptionConditionPB, option_ids: Vec, }, CreateChecklistFilter { - condition: ChecklistFilterCondition, + condition: ChecklistFilterConditionPB, }, AssertFilterCount { count: i32, @@ -98,6 +99,10 @@ impl GridFilterTest { } } + pub fn view_id(&self) -> String { + self.grid_id.clone() + } + pub async fn get_all_filters(&self) -> Vec { self.editor.get_all_filters().await.unwrap() } @@ -128,11 +133,14 @@ impl GridFilterTest { content }; let payload = - AlterFilterPayloadPB::new(field_rev, text_filter); + AlterFilterPayloadPB::new( + & self.view_id(), + field_rev, text_filter); self.insert_filter(payload).await; } FilterScript::UpdateTextFilter { filter, condition, content} => { let params = AlterFilterParams { + view_id: self.view_id(), field_id: filter.field_id, filter_id: Some(filter.id), field_type: filter.field_type.into(), @@ -148,7 +156,9 @@ impl GridFilterTest { content }; let payload = - AlterFilterPayloadPB::new(field_rev, number_filter); + AlterFilterPayloadPB::new( + &self.view_id(), + field_rev, number_filter); self.insert_filter(payload).await; } FilterScript::CreateCheckboxFilter {condition} => { @@ -157,7 +167,7 @@ impl GridFilterTest { condition }; let payload = - AlterFilterPayloadPB::new(field_rev, checkbox_filter); + AlterFilterPayloadPB::new(& self.view_id(), field_rev, checkbox_filter); self.insert_filter(payload).await; } FilterScript::CreateDateFilter { condition, start, end, timestamp} => { @@ -170,21 +180,21 @@ impl GridFilterTest { }; let payload = - AlterFilterPayloadPB::new(field_rev, date_filter); + AlterFilterPayloadPB::new( &self.view_id(), field_rev, date_filter); self.insert_filter(payload).await; } FilterScript::CreateMultiSelectFilter { condition, option_ids} => { let field_rev = self.get_first_field_rev(FieldType::MultiSelect); let filter = SelectOptionFilterPB { condition, option_ids }; let payload = - AlterFilterPayloadPB::new(field_rev, filter); + AlterFilterPayloadPB::new( &self.view_id(),field_rev, filter); self.insert_filter(payload).await; } FilterScript::CreateSingleSelectFilter { condition, option_ids} => { let field_rev = self.get_first_field_rev(FieldType::SingleSelect); let filter = SelectOptionFilterPB { condition, option_ids }; let payload = - AlterFilterPayloadPB::new(field_rev, filter); + AlterFilterPayloadPB::new(& self.view_id(),field_rev, filter); self.insert_filter(payload).await; } FilterScript::CreateChecklistFilter { condition} => { @@ -192,7 +202,7 @@ impl GridFilterTest { // let type_option = self.get_checklist_type_option(&field_rev.id); let filter = ChecklistFilterPB { condition }; let payload = - AlterFilterPayloadPB::new(field_rev, filter); + AlterFilterPayloadPB::new(& self.view_id(),field_rev, filter); self.insert_filter(payload).await; } FilterScript::AssertFilterCount { count } => { @@ -206,7 +216,7 @@ impl GridFilterTest { } FilterScript::DeleteFilter { filter_id, filter_type } => { - let params = DeleteFilterParams { filter_type, filter_id }; + let params = DeleteFilterParams { view_id: self.view_id(),filter_type, filter_id }; let _ = self.editor.delete_filter(params).await.unwrap(); } FilterScript::AssertGridSetting { expected_setting } => { @@ -214,22 +224,28 @@ impl GridFilterTest { assert_eq!(expected_setting, setting); } FilterScript::AssertFilterChanged { visible_row_len, hide_row_len} => { - let mut receiver = self.editor.subscribe_view_changed(&self.grid_id).await.unwrap(); + let editor = self.editor.clone(); + let view_id = self.view_id(); + let mut receiver = + tokio::spawn(async move { + editor.subscribe_view_changed(&view_id).await.unwrap() + }).await.unwrap(); match tokio::time::timeout(Duration::from_secs(2), receiver.recv()).await { - Ok(changed) => match changed.unwrap() { GridViewChanged::DidReceiveFilterResult(changed) => { - assert_eq!(changed.visible_rows.len(), visible_row_len, "visible rows not match"); - assert_eq!(changed.invisible_rows.len(), hide_row_len, "invisible rows not match"); - } }, + Ok(changed) => { + // + match changed.unwrap() { GridViewChanged::DidReceiveFilterResult(changed) => { + assert_eq!(changed.visible_rows.len(), visible_row_len, "visible rows not match"); + assert_eq!(changed.invisible_rows.len(), hide_row_len, "invisible rows not match"); + } } + }, Err(e) => { panic!("Process task timeout: {:?}", e); } } } FilterScript::AssertNumberOfVisibleRows { expected } => { - // - let grid = self.editor.get_grid().await.unwrap(); - let rows = grid.blocks.into_iter().map(|block| block.rows).flatten().collect::>(); - assert_eq!(rows.len(), expected); + let grid = self.editor.get_grid(&self.view_id()).await.unwrap(); + assert_eq!(grid.rows.len(), expected); } FilterScript::Wait { millisecond } => { tokio::time::sleep(Duration::from_millis(millisecond)).await; diff --git a/frontend/rust-lib/flowy-grid/tests/grid/filter_test/select_option_filter_test.rs b/frontend/rust-lib/flowy-grid/tests/grid/filter_test/select_option_filter_test.rs index fb654f887b..53c7962ece 100644 --- a/frontend/rust-lib/flowy-grid/tests/grid/filter_test/select_option_filter_test.rs +++ b/frontend/rust-lib/flowy-grid/tests/grid/filter_test/select_option_filter_test.rs @@ -1,13 +1,13 @@ use crate::grid::filter_test::script::FilterScript::*; use crate::grid::filter_test::script::GridFilterTest; -use flowy_grid::entities::{FieldType, SelectOptionCondition}; +use flowy_grid::entities::{FieldType, SelectOptionConditionPB}; #[tokio::test] async fn grid_filter_multi_select_is_empty_test() { let mut test = GridFilterTest::new().await; let scripts = vec![ CreateMultiSelectFilter { - condition: SelectOptionCondition::OptionIsEmpty, + condition: SelectOptionConditionPB::OptionIsEmpty, option_ids: vec![], }, AssertNumberOfVisibleRows { expected: 2 }, @@ -20,7 +20,7 @@ async fn grid_filter_multi_select_is_not_empty_test() { let mut test = GridFilterTest::new().await; let scripts = vec![ CreateMultiSelectFilter { - condition: SelectOptionCondition::OptionIsNotEmpty, + condition: SelectOptionConditionPB::OptionIsNotEmpty, option_ids: vec![], }, AssertNumberOfVisibleRows { expected: 3 }, @@ -35,7 +35,7 @@ async fn grid_filter_multi_select_is_test() { let mut options = test.get_multi_select_type_option(&field_rev.id); let scripts = vec![ CreateMultiSelectFilter { - condition: SelectOptionCondition::OptionIs, + condition: SelectOptionConditionPB::OptionIs, option_ids: vec![options.remove(0).id, options.remove(0).id], }, AssertNumberOfVisibleRows { expected: 3 }, @@ -50,7 +50,7 @@ async fn grid_filter_multi_select_is_test2() { let mut options = test.get_multi_select_type_option(&field_rev.id); let scripts = vec![ CreateMultiSelectFilter { - condition: SelectOptionCondition::OptionIs, + condition: SelectOptionConditionPB::OptionIs, option_ids: vec![options.remove(1).id], }, AssertNumberOfVisibleRows { expected: 3 }, @@ -63,7 +63,7 @@ async fn grid_filter_single_select_is_empty_test() { let mut test = GridFilterTest::new().await; let scripts = vec![ CreateSingleSelectFilter { - condition: SelectOptionCondition::OptionIsEmpty, + condition: SelectOptionConditionPB::OptionIsEmpty, option_ids: vec![], }, AssertNumberOfVisibleRows { expected: 2 }, @@ -78,7 +78,7 @@ async fn grid_filter_single_select_is_test() { let mut options = test.get_single_select_type_option(&field_rev.id).options; let scripts = vec![ CreateSingleSelectFilter { - condition: SelectOptionCondition::OptionIs, + condition: SelectOptionConditionPB::OptionIs, option_ids: vec![options.remove(0).id], }, AssertNumberOfVisibleRows { expected: 2 }, @@ -94,7 +94,7 @@ async fn grid_filter_single_select_is_test2() { let option = options.remove(0); let scripts = vec![ CreateSingleSelectFilter { - condition: SelectOptionCondition::OptionIs, + condition: SelectOptionConditionPB::OptionIs, option_ids: vec![option.id.clone()], }, AssertNumberOfVisibleRows { expected: 2 }, diff --git a/frontend/rust-lib/flowy-grid/tests/grid/filter_test/text_filter_test.rs b/frontend/rust-lib/flowy-grid/tests/grid/filter_test/text_filter_test.rs index acbcf267cb..7e07b3cd01 100644 --- a/frontend/rust-lib/flowy-grid/tests/grid/filter_test/text_filter_test.rs +++ b/frontend/rust-lib/flowy-grid/tests/grid/filter_test/text_filter_test.rs @@ -1,6 +1,6 @@ use crate::grid::filter_test::script::FilterScript::*; use crate::grid::filter_test::script::*; -use flowy_grid::entities::{AlterFilterPayloadPB, FieldType, TextFilterCondition, TextFilterPB}; +use flowy_grid::entities::{AlterFilterPayloadPB, FieldType, TextFilterConditionPB, TextFilterPB}; use flowy_grid::services::filter::FilterType; #[tokio::test] @@ -8,7 +8,7 @@ async fn grid_filter_text_is_empty_test() { let mut test = GridFilterTest::new().await; let scripts = vec![ CreateTextFilter { - condition: TextFilterCondition::TextIsEmpty, + condition: TextFilterConditionPB::TextIsEmpty, content: "".to_string(), }, AssertFilterCount { count: 1 }, @@ -26,7 +26,7 @@ async fn grid_filter_text_is_not_empty_test() { // Only one row's text of the initial rows is "" let scripts = vec![ CreateTextFilter { - condition: TextFilterCondition::TextIsNotEmpty, + condition: TextFilterConditionPB::TextIsNotEmpty, content: "".to_string(), }, AssertFilterCount { count: 1 }, @@ -58,7 +58,7 @@ async fn grid_filter_is_text_test() { // Only one row's text of the initial rows is "A" let scripts = vec![ CreateTextFilter { - condition: TextFilterCondition::Is, + condition: TextFilterConditionPB::Is, content: "A".to_string(), }, AssertFilterChanged { @@ -74,7 +74,7 @@ async fn grid_filter_contain_text_test() { let mut test = GridFilterTest::new().await; let scripts = vec![ CreateTextFilter { - condition: TextFilterCondition::Contains, + condition: TextFilterConditionPB::Contains, content: "A".to_string(), }, AssertFilterChanged { @@ -90,7 +90,7 @@ async fn grid_filter_contain_text_test2() { let mut test = GridFilterTest::new().await; let scripts = vec![ CreateTextFilter { - condition: TextFilterCondition::Contains, + condition: TextFilterConditionPB::Contains, content: "A".to_string(), }, AssertFilterChanged { @@ -115,7 +115,7 @@ async fn grid_filter_does_not_contain_text_test() { // None of the initial rows contains the text "AB" let scripts = vec![ CreateTextFilter { - condition: TextFilterCondition::DoesNotContain, + condition: TextFilterConditionPB::DoesNotContain, content: "AB".to_string(), }, AssertFilterChanged { @@ -131,7 +131,7 @@ async fn grid_filter_start_with_text_test() { let mut test = GridFilterTest::new().await; let scripts = vec![ CreateTextFilter { - condition: TextFilterCondition::StartsWith, + condition: TextFilterConditionPB::StartsWith, content: "A".to_string(), }, AssertFilterChanged { @@ -147,7 +147,7 @@ async fn grid_filter_ends_with_text_test() { let mut test = GridFilterTest::new().await; let scripts = vec![ CreateTextFilter { - condition: TextFilterCondition::EndsWith, + condition: TextFilterConditionPB::EndsWith, content: "A".to_string(), }, AssertNumberOfVisibleRows { expected: 2 }, @@ -160,7 +160,7 @@ async fn grid_update_text_filter_test() { let mut test = GridFilterTest::new().await; let scripts = vec![ CreateTextFilter { - condition: TextFilterCondition::EndsWith, + condition: TextFilterConditionPB::EndsWith, content: "A".to_string(), }, AssertNumberOfVisibleRows { expected: 2 }, @@ -172,7 +172,7 @@ async fn grid_update_text_filter_test() { let scripts = vec![ UpdateTextFilter { filter, - condition: TextFilterCondition::Is, + condition: TextFilterConditionPB::Is, content: "A".to_string(), }, AssertNumberOfVisibleRows { expected: 1 }, @@ -186,10 +186,10 @@ async fn grid_filter_delete_test() { let mut test = GridFilterTest::new().await; let field_rev = test.get_first_field_rev(FieldType::RichText).clone(); let text_filter = TextFilterPB { - condition: TextFilterCondition::TextIsEmpty, + condition: TextFilterConditionPB::TextIsEmpty, content: "".to_string(), }; - let payload = AlterFilterPayloadPB::new(&field_rev, text_filter); + let payload = AlterFilterPayloadPB::new(&test.view_id(), &field_rev, text_filter); let scripts = vec![ InsertFilter { payload }, AssertFilterCount { count: 1 }, @@ -214,7 +214,7 @@ async fn grid_filter_update_empty_text_cell_test() { let mut test = GridFilterTest::new().await; let scripts = vec![ CreateTextFilter { - condition: TextFilterCondition::TextIsEmpty, + condition: TextFilterConditionPB::TextIsEmpty, content: "".to_string(), }, AssertFilterCount { count: 1 }, diff --git a/frontend/rust-lib/flowy-grid/tests/grid/grid_editor.rs b/frontend/rust-lib/flowy-grid/tests/grid/grid_editor.rs index 67fb69fde6..6eeb5743a5 100644 --- a/frontend/rust-lib/flowy-grid/tests/grid/grid_editor.rs +++ b/frontend/rust-lib/flowy-grid/tests/grid/grid_editor.rs @@ -30,7 +30,7 @@ pub struct GridEditorTest { pub block_meta_revs: Vec>, pub row_revs: Vec>, pub field_count: usize, - pub row_order_by_row_id: HashMap, + pub row_by_row_id: HashMap, } impl GridEditorTest { @@ -77,7 +77,7 @@ impl GridEditorTest { block_meta_revs, row_revs, field_count: FieldType::COUNT, - row_order_by_row_id: HashMap::default(), + row_by_row_id: HashMap::default(), } } diff --git a/shared-lib/flowy-sync/src/client_grid/view_revision_pad.rs b/shared-lib/flowy-sync/src/client_grid/view_revision_pad.rs index afa9b5fc9a..93e3c739dd 100644 --- a/shared-lib/flowy-sync/src/client_grid/view_revision_pad.rs +++ b/shared-lib/flowy-sync/src/client_grid/view_revision_pad.rs @@ -4,6 +4,7 @@ use flowy_http_model::revision::Revision; use flowy_http_model::util::md5; use grid_rev_model::{ FieldRevision, FieldTypeRevision, FilterRevision, GridViewRevision, GroupConfigurationRevision, LayoutRevision, + SortRevision, }; use lib_ot::core::{DeltaBuilder, DeltaOperations, EmptyAttributes, OperationTransform}; use std::sync::Arc; @@ -126,10 +127,78 @@ impl GridViewRevisionPad { }) } + pub fn get_all_sorts(&self, field_revs: &[Arc]) -> Vec> { + self.sorts.get_objects_by_field_revs(field_revs) + } + + /// For the moment, a field type only have one filter. + pub fn get_sorts(&self, field_id: &str, field_type_rev: &FieldTypeRevision) -> Vec> { + self.sorts.get_objects(field_id, field_type_rev).unwrap_or_default() + } + + pub fn get_sort( + &self, + field_id: &str, + field_type_rev: &FieldTypeRevision, + sort_id: &str, + ) -> Option> { + self.sorts + .get_object(field_id, field_type_rev, |sort| sort.id == sort_id) + } + + pub fn insert_sort( + &mut self, + sort_id: &str, + sort_rev: SortRevision, + ) -> CollaborateResult> { + self.modify(|view| { + let field_type = sort_rev.field_type; + view.sorts.add_object(sort_id, &field_type, sort_rev); + Ok(Some(())) + }) + } + + pub fn update_sort( + &mut self, + field_id: &str, + sort_rev: SortRevision, + ) -> CollaborateResult> { + self.modify(|view| { + if let Some(sort) = view + .sorts + .get_mut_object(field_id, &sort_rev.field_type, |sort| sort.id == sort_rev.id) + { + let sort = Arc::make_mut(sort); + sort.condition = sort_rev.condition; + Ok(Some(())) + } else { + Ok(None) + } + }) + } + + pub fn delete_sort>( + &mut self, + sort_id: &str, + field_id: &str, + field_type: T, + ) -> CollaborateResult> { + let field_type = field_type.into(); + self.modify(|view| { + if let Some(sorts) = view.sorts.get_mut_objects(field_id, &field_type) { + sorts.retain(|sort| sort.id != sort_id); + Ok(Some(())) + } else { + Ok(None) + } + }) + } + pub fn get_all_filters(&self, field_revs: &[Arc]) -> Vec> { self.filters.get_objects_by_field_revs(field_revs) } + /// For the moment, a field type only have one filter. pub fn get_filters(&self, field_id: &str, field_type_rev: &FieldTypeRevision) -> Vec> { self.filters.get_objects(field_id, field_type_rev).unwrap_or_default() } @@ -176,14 +245,15 @@ impl GridViewRevisionPad { }) } - pub fn delete_filter( + pub fn delete_filter>( &mut self, filter_id: &str, field_id: &str, - field_type: &FieldTypeRevision, + field_type: T, ) -> CollaborateResult> { + let field_type = field_type.into(); self.modify(|view| { - if let Some(filters) = view.filters.get_mut_objects(field_id, field_type) { + if let Some(filters) = view.filters.get_mut_objects(field_id, &field_type) { filters.retain(|filter| filter.id != filter_id); Ok(Some(())) } else { diff --git a/shared-lib/grid-rev-model/src/grid_setting_rev.rs b/shared-lib/grid-rev-model/src/grid_setting_rev.rs index 8e69f052ab..df665cbcfb 100644 --- a/shared-lib/grid-rev-model/src/grid_setting_rev.rs +++ b/shared-lib/grid-rev-model/src/grid_setting_rev.rs @@ -1,8 +1,7 @@ -use crate::{FieldRevision, FieldTypeRevision, FilterRevision, GroupConfigurationRevision}; +use crate::{FieldRevision, FieldTypeRevision, FilterRevision, GroupConfigurationRevision, SortRevision}; use indexmap::IndexMap; use nanoid::nanoid; use serde::{Deserialize, Serialize}; -use std::collections::HashMap; use std::fmt::Debug; use std::sync::Arc; @@ -20,10 +19,10 @@ pub fn gen_grid_sort_id() -> String { } pub type FilterConfiguration = Configuration; -pub type FilterConfigurationsByFieldId = HashMap>>; -// + pub type GroupConfiguration = Configuration; -pub type GroupConfigurationsByFieldId = HashMap>>; + +pub type SortConfiguration = Configuration; #[derive(Debug, Clone, Serialize, Deserialize, Default)] #[serde(transparent)] diff --git a/shared-lib/grid-rev-model/src/grid_view.rs b/shared-lib/grid-rev-model/src/grid_view.rs index aa4dac5dea..8f5c841d38 100644 --- a/shared-lib/grid-rev-model/src/grid_view.rs +++ b/shared-lib/grid-rev-model/src/grid_view.rs @@ -1,4 +1,4 @@ -use crate::{FilterConfiguration, GroupConfiguration}; +use crate::{FilterConfiguration, GroupConfiguration, SortConfiguration}; use nanoid::nanoid; use serde::{Deserialize, Serialize}; use serde_repr::*; @@ -41,10 +41,9 @@ pub struct GridViewRevision { #[serde(default)] pub groups: GroupConfiguration, - // // For the moment, we just use the order returned from the GridRevision - // #[allow(dead_code)] - // #[serde(skip, rename = "rows")] - // pub row_orders: Vec, + + #[serde(default)] + pub sorts: SortConfiguration, } impl GridViewRevision { @@ -55,7 +54,7 @@ impl GridViewRevision { layout, filters: Default::default(), groups: Default::default(), - // row_orders: vec![], + sorts: Default::default(), } } @@ -81,11 +80,12 @@ mod tests { layout: Default::default(), filters: Default::default(), groups: Default::default(), + sorts: Default::default(), }; let s = serde_json::to_string(&grid_view_revision).unwrap(); assert_eq!( s, - r#"{"view_id":"1","grid_id":"1","layout":0,"filters":[],"groups":[]}"# + r#"{"view_id":"1","grid_id":"1","layout":0,"filters":[],"groups":[],"sorts":[]}"# ); } } diff --git a/shared-lib/grid-rev-model/src/lib.rs b/shared-lib/grid-rev-model/src/lib.rs index 460370b86b..df852779b4 100644 --- a/shared-lib/grid-rev-model/src/lib.rs +++ b/shared-lib/grid-rev-model/src/lib.rs @@ -4,6 +4,7 @@ mod grid_rev; mod grid_setting_rev; mod grid_view; mod group_rev; +mod sort_rev; pub use filter_rev::*; pub use grid_block::*; @@ -11,3 +12,4 @@ pub use grid_rev::*; pub use grid_setting_rev::*; pub use grid_view::*; pub use group_rev::*; +pub use sort_rev::*; diff --git a/shared-lib/grid-rev-model/src/sort_rev.rs b/shared-lib/grid-rev-model/src/sort_rev.rs new file mode 100644 index 0000000000..5fed325fb1 --- /dev/null +++ b/shared-lib/grid-rev-model/src/sort_rev.rs @@ -0,0 +1,10 @@ +use crate::FieldTypeRevision; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq, Hash)] +pub struct SortRevision { + pub id: String, + pub field_id: String, + pub field_type: FieldTypeRevision, + pub condition: u8, +}