浏览代码

chore: refactor multi-select type option and add GroupPB

appflowy 2 年之前
父节点
当前提交
aae2d96a4f
共有 34 个文件被更改,包括 555 次插入239 次删除
  1. 20 0
      frontend/app_flowy/lib/plugins/board/application/group.dart
  2. 18 11
      frontend/app_flowy/lib/plugins/grid/application/field/type_option/multi_select_type_option.dart
  3. 195 0
      frontend/app_flowy/lib/plugins/grid/application/field/type_option/type_option_context.dart
  4. 2 2
      frontend/app_flowy/lib/plugins/grid/presentation/widgets/header/type_option/builder.dart
  5. 2 2
      frontend/app_flowy/lib/plugins/grid/presentation/widgets/header/type_option/multi_select.dart
  6. 1 0
      frontend/rust-lib/Cargo.lock
  7. 8 8
      frontend/rust-lib/flowy-grid/src/entities/filter_entities/util.rs
  8. 28 10
      frontend/rust-lib/flowy-grid/src/entities/group_entities/group.rs
  9. 3 3
      frontend/rust-lib/flowy-grid/src/entities/setting_entities.rs
  10. 11 0
      frontend/rust-lib/flowy-grid/src/event_handler.rs
  11. 6 1
      frontend/rust-lib/flowy-grid/src/event_map.rs
  12. 2 2
      frontend/rust-lib/flowy-grid/src/services/cell/cell_operation.rs
  13. 1 1
      frontend/rust-lib/flowy-grid/src/services/field/field_builder.rs
  14. 9 9
      frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/multi_select_type_option.rs
  15. 2 2
      frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/select_option.rs
  16. 1 1
      frontend/rust-lib/flowy-grid/src/services/field/type_options/text_type_option/text_type_option.rs
  17. 4 7
      frontend/rust-lib/flowy-grid/src/services/filter/filter_service.rs
  18. 2 2
      frontend/rust-lib/flowy-grid/src/services/filter/impls/select_option_filter.rs
  19. 8 3
      frontend/rust-lib/flowy-grid/src/services/grid_editor.rs
  20. 22 3
      frontend/rust-lib/flowy-grid/src/services/group/group_service.rs
  21. 8 7
      frontend/rust-lib/flowy-grid/src/services/setting/setting_builder.rs
  22. 2 2
      frontend/rust-lib/flowy-grid/tests/grid/block_test/util.rs
  23. 2 2
      frontend/rust-lib/flowy-grid/tests/grid/cell_test/test.rs
  24. 1 1
      frontend/rust-lib/flowy-grid/tests/grid/grid_editor.rs
  25. 3 3
      frontend/rust-lib/flowy-grid/tests/grid/grid_test.rs
  26. 1 0
      shared-lib/Cargo.lock
  27. 1 0
      shared-lib/flowy-grid-data-model/Cargo.toml
  28. 0 3
      shared-lib/flowy-grid-data-model/src/revision/filter_rev.rs
  29. 0 3
      shared-lib/flowy-grid-data-model/src/revision/grid_group.rs
  30. 129 85
      shared-lib/flowy-grid-data-model/src/revision/grid_setting_rev.rs
  31. 0 0
      shared-lib/flowy-grid-data-model/src/revision/grid_sort.rs
  32. 4 2
      shared-lib/flowy-grid-data-model/src/revision/mod.rs
  33. 0 1
      shared-lib/flowy-sync/src/client_folder/folder_pad.rs
  34. 59 63
      shared-lib/flowy-sync/src/client_grid/grid_revision_pad.rs

+ 20 - 0
frontend/app_flowy/lib/plugins/board/application/group.dart

@@ -0,0 +1,20 @@
+import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart';
+
+class BoardGroupService {
+  final String gridId;
+  GridFieldPB? groupField;
+
+  BoardGroupService(this.gridId);
+
+  void setGroupField(GridFieldPB field) {
+    groupField = field;
+  }
+}
+
+abstract class CanBeGroupField {
+  String get groupContent;
+}
+
+// class SingleSelectGroup extends CanBeGroupField {
+//   final SingleSelectTypeOptionContext typeOptionContext;
+// }

+ 18 - 11
frontend/app_flowy/lib/plugins/grid/application/field/type_option/multi_select_type_option.dart

@@ -4,22 +4,29 @@ import 'package:flowy_sdk/protobuf/flowy-grid/select_option.pb.dart';
 import 'dart:async';
 import 'select_option_type_option_bloc.dart';
 import 'type_option_context.dart';
-import 'type_option_data_controller.dart';
 import 'type_option_service.dart';
 import 'package:protobuf/protobuf.dart';
 
-class MultiSelectTypeOptionContext
-    extends TypeOptionContext<MultiSelectTypeOption> with ISelectOptionAction {
+class MultiSelectAction with ISelectOptionAction {
+  final String gridId;
+  final String fieldId;
   final TypeOptionFFIService service;
+  final MultiSelectTypeOptionContext typeOptionContext;
 
-  MultiSelectTypeOptionContext({
-    required MultiSelectTypeOptionWidgetDataParser dataParser,
-    required TypeOptionDataController dataController,
-  })  : service = TypeOptionFFIService(
-          gridId: dataController.gridId,
-          fieldId: dataController.field.id,
-        ),
-        super(dataParser: dataParser, dataController: dataController);
+  MultiSelectAction({
+    required this.gridId,
+    required this.fieldId,
+    required this.typeOptionContext,
+  }) : service = TypeOptionFFIService(
+          gridId: gridId,
+          fieldId: fieldId,
+        );
+
+  MultiSelectTypeOptionPB get typeOption => typeOptionContext.typeOption;
+
+  set typeOption(MultiSelectTypeOptionPB newTypeOption) {
+    typeOptionContext.typeOption = newTypeOption;
+  }
 
   @override
   List<SelectOptionPB> Function(SelectOptionPB) get deleteOption {

+ 195 - 0
frontend/app_flowy/lib/plugins/grid/application/field/type_option/type_option_context.dart

@@ -0,0 +1,195 @@
+import 'package:flowy_sdk/dispatch/dispatch.dart';
+import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';
+import 'package:flowy_sdk/protobuf/flowy-grid/checkbox_type_option.pb.dart';
+import 'package:flowy_sdk/protobuf/flowy-grid/date_type_option.pb.dart';
+import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart';
+import 'package:dartz/dartz.dart';
+import 'package:flowy_sdk/protobuf/flowy-grid/multi_select_type_option.pb.dart';
+import 'package:flowy_sdk/protobuf/flowy-grid/number_type_option.pb.dart';
+import 'package:flowy_sdk/protobuf/flowy-grid/single_select_type_option.pb.dart';
+import 'package:flowy_sdk/protobuf/flowy-grid/text_type_option.pb.dart';
+import 'package:flowy_sdk/protobuf/flowy-grid/url_type_option.pb.dart';
+import 'package:protobuf/protobuf.dart';
+
+import 'type_option_data_controller.dart';
+
+abstract class TypeOptionDataParser<T> {
+  T fromBuffer(List<int> buffer);
+}
+
+// Number
+typedef NumberTypeOptionContext = TypeOptionContext<NumberTypeOption>;
+
+class NumberTypeOptionWidgetDataParser
+    extends TypeOptionDataParser<NumberTypeOption> {
+  @override
+  NumberTypeOption fromBuffer(List<int> buffer) {
+    return NumberTypeOption.fromBuffer(buffer);
+  }
+}
+
+// RichText
+typedef RichTextTypeOptionContext = TypeOptionContext<RichTextTypeOption>;
+
+class RichTextTypeOptionWidgetDataParser
+    extends TypeOptionDataParser<RichTextTypeOption> {
+  @override
+  RichTextTypeOption fromBuffer(List<int> buffer) {
+    return RichTextTypeOption.fromBuffer(buffer);
+  }
+}
+
+// Checkbox
+typedef CheckboxTypeOptionContext = TypeOptionContext<CheckboxTypeOption>;
+
+class CheckboxTypeOptionWidgetDataParser
+    extends TypeOptionDataParser<CheckboxTypeOption> {
+  @override
+  CheckboxTypeOption fromBuffer(List<int> buffer) {
+    return CheckboxTypeOption.fromBuffer(buffer);
+  }
+}
+
+// URL
+typedef URLTypeOptionContext = TypeOptionContext<URLTypeOption>;
+
+class URLTypeOptionWidgetDataParser
+    extends TypeOptionDataParser<URLTypeOption> {
+  @override
+  URLTypeOption fromBuffer(List<int> buffer) {
+    return URLTypeOption.fromBuffer(buffer);
+  }
+}
+
+// Date
+typedef DateTypeOptionContext = TypeOptionContext<DateTypeOption>;
+
+class DateTypeOptionDataParser extends TypeOptionDataParser<DateTypeOption> {
+  @override
+  DateTypeOption fromBuffer(List<int> buffer) {
+    return DateTypeOption.fromBuffer(buffer);
+  }
+}
+
+// SingleSelect
+typedef SingleSelectTypeOptionContext
+    = TypeOptionContext<SingleSelectTypeOptionPB>;
+
+class SingleSelectTypeOptionWidgetDataParser
+    extends TypeOptionDataParser<SingleSelectTypeOptionPB> {
+  @override
+  SingleSelectTypeOptionPB fromBuffer(List<int> buffer) {
+    return SingleSelectTypeOptionPB.fromBuffer(buffer);
+  }
+}
+
+// Multi-select
+typedef MultiSelectTypeOptionContext
+    = TypeOptionContext<MultiSelectTypeOptionPB>;
+
+class MultiSelectTypeOptionWidgetDataParser
+    extends TypeOptionDataParser<MultiSelectTypeOptionPB> {
+  @override
+  MultiSelectTypeOptionPB fromBuffer(List<int> buffer) {
+    return MultiSelectTypeOptionPB.fromBuffer(buffer);
+  }
+}
+
+class TypeOptionContext<T extends GeneratedMessage> {
+  T? _typeOptionObject;
+  final TypeOptionDataParser<T> dataParser;
+  final TypeOptionDataController _dataController;
+
+  TypeOptionContext({
+    required this.dataParser,
+    required TypeOptionDataController dataController,
+  }) : _dataController = dataController;
+
+  String get gridId => _dataController.gridId;
+
+  String get fieldId => _dataController.field.id;
+
+  Future<void> loadTypeOptionData({
+    required void Function(T) onCompleted,
+    required void Function(FlowyError) onError,
+  }) async {
+    await _dataController.loadTypeOptionData().then((result) {
+      result.fold((l) => null, (err) => onError(err));
+    });
+
+    onCompleted(typeOption);
+  }
+
+  T get typeOption {
+    if (_typeOptionObject != null) {
+      return _typeOptionObject!;
+    }
+
+    final T object = _dataController.getTypeOption(dataParser);
+    _typeOptionObject = object;
+    return object;
+  }
+
+  set typeOption(T typeOption) {
+    _dataController.typeOptionData = typeOption.writeToBuffer();
+    _typeOptionObject = typeOption;
+  }
+}
+
+abstract class TypeOptionFieldDelegate {
+  void onFieldChanged(void Function(String) callback);
+  void dispose();
+}
+
+abstract class IFieldTypeOptionLoader {
+  String get gridId;
+  Future<Either<FieldTypeOptionDataPB, FlowyError>> load();
+
+  Future<Either<FieldTypeOptionDataPB, FlowyError>> switchToField(
+      String fieldId, FieldType fieldType) {
+    final payload = EditFieldPayloadPB.create()
+      ..gridId = gridId
+      ..fieldId = fieldId
+      ..fieldType = fieldType;
+
+    return GridEventSwitchToField(payload).send();
+  }
+}
+
+class NewFieldTypeOptionLoader extends IFieldTypeOptionLoader {
+  @override
+  final String gridId;
+  NewFieldTypeOptionLoader({
+    required this.gridId,
+  });
+
+  @override
+  Future<Either<FieldTypeOptionDataPB, FlowyError>> load() {
+    final payload = CreateFieldPayloadPB.create()
+      ..gridId = gridId
+      ..fieldType = FieldType.RichText;
+
+    return GridEventCreateFieldTypeOption(payload).send();
+  }
+}
+
+class FieldTypeOptionLoader extends IFieldTypeOptionLoader {
+  @override
+  final String gridId;
+  final GridFieldPB field;
+
+  FieldTypeOptionLoader({
+    required this.gridId,
+    required this.field,
+  });
+
+  @override
+  Future<Either<FieldTypeOptionDataPB, FlowyError>> load() {
+    final payload = GridFieldTypeOptionIdPB.create()
+      ..gridId = gridId
+      ..fieldId = field.id
+      ..fieldType = field.fieldType;
+
+    return GridEventGetFieldTypeOption(payload).send();
+  }
+}

+ 2 - 2
frontend/app_flowy/lib/plugins/grid/presentation/widgets/header/type_option/builder.dart

@@ -92,11 +92,11 @@ TypeOptionWidgetBuilder makeTypeOptionWidgetBuilder({
       );
     case FieldType.MultiSelect:
       return MultiSelectTypeOptionWidgetBuilder(
-        makeTypeOptionContextWithDataController<MultiSelectTypeOption>(
+        makeTypeOptionContextWithDataController<MultiSelectTypeOptionPB>(
           gridId: gridId,
           fieldType: fieldType,
           dataController: dataController,
-        ) as MultiSelectTypeOptionContext,
+        ),
         overlayDelegate,
       );
     case FieldType.Number:

+ 2 - 2
frontend/app_flowy/lib/plugins/grid/presentation/widgets/header/type_option/multi_select.dart

@@ -9,7 +9,7 @@ class MultiSelectTypeOptionWidgetBuilder extends TypeOptionWidgetBuilder {
   final MultiSelectTypeOptionWidget _widget;
 
   MultiSelectTypeOptionWidgetBuilder(
-    MultiSelectTypeOptionContext typeOptionContext,
+    MultiSelectAction typeOptionContext,
     TypeOptionOverlayDelegate overlayDelegate,
   ) : _widget = MultiSelectTypeOptionWidget(
           typeOptionContext: typeOptionContext,
@@ -21,7 +21,7 @@ class MultiSelectTypeOptionWidgetBuilder extends TypeOptionWidgetBuilder {
 }
 
 class MultiSelectTypeOptionWidget extends TypeOptionWidget {
-  final MultiSelectTypeOptionContext typeOptionContext;
+  final MultiSelectAction typeOptionContext;
   final TypeOptionOverlayDelegate overlayDelegate;
 
   const MultiSelectTypeOptionWidget({

+ 1 - 0
frontend/rust-lib/Cargo.lock

@@ -981,6 +981,7 @@ dependencies = [
  "serde",
  "serde_json",
  "serde_repr",
+ "tracing",
 ]
 
 [[package]]

+ 8 - 8
frontend/rust-lib/flowy-grid/src/entities/filter_entities/util.rs

@@ -11,33 +11,33 @@ use std::convert::TryInto;
 use std::sync::Arc;
 
 #[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)]
-pub struct GridFilter {
+pub struct GridFilterConfiguration {
     #[pb(index = 1)]
     pub id: String,
 }
 
 #[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)]
-pub struct RepeatedGridFilterPB {
+pub struct RepeatedGridConfigurationFilterPB {
     #[pb(index = 1)]
-    pub items: Vec<GridFilter>,
+    pub items: Vec<GridFilterConfiguration>,
 }
 
-impl std::convert::From<&GridFilterRevision> for GridFilter {
+impl std::convert::From<&GridFilterRevision> for GridFilterConfiguration {
     fn from(rev: &GridFilterRevision) -> Self {
         Self { id: rev.id.clone() }
     }
 }
 
-impl std::convert::From<Vec<Arc<GridFilterRevision>>> for RepeatedGridFilterPB {
+impl std::convert::From<Vec<Arc<GridFilterRevision>>> for RepeatedGridConfigurationFilterPB {
     fn from(revs: Vec<Arc<GridFilterRevision>>) -> Self {
-        RepeatedGridFilterPB {
+        RepeatedGridConfigurationFilterPB {
             items: revs.into_iter().map(|rev| rev.as_ref().into()).collect(),
         }
     }
 }
 
-impl std::convert::From<Vec<GridFilter>> for RepeatedGridFilterPB {
-    fn from(items: Vec<GridFilter>) -> Self {
+impl std::convert::From<Vec<GridFilterConfiguration>> for RepeatedGridConfigurationFilterPB {
+    fn from(items: Vec<GridFilterConfiguration>) -> Self {
         Self { items }
     }
 }

+ 28 - 10
frontend/rust-lib/flowy-grid/src/entities/group_entities/group.rs

@@ -1,4 +1,4 @@
-use crate::entities::FieldType;
+use crate::entities::{FieldType, GridRowPB};
 use flowy_derive::ProtoBuf;
 use flowy_error::ErrorCode;
 use flowy_grid_data_model::parser::NotEmptyStr;
@@ -8,7 +8,7 @@ use std::convert::TryInto;
 use std::sync::Arc;
 
 #[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)]
-pub struct GridGroupPB {
+pub struct GridGroupConfigurationPB {
     #[pb(index = 1)]
     pub id: String,
 
@@ -19,9 +19,9 @@ pub struct GridGroupPB {
     pub sub_group_field_id: Option<String>,
 }
 
-impl std::convert::From<&GridGroupRevision> for GridGroupPB {
+impl std::convert::From<&GridGroupRevision> for GridGroupConfigurationPB {
     fn from(rev: &GridGroupRevision) -> Self {
-        GridGroupPB {
+        GridGroupConfigurationPB {
             id: rev.id.clone(),
             group_field_id: rev.field_id.clone(),
             sub_group_field_id: rev.sub_field_id.clone(),
@@ -29,21 +29,39 @@ impl std::convert::From<&GridGroupRevision> for GridGroupPB {
     }
 }
 
-#[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)]
+#[derive(ProtoBuf, Debug, Default, Clone)]
 pub struct RepeatedGridGroupPB {
     #[pb(index = 1)]
-    pub items: Vec<GridGroupPB>,
+    groups: Vec<GroupPB>,
+}
+
+#[derive(ProtoBuf, Debug, Default, Clone)]
+pub struct GroupPB {
+    #[pb(index = 1)]
+    pub group_id: String,
+
+    #[pb(index = 2)]
+    pub desc: String,
+
+    #[pb(index = 3)]
+    pub rows: Vec<GridRowPB>,
+}
+
+#[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)]
+pub struct RepeatedGridGroupConfigurationPB {
+    #[pb(index = 1)]
+    pub items: Vec<GridGroupConfigurationPB>,
 }
 
-impl std::convert::From<Vec<GridGroupPB>> for RepeatedGridGroupPB {
-    fn from(items: Vec<GridGroupPB>) -> Self {
+impl std::convert::From<Vec<GridGroupConfigurationPB>> for RepeatedGridGroupConfigurationPB {
+    fn from(items: Vec<GridGroupConfigurationPB>) -> Self {
         Self { items }
     }
 }
 
-impl std::convert::From<Vec<Arc<GridGroupRevision>>> for RepeatedGridGroupPB {
+impl std::convert::From<Vec<Arc<GridGroupRevision>>> for RepeatedGridGroupConfigurationPB {
     fn from(revs: Vec<Arc<GridGroupRevision>>) -> Self {
-        RepeatedGridGroupPB {
+        RepeatedGridGroupConfigurationPB {
             items: revs.iter().map(|rev| rev.as_ref().into()).collect(),
         }
     }

+ 3 - 3
frontend/rust-lib/flowy-grid/src/entities/setting_entities.rs

@@ -1,6 +1,6 @@
 use crate::entities::{
     CreateGridFilterPayloadPB, CreateGridGroupPayloadPB, CreateGridSortPayloadPB, DeleteFilterPayloadPB,
-    DeleteGroupPayloadPB, RepeatedGridFilterPB, RepeatedGridGroupPB, RepeatedGridSortPB,
+    DeleteGroupPayloadPB, RepeatedGridConfigurationFilterPB, RepeatedGridGroupConfigurationPB, RepeatedGridSortPB,
 };
 use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
 use flowy_error::ErrorCode;
@@ -22,10 +22,10 @@ pub struct GridSettingPB {
     pub current_layout_type: GridLayoutType,
 
     #[pb(index = 3)]
-    pub filters_by_field_id: HashMap<String, RepeatedGridFilterPB>,
+    pub filter_configuration_by_field_id: HashMap<String, RepeatedGridConfigurationFilterPB>,
 
     #[pb(index = 4)]
-    pub groups_by_field_id: HashMap<String, RepeatedGridGroupPB>,
+    pub group_configuration_by_field_id: HashMap<String, RepeatedGridGroupConfigurationPB>,
 
     #[pb(index = 5)]
     pub sorts_by_field_id: HashMap<String, RepeatedGridSortPB>,

+ 11 - 0
frontend/rust-lib/flowy-grid/src/event_handler.rs

@@ -405,3 +405,14 @@ pub(crate) async fn update_date_cell_handler(
     let _ = editor.update_cell(params.into()).await?;
     Ok(())
 }
+
+#[tracing::instrument(level = "trace", skip_all, err)]
+pub(crate) async fn get_group_handler(
+    data: Data<GridIdPB>,
+    manager: AppData<Arc<GridManager>>,
+) -> DataResult<RepeatedGridGroupPB, FlowyError> {
+    let params: GridIdPB = data.into_inner();
+    let editor = manager.get_grid_editor(&params.value)?;
+    let group = editor.get_group().await?;
+    data_result(group)
+}

+ 6 - 1
frontend/rust-lib/flowy-grid/src/event_map.rs

@@ -37,7 +37,9 @@ pub fn create(grid_manager: Arc<GridManager>) -> Module {
         .event(GridEvent::GetSelectOptionCellData, get_select_option_handler)
         .event(GridEvent::UpdateSelectOptionCell, update_select_option_cell_handler)
         // Date
-        .event(GridEvent::UpdateDateCell, update_date_cell_handler);
+        .event(GridEvent::UpdateDateCell, update_date_cell_handler)
+        // Group
+        .event(GridEvent::GetGroup, update_date_cell_handler);
 
     module
 }
@@ -204,4 +206,7 @@ pub enum GridEvent {
     /// will be used by the `update_cell` function.
     #[event(input = "DateChangesetPayloadPB")]
     UpdateDateCell = 80,
+
+    #[event(input = "GridIdPB", output = "RepeatedGridGroupPB")]
+    GetGroup = 100,
 }

+ 2 - 2
frontend/rust-lib/flowy-grid/src/services/cell/cell_operation.rs

@@ -61,7 +61,7 @@ pub fn apply_cell_data_changeset<C: ToString, T: AsRef<FieldRevision>>(
         FieldType::SingleSelect => {
             SingleSelectTypeOptionPB::from(field_rev).apply_changeset(changeset.into(), cell_rev)
         }
-        FieldType::MultiSelect => MultiSelectTypeOption::from(field_rev).apply_changeset(changeset.into(), cell_rev),
+        FieldType::MultiSelect => MultiSelectTypeOptionPB::from(field_rev).apply_changeset(changeset.into(), cell_rev),
         FieldType::Checkbox => CheckboxTypeOption::from(field_rev).apply_changeset(changeset.into(), cell_rev),
         FieldType::URL => URLTypeOption::from(field_rev).apply_changeset(changeset.into(), cell_rev),
     }?;
@@ -109,7 +109,7 @@ pub fn try_decode_cell_data(
                 .get_type_option_entry::<SingleSelectTypeOptionPB>(field_type)?
                 .decode_cell_data(cell_data.into(), s_field_type, field_rev),
             FieldType::MultiSelect => field_rev
-                .get_type_option_entry::<MultiSelectTypeOption>(field_type)?
+                .get_type_option_entry::<MultiSelectTypeOptionPB>(field_type)?
                 .decode_cell_data(cell_data.into(), s_field_type, field_rev),
             FieldType::Checkbox => field_rev
                 .get_type_option_entry::<CheckboxTypeOption>(field_type)?

+ 1 - 1
frontend/rust-lib/flowy-grid/src/services/field/field_builder.rs

@@ -94,7 +94,7 @@ pub fn default_type_option_builder_from_type(field_type: &FieldType) -> Box<dyn
         FieldType::Number => NumberTypeOption::default().into(),
         FieldType::DateTime => DateTypeOption::default().into(),
         FieldType::SingleSelect => SingleSelectTypeOptionPB::default().into(),
-        FieldType::MultiSelect => MultiSelectTypeOption::default().into(),
+        FieldType::MultiSelect => MultiSelectTypeOptionPB::default().into(),
         FieldType::Checkbox => CheckboxTypeOption::default().into(),
         FieldType::URL => URLTypeOption::default().into(),
     };

+ 9 - 9
frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/multi_select_type_option.rs

@@ -14,16 +14,16 @@ use serde::{Deserialize, Serialize};
 
 // Multiple select
 #[derive(Clone, Debug, Default, Serialize, Deserialize, ProtoBuf)]
-pub struct MultiSelectTypeOption {
+pub struct MultiSelectTypeOptionPB {
     #[pb(index = 1)]
     pub options: Vec<SelectOptionPB>,
 
     #[pb(index = 2)]
     pub disable_color: bool,
 }
-impl_type_option!(MultiSelectTypeOption, FieldType::MultiSelect);
+impl_type_option!(MultiSelectTypeOptionPB, FieldType::MultiSelect);
 
-impl SelectOptionOperation for MultiSelectTypeOption {
+impl SelectOptionOperation for MultiSelectTypeOptionPB {
     fn selected_select_option(&self, cell_data: CellData<SelectOptionIds>) -> SelectOptionCellDataPB {
         let select_options = make_selected_select_options(cell_data, &self.options);
         SelectOptionCellDataPB {
@@ -41,7 +41,7 @@ impl SelectOptionOperation for MultiSelectTypeOption {
     }
 }
 
-impl CellDataOperation<SelectOptionIds, SelectOptionCellChangeset> for MultiSelectTypeOption {
+impl CellDataOperation<SelectOptionIds, SelectOptionCellChangeset> for MultiSelectTypeOptionPB {
     fn decode_cell_data(
         &self,
         cell_data: CellData<SelectOptionIds>,
@@ -93,9 +93,9 @@ impl CellDataOperation<SelectOptionIds, SelectOptionCellChangeset> for MultiSele
 }
 
 #[derive(Default)]
-pub struct MultiSelectTypeOptionBuilder(MultiSelectTypeOption);
+pub struct MultiSelectTypeOptionBuilder(MultiSelectTypeOptionPB);
 impl_into_box_type_option_builder!(MultiSelectTypeOptionBuilder);
-impl_builder_from_json_str_and_from_bytes!(MultiSelectTypeOptionBuilder, MultiSelectTypeOption);
+impl_builder_from_json_str_and_from_bytes!(MultiSelectTypeOptionBuilder, MultiSelectTypeOptionPB);
 impl MultiSelectTypeOptionBuilder {
     pub fn option(mut self, opt: SelectOptionPB) -> Self {
         self.0.options.push(opt);
@@ -118,7 +118,7 @@ mod tests {
     use crate::services::cell::CellDataOperation;
     use crate::services::field::type_options::selection_type_option::*;
     use crate::services::field::FieldBuilder;
-    use crate::services::field::{MultiSelectTypeOption, MultiSelectTypeOptionBuilder};
+    use crate::services::field::{MultiSelectTypeOptionBuilder, MultiSelectTypeOptionPB};
     use flowy_grid_data_model::revision::FieldRevision;
 
     #[test]
@@ -136,7 +136,7 @@ mod tests {
             .visibility(true)
             .build();
 
-        let type_option = MultiSelectTypeOption::from(&field_rev);
+        let type_option = MultiSelectTypeOptionPB::from(&field_rev);
 
         let option_ids = vec![google_option.id.clone(), facebook_option.id.clone()].join(SELECTION_IDS_SEPARATOR);
         let data = SelectOptionCellChangeset::from_insert(&option_ids).to_str();
@@ -170,7 +170,7 @@ mod tests {
 
     fn assert_multi_select_options(
         cell_data: String,
-        type_option: &MultiSelectTypeOption,
+        type_option: &MultiSelectTypeOptionPB,
         field_rev: &FieldRevision,
         expected: Vec<SelectOptionPB>,
     ) {

+ 2 - 2
frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/select_option.rs

@@ -1,6 +1,6 @@
 use crate::entities::{CellChangesetPB, FieldType, GridCellIdPB, GridCellIdParams};
 use crate::services::cell::{CellBytes, CellBytesParser, CellData, CellDisplayable, FromCellChangeset, FromCellString};
-use crate::services::field::{MultiSelectTypeOption, SingleSelectTypeOptionPB};
+use crate::services::field::{MultiSelectTypeOptionPB, SingleSelectTypeOptionPB};
 use bytes::Bytes;
 use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
 use flowy_error::{internal_error, ErrorCode, FlowyResult};
@@ -130,7 +130,7 @@ pub fn select_option_operation(field_rev: &FieldRevision) -> FlowyResult<Box<dyn
             Ok(Box::new(type_option))
         }
         FieldType::MultiSelect => {
-            let type_option = MultiSelectTypeOption::from(field_rev);
+            let type_option = MultiSelectTypeOptionPB::from(field_rev);
             Ok(Box::new(type_option))
         }
         ty => {

+ 1 - 1
frontend/rust-lib/flowy-grid/src/services/field/type_options/text_type_option/text_type_option.rs

@@ -159,7 +159,7 @@ mod tests {
             .option(google_option.clone())
             .option(facebook_option.clone());
         let multi_select_field_rev = FieldBuilder::new(multi_select).build();
-        let multi_type_option = MultiSelectTypeOption::from(&multi_select_field_rev);
+        let multi_type_option = MultiSelectTypeOptionPB::from(&multi_select_field_rev);
         let cell_data = multi_type_option
             .apply_changeset(cell_data_changeset.into(), None)
             .unwrap();

+ 4 - 7
frontend/rust-lib/flowy-grid/src/services/filter/filter_service.rs

@@ -3,7 +3,7 @@ use crate::entities::{FieldType, GridBlockChangesetPB};
 use crate::services::block_manager::GridBlockManager;
 use crate::services::cell::{AnyCellData, CellFilterOperation};
 use crate::services::field::{
-    CheckboxTypeOption, DateTypeOption, MultiSelectTypeOption, NumberTypeOption, RichTextTypeOption,
+    CheckboxTypeOption, DateTypeOption, MultiSelectTypeOptionPB, NumberTypeOption, RichTextTypeOption,
     SingleSelectTypeOptionPB, URLTypeOption,
 };
 use crate::services::filter::filter_cache::{
@@ -22,8 +22,6 @@ use std::sync::Arc;
 use tokio::sync::RwLock;
 
 pub(crate) struct GridFilterService {
-    #[allow(dead_code)]
-    grid_id: String,
     scheduler: Arc<dyn GridServiceTaskScheduler>,
     grid_pad: Arc<RwLock<GridRevisionPad>>,
     block_manager: Arc<GridBlockManager>,
@@ -36,12 +34,10 @@ impl GridFilterService {
         block_manager: Arc<GridBlockManager>,
         scheduler: S,
     ) -> Self {
-        let grid_id = grid_pad.read().await.grid_id();
         let scheduler = Arc::new(scheduler);
         let filter_cache = FilterCache::from_grid_pad(&grid_pad).await;
         let filter_result_cache = FilterResultCache::new();
         Self {
-            grid_id,
             grid_pad,
             block_manager,
             scheduler,
@@ -134,8 +130,9 @@ impl GridFilterService {
     }
 
     async fn notify(&self, changesets: Vec<GridBlockChangesetPB>) {
+        let grid_id = self.grid_pad.read().await.grid_id();
         for changeset in changesets {
-            send_dart_notification(&self.grid_id, GridNotification::DidUpdateGridBlock)
+            send_dart_notification(&grid_id, GridNotification::DidUpdateGridBlock)
                 .payload(changeset)
                 .send();
         }
@@ -217,7 +214,7 @@ fn filter_cell(
         FieldType::MultiSelect => filter_cache.select_option_filter.get(&filter_id).and_then(|filter| {
             Some(
                 field_rev
-                    .get_type_option_entry::<MultiSelectTypeOption>(field_type_rev)?
+                    .get_type_option_entry::<MultiSelectTypeOptionPB>(field_type_rev)?
                     .apply_filter(any_cell_data, filter.value())
                     .ok(),
             )

+ 2 - 2
frontend/rust-lib/flowy-grid/src/services/filter/impls/select_option_filter.rs

@@ -2,7 +2,7 @@
 
 use crate::entities::{GridSelectOptionFilter, SelectOptionCondition};
 use crate::services::cell::{AnyCellData, CellFilterOperation};
-use crate::services::field::{MultiSelectTypeOption, SingleSelectTypeOptionPB};
+use crate::services::field::{MultiSelectTypeOptionPB, SingleSelectTypeOptionPB};
 use crate::services::field::{SelectOptionOperation, SelectedSelectOptions};
 use flowy_error::FlowyResult;
 
@@ -39,7 +39,7 @@ impl GridSelectOptionFilter {
     }
 }
 
-impl CellFilterOperation<GridSelectOptionFilter> for MultiSelectTypeOption {
+impl CellFilterOperation<GridSelectOptionFilter> for MultiSelectTypeOptionPB {
     fn apply_filter(&self, any_cell_data: AnyCellData, filter: &GridSelectOptionFilter) -> FlowyResult<bool> {
         if !any_cell_data.is_multi_select() {
             return Ok(true);

+ 8 - 3
frontend/rust-lib/flowy-grid/src/services/grid_editor.rs

@@ -61,7 +61,8 @@ impl GridRevisionEditor {
         let block_manager = Arc::new(GridBlockManager::new(grid_id, &user, block_meta_revs, persistence).await?);
         let filter_service =
             Arc::new(GridFilterService::new(grid_pad.clone(), block_manager.clone(), task_scheduler.clone()).await);
-        let group_service = Arc::new(GridGroupService::new());
+        let group_service =
+            Arc::new(GridGroupService::new(grid_pad.clone(), block_manager.clone(), task_scheduler.clone()).await);
         let editor = Arc::new(Self {
             grid_id: grid_id.to_owned(),
             user,
@@ -455,14 +456,14 @@ impl GridRevisionEditor {
         Ok(grid_setting)
     }
 
-    pub async fn get_grid_filter(&self, layout_type: &GridLayoutType) -> FlowyResult<Vec<GridFilter>> {
+    pub async fn get_grid_filter(&self, layout_type: &GridLayoutType) -> FlowyResult<Vec<GridFilterConfiguration>> {
         let read_guard = self.grid_pad.read().await;
         let layout_rev = layout_type.clone().into();
         match read_guard.get_filters(Some(&layout_rev), None) {
             Some(filter_revs) => Ok(filter_revs
                 .iter()
                 .map(|filter_rev| filter_rev.as_ref().into())
-                .collect::<Vec<GridFilter>>()),
+                .collect::<Vec<GridFilterConfiguration>>()),
             None => Ok(vec![]),
         }
     }
@@ -561,6 +562,10 @@ impl GridRevisionEditor {
         })
     }
 
+    pub async fn get_group(&self) -> FlowyResult<RepeatedGridGroupPB> {
+        todo!()
+    }
+
     async fn modify<F>(&self, f: F) -> FlowyResult<()>
     where
         F: for<'a> FnOnce(&'a mut GridRevisionPad) -> FlowyResult<Option<GridChangeset>>,

+ 22 - 3
frontend/rust-lib/flowy-grid/src/services/group/group_service.rs

@@ -1,7 +1,26 @@
-pub struct GridGroupService {}
+use crate::services::block_manager::GridBlockManager;
+use crate::services::grid_editor_task::GridServiceTaskScheduler;
+use flowy_sync::client_grid::GridRevisionPad;
+use std::sync::Arc;
+use tokio::sync::RwLock;
+
+pub(crate) struct GridGroupService {
+    scheduler: Arc<dyn GridServiceTaskScheduler>,
+    grid_pad: Arc<RwLock<GridRevisionPad>>,
+    block_manager: Arc<GridBlockManager>,
+}
 
 impl GridGroupService {
-    pub fn new() -> Self {
-        Self {}
+    pub(crate) async fn new<S: GridServiceTaskScheduler>(
+        grid_pad: Arc<RwLock<GridRevisionPad>>,
+        block_manager: Arc<GridBlockManager>,
+        scheduler: S,
+    ) -> Self {
+        let scheduler = Arc::new(scheduler);
+        Self {
+            scheduler,
+            grid_pad,
+            block_manager,
+        }
     }
 }

+ 8 - 7
frontend/rust-lib/flowy-grid/src/services/setting/setting_builder.rs

@@ -1,5 +1,6 @@
 use crate::entities::{
-    GridLayoutPB, GridLayoutType, GridSettingPB, RepeatedGridFilterPB, RepeatedGridGroupPB, RepeatedGridSortPB,
+    GridLayoutPB, GridLayoutType, GridSettingPB, RepeatedGridConfigurationFilterPB, RepeatedGridGroupConfigurationPB,
+    RepeatedGridSortPB,
 };
 use flowy_grid_data_model::revision::{FieldRevision, GridSettingRevision};
 use flowy_sync::entities::grid::{CreateGridFilterParams, DeleteFilterParams, GridSettingChangesetParams};
@@ -43,21 +44,21 @@ impl GridSettingChangesetBuilder {
 pub fn make_grid_setting(grid_setting_rev: &GridSettingRevision, field_revs: &[Arc<FieldRevision>]) -> GridSettingPB {
     let current_layout_type: GridLayoutType = grid_setting_rev.layout.clone().into();
     let filters_by_field_id = grid_setting_rev
-        .get_all_filter(field_revs)
+        .get_all_filters(field_revs)
         .map(|filters_by_field_id| {
             filters_by_field_id
                 .into_iter()
                 .map(|(k, v)| (k, v.into()))
-                .collect::<HashMap<String, RepeatedGridFilterPB>>()
+                .collect::<HashMap<String, RepeatedGridConfigurationFilterPB>>()
         })
         .unwrap_or_default();
     let groups_by_field_id = grid_setting_rev
-        .get_all_group()
+        .get_all_groups(field_revs)
         .map(|groups_by_field_id| {
             groups_by_field_id
                 .into_iter()
                 .map(|(k, v)| (k, v.into()))
-                .collect::<HashMap<String, RepeatedGridGroupPB>>()
+                .collect::<HashMap<String, RepeatedGridGroupConfigurationPB>>()
         })
         .unwrap_or_default();
     let sorts_by_field_id = grid_setting_rev
@@ -73,8 +74,8 @@ pub fn make_grid_setting(grid_setting_rev: &GridSettingRevision, field_revs: &[A
     GridSettingPB {
         layouts: GridLayoutPB::all(),
         current_layout_type,
-        filters_by_field_id,
-        groups_by_field_id,
+        filter_configuration_by_field_id: filters_by_field_id,
+        group_configuration_by_field_id: groups_by_field_id,
         sorts_by_field_id,
     }
 }

+ 2 - 2
frontend/rust-lib/flowy-grid/tests/grid/block_test/util.rs

@@ -2,7 +2,7 @@ use flowy_grid::entities::FieldType;
 use std::sync::Arc;
 
 use flowy_grid::services::field::{
-    DateCellChangesetPB, MultiSelectTypeOption, SelectOptionPB, SingleSelectTypeOptionPB, SELECTION_IDS_SEPARATOR,
+    DateCellChangesetPB, MultiSelectTypeOptionPB, SelectOptionPB, SingleSelectTypeOptionPB, SELECTION_IDS_SEPARATOR,
 };
 use flowy_grid::services::row::RowRevisionBuilder;
 use flowy_grid_data_model::revision::{FieldRevision, RowRevision};
@@ -87,7 +87,7 @@ impl<'a> GridRowTestBuilder<'a> {
         F: Fn(Vec<SelectOptionPB>) -> Vec<SelectOptionPB>,
     {
         let multi_select_field = self.field_rev_with_type(&FieldType::MultiSelect);
-        let type_option = MultiSelectTypeOption::from(&multi_select_field);
+        let type_option = MultiSelectTypeOptionPB::from(&multi_select_field);
         let options = f(type_option.options);
         let ops_ids = options
             .iter()

+ 2 - 2
frontend/rust-lib/flowy-grid/tests/grid/cell_test/test.rs

@@ -3,7 +3,7 @@ use crate::grid::cell_test::script::GridCellTest;
 use crate::grid::field_test::util::make_date_cell_string;
 use flowy_grid::entities::{CellChangesetPB, FieldType};
 use flowy_grid::services::field::selection_type_option::SelectOptionCellChangeset;
-use flowy_grid::services::field::{MultiSelectTypeOption, SingleSelectTypeOptionPB};
+use flowy_grid::services::field::{MultiSelectTypeOptionPB, SingleSelectTypeOptionPB};
 
 #[tokio::test]
 async fn grid_cell_update() {
@@ -28,7 +28,7 @@ async fn grid_cell_update() {
                     SelectOptionCellChangeset::from_insert(&type_option.options.first().unwrap().id).to_str()
                 }
                 FieldType::MultiSelect => {
-                    let type_option = MultiSelectTypeOption::from(field_rev);
+                    let type_option = MultiSelectTypeOptionPB::from(field_rev);
                     SelectOptionCellChangeset::from_insert(&type_option.options.first().unwrap().id).to_str()
                 }
                 FieldType::Checkbox => "1".to_string(),

+ 1 - 1
frontend/rust-lib/flowy-grid/tests/grid/grid_editor.rs

@@ -75,7 +75,7 @@ impl GridEditorTest {
             .row_revs
     }
 
-    pub async fn grid_filters(&self) -> Vec<GridFilter> {
+    pub async fn grid_filters(&self) -> Vec<GridFilterConfiguration> {
         let layout_type = GridLayoutType::Table;
         self.editor.get_grid_filter(&layout_type).await.unwrap()
     }

+ 3 - 3
frontend/rust-lib/flowy-grid/tests/grid/grid_test.rs

@@ -2,7 +2,7 @@ use crate::grid::script::EditorScript::*;
 use crate::grid::script::*;
 use chrono::NaiveDateTime;
 use flowy_grid::services::field::{
-    DateCellContentChangeset, DateCellData, MultiSelectTypeOption, SelectOption, SelectOptionCellContentChangeset,
+    DateCellContentChangeset, DateCellData, MultiSelectTypeOptionPB, SelectOption, SelectOptionCellContentChangeset,
     SingleSelectTypeOption, SELECTION_IDS_SEPARATOR,
 };
 use flowy_grid::services::row::{decode_cell_data_from_type_option_cell_data, CreateRowMetaBuilder};
@@ -250,7 +250,7 @@ async fn grid_row_add_cells_test() {
                 builder.add_select_option_cell(&field.id, option.id.clone()).unwrap();
             }
             FieldType::MultiSelect => {
-                let type_option = MultiSelectTypeOption::from(field);
+                let type_option = MultiSelectTypeOptionPB::from(field);
                 let ops_ids = type_option
                     .options
                     .iter()
@@ -327,7 +327,7 @@ async fn grid_cell_update() {
                         SelectOptionCellContentChangeset::from_insert(&type_option.options.first().unwrap().id).to_str()
                     }
                     FieldType::MultiSelect => {
-                        let type_option = MultiSelectTypeOption::from(field_meta);
+                        let type_option = MultiSelectTypeOptionPB::from(field_meta);
                         SelectOptionCellContentChangeset::from_insert(&type_option.options.first().unwrap().id).to_str()
                     }
                     FieldType::Checkbox => "1".to_string(),

+ 1 - 0
shared-lib/Cargo.lock

@@ -436,6 +436,7 @@ dependencies = [
  "serde",
  "serde_json",
  "serde_repr",
+ "tracing",
 ]
 
 [[package]]

+ 1 - 0
shared-lib/flowy-grid-data-model/Cargo.toml

@@ -13,6 +13,7 @@ serde_repr = "0.1"
 nanoid = "0.4.0"
 flowy-error-code = { path = "../flowy-error-code"}
 indexmap = {version = "1.8.1", features = ["serde"]}
+tracing = { version = "0.1", features = ["log"] }
 
 [build-dependencies]
 lib-infra = { path = "../lib-infra", features = ["protobuf_file_gen"] }

+ 0 - 3
shared-lib/flowy-grid-data-model/src/revision/filter_rev.rs

@@ -1,7 +1,4 @@
-use crate::revision::FieldTypeRevision;
-use indexmap::IndexMap;
 use serde::{Deserialize, Serialize};
-use std::sync::Arc;
 
 #[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq, Hash)]
 pub struct GridFilterRevision {

+ 0 - 3
shared-lib/flowy-grid-data-model/src/revision/group_rev.rs → shared-lib/flowy-grid-data-model/src/revision/grid_group.rs

@@ -1,7 +1,4 @@
-use crate::revision::FieldTypeRevision;
-use indexmap::IndexMap;
 use serde::{Deserialize, Serialize};
-use std::sync::Arc;
 
 #[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq)]
 pub struct GridGroupRevision {

+ 129 - 85
shared-lib/flowy-grid-data-model/src/revision/grid_setting_rev.rs

@@ -1,5 +1,5 @@
 use crate::revision::filter_rev::GridFilterRevision;
-use crate::revision::group_rev::GridGroupRevision;
+use crate::revision::grid_group::GridGroupRevision;
 use crate::revision::{FieldRevision, FieldTypeRevision};
 use indexmap::IndexMap;
 use nanoid::nanoid;
@@ -21,28 +21,28 @@ pub fn gen_grid_sort_id() -> String {
     nanoid!(6)
 }
 
+pub type GridFilters = SettingContainer<GridFilterRevision>;
+pub type GridFilterRevisionMap = GridObjectRevisionMap<GridFilterRevision>;
+pub type FiltersByFieldId = HashMap<String, Vec<Arc<GridFilterRevision>>>;
+//
+pub type GridGroups = SettingContainer<GridGroupRevision>;
+pub type GridGroupRevisionMap = GridObjectRevisionMap<GridGroupRevision>;
+pub type GroupsByFieldId = HashMap<String, Vec<Arc<GridGroupRevision>>>;
+//
+pub type GridSorts = SettingContainer<GridSortRevision>;
+pub type GridSortRevisionMap = GridObjectRevisionMap<GridSortRevision>;
+pub type SortsByFieldId = HashMap<String, Vec<Arc<GridSortRevision>>>;
+
 #[derive(Debug, Clone, Serialize, Deserialize, Default, Eq, PartialEq)]
 pub struct GridSettingRevision {
     pub layout: GridLayoutRevision,
 
-    /// Each layout contains multiple key/value.
-    /// Key:    field_id
-    /// Value:  this value contains key/value.
-    ///         Key: FieldType,
-    ///         Value: the corresponding filters.
-    #[serde(with = "indexmap::serde_seq")]
-    filters: IndexMap<GridLayoutRevision, IndexMap<String, GridFilterRevisionMap>>,
+    pub filters: GridFilters,
 
-    /// Each layout contains multiple key/value.
-    /// Key:    field_id
-    /// Value:  this value contains key/value.
-    ///         Key: FieldType,
-    ///         Value: the corresponding groups.
-    #[serde(skip, with = "indexmap::serde_seq")]
-    pub groups: IndexMap<GridLayoutRevision, IndexMap<String, GridGroupRevisionMap>>,
+    pub groups: GridGroups,
 
-    #[serde(skip, with = "indexmap::serde_seq")]
-    pub sorts: IndexMap<GridLayoutRevision, Vec<GridSortRevision>>,
+    #[serde(skip)]
+    pub sorts: GridSorts,
 }
 
 #[derive(Debug, PartialEq, Eq, Hash, Clone, Serialize_repr, Deserialize_repr)]
@@ -65,12 +65,18 @@ impl std::default::Default for GridLayoutRevision {
     }
 }
 
-pub type FiltersByFieldId = HashMap<String, Vec<Arc<GridFilterRevision>>>;
-pub type GroupsByFieldId = HashMap<String, Vec<Arc<GridGroupRevision>>>;
-pub type SortsByFieldId = HashMap<String, Vec<Arc<GridSortRevision>>>;
 impl GridSettingRevision {
-    pub fn get_all_group(&self) -> Option<GroupsByFieldId> {
-        None
+    pub fn get_all_groups(&self, field_revs: &[Arc<FieldRevision>]) -> Option<GroupsByFieldId> {
+        self.groups.get_all_objects(&self.layout, field_revs)
+    }
+
+    pub fn get_groups(
+        &self,
+        layout: &GridLayoutRevision,
+        field_id: &str,
+        field_type_rev: &FieldTypeRevision,
+    ) -> Option<Vec<Arc<GridGroupRevision>>> {
+        self.groups.get_objects(layout, field_id, field_type_rev)
     }
 
     pub fn get_mut_groups(
@@ -79,10 +85,7 @@ impl GridSettingRevision {
         field_id: &str,
         field_type: &FieldTypeRevision,
     ) -> Option<&mut Vec<Arc<GridGroupRevision>>> {
-        self.groups
-            .get_mut(layout)
-            .and_then(|group_rev_map_by_field_id| group_rev_map_by_field_id.get_mut(field_id))
-            .and_then(|group_rev_map| group_rev_map.get_mut(field_type))
+        self.groups.get_mut_objects(layout, field_id, field_type)
     }
 
     pub fn insert_group(
@@ -90,102 +93,143 @@ impl GridSettingRevision {
         layout: &GridLayoutRevision,
         field_id: &str,
         field_type: &FieldTypeRevision,
-        filter_rev: GridGroupRevision,
+        group_rev: GridGroupRevision,
     ) {
-        let filter_rev_map_by_field_id = self.groups.entry(layout.clone()).or_insert_with(IndexMap::new);
-        let filter_rev_map = filter_rev_map_by_field_id
-            .entry(field_id.to_string())
-            .or_insert_with(GridGroupRevisionMap::new);
+        self.groups.insert_object(layout, field_id, field_type, group_rev);
+    }
 
-        filter_rev_map
-            .entry(field_type.to_owned())
-            .or_insert_with(Vec::new)
-            .push(Arc::new(filter_rev))
+    pub fn get_all_filters(&self, field_revs: &[Arc<FieldRevision>]) -> Option<FiltersByFieldId> {
+        self.filters.get_all_objects(&self.layout, field_revs)
     }
 
-    pub fn get_all_sort(&self) -> Option<SortsByFieldId> {
-        None
+    pub fn get_filters(
+        &self,
+        layout: &GridLayoutRevision,
+        field_id: &str,
+        field_type_rev: &FieldTypeRevision,
+    ) -> Option<Vec<Arc<GridFilterRevision>>> {
+        self.filters.get_objects(layout, field_id, field_type_rev)
     }
 
-    /// Return the Filters of the current layout
-    pub fn get_all_filter(&self, field_revs: &[Arc<FieldRevision>]) -> Option<FiltersByFieldId> {
-        let layout = &self.layout;
-        // Acquire the read lock of the filters.
-        let filter_rev_map_by_field_id = self.filters.get(layout)?;
-        // Get the filters according to the FieldType, so we need iterate the field_revs.
-        let filters_by_field_id = field_revs
-            .iter()
-            .flat_map(|field_rev| {
-                let field_type = &field_rev.field_type_rev;
-                let field_id = &field_rev.id;
+    pub fn get_mut_filters(
+        &mut self,
+        layout: &GridLayoutRevision,
+        field_id: &str,
+        field_type: &FieldTypeRevision,
+    ) -> Option<&mut Vec<Arc<GridFilterRevision>>> {
+        self.filters.get_mut_objects(layout, field_id, field_type)
+    }
 
-                let filter_rev_map: &GridFilterRevisionMap = filter_rev_map_by_field_id.get(field_id)?;
-                let filters: Vec<Arc<GridFilterRevision>> = filter_rev_map.get(field_type)?.clone();
-                Some((field_rev.id.clone(), filters))
-            })
-            .collect::<FiltersByFieldId>();
-        Some(filters_by_field_id)
+    pub fn insert_filter(
+        &mut self,
+        layout: &GridLayoutRevision,
+        field_id: &str,
+        field_type: &FieldTypeRevision,
+        filter_rev: GridFilterRevision,
+    ) {
+        self.filters.insert_object(layout, field_id, field_type, filter_rev);
     }
 
-    #[allow(dead_code)]
-    fn get_filter_rev_map(&self, layout: &GridLayoutRevision, field_id: &str) -> Option<&GridFilterRevisionMap> {
-        let filter_rev_map_by_field_id = self.filters.get(layout)?;
-        filter_rev_map_by_field_id.get(field_id)
+    pub fn get_all_sort(&self) -> Option<SortsByFieldId> {
+        None
     }
+}
 
-    pub fn get_mut_filters(
+#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq)]
+pub struct GridSortRevision {
+    pub id: String,
+    pub field_id: Option<String>,
+}
+
+#[derive(Debug, Clone, Serialize, Deserialize, Default, Eq, PartialEq)]
+#[serde(transparent)]
+pub struct SettingContainer<T>
+where
+    T: Debug + Clone + Default + Eq + PartialEq + serde::Serialize + serde::de::DeserializeOwned + 'static,
+{
+    /// Each layout contains multiple key/value.
+    /// Key:    field_id
+    /// Value:  this value contains key/value.
+    ///         Key: FieldType,
+    ///         Value: the corresponding objects.
+    #[serde(with = "indexmap::serde_seq")]
+    inner: IndexMap<GridLayoutRevision, IndexMap<String, GridObjectRevisionMap<T>>>,
+}
+
+impl<T> SettingContainer<T>
+where
+    T: Debug + Clone + Default + Eq + PartialEq + serde::Serialize + serde::de::DeserializeOwned + 'static,
+{
+    pub fn get_mut_objects(
         &mut self,
         layout: &GridLayoutRevision,
         field_id: &str,
         field_type: &FieldTypeRevision,
-    ) -> Option<&mut Vec<Arc<GridFilterRevision>>> {
-        self.filters
+    ) -> Option<&mut Vec<Arc<T>>> {
+        let value = self
+            .inner
             .get_mut(layout)
-            .and_then(|filter_rev_map_by_field_id| filter_rev_map_by_field_id.get_mut(field_id))
-            .and_then(|filter_rev_map| filter_rev_map.get_mut(field_type))
+            .and_then(|object_rev_map_by_field_id| object_rev_map_by_field_id.get_mut(field_id))
+            .and_then(|object_rev_map| object_rev_map.get_mut(field_type));
+        if value.is_none() {
+            tracing::warn!("Can't find the {:?} with", std::any::type_name::<T>());
+        }
+        value
     }
-
-    pub fn get_filters(
+    pub fn get_objects(
         &self,
         layout: &GridLayoutRevision,
         field_id: &str,
         field_type_rev: &FieldTypeRevision,
-    ) -> Option<Vec<Arc<GridFilterRevision>>> {
-        self.filters
+    ) -> Option<Vec<Arc<T>>> {
+        self.inner
             .get(layout)
-            .and_then(|filter_rev_map_by_field_id| filter_rev_map_by_field_id.get(field_id))
-            .and_then(|filter_rev_map| filter_rev_map.get(field_type_rev))
+            .and_then(|object_rev_map_by_field_id| object_rev_map_by_field_id.get(field_id))
+            .and_then(|object_rev_map| object_rev_map.get(field_type_rev))
             .cloned()
     }
 
-    pub fn insert_filter(
+    pub fn get_all_objects(
+        &self,
+        layout: &GridLayoutRevision,
+        field_revs: &[Arc<FieldRevision>],
+    ) -> Option<HashMap<String, Vec<Arc<T>>>> {
+        // Acquire the read lock.
+        let object_rev_map_by_field_id = self.inner.get(layout)?;
+        // Get the objects according to the FieldType, so we need iterate the field_revs.
+        let objects_by_field_id = field_revs
+            .iter()
+            .flat_map(|field_rev| {
+                let field_type = &field_rev.field_type_rev;
+                let field_id = &field_rev.id;
+
+                let object_rev_map = object_rev_map_by_field_id.get(field_id)?;
+                let objects: Vec<Arc<T>> = object_rev_map.get(field_type)?.clone();
+                Some((field_rev.id.clone(), objects))
+            })
+            .collect::<HashMap<String, Vec<Arc<T>>>>();
+        Some(objects_by_field_id)
+    }
+
+    pub fn insert_object(
         &mut self,
         layout: &GridLayoutRevision,
         field_id: &str,
         field_type: &FieldTypeRevision,
-        filter_rev: GridFilterRevision,
+        object: T,
     ) {
-        let filter_rev_map_by_field_id = self.filters.entry(layout.clone()).or_insert_with(IndexMap::new);
-        let filter_rev_map = filter_rev_map_by_field_id
+        let object_rev_map_by_field_id = self.inner.entry(layout.clone()).or_insert_with(IndexMap::new);
+        let object_rev_map = object_rev_map_by_field_id
             .entry(field_id.to_string())
-            .or_insert_with(GridFilterRevisionMap::new);
+            .or_insert_with(GridObjectRevisionMap::<T>::new);
 
-        filter_rev_map
+        object_rev_map
             .entry(field_type.to_owned())
             .or_insert_with(Vec::new)
-            .push(Arc::new(filter_rev))
+            .push(Arc::new(object))
     }
 }
 
-#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq)]
-pub struct GridSortRevision {
-    pub id: String,
-    pub field_id: Option<String>,
-}
-
-pub type GridFilterRevisionMap = GridObjectRevisionMap<GridFilterRevision>;
-pub type GridGroupRevisionMap = GridObjectRevisionMap<GridGroupRevision>;
-
 #[derive(Debug, Clone, Serialize, Deserialize, Default, Eq, PartialEq)]
 #[serde(transparent)]
 pub struct GridObjectRevisionMap<T>

+ 0 - 0
shared-lib/flowy-grid-data-model/src/revision/grid_sort.rs


+ 4 - 2
shared-lib/flowy-grid-data-model/src/revision/mod.rs

@@ -1,9 +1,11 @@
 mod filter_rev;
+mod grid_group;
 mod grid_rev;
 mod grid_setting_rev;
-mod group_rev;
+mod grid_sort;
 
 pub use filter_rev::*;
+pub use grid_group::*;
 pub use grid_rev::*;
 pub use grid_setting_rev::*;
-pub use group_rev::*;
+pub use grid_sort::*;

+ 0 - 1
shared-lib/flowy-sync/src/client_folder/folder_pad.rs

@@ -457,7 +457,6 @@ mod tests {
         AppRevision, FolderRevision, TrashRevision, ViewRevision, WorkspaceRevision,
     };
     use lib_ot::core::{OperationTransform, TextDelta, TextDeltaBuilder};
-    use serde_json::json;
 
     #[test]
     fn folder_add_workspace() {

+ 59 - 63
shared-lib/flowy-sync/src/client_grid/grid_revision_pad.rs

@@ -1,4 +1,6 @@
-use crate::entities::grid::{FieldChangesetParams, GridSettingChangesetParams};
+use crate::entities::grid::{
+    CreateGridFilterParams, CreateGridGroupParams, FieldChangesetParams, GridSettingChangesetParams,
+};
 use crate::entities::revision::{md5, RepeatedRevision, Revision};
 use crate::errors::{internal_error, CollaborateError, CollaborateResult};
 use crate::util::{cal_diff, make_delta_from_revisions};
@@ -380,88 +382,65 @@ impl GridRevisionPad {
         self.modify_grid(|grid_rev| {
             let mut is_changed = None;
             let layout_rev = changeset.layout_type;
-
             if let Some(params) = changeset.insert_filter {
-                let filter_rev = GridFilterRevision {
-                    id: gen_grid_filter_id(),
-                    field_id: params.field_id.clone(),
-                    condition: params.condition,
-                    content: params.content,
-                };
-
-                grid_rev
-                    .setting
-                    .insert_filter(&layout_rev, &params.field_id, &params.field_type_rev, filter_rev);
+                grid_rev.setting.insert_filter(
+                    &layout_rev,
+                    &params.field_id,
+                    &params.field_type_rev,
+                    make_filter_revision(&params),
+                );
 
                 is_changed = Some(())
             }
             if let Some(params) = changeset.delete_filter {
-                match grid_rev
-                    .setting
-                    .get_mut_filters(&layout_rev, &params.field_id, &params.field_type_rev)
+                if let Some(filters) =
+                    grid_rev
+                        .setting
+                        .get_mut_filters(&layout_rev, &params.field_id, &params.field_type_rev)
                 {
-                    Some(filters) => {
-                        filters.retain(|filter| filter.id != params.filter_id);
-                    }
-                    None => {
-                        tracing::warn!("Can't find the filter with {:?}", layout_rev);
-                    }
+                    filters.retain(|filter| filter.id != params.filter_id);
                 }
             }
             if let Some(params) = changeset.insert_group {
-                let group_rev = GridGroupRevision {
-                    id: gen_grid_group_id(),
-                    field_id: params.field_id.clone(),
-                    sub_field_id: params.sub_field_id,
-                };
-
-                grid_rev
-                    .setting
-                    .insert_group(&layout_rev, &params.field_id, &params.field_type_rev, group_rev);
+                grid_rev.setting.insert_group(
+                    &layout_rev,
+                    &params.field_id,
+                    &params.field_type_rev,
+                    make_group_revision(&params),
+                );
                 is_changed = Some(());
             }
             if let Some(params) = changeset.delete_group {
-                // match grid_rev.setting.groups.get_mut(&layout_rev) {
-                //     Some(groups) => groups.retain(|group| group.id != delete_group_id),
-                //     None => {
-                //         tracing::warn!("Can't find the group with {:?}", layout_rev);
-                //     }
-                // }
-
-                match grid_rev
-                    .setting
-                    .get_mut_groups(&layout_rev, &params.field_id, &params.field_type_rev)
+                if let Some(groups) =
+                    grid_rev
+                        .setting
+                        .get_mut_groups(&layout_rev, &params.field_id, &params.field_type_rev)
                 {
-                    Some(groups) => {
-                        groups.retain(|filter| filter.id != params.group_id);
-                    }
-                    None => {
-                        tracing::warn!("Can't find the group with {:?}", layout_rev);
-                    }
+                    groups.retain(|filter| filter.id != params.group_id);
                 }
             }
             if let Some(sort) = changeset.insert_sort {
-                let rev = GridSortRevision {
-                    id: gen_grid_sort_id(),
-                    field_id: sort.field_id,
-                };
-
-                grid_rev
-                    .setting
-                    .sorts
-                    .entry(layout_rev.clone())
-                    .or_insert_with(std::vec::Vec::new)
-                    .push(rev);
+                // let rev = GridSortRevision {
+                //     id: gen_grid_sort_id(),
+                //     field_id: sort.field_id,
+                // };
+                //
+                // grid_rev
+                //     .setting
+                //     .sorts
+                //     .entry(layout_rev.clone())
+                //     .or_insert_with(std::vec::Vec::new)
+                //     .push(rev);
                 is_changed = Some(())
             }
 
             if let Some(delete_sort_id) = changeset.delete_sort {
-                match grid_rev.setting.sorts.get_mut(&layout_rev) {
-                    Some(sorts) => sorts.retain(|sort| sort.id != delete_sort_id),
-                    None => {
-                        tracing::warn!("Can't find the sort with {:?}", layout_rev);
-                    }
-                }
+                // match grid_rev.setting.sorts.get_mut(&layout_rev) {
+                //     Some(sorts) => sorts.retain(|sort| sort.id != delete_sort_id),
+                //     None => {
+                //         tracing::warn!("Can't find the sort with {:?}", layout_rev);
+                //     }
+                // }
             }
             Ok(is_changed)
         })
@@ -579,3 +558,20 @@ impl std::default::Default for GridRevisionPad {
         }
     }
 }
+
+fn make_filter_revision(params: &CreateGridFilterParams) -> GridFilterRevision {
+    GridFilterRevision {
+        id: gen_grid_filter_id(),
+        field_id: params.field_id.clone(),
+        condition: params.condition.clone(),
+        content: params.content.clone(),
+    }
+}
+
+fn make_group_revision(params: &CreateGridGroupParams) -> GridGroupRevision {
+    GridGroupRevision {
+        id: gen_grid_group_id(),
+        field_id: params.field_id.clone(),
+        sub_field_id: params.sub_field_id.clone(),
+    }
+}