Explorar o código

chore: refactor grid setting

appflowy %!s(int64=2) %!d(string=hai) anos
pai
achega
29ea3c83c8

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

@@ -1,8 +1,9 @@
+use crate::entities::FieldType;
 use flowy_derive::ProtoBuf;
 use flowy_error::ErrorCode;
 use flowy_grid_data_model::parser::NotEmptyStr;
 use flowy_grid_data_model::revision::GridGroupRevision;
-use flowy_sync::entities::grid::CreateGridGroupParams;
+use flowy_sync::entities::grid::{CreateGridGroupParams, DeleteGroupParams};
 use std::convert::TryInto;
 use std::sync::Arc;
 
@@ -11,8 +12,8 @@ pub struct GridGroupPB {
     #[pb(index = 1)]
     pub id: String,
 
-    #[pb(index = 2, one_of)]
-    pub group_field_id: Option<String>,
+    #[pb(index = 2)]
+    pub group_field_id: String,
 
     #[pb(index = 3, one_of)]
     pub sub_group_field_id: Option<String>,
@@ -50,27 +51,64 @@ impl std::convert::From<Vec<Arc<GridGroupRevision>>> for RepeatedGridGroupPB {
 
 #[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)]
 pub struct CreateGridGroupPayloadPB {
-    #[pb(index = 1, one_of)]
-    pub field_id: Option<String>,
+    #[pb(index = 1)]
+    pub field_id: String,
 
     #[pb(index = 2, one_of)]
     pub sub_field_id: Option<String>,
+
+    #[pb(index = 3)]
+    pub field_type: FieldType,
 }
 
 impl TryInto<CreateGridGroupParams> for CreateGridGroupPayloadPB {
     type Error = ErrorCode;
 
     fn try_into(self) -> Result<CreateGridGroupParams, Self::Error> {
-        let field_id = match self.field_id {
-            None => None,
-            Some(field_id) => Some(NotEmptyStr::parse(field_id).map_err(|_| ErrorCode::FieldIdIsEmpty)?.0),
-        };
+        let field_id = NotEmptyStr::parse(self.field_id)
+            .map_err(|_| ErrorCode::FieldIdIsEmpty)?
+            .0;
 
         let sub_field_id = match self.sub_field_id {
             None => None,
             Some(field_id) => Some(NotEmptyStr::parse(field_id).map_err(|_| ErrorCode::FieldIdIsEmpty)?.0),
         };
 
-        Ok(CreateGridGroupParams { field_id, sub_field_id })
+        Ok(CreateGridGroupParams {
+            field_id,
+            sub_field_id,
+            field_type_rev: self.field_type.into(),
+        })
+    }
+}
+
+#[derive(ProtoBuf, Debug, Default, Clone)]
+pub struct DeleteGroupPayloadPB {
+    #[pb(index = 1)]
+    pub field_id: String,
+
+    #[pb(index = 2)]
+    pub group_id: String,
+
+    #[pb(index = 3)]
+    pub field_type: FieldType,
+}
+
+impl TryInto<DeleteGroupParams> for DeleteGroupPayloadPB {
+    type Error = ErrorCode;
+
+    fn try_into(self) -> Result<DeleteGroupParams, Self::Error> {
+        let field_id = NotEmptyStr::parse(self.field_id)
+            .map_err(|_| ErrorCode::FieldIdIsEmpty)?
+            .0;
+        let group_id = NotEmptyStr::parse(self.group_id)
+            .map_err(|_| ErrorCode::FieldIdIsEmpty)?
+            .0;
+
+        Ok(DeleteGroupParams {
+            field_id,
+            field_type_rev: self.field_type.into(),
+            group_id,
+        })
     }
 }

+ 3 - 0
frontend/rust-lib/flowy-grid/src/entities/group_entities/mod.rs

@@ -0,0 +1,3 @@
+mod group;
+
+pub use group::*;

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

@@ -1,12 +1,12 @@
 use crate::entities::{
     CreateGridFilterPayloadPB, CreateGridGroupPayloadPB, CreateGridSortPayloadPB, DeleteFilterPayloadPB,
-    RepeatedGridFilterPB, RepeatedGridGroupPB, RepeatedGridSortPB,
+    DeleteGroupPayloadPB, RepeatedGridFilterPB, RepeatedGridGroupPB, RepeatedGridSortPB,
 };
 use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
 use flowy_error::ErrorCode;
 use flowy_grid_data_model::parser::NotEmptyStr;
 use flowy_grid_data_model::revision::GridLayoutRevision;
-use flowy_sync::entities::grid::GridSettingChangesetParams;
+use flowy_sync::entities::grid::{DeleteGroupParams, GridSettingChangesetParams};
 use std::collections::HashMap;
 use std::convert::TryInto;
 use strum::IntoEnumIterator;
@@ -97,7 +97,7 @@ pub struct GridSettingChangesetPayloadPB {
     pub insert_group: Option<CreateGridGroupPayloadPB>,
 
     #[pb(index = 6, one_of)]
-    pub delete_group: Option<String>,
+    pub delete_group: Option<DeleteGroupPayloadPB>,
 
     #[pb(index = 7, one_of)]
     pub insert_sort: Option<CreateGridSortPayloadPB>,
@@ -130,8 +130,8 @@ impl TryInto<GridSettingChangesetParams> for GridSettingChangesetPayloadPB {
         };
 
         let delete_group = match self.delete_group {
+            Some(payload) => Some(payload.try_into()?),
             None => None,
-            Some(filter_id) => Some(NotEmptyStr::parse(filter_id).map_err(|_| ErrorCode::FieldIdIsEmpty)?.0),
         };
 
         let insert_sort = match self.insert_sort {

+ 4 - 0
frontend/rust-lib/flowy-grid/src/services/grid_editor.rs

@@ -6,6 +6,7 @@ use crate::services::block_manager::GridBlockManager;
 use crate::services::cell::{apply_cell_data_changeset, decode_any_cell_data, CellBytes};
 use crate::services::field::{default_type_option_builder_from_type, type_option_builder_from_bytes, FieldBuilder};
 use crate::services::filter::{GridFilterChangeset, GridFilterService};
+use crate::services::group::GridGroupService;
 use crate::services::persistence::block_index::BlockIndexCache;
 use crate::services::row::{
     make_grid_blocks, make_row_from_row_rev, make_rows_from_row_revs, GridBlockSnapshot, RowRevisionBuilder,
@@ -34,6 +35,7 @@ pub struct GridRevisionEditor {
     block_manager: Arc<GridBlockManager>,
     #[allow(dead_code)]
     pub(crate) filter_service: Arc<GridFilterService>,
+    pub(crate) group_service: Arc<GridGroupService>,
 }
 
 impl Drop for GridRevisionEditor {
@@ -59,6 +61,7 @@ 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 editor = Arc::new(Self {
             grid_id: grid_id.to_owned(),
             user,
@@ -66,6 +69,7 @@ impl GridRevisionEditor {
             rev_manager,
             block_manager,
             filter_service,
+            group_service,
         });
 
         Ok(editor)

+ 1 - 0
frontend/rust-lib/flowy-grid/src/services/grid_editor_task.rs

@@ -19,6 +19,7 @@ impl GridTaskHandler for GridRevisionEditor {
         Box::pin(async move {
             match content {
                 TaskContent::Snapshot => {}
+                TaskContent::Group => {}
                 TaskContent::Filter(context) => self.filter_service.process(context).await?,
             }
             Ok(())

+ 7 - 0
frontend/rust-lib/flowy-grid/src/services/group/group_service.rs

@@ -0,0 +1,7 @@
+pub struct GridGroupService {}
+
+impl GridGroupService {
+    pub fn new() -> Self {
+        Self {}
+    }
+}

+ 3 - 0
frontend/rust-lib/flowy-grid/src/services/group/mod.rs

@@ -0,0 +1,3 @@
+mod group_service;
+
+pub use group_service::*;

+ 1 - 0
frontend/rust-lib/flowy-grid/src/services/mod.rs

@@ -7,6 +7,7 @@ pub mod field;
 mod filter;
 pub mod grid_editor;
 mod grid_editor_task;
+pub mod group;
 pub mod persistence;
 pub mod row;
 pub mod setting;

+ 1 - 0
frontend/rust-lib/flowy-grid/src/services/tasks/queue.rs

@@ -27,6 +27,7 @@ impl GridTaskQueue {
 
         let task_type = match task.content.as_ref().unwrap() {
             TaskContent::Snapshot => TaskType::Snapshot,
+            TaskContent::Group => TaskType::Group,
             TaskContent::Filter { .. } => TaskType::Filter,
         };
         let pending_task = PendingTask {

+ 9 - 0
frontend/rust-lib/flowy-grid/src/services/tasks/task.rs

@@ -10,6 +10,8 @@ pub enum TaskType {
     Filter,
     /// Generate snapshot for grid, unused by now.
     Snapshot,
+
+    Group,
 }
 
 impl PartialEq for TaskType {
@@ -44,9 +46,15 @@ impl PartialOrd for PendingTask {
 impl Ord for PendingTask {
     fn cmp(&self, other: &Self) -> Ordering {
         match (self.ty, other.ty) {
+            // Snapshot
             (TaskType::Snapshot, TaskType::Snapshot) => Ordering::Equal,
             (TaskType::Snapshot, _) => Ordering::Greater,
             (_, TaskType::Snapshot) => Ordering::Less,
+            // Group
+            (TaskType::Group, TaskType::Group) => self.id.cmp(&other.id).reverse(),
+            (TaskType::Group, _) => Ordering::Greater,
+            (_, TaskType::Group) => Ordering::Greater,
+            // Filter
             (TaskType::Filter, TaskType::Filter) => self.id.cmp(&other.id).reverse(),
         }
     }
@@ -59,6 +67,7 @@ pub(crate) struct FilterTaskContext {
 pub(crate) enum TaskContent {
     #[allow(dead_code)]
     Snapshot,
+    Group,
     Filter(FilterTaskContext),
 }
 

+ 7 - 17
frontend/rust-lib/flowy-grid/src/util.rs

@@ -54,24 +54,14 @@ pub fn make_default_board() -> BuildGridContext {
     let single_select_field_id = single_select_field.id.clone();
     grid_builder.add_field(single_select_field);
 
-    let field_revs = grid_builder.field_revs();
-    let block_id = grid_builder.block_id();
-
     // rows
-    let row_1 = RowRevisionBuilder::new(block_id, field_revs)
-        .insert_select_option_cell(&single_select_field_id, not_started_option.id.clone())
-        .build();
-    grid_builder.add_row(row_1);
-
-    let row_2 = RowRevisionBuilder::new(block_id, field_revs)
-        .insert_select_option_cell(&single_select_field_id, not_started_option.id.clone())
-        .build();
-    grid_builder.add_row(row_2);
-
-    let row_3 = RowRevisionBuilder::new(block_id, field_revs)
-        .insert_select_option_cell(&single_select_field_id, not_started_option.id.clone())
-        .build();
-    grid_builder.add_row(row_3);
+    for _ in 0..3 {
+        grid_builder.add_row(
+            RowRevisionBuilder::new(grid_builder.block_id(), grid_builder.field_revs())
+                .insert_select_option_cell(&single_select_field_id, not_started_option.id.clone())
+                .build(),
+        );
+    }
 
     grid_builder.build()
 }

+ 1 - 0
frontend/rust-lib/flowy-test/src/helper.rs

@@ -97,6 +97,7 @@ async fn create_view(sdk: &FlowySDKTest, app_id: &str, data_type: ViewDataTypePB
         desc: "".to_string(),
         thumbnail: Some("http://1.png".to_string()),
         data_type,
+        sub_data_type: None,
         plugin_type: 0,
         data,
     };

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

@@ -0,0 +1,12 @@
+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 {
+    pub id: String,
+    pub field_id: String,
+    pub condition: u8,
+    pub content: Option<String>,
+}

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

@@ -1,94 +0,0 @@
-use crate::entities::NumberFilterCondition;
-use indexmap::IndexMap;
-use nanoid::nanoid;
-use serde::{Deserialize, Serialize};
-use serde_repr::*;
-use std::str::FromStr;
-
-#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq)]
-pub struct GridFilterRevision {
-    pub id: String,
-    pub field_id: String,
-    pub condition: u8,
-    pub content: Option<String>,
-}
-
-#[derive(Debug, PartialEq, Eq, Hash, Clone, Serialize_repr, Deserialize_repr)]
-#[repr(u8)]
-pub enum TextFilterConditionRevision {
-    Is = 0,
-    IsNot = 1,
-    Contains = 2,
-    DoesNotContain = 3,
-    StartsWith = 4,
-    EndsWith = 5,
-    IsEmpty = 6,
-    IsNotEmpty = 7,
-}
-
-impl ToString for TextFilterConditionRevision {
-    fn to_string(&self) -> String {
-        (self.clone() as u8).to_string()
-    }
-}
-
-impl FromStr for TextFilterConditionRevision {
-    type Err = serde_json::Error;
-
-    fn from_str(s: &str) -> Result<Self, Self::Err> {
-        let rev = serde_json::from_str(s)?;
-        Ok(rev)
-    }
-}
-
-#[derive(Debug, PartialEq, Eq, Hash, Clone, Serialize_repr, Deserialize_repr)]
-#[repr(u8)]
-pub enum NumberFilterConditionRevision {
-    Equal = 0,
-    NotEqual = 1,
-    GreaterThan = 2,
-    LessThan = 3,
-    GreaterThanOrEqualTo = 4,
-    LessThanOrEqualTo = 5,
-    IsEmpty = 6,
-    IsNotEmpty = 7,
-}
-
-impl ToString for NumberFilterConditionRevision {
-    fn to_string(&self) -> String {
-        (self.clone() as u8).to_string()
-    }
-}
-
-impl FromStr for NumberFilterConditionRevision {
-    type Err = serde_json::Error;
-
-    fn from_str(s: &str) -> Result<Self, Self::Err> {
-        let rev = serde_json::from_str(s)?;
-        Ok(rev)
-    }
-}
-
-#[derive(Debug, PartialEq, Eq, Hash, Clone, Serialize_repr, Deserialize_repr)]
-#[repr(u8)]
-pub enum SelectOptionConditionRevision {
-    OptionIs = 0,
-    OptionIsNot = 1,
-    OptionIsEmpty = 2,
-    OptionIsNotEmpty = 3,
-}
-
-impl ToString for SelectOptionConditionRevision {
-    fn to_string(&self) -> String {
-        (self.clone() as u8).to_string()
-    }
-}
-
-impl FromStr for SelectOptionConditionRevision {
-    type Err = serde_json::Error;
-
-    fn from_str(s: &str) -> Result<Self, Self::Err> {
-        let rev = serde_json::from_str(s)?;
-        Ok(rev)
-    }
-}

+ 94 - 72
shared-lib/flowy-grid-data-model/src/revision/grid_setting_rev.rs

@@ -1,9 +1,12 @@
+use crate::revision::filter_rev::GridFilterRevision;
+use crate::revision::group_rev::GridGroupRevision;
 use crate::revision::{FieldRevision, FieldTypeRevision};
 use indexmap::IndexMap;
 use nanoid::nanoid;
 use serde::{Deserialize, Serialize};
 use serde_repr::*;
 use std::collections::HashMap;
+use std::fmt::Debug;
 use std::sync::Arc;
 
 pub fn gen_grid_filter_id() -> String {
@@ -18,41 +21,50 @@ pub fn gen_grid_sort_id() -> String {
     nanoid!(6)
 }
 
-/// Each layout contains multiple key/value.
-/// Key:    field_id
-/// Value:  this value also contains key/value.
-///         Key: FieldType,
-///         Value: the corresponding filter.
-///
-/// This overall struct is described below:
-/// GridSettingRevision
-///     layout:
-///           field_id:
-///                   FieldType: GridFilterRevision
-///                   FieldType: GridFilterRevision
-///           field_id:
-///                   FieldType: GridFilterRevision
-///                   FieldType: GridFilterRevision
-///     layout:
-///           field_id:
-///                   FieldType: GridFilterRevision
-///                   FieldType: GridFilterRevision
-///
-/// Group and sorts will be the same structure as filters.
 #[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>>,
 
+    /// 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, Vec<GridGroupRevision>>,
+    pub groups: IndexMap<GridLayoutRevision, IndexMap<String, GridGroupRevisionMap>>,
 
     #[serde(skip, with = "indexmap::serde_seq")]
     pub sorts: IndexMap<GridLayoutRevision, Vec<GridSortRevision>>,
 }
 
+#[derive(Debug, PartialEq, Eq, Hash, Clone, Serialize_repr, Deserialize_repr)]
+#[repr(u8)]
+pub enum GridLayoutRevision {
+    Table = 0,
+    Board = 1,
+}
+
+impl ToString for GridLayoutRevision {
+    fn to_string(&self) -> String {
+        let layout_rev = self.clone() as u8;
+        layout_rev.to_string()
+    }
+}
+
+impl std::default::Default for GridLayoutRevision {
+    fn default() -> Self {
+        GridLayoutRevision::Table
+    }
+}
+
 pub type FiltersByFieldId = HashMap<String, Vec<Arc<GridFilterRevision>>>;
 pub type GroupsByFieldId = HashMap<String, Vec<Arc<GridGroupRevision>>>;
 pub type SortsByFieldId = HashMap<String, Vec<Arc<GridSortRevision>>>;
@@ -61,6 +73,36 @@ impl GridSettingRevision {
         None
     }
 
+    pub fn get_mut_groups(
+        &mut self,
+        layout: &GridLayoutRevision,
+        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))
+    }
+
+    pub fn insert_group(
+        &mut self,
+        layout: &GridLayoutRevision,
+        field_id: &str,
+        field_type: &FieldTypeRevision,
+        filter_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);
+
+        filter_rev_map
+            .entry(field_type.to_owned())
+            .or_insert_with(Vec::new)
+            .push(Arc::new(filter_rev))
+    }
+
     pub fn get_all_sort(&self) -> Option<SortsByFieldId> {
         None
     }
@@ -135,70 +177,50 @@ impl GridSettingRevision {
     }
 }
 
+#[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 GridFilterRevisionMap {
+pub struct GridObjectRevisionMap<T>
+where
+    T: Debug + Clone + Default + Eq + PartialEq + serde::Serialize + serde::de::DeserializeOwned + 'static,
+{
     #[serde(with = "indexmap::serde_seq")]
-    pub filter_by_field_type: IndexMap<FieldTypeRevision, Vec<Arc<GridFilterRevision>>>,
+    pub object_by_field_type: IndexMap<FieldTypeRevision, Vec<Arc<T>>>,
 }
 
-impl GridFilterRevisionMap {
+impl<T> GridObjectRevisionMap<T>
+where
+    T: Debug + Clone + Default + Eq + PartialEq + serde::Serialize + serde::de::DeserializeOwned + 'static,
+{
     pub fn new() -> Self {
-        GridFilterRevisionMap::default()
+        GridObjectRevisionMap::default()
     }
 }
 
-impl std::ops::Deref for GridFilterRevisionMap {
-    type Target = IndexMap<FieldTypeRevision, Vec<Arc<GridFilterRevision>>>;
+impl<T> std::ops::Deref for GridObjectRevisionMap<T>
+where
+    T: Debug + Clone + Default + Eq + PartialEq + serde::Serialize + serde::de::DeserializeOwned + 'static,
+{
+    type Target = IndexMap<FieldTypeRevision, Vec<Arc<T>>>;
 
     fn deref(&self) -> &Self::Target {
-        &self.filter_by_field_type
+        &self.object_by_field_type
     }
 }
 
-impl std::ops::DerefMut for GridFilterRevisionMap {
+impl<T> std::ops::DerefMut for GridObjectRevisionMap<T>
+where
+    T: Debug + Clone + Default + Eq + PartialEq + serde::Serialize + serde::de::DeserializeOwned + 'static,
+{
     fn deref_mut(&mut self) -> &mut Self::Target {
-        &mut self.filter_by_field_type
-    }
-}
-
-#[derive(Debug, PartialEq, Eq, Hash, Clone, Serialize_repr, Deserialize_repr)]
-#[repr(u8)]
-pub enum GridLayoutRevision {
-    Table = 0,
-    Board = 1,
-}
-
-impl ToString for GridLayoutRevision {
-    fn to_string(&self) -> String {
-        let layout_rev = self.clone() as u8;
-        layout_rev.to_string()
+        &mut self.object_by_field_type
     }
 }
-
-impl std::default::Default for GridLayoutRevision {
-    fn default() -> Self {
-        GridLayoutRevision::Table
-    }
-}
-
-#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq, Hash)]
-pub struct GridFilterRevision {
-    pub id: String,
-    pub field_id: String,
-    pub condition: u8,
-    pub content: Option<String>,
-}
-
-#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq)]
-pub struct GridGroupRevision {
-    pub id: String,
-    pub field_id: Option<String>,
-    pub sub_field_id: Option<String>,
-}
-
-#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq)]
-pub struct GridSortRevision {
-    pub id: String,
-    pub field_id: Option<String>,
-}

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

@@ -0,0 +1,11 @@
+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 {
+    pub id: String,
+    pub field_id: String,
+    pub sub_field_id: Option<String>,
+}

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

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

+ 19 - 11
shared-lib/flowy-sync/src/client_grid/grid_revision_pad.rs

@@ -409,24 +409,32 @@ impl GridRevisionPad {
                 }
             }
             if let Some(params) = changeset.insert_group {
-                let rev = GridGroupRevision {
+                let group_rev = GridGroupRevision {
                     id: gen_grid_group_id(),
-                    field_id: params.field_id,
+                    field_id: params.field_id.clone(),
                     sub_field_id: params.sub_field_id,
                 };
 
                 grid_rev
                     .setting
-                    .groups
-                    .entry(layout_rev.clone())
-                    .or_insert_with(std::vec::Vec::new)
-                    .push(rev);
-
-                is_changed = Some(())
+                    .insert_group(&layout_rev, &params.field_id, &params.field_type_rev, group_rev);
+                is_changed = Some(());
             }
-            if let Some(delete_group_id) = changeset.delete_group {
-                match grid_rev.setting.groups.get_mut(&layout_rev) {
-                    Some(groups) => groups.retain(|group| group.id != delete_group_id),
+            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)
+                {
+                    Some(groups) => {
+                        groups.retain(|filter| filter.id != params.group_id);
+                    }
                     None => {
                         tracing::warn!("Can't find the group with {:?}", layout_rev);
                     }

+ 11 - 2
shared-lib/flowy-sync/src/entities/grid.rs

@@ -6,7 +6,7 @@ pub struct GridSettingChangesetParams {
     pub insert_filter: Option<CreateGridFilterParams>,
     pub delete_filter: Option<DeleteFilterParams>,
     pub insert_group: Option<CreateGridGroupParams>,
-    pub delete_group: Option<String>,
+    pub delete_group: Option<DeleteGroupParams>,
     pub insert_sort: Option<CreateGridSortParams>,
     pub delete_sort: Option<String>,
 }
@@ -28,10 +28,19 @@ pub struct DeleteFilterParams {
     pub filter_id: String,
     pub field_type_rev: FieldTypeRevision,
 }
+
 pub struct CreateGridGroupParams {
-    pub field_id: Option<String>,
+    pub field_id: String,
     pub sub_field_id: Option<String>,
+    pub field_type_rev: FieldTypeRevision,
 }
+
+pub struct DeleteGroupParams {
+    pub field_id: String,
+    pub group_id: String,
+    pub field_type_rev: FieldTypeRevision,
+}
+
 pub struct CreateGridSortParams {
     pub field_id: Option<String>,
 }