From 91b2917d603b9dc674bca8f282abe34f0e7a1b42 Mon Sep 17 00:00:00 2001
From: appflowy <annie@appflowy.io>
Date: Sat, 20 Aug 2022 15:40:13 +0800
Subject: [PATCH] chore: reader and writter for group configuration

---
 .../flowy-grid/src/entities/field_entities.rs |   1 -
 .../rust-lib/flowy-grid/src/entities/mod.rs   |   2 -
 .../src/entities/setting_entities.rs          |  30 +-
 .../flowy-grid/src/entities/sort_entities.rs  |  68 -----
 .../rust-lib/flowy-grid/src/event_handler.rs  |   1 -
 .../src/services/filter/filter_service.rs     |   3 +-
 .../flowy-grid/src/services/grid_editor.rs    |  92 +++---
 .../src/services/grid_view_editor.rs          | 143 ++++++---
 .../src/services/grid_view_manager.rs         |   5 +-
 .../flowy-grid/src/services/group/action.rs   |  23 ++
 .../src/services/group/configuration.rs       |  76 +++++
 .../checkbox_controller.rs                    |  44 ++-
 .../{controllers => controller_impls}/mod.rs  |   2 -
 .../select_option_controller/mod.rs           |   6 +
 .../multi_select_controller.rs                | 110 +++++++
 .../single_select_controller.rs               | 111 +++++++
 .../select_option_controller/util.rs          | 108 +++++++
 .../controllers/select_option_controller.rs   | 286 ------------------
 .../flowy-grid/src/services/group/entities.rs |  73 +++++
 .../{controllers => }/group_controller.rs     | 190 ++++--------
 .../src/services/group/group_service.rs       | 113 ++++---
 .../flowy-grid/src/services/group/mod.rs      |  10 +-
 .../src/services/setting/setting_builder.rs   |  50 +--
 .../src/revision/filter_rev.rs                |   9 +
 .../src/revision/grid_setting_rev.rs          | 147 +--------
 .../src/revision/grid_view.rs                 | 104 ++++++-
 .../src/revision/group_rev.rs                 |  65 ++++
 .../flowy-grid-data-model/src/revision/mod.rs |   2 +
 .../src/client_grid/view_revision_pad.rs      |  36 +--
 29 files changed, 1015 insertions(+), 895 deletions(-)
 delete mode 100644 frontend/rust-lib/flowy-grid/src/entities/sort_entities.rs
 create mode 100644 frontend/rust-lib/flowy-grid/src/services/group/action.rs
 create mode 100644 frontend/rust-lib/flowy-grid/src/services/group/configuration.rs
 rename frontend/rust-lib/flowy-grid/src/services/group/{controllers => controller_impls}/checkbox_controller.rs (59%)
 rename frontend/rust-lib/flowy-grid/src/services/group/{controllers => controller_impls}/mod.rs (71%)
 create mode 100644 frontend/rust-lib/flowy-grid/src/services/group/controller_impls/select_option_controller/mod.rs
 create mode 100644 frontend/rust-lib/flowy-grid/src/services/group/controller_impls/select_option_controller/multi_select_controller.rs
 create mode 100644 frontend/rust-lib/flowy-grid/src/services/group/controller_impls/select_option_controller/single_select_controller.rs
 create mode 100644 frontend/rust-lib/flowy-grid/src/services/group/controller_impls/select_option_controller/util.rs
 delete mode 100644 frontend/rust-lib/flowy-grid/src/services/group/controllers/select_option_controller.rs
 create mode 100644 frontend/rust-lib/flowy-grid/src/services/group/entities.rs
 rename frontend/rust-lib/flowy-grid/src/services/group/{controllers => }/group_controller.rs (57%)
 create mode 100644 shared-lib/flowy-grid-data-model/src/revision/filter_rev.rs

diff --git a/frontend/rust-lib/flowy-grid/src/entities/field_entities.rs b/frontend/rust-lib/flowy-grid/src/entities/field_entities.rs
index 0993853b8e..271cbcf424 100644
--- a/frontend/rust-lib/flowy-grid/src/entities/field_entities.rs
+++ b/frontend/rust-lib/flowy-grid/src/entities/field_entities.rs
@@ -2,7 +2,6 @@ use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
 use flowy_error::ErrorCode;
 use flowy_grid_data_model::parser::NotEmptyStr;
 use flowy_grid_data_model::revision::{FieldRevision, FieldTypeRevision};
-use flowy_sync::entities::grid::FieldChangesetParams;
 use serde_repr::*;
 use std::sync::Arc;
 
diff --git a/frontend/rust-lib/flowy-grid/src/entities/mod.rs b/frontend/rust-lib/flowy-grid/src/entities/mod.rs
index 96c7a9ba60..eb11d982a4 100644
--- a/frontend/rust-lib/flowy-grid/src/entities/mod.rs
+++ b/frontend/rust-lib/flowy-grid/src/entities/mod.rs
@@ -6,7 +6,6 @@ mod grid_entities;
 mod group_entities;
 mod row_entities;
 mod setting_entities;
-mod sort_entities;
 
 pub use block_entities::*;
 pub use cell_entities::*;
@@ -16,4 +15,3 @@ pub use grid_entities::*;
 pub use group_entities::*;
 pub use row_entities::*;
 pub use setting_entities::*;
-pub use sort_entities::*;
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 67fcc884e9..9c02a2c692 100644
--- a/frontend/rust-lib/flowy-grid/src/entities/setting_entities.rs
+++ b/frontend/rust-lib/flowy-grid/src/entities/setting_entities.rs
@@ -1,13 +1,12 @@
 use crate::entities::{
-    CreatGroupParams, CreateFilterParams, CreateGridFilterPayloadPB, CreateGridGroupPayloadPB, CreateGridSortPayloadPB,
-    CreateSortParams, DeleteFilterParams, DeleteFilterPayloadPB, DeleteGroupParams, DeleteGroupPayloadPB,
-    RepeatedGridConfigurationFilterPB, RepeatedGridGroupConfigurationPB, RepeatedGridSortPB,
+    CreatGroupParams, CreateFilterParams, CreateGridFilterPayloadPB, CreateGridGroupPayloadPB, DeleteFilterParams,
+    DeleteFilterPayloadPB, DeleteGroupParams, DeleteGroupPayloadPB, RepeatedGridConfigurationFilterPB,
+    RepeatedGridGroupConfigurationPB,
 };
 use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
 use flowy_error::ErrorCode;
 use flowy_grid_data_model::parser::NotEmptyStr;
 use flowy_grid_data_model::revision::LayoutRevision;
-use flowy_sync::entities::grid::GridSettingChangesetParams;
 use std::collections::HashMap;
 use std::convert::TryInto;
 use strum::IntoEnumIterator;
@@ -27,9 +26,6 @@ pub struct GridSettingPB {
 
     #[pb(index = 4)]
     pub group_configuration_by_field_id: HashMap<String, RepeatedGridGroupConfigurationPB>,
-
-    #[pb(index = 5)]
-    pub sorts_by_field_id: HashMap<String, RepeatedGridSortPB>,
 }
 
 #[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)]
@@ -99,12 +95,6 @@ pub struct GridSettingChangesetPayloadPB {
 
     #[pb(index = 6, one_of)]
     pub delete_group: Option<DeleteGroupPayloadPB>,
-
-    #[pb(index = 7, one_of)]
-    pub insert_sort: Option<CreateGridSortPayloadPB>,
-
-    #[pb(index = 8, one_of)]
-    pub delete_sort: Option<String>,
 }
 
 impl TryInto<GridSettingChangesetParams> for GridSettingChangesetPayloadPB {
@@ -135,16 +125,6 @@ impl TryInto<GridSettingChangesetParams> for GridSettingChangesetPayloadPB {
             None => None,
         };
 
-        let insert_sort = match self.insert_sort {
-            None => None,
-            Some(payload) => Some(payload.try_into()?),
-        };
-
-        let delete_sort = match self.delete_sort {
-            None => None,
-            Some(filter_id) => Some(NotEmptyStr::parse(filter_id).map_err(|_| ErrorCode::FieldIdIsEmpty)?.0),
-        };
-
         Ok(GridSettingChangesetParams {
             grid_id: view_id,
             layout_type: self.layout_type.into(),
@@ -152,8 +132,6 @@ impl TryInto<GridSettingChangesetParams> for GridSettingChangesetPayloadPB {
             delete_filter,
             insert_group,
             delete_group,
-            insert_sort,
-            delete_sort,
         })
     }
 }
@@ -165,8 +143,6 @@ pub struct GridSettingChangesetParams {
     pub delete_filter: Option<DeleteFilterParams>,
     pub insert_group: Option<CreatGroupParams>,
     pub delete_group: Option<DeleteGroupParams>,
-    pub insert_sort: Option<CreateSortParams>,
-    pub delete_sort: Option<String>,
 }
 
 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
deleted file mode 100644
index 28486a1ee6..0000000000
--- a/frontend/rust-lib/flowy-grid/src/entities/sort_entities.rs
+++ /dev/null
@@ -1,68 +0,0 @@
-use flowy_derive::ProtoBuf;
-use flowy_error::ErrorCode;
-use flowy_grid_data_model::parser::NotEmptyStr;
-use flowy_grid_data_model::revision::SortConfigurationRevision;
-use std::convert::TryInto;
-use std::sync::Arc;
-
-#[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)]
-pub struct GridSort {
-    #[pb(index = 1)]
-    pub id: String,
-
-    #[pb(index = 2, one_of)]
-    pub field_id: Option<String>,
-}
-
-impl std::convert::From<&SortConfigurationRevision> for GridSort {
-    fn from(rev: &SortConfigurationRevision) -> Self {
-        GridSort {
-            id: rev.id.clone(),
-
-            field_id: rev.field_id.clone(),
-        }
-    }
-}
-
-#[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)]
-pub struct RepeatedGridSortPB {
-    #[pb(index = 1)]
-    pub items: Vec<GridSort>,
-}
-
-impl std::convert::From<Vec<Arc<SortConfigurationRevision>>> for RepeatedGridSortPB {
-    fn from(revs: Vec<Arc<SortConfigurationRevision>>) -> Self {
-        RepeatedGridSortPB {
-            items: revs.into_iter().map(|rev| rev.as_ref().into()).collect(),
-        }
-    }
-}
-
-impl std::convert::From<Vec<GridSort>> for RepeatedGridSortPB {
-    fn from(items: Vec<GridSort>) -> Self {
-        Self { items }
-    }
-}
-
-#[derive(ProtoBuf, Debug, Default, Clone)]
-pub struct CreateGridSortPayloadPB {
-    #[pb(index = 1, one_of)]
-    pub field_id: Option<String>,
-}
-
-impl TryInto<CreateSortParams> for CreateGridSortPayloadPB {
-    type Error = ErrorCode;
-
-    fn try_into(self) -> Result<CreateSortParams, Self::Error> {
-        let field_id = match self.field_id {
-            None => None,
-            Some(field_id) => Some(NotEmptyStr::parse(field_id).map_err(|_| ErrorCode::FieldIdIsEmpty)?.0),
-        };
-
-        Ok(CreateSortParams { field_id })
-    }
-}
-
-pub struct CreateSortParams {
-    pub field_id: Option<String>,
-}
diff --git a/frontend/rust-lib/flowy-grid/src/event_handler.rs b/frontend/rust-lib/flowy-grid/src/event_handler.rs
index f9f5e39399..47df88b976 100644
--- a/frontend/rust-lib/flowy-grid/src/event_handler.rs
+++ b/frontend/rust-lib/flowy-grid/src/event_handler.rs
@@ -10,7 +10,6 @@ use crate::services::field::{
 use crate::services::row::make_row_from_row_rev;
 use flowy_error::{ErrorCode, FlowyError, FlowyResult};
 use flowy_grid_data_model::revision::FieldRevision;
-use flowy_sync::entities::grid::{FieldChangesetParams, GridSettingChangesetParams};
 use lib_dispatch::prelude::{data_result, AppData, Data, DataResult};
 use std::sync::Arc;
 
diff --git a/frontend/rust-lib/flowy-grid/src/services/filter/filter_service.rs b/frontend/rust-lib/flowy-grid/src/services/filter/filter_service.rs
index a2831c0ad9..8335a36fb2 100644
--- a/frontend/rust-lib/flowy-grid/src/services/filter/filter_service.rs
+++ b/frontend/rust-lib/flowy-grid/src/services/filter/filter_service.rs
@@ -4,7 +4,7 @@
 #![allow(unused_imports)]
 #![allow(unused_results)]
 use crate::dart_notification::{send_dart_notification, GridNotification};
-use crate::entities::{FieldType, GridBlockChangesetPB};
+use crate::entities::{FieldType, GridBlockChangesetPB, GridSettingChangesetParams};
 use crate::services::block_manager::GridBlockManager;
 use crate::services::cell::{AnyCellData, CellFilterOperation};
 use crate::services::field::{
@@ -20,7 +20,6 @@ use crate::services::tasks::{FilterTaskContext, Task, TaskContent};
 use flowy_error::FlowyResult;
 use flowy_grid_data_model::revision::{CellRevision, FieldId, FieldRevision, RowRevision};
 use flowy_sync::client_grid::GridRevisionPad;
-use flowy_sync::entities::grid::GridSettingChangesetParams;
 use rayon::prelude::*;
 use std::collections::HashMap;
 use std::sync::Arc;
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 055501e117..0559cfa364 100644
--- a/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs
+++ b/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs
@@ -15,7 +15,6 @@ use flowy_error::{ErrorCode, FlowyError, FlowyResult};
 use flowy_grid_data_model::revision::*;
 use flowy_revision::{RevisionCloudService, RevisionCompactor, RevisionManager, RevisionObjectBuilder};
 use flowy_sync::client_grid::{GridRevisionChangeset, GridRevisionPad, JsonDeserializer};
-use flowy_sync::entities::grid::{FieldChangesetParams, GridSettingChangesetParams};
 use flowy_sync::entities::revision::Revision;
 use flowy_sync::errors::CollaborateResult;
 use flowy_sync::util::make_text_delta_from_revisions;
@@ -101,14 +100,14 @@ impl GridRevisionEditor {
                 grid_id,
                 name: Some(field.name),
                 desc: Some(field.desc),
-                field_type: Some(field.field_type.into()),
+                field_type: Some(field.field_type.clone().into()),
                 frozen: Some(field.frozen),
                 visibility: Some(field.visibility),
                 width: Some(field.width),
                 type_option_data: Some(type_option_data),
             };
 
-            let _ = self.update_field_rev(changeset, field.field_type.clone()).await?;
+            let _ = self.update_field_rev(changeset, field.field_type).await?;
             let _ = self.notify_did_update_grid_field(&field_id).await?;
         } else {
             let _ = self
@@ -262,60 +261,59 @@ impl GridRevisionEditor {
     }
 
     async fn update_field_rev(&self, params: FieldChangesetParams, field_type: FieldType) -> FlowyResult<()> {
-        let _ = self
-            .modify(|grid| {
-                let deserializer = TypeOptionJsonDeserializer(field_type);
+        self.modify(|grid| {
+            let deserializer = TypeOptionJsonDeserializer(field_type);
 
-                let changeset = grid.modify_field(&params.field_id, |field| {
-                    let mut is_changed = None;
-                    if let Some(name) = changeset.name {
-                        field.name = name;
-                        is_changed = Some(())
-                    }
+            let changeset = grid.modify_field(&params.field_id, |field| {
+                let mut is_changed = None;
+                if let Some(name) = params.name {
+                    field.name = name;
+                    is_changed = Some(())
+                }
 
-                    if let Some(desc) = changeset.desc {
-                        field.desc = desc;
-                        is_changed = Some(())
-                    }
+                if let Some(desc) = params.desc {
+                    field.desc = desc;
+                    is_changed = Some(())
+                }
 
-                    if let Some(field_type) = changeset.field_type {
-                        field.ty = field_type;
-                        is_changed = Some(())
-                    }
+                if let Some(field_type) = params.field_type {
+                    field.ty = field_type;
+                    is_changed = Some(())
+                }
 
-                    if let Some(frozen) = changeset.frozen {
-                        field.frozen = frozen;
-                        is_changed = Some(())
-                    }
+                if let Some(frozen) = params.frozen {
+                    field.frozen = frozen;
+                    is_changed = Some(())
+                }
 
-                    if let Some(visibility) = changeset.visibility {
-                        field.visibility = visibility;
-                        is_changed = Some(())
-                    }
+                if let Some(visibility) = params.visibility {
+                    field.visibility = visibility;
+                    is_changed = Some(())
+                }
 
-                    if let Some(width) = changeset.width {
-                        field.width = width;
-                        is_changed = Some(())
-                    }
+                if let Some(width) = params.width {
+                    field.width = width;
+                    is_changed = Some(())
+                }
 
-                    if let Some(type_option_data) = changeset.type_option_data {
-                        match deserializer.deserialize(type_option_data) {
-                            Ok(json_str) => {
-                                let field_type = field.ty;
-                                field.insert_type_option_str(&field_type, json_str);
-                                is_changed = Some(())
-                            }
-                            Err(err) => {
-                                tracing::error!("Deserialize data to type option json failed: {}", err);
-                            }
+                if let Some(type_option_data) = params.type_option_data {
+                    match deserializer.deserialize(type_option_data) {
+                        Ok(json_str) => {
+                            let field_type = field.ty;
+                            field.insert_type_option_str(&field_type, json_str);
+                            is_changed = Some(())
+                        }
+                        Err(err) => {
+                            tracing::error!("Deserialize data to type option json failed: {}", err);
                         }
                     }
+                }
 
-                    Ok(is_changed)
-                })?;
-                Ok(changeset)
-            })
-            .await?;
+                Ok(is_changed)
+            })?;
+            Ok(changeset)
+        })
+        .await
     }
 
     pub async fn create_block(&self, block_meta_rev: GridBlockMetaRevision) -> FlowyResult<()> {
diff --git a/frontend/rust-lib/flowy-grid/src/services/grid_view_editor.rs b/frontend/rust-lib/flowy-grid/src/services/grid_view_editor.rs
index ac1e905d8a..9a7173035a 100644
--- a/frontend/rust-lib/flowy-grid/src/services/grid_view_editor.rs
+++ b/frontend/rust-lib/flowy-grid/src/services/grid_view_editor.rs
@@ -1,18 +1,23 @@
 use crate::dart_notification::{send_dart_notification, GridNotification};
 use crate::entities::{
-    CreateRowParams, GridFilterConfiguration, GridSettingPB, GroupPB, GroupRowsChangesetPB, InsertedRowPB, RowPB,
+    CreateRowParams, GridFilterConfiguration, GridLayout, GridLayoutPB, GridSettingChangesetParams, GridSettingPB,
+    GroupPB, GroupRowsChangesetPB, InsertedRowPB, RepeatedGridConfigurationFilterPB, RepeatedGridGroupConfigurationPB,
+    RowPB,
 };
 use crate::services::grid_editor_task::GridServiceTaskScheduler;
 use crate::services::grid_view_manager::{GridViewFieldDelegate, GridViewRowDelegate};
-use crate::services::group::{default_group_configuration, GroupConfigurationDelegate, GroupService};
-use crate::services::setting::make_grid_setting;
+use crate::services::group::{
+    default_group_configuration, GroupConfigurationReader, GroupConfigurationWriter, GroupService,
+};
 use flowy_error::{FlowyError, FlowyResult};
-use flowy_grid_data_model::revision::{FieldRevision, GroupConfigurationRevision, RowChangeset, RowRevision};
+use flowy_grid_data_model::revision::{
+    FieldRevision, FieldTypeRevision, GroupConfigurationRevision, RowChangeset, RowRevision,
+};
 use flowy_revision::{RevisionCloudService, RevisionManager, RevisionObjectBuilder};
 use flowy_sync::client_grid::{GridViewRevisionChangeset, GridViewRevisionPad};
-use flowy_sync::entities::grid::GridSettingChangesetParams;
 use flowy_sync::entities::revision::Revision;
 use lib_infra::future::{wrap_future, AFFuture, FutureResult};
+use std::collections::HashMap;
 use std::sync::atomic::{AtomicBool, Ordering};
 use std::sync::Arc;
 use tokio::sync::RwLock;
@@ -46,7 +51,14 @@ impl GridViewRevisionEditor {
         let view_revision_pad = rev_manager.load::<GridViewRevisionPadBuilder>(Some(cloud)).await?;
         let pad = Arc::new(RwLock::new(view_revision_pad));
         let rev_manager = Arc::new(rev_manager);
-        let group_service = GroupService::new(Box::new(pad.clone())).await;
+
+        let configuration_reader = GroupConfigurationReaderImpl(pad.clone());
+        let configuration_writer = GroupConfigurationWriterImpl {
+            user_id: user_id.to_owned(),
+            rev_manager: rev_manager.clone(),
+            view_pad: pad.clone(),
+        };
+        let group_service = GroupService::new(configuration_reader, configuration_writer).await;
         let user_id = user_id.to_owned();
         let did_load_group = AtomicBool::new(false);
         Ok(Self {
@@ -167,7 +179,7 @@ impl GridViewRevisionEditor {
 
     pub(crate) async fn get_setting(&self) -> GridSettingPB {
         let field_revs = self.field_delegate.get_field_revs().await;
-        let grid_setting = make_grid_setting(self.pad.read().await.get_setting_rev(), &field_revs);
+        let grid_setting = make_grid_setting(&*self.pad.read().await, &field_revs);
         grid_setting
     }
 
@@ -177,13 +189,9 @@ impl GridViewRevisionEditor {
         todo!()
     }
 
-    // pub(crate) async fn insert_group(&self, params: CreateGroupParams) -> FlowyResult<()> {
-    //
-    // }
-
     pub(crate) async fn get_filters(&self) -> Vec<GridFilterConfiguration> {
         let field_revs = self.field_delegate.get_field_revs().await;
-        match self.pad.read().await.get_setting_rev().get_all_filters(&field_revs) {
+        match self.pad.read().await.get_all_filters(&field_revs) {
             None => vec![],
             Some(filters) => filters
                 .into_values()
@@ -207,28 +215,24 @@ impl GridViewRevisionEditor {
         match f(&mut *write_guard)? {
             None => {}
             Some(change) => {
-                let _ = self.apply_change(change).await?;
+                let _ = apply_change(&self.user_id, self.rev_manager.clone(), change).await?;
             }
         }
         Ok(())
     }
+}
 
-    async fn apply_change(&self, change: GridViewRevisionChangeset) -> FlowyResult<()> {
-        let GridViewRevisionChangeset { delta, md5 } = change;
-        let user_id = self.user_id.clone();
-        let (base_rev_id, rev_id) = self.rev_manager.next_rev_id_pair();
-        let delta_data = delta.json_bytes();
-        let revision = Revision::new(
-            &self.rev_manager.object_id,
-            base_rev_id,
-            rev_id,
-            delta_data,
-            &user_id,
-            md5,
-        );
-        let _ = self.rev_manager.add_local_revision(&revision).await?;
-        Ok(())
-    }
+async fn apply_change(
+    user_id: &str,
+    rev_manager: Arc<RevisionManager>,
+    change: GridViewRevisionChangeset,
+) -> FlowyResult<()> {
+    let GridViewRevisionChangeset { delta, md5 } = change;
+    let (base_rev_id, rev_id) = rev_manager.next_rev_id_pair();
+    let delta_data = delta.json_bytes();
+    let revision = Revision::new(&rev_manager.object_id, base_rev_id, rev_id, delta_data, &user_id, md5);
+    let _ = rev_manager.add_local_revision(&revision).await?;
+    Ok(())
 }
 
 struct GridViewRevisionCloudService {
@@ -253,19 +257,82 @@ impl RevisionObjectBuilder for GridViewRevisionPadBuilder {
     }
 }
 
-impl GroupConfigurationDelegate for Arc<RwLock<GridViewRevisionPad>> {
-    fn get_group_configuration(&self, field_rev: Arc<FieldRevision>) -> AFFuture<GroupConfigurationRevision> {
-        let view_pad = self.clone();
+struct GroupConfigurationReaderImpl(Arc<RwLock<GridViewRevisionPad>>);
+
+impl GroupConfigurationReader for GroupConfigurationReaderImpl {
+    fn get_group_configuration(&self, field_rev: Arc<FieldRevision>) -> AFFuture<Arc<GroupConfigurationRevision>> {
+        let view_pad = self.0.clone();
         wrap_future(async move {
-            let grid_pad = view_pad.read().await;
-            let configurations = grid_pad.get_groups(&field_rev.id, &field_rev.ty);
+            let view_pad = view_pad.read().await;
+            let configurations = view_pad.get_groups(&field_rev.id, &field_rev.ty);
             match configurations {
-                None => default_group_configuration(&field_rev),
-                Some(mut configurations) => {
-                    assert_eq!(configurations.len(), 1);
-                    (&*configurations.pop().unwrap()).clone()
+                None => {
+                    let default_configuration = default_group_configuration(&field_rev);
+                    Arc::new(default_configuration)
                 }
+                Some(configuration) => configuration,
             }
         })
     }
 }
+
+struct GroupConfigurationWriterImpl {
+    user_id: String,
+    rev_manager: Arc<RevisionManager>,
+    view_pad: Arc<RwLock<GridViewRevisionPad>>,
+}
+
+impl GroupConfigurationWriter for GroupConfigurationWriterImpl {
+    fn save_group_configuration(
+        &self,
+        field_id: &str,
+        field_type: FieldTypeRevision,
+        configuration: Arc<GroupConfigurationRevision>,
+    ) -> AFFuture<FlowyResult<()>> {
+        let user_id = self.user_id.clone();
+        let rev_manager = self.rev_manager.clone();
+        let view_pad = self.view_pad.clone();
+        let field_id = field_id.to_owned();
+
+        wrap_future(async move {
+            let configuration = (&*configuration).clone();
+            match view_pad
+                .write()
+                .await
+                .insert_group_configuration(&field_id, &field_type, configuration)?
+            {
+                None => Ok(()),
+                Some(changeset) => apply_change(&user_id, rev_manager, changeset).await,
+            }
+        })
+    }
+}
+
+pub fn make_grid_setting(view_pad: &GridViewRevisionPad, field_revs: &[Arc<FieldRevision>]) -> GridSettingPB {
+    let current_layout_type: GridLayout = view_pad.layout.clone().into();
+    let filters_by_field_id = view_pad
+        .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, RepeatedGridConfigurationFilterPB>>()
+        })
+        .unwrap_or_default();
+    let groups_by_field_id = view_pad
+        .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, RepeatedGridGroupConfigurationPB>>()
+        })
+        .unwrap_or_default();
+
+    GridSettingPB {
+        layouts: GridLayoutPB::all(),
+        current_layout_type,
+        filter_configuration_by_field_id: filters_by_field_id,
+        group_configuration_by_field_id: groups_by_field_id,
+    }
+}
diff --git a/frontend/rust-lib/flowy-grid/src/services/grid_view_manager.rs b/frontend/rust-lib/flowy-grid/src/services/grid_view_manager.rs
index 178befc10a..42c4ff1c65 100644
--- a/frontend/rust-lib/flowy-grid/src/services/grid_view_manager.rs
+++ b/frontend/rust-lib/flowy-grid/src/services/grid_view_manager.rs
@@ -1,4 +1,6 @@
-use crate::entities::{CreateRowParams, GridFilterConfiguration, GridSettingPB, RepeatedGridGroupPB, RowPB};
+use crate::entities::{
+    CreateRowParams, GridFilterConfiguration, GridSettingChangesetParams, GridSettingPB, RepeatedGridGroupPB, RowPB,
+};
 use crate::manager::GridUser;
 use crate::services::grid_editor_task::GridServiceTaskScheduler;
 use crate::services::grid_view_editor::GridViewRevisionEditor;
@@ -8,7 +10,6 @@ use flowy_error::FlowyResult;
 use flowy_grid_data_model::revision::{FieldRevision, RowChangeset, RowRevision};
 use flowy_revision::disk::SQLiteGridViewRevisionPersistence;
 use flowy_revision::{RevisionCompactor, RevisionManager, RevisionPersistence, SQLiteRevisionSnapshotPersistence};
-use flowy_sync::entities::grid::GridSettingChangesetParams;
 use flowy_sync::entities::revision::Revision;
 use flowy_sync::util::make_text_delta_from_revisions;
 use lib_infra::future::AFFuture;
diff --git a/frontend/rust-lib/flowy-grid/src/services/group/action.rs b/frontend/rust-lib/flowy-grid/src/services/group/action.rs
new file mode 100644
index 0000000000..a495fe0a1f
--- /dev/null
+++ b/frontend/rust-lib/flowy-grid/src/services/group/action.rs
@@ -0,0 +1,23 @@
+use crate::entities::GroupRowsChangesetPB;
+
+use flowy_grid_data_model::revision::{FieldRevision, RowChangeset, RowRevision};
+
+pub trait GroupAction: Send + Sync {
+    type CellDataType;
+    fn can_group(&self, content: &str, cell_data: &Self::CellDataType) -> bool;
+    fn add_row_if_match(&mut self, row_rev: &RowRevision, cell_data: &Self::CellDataType) -> Vec<GroupRowsChangesetPB>;
+    fn remove_row_if_match(
+        &mut self,
+        row_rev: &RowRevision,
+        cell_data: &Self::CellDataType,
+    ) -> Vec<GroupRowsChangesetPB>;
+
+    fn move_row_if_match(
+        &mut self,
+        field_rev: &FieldRevision,
+        row_rev: &RowRevision,
+        row_changeset: &mut RowChangeset,
+        cell_data: &Self::CellDataType,
+        to_row_id: &str,
+    ) -> Vec<GroupRowsChangesetPB>;
+}
diff --git a/frontend/rust-lib/flowy-grid/src/services/group/configuration.rs b/frontend/rust-lib/flowy-grid/src/services/group/configuration.rs
new file mode 100644
index 0000000000..3d737c307f
--- /dev/null
+++ b/frontend/rust-lib/flowy-grid/src/services/group/configuration.rs
@@ -0,0 +1,76 @@
+use flowy_error::FlowyResult;
+use flowy_grid_data_model::revision::{
+    FieldRevision, FieldTypeRevision, GroupConfigurationContentSerde, GroupConfigurationRevision, GroupRecordRevision,
+};
+use lib_infra::future::AFFuture;
+use std::sync::Arc;
+
+pub trait GroupConfigurationReader: Send + Sync + 'static {
+    fn get_group_configuration(&self, field_rev: Arc<FieldRevision>) -> AFFuture<Arc<GroupConfigurationRevision>>;
+}
+
+pub trait GroupConfigurationWriter: Send + Sync + 'static {
+    fn save_group_configuration(
+        &self,
+        field_id: &str,
+        field_type: FieldTypeRevision,
+        configuration: Arc<GroupConfigurationRevision>,
+    ) -> AFFuture<FlowyResult<()>>;
+}
+
+pub trait GroupConfigurationAction: Send + Sync {
+    fn group_records(&self) -> &[GroupRecordRevision];
+    fn save_groups(&self) -> FlowyResult<()>;
+    fn hide_group(&self, group_id: &str) -> FlowyResult<()>;
+    fn show_group(&self, group_id: &str) -> FlowyResult<()>;
+}
+
+pub struct GenericGroupConfiguration<C> {
+    field_rev: Arc<FieldRevision>,
+    reader: Arc<dyn GroupConfigurationReader>,
+    writer: Arc<dyn GroupConfigurationWriter>,
+    configuration: C,
+}
+
+impl<C> GenericGroupConfiguration<C>
+where
+    C: GroupConfigurationContentSerde,
+{
+    pub async fn new(
+        field_rev: Arc<FieldRevision>,
+        reader: Arc<dyn GroupConfigurationReader>,
+        writer: Arc<dyn GroupConfigurationWriter>,
+    ) -> FlowyResult<Self> {
+        let configuration = reader.get_group_configuration(field_rev.clone()).await;
+        let configuration = C::from_configuration(&configuration.content)?;
+        Ok(Self {
+            field_rev,
+            reader,
+            writer,
+            configuration,
+        })
+    }
+}
+
+impl<T> GroupConfigurationReader for Arc<T>
+where
+    T: GroupConfigurationReader,
+{
+    fn get_group_configuration(&self, field_rev: Arc<FieldRevision>) -> AFFuture<Arc<GroupConfigurationRevision>> {
+        (**self).get_group_configuration(field_rev)
+    }
+}
+
+impl<T> GroupConfigurationWriter for Arc<T>
+where
+    T: GroupConfigurationWriter,
+{
+    fn save_group_configuration(
+        &self,
+        field_id: &str,
+        field_type: FieldTypeRevision,
+        configuration: Arc<GroupConfigurationRevision>,
+    ) -> AFFuture<FlowyResult<()>> {
+        (**self).save_group_configuration(field_id, field_type, configuration)
+    }
+}
diff --git a/frontend/rust-lib/flowy-grid/src/services/group/controllers/checkbox_controller.rs b/frontend/rust-lib/flowy-grid/src/services/group/controller_impls/checkbox_controller.rs
similarity index 59%
rename from frontend/rust-lib/flowy-grid/src/services/group/controllers/checkbox_controller.rs
rename to frontend/rust-lib/flowy-grid/src/services/group/controller_impls/checkbox_controller.rs
index c1284dd659..fca49513c8 100644
--- a/frontend/rust-lib/flowy-grid/src/services/group/controllers/checkbox_controller.rs
+++ b/frontend/rust-lib/flowy-grid/src/services/group/controller_impls/checkbox_controller.rs
@@ -1,20 +1,42 @@
-use crate::entities::{CheckboxGroupConfigurationPB, GroupRowsChangesetPB};
-
-use flowy_grid_data_model::revision::{FieldRevision, RowChangeset, RowRevision};
-
+use crate::entities::GroupRowsChangesetPB;
 use crate::services::field::{CheckboxCellData, CheckboxCellDataParser, CheckboxTypeOptionPB, CHECK, UNCHECK};
-use crate::services::group::{GenericGroupController, Group, GroupController, GroupGenerator, Groupable};
+use crate::services::group::action::GroupAction;
+use crate::services::group::configuration::{GenericGroupConfiguration, GroupConfigurationAction};
+use crate::services::group::entities::Group;
+use crate::services::group::group_controller::{GenericGroupController, GroupController, GroupGenerator};
+use flowy_error::FlowyResult;
+use flowy_grid_data_model::revision::{
+    CheckboxGroupConfigurationRevision, FieldRevision, GroupRecordRevision, RowChangeset, RowRevision,
+};
 
 pub type CheckboxGroupController = GenericGroupController<
-    CheckboxGroupConfigurationPB,
+    CheckboxGroupConfigurationRevision,
     CheckboxTypeOptionPB,
     CheckboxGroupGenerator,
     CheckboxCellDataParser,
 >;
 
-impl Groupable for CheckboxGroupController {
-    type CellDataType = CheckboxCellData;
+pub type CheckboxGroupConfiguration = GenericGroupConfiguration<CheckboxGroupConfigurationRevision>;
+impl GroupConfigurationAction for CheckboxGroupConfiguration {
+    fn group_records(&self) -> &[GroupRecordRevision] {
+        todo!()
+    }
 
+    fn save_groups(&self) -> FlowyResult<()> {
+        todo!()
+    }
+
+    fn hide_group(&self, group_id: &str) -> FlowyResult<()> {
+        todo!()
+    }
+
+    fn show_group(&self, group_id: &str) -> FlowyResult<()> {
+        todo!()
+    }
+}
+
+impl GroupAction for CheckboxGroupController {
+    type CellDataType = CheckboxCellData;
     fn can_group(&self, _content: &str, _cell_data: &Self::CellDataType) -> bool {
         false
     }
@@ -55,13 +77,13 @@ impl GroupController for CheckboxGroupController {
 
 pub struct CheckboxGroupGenerator();
 impl GroupGenerator for CheckboxGroupGenerator {
-    type ConfigurationType = CheckboxGroupConfigurationPB;
+    type ConfigurationType = CheckboxGroupConfiguration;
     type TypeOptionType = CheckboxTypeOptionPB;
 
     fn generate_groups(
         field_id: &str,
-        _configuration: &Option<Self::ConfigurationType>,
-        _type_option: &Option<Self::TypeOptionType>,
+        configuration: &Self::ConfigurationType,
+        type_option: &Option<Self::TypeOptionType>,
     ) -> Vec<Group> {
         let check_group = Group::new(
             "true".to_string(),
diff --git a/frontend/rust-lib/flowy-grid/src/services/group/controllers/mod.rs b/frontend/rust-lib/flowy-grid/src/services/group/controller_impls/mod.rs
similarity index 71%
rename from frontend/rust-lib/flowy-grid/src/services/group/controllers/mod.rs
rename to frontend/rust-lib/flowy-grid/src/services/group/controller_impls/mod.rs
index 29ce5d091e..974f311a48 100644
--- a/frontend/rust-lib/flowy-grid/src/services/group/controllers/mod.rs
+++ b/frontend/rust-lib/flowy-grid/src/services/group/controller_impls/mod.rs
@@ -1,7 +1,5 @@
 mod checkbox_controller;
-mod group_controller;
 mod select_option_controller;
 
 pub use checkbox_controller::*;
-pub use group_controller::*;
 pub use select_option_controller::*;
diff --git a/frontend/rust-lib/flowy-grid/src/services/group/controller_impls/select_option_controller/mod.rs b/frontend/rust-lib/flowy-grid/src/services/group/controller_impls/select_option_controller/mod.rs
new file mode 100644
index 0000000000..a2f393d093
--- /dev/null
+++ b/frontend/rust-lib/flowy-grid/src/services/group/controller_impls/select_option_controller/mod.rs
@@ -0,0 +1,6 @@
+mod multi_select_controller;
+mod single_select_controller;
+mod util;
+
+pub use multi_select_controller::*;
+pub use single_select_controller::*;
diff --git a/frontend/rust-lib/flowy-grid/src/services/group/controller_impls/select_option_controller/multi_select_controller.rs b/frontend/rust-lib/flowy-grid/src/services/group/controller_impls/select_option_controller/multi_select_controller.rs
new file mode 100644
index 0000000000..33cd0613cd
--- /dev/null
+++ b/frontend/rust-lib/flowy-grid/src/services/group/controller_impls/select_option_controller/multi_select_controller.rs
@@ -0,0 +1,110 @@
+use crate::entities::GroupRowsChangesetPB;
+use crate::services::cell::insert_select_option_cell;
+use crate::services::field::{MultiSelectTypeOptionPB, SelectOptionCellDataPB, SelectOptionCellDataParser};
+use crate::services::group::action::GroupAction;
+
+use crate::services::group::controller_impls::select_option_controller::util::*;
+use crate::services::group::entities::Group;
+use crate::services::group::group_controller::{GenericGroupController, GroupController, GroupGenerator};
+use flowy_grid_data_model::revision::{
+    FieldRevision, RowChangeset, RowRevision, SelectOptionGroupConfigurationRevision,
+};
+
+// MultiSelect
+pub type MultiSelectGroupController = GenericGroupController<
+    SelectOptionGroupConfigurationRevision,
+    MultiSelectTypeOptionPB,
+    MultiSelectGroupGenerator,
+    SelectOptionCellDataParser,
+>;
+
+impl GroupAction for MultiSelectGroupController {
+    type CellDataType = SelectOptionCellDataPB;
+
+    fn can_group(&self, content: &str, cell_data: &SelectOptionCellDataPB) -> bool {
+        cell_data.select_options.iter().any(|option| option.id == content)
+    }
+
+    fn add_row_if_match(&mut self, row_rev: &RowRevision, cell_data: &Self::CellDataType) -> Vec<GroupRowsChangesetPB> {
+        let mut changesets = vec![];
+        self.groups_map.iter_mut().for_each(|(_, group): (_, &mut Group)| {
+            add_row(group, &mut changesets, cell_data, row_rev);
+        });
+        changesets
+    }
+
+    fn remove_row_if_match(
+        &mut self,
+        row_rev: &RowRevision,
+        cell_data: &Self::CellDataType,
+    ) -> Vec<GroupRowsChangesetPB> {
+        let mut changesets = vec![];
+        self.groups_map.iter_mut().for_each(|(_, group): (_, &mut Group)| {
+            remove_row(group, &mut changesets, cell_data, row_rev);
+        });
+        changesets
+    }
+
+    fn move_row_if_match(
+        &mut self,
+        field_rev: &FieldRevision,
+        row_rev: &RowRevision,
+        row_changeset: &mut RowChangeset,
+        cell_data: &Self::CellDataType,
+        to_row_id: &str,
+    ) -> Vec<GroupRowsChangesetPB> {
+        let mut group_changeset = vec![];
+        self.groups_map.iter_mut().for_each(|(_, group): (_, &mut Group)| {
+            move_row(
+                group,
+                &mut group_changeset,
+                field_rev,
+                row_rev,
+                row_changeset,
+                cell_data,
+                to_row_id,
+            );
+        });
+        group_changeset
+    }
+}
+
+impl GroupController for MultiSelectGroupController {
+    fn will_create_row(&mut self, row_rev: &mut RowRevision, field_rev: &FieldRevision, group_id: &str) {
+        let group: Option<&Group> = self.groups_map.get(group_id);
+        match group {
+            None => tracing::warn!("Can not find the group: {}", group_id),
+            Some(group) => {
+                let cell_rev = insert_select_option_cell(group.id.clone(), field_rev);
+                row_rev.cells.insert(field_rev.id.clone(), cell_rev);
+            }
+        }
+    }
+}
+
+pub struct MultiSelectGroupGenerator();
+impl GroupGenerator for MultiSelectGroupGenerator {
+    type ConfigurationType = SelectOptionGroupConfiguration;
+    type TypeOptionType = MultiSelectTypeOptionPB;
+    fn generate_groups(
+        field_id: &str,
+        configuration: &Self::ConfigurationType,
+        type_option: &Option<Self::TypeOptionType>,
+    ) -> Vec<Group> {
+        match type_option {
+            None => vec![],
+            Some(type_option) => type_option
+                .options
+                .iter()
+                .map(|option| {
+                    Group::new(
+                        option.id.clone(),
+                        field_id.to_owned(),
+                        option.name.clone(),
+                        option.id.clone(),
+                    )
+                })
+                .collect(),
+        }
+    }
+}
diff --git a/frontend/rust-lib/flowy-grid/src/services/group/controller_impls/select_option_controller/single_select_controller.rs b/frontend/rust-lib/flowy-grid/src/services/group/controller_impls/select_option_controller/single_select_controller.rs
new file mode 100644
index 0000000000..4c8360f427
--- /dev/null
+++ b/frontend/rust-lib/flowy-grid/src/services/group/controller_impls/select_option_controller/single_select_controller.rs
@@ -0,0 +1,111 @@
+use crate::entities::{GroupRowsChangesetPB, RowPB};
+use crate::services::cell::insert_select_option_cell;
+use crate::services::field::{SelectOptionCellDataPB, SelectOptionCellDataParser, SingleSelectTypeOptionPB};
+use crate::services::group::action::GroupAction;
+
+use crate::services::group::controller_impls::select_option_controller::util::*;
+use crate::services::group::entities::Group;
+use crate::services::group::group_controller::{GenericGroupController, GroupController, GroupGenerator};
+
+use flowy_grid_data_model::revision::{
+    FieldRevision, RowChangeset, RowRevision, SelectOptionGroupConfigurationRevision,
+};
+
+// SingleSelect
+pub type SingleSelectGroupController = GenericGroupController<
+    SelectOptionGroupConfigurationRevision,
+    SingleSelectTypeOptionPB,
+    SingleSelectGroupGenerator,
+    SelectOptionCellDataParser,
+>;
+
+impl GroupAction for SingleSelectGroupController {
+    type CellDataType = SelectOptionCellDataPB;
+    fn can_group(&self, content: &str, cell_data: &SelectOptionCellDataPB) -> bool {
+        cell_data.select_options.iter().any(|option| option.id == content)
+    }
+
+    fn add_row_if_match(&mut self, row_rev: &RowRevision, cell_data: &Self::CellDataType) -> Vec<GroupRowsChangesetPB> {
+        let mut changesets = vec![];
+        self.groups_map.iter_mut().for_each(|(_, group): (_, &mut Group)| {
+            add_row(group, &mut changesets, cell_data, row_rev);
+        });
+        changesets
+    }
+
+    fn remove_row_if_match(
+        &mut self,
+        row_rev: &RowRevision,
+        cell_data: &Self::CellDataType,
+    ) -> Vec<GroupRowsChangesetPB> {
+        let mut changesets = vec![];
+        self.groups_map.iter_mut().for_each(|(_, group): (_, &mut Group)| {
+            remove_row(group, &mut changesets, cell_data, row_rev);
+        });
+        changesets
+    }
+
+    fn move_row_if_match(
+        &mut self,
+        field_rev: &FieldRevision,
+        row_rev: &RowRevision,
+        row_changeset: &mut RowChangeset,
+        cell_data: &Self::CellDataType,
+        to_row_id: &str,
+    ) -> Vec<GroupRowsChangesetPB> {
+        let mut group_changeset = vec![];
+        self.groups_map.iter_mut().for_each(|(_, group): (_, &mut Group)| {
+            move_row(
+                group,
+                &mut group_changeset,
+                field_rev,
+                row_rev,
+                row_changeset,
+                cell_data,
+                to_row_id,
+            );
+        });
+        group_changeset
+    }
+}
+
+impl GroupController for SingleSelectGroupController {
+    fn will_create_row(&mut self, row_rev: &mut RowRevision, field_rev: &FieldRevision, group_id: &str) {
+        let group: Option<&mut Group> = self.groups_map.get_mut(group_id);
+        match group {
+            None => {}
+            Some(group) => {
+                let cell_rev = insert_select_option_cell(group.id.clone(), field_rev);
+                row_rev.cells.insert(field_rev.id.clone(), cell_rev);
+                group.add_row(RowPB::from(row_rev));
+            }
+        }
+    }
+}
+
+pub struct SingleSelectGroupGenerator();
+impl GroupGenerator for SingleSelectGroupGenerator {
+    type ConfigurationType = SelectOptionGroupConfiguration;
+    type TypeOptionType = SingleSelectTypeOptionPB;
+    fn generate_groups(
+        field_id: &str,
+        configuration: &Self::ConfigurationType,
+        type_option: &Option<Self::TypeOptionType>,
+    ) -> Vec<Group> {
+        match type_option {
+            None => vec![],
+            Some(type_option) => type_option
+                .options
+                .iter()
+                .map(|option| {
+                    Group::new(
+                        option.id.clone(),
+                        field_id.to_owned(),
+                        option.name.clone(),
+                        option.id.clone(),
+                    )
+                })
+                .collect(),
+        }
+    }
+}
diff --git a/frontend/rust-lib/flowy-grid/src/services/group/controller_impls/select_option_controller/util.rs b/frontend/rust-lib/flowy-grid/src/services/group/controller_impls/select_option_controller/util.rs
new file mode 100644
index 0000000000..d95a39f60c
--- /dev/null
+++ b/frontend/rust-lib/flowy-grid/src/services/group/controller_impls/select_option_controller/util.rs
@@ -0,0 +1,108 @@
+use crate::entities::{GroupRowsChangesetPB, InsertedRowPB, RowPB};
+use crate::services::cell::insert_select_option_cell;
+use crate::services::field::SelectOptionCellDataPB;
+use crate::services::group::configuration::{GenericGroupConfiguration, GroupConfigurationAction};
+use crate::services::group::Group;
+use flowy_error::FlowyResult;
+use flowy_grid_data_model::revision::{
+    FieldRevision, GroupRecordRevision, RowChangeset, RowRevision, SelectOptionGroupConfigurationRevision,
+};
+
+pub type SelectOptionGroupConfiguration = GenericGroupConfiguration<SelectOptionGroupConfigurationRevision>;
+impl GroupConfigurationAction for SelectOptionGroupConfiguration {
+    fn group_records(&self) -> &[GroupRecordRevision] {
+        todo!()
+    }
+
+    fn save_groups(&self) -> FlowyResult<()> {
+        todo!()
+    }
+
+    fn hide_group(&self, group_id: &str) -> FlowyResult<()> {
+        todo!()
+    }
+
+    fn show_group(&self, group_id: &str) -> FlowyResult<()> {
+        todo!()
+    }
+}
+
+pub fn add_row(
+    group: &mut Group,
+    changesets: &mut Vec<GroupRowsChangesetPB>,
+    cell_data: &SelectOptionCellDataPB,
+    row_rev: &RowRevision,
+) {
+    cell_data.select_options.iter().for_each(|option| {
+        if option.id == group.id {
+            if !group.contains_row(&row_rev.id) {
+                let row_pb = RowPB::from(row_rev);
+                changesets.push(GroupRowsChangesetPB::insert(
+                    group.id.clone(),
+                    vec![InsertedRowPB::new(row_pb.clone())],
+                ));
+                group.add_row(row_pb);
+            }
+        } else if group.contains_row(&row_rev.id) {
+            changesets.push(GroupRowsChangesetPB::delete(group.id.clone(), vec![row_rev.id.clone()]));
+            group.remove_row(&row_rev.id);
+        }
+    });
+}
+
+pub fn remove_row(
+    group: &mut Group,
+    changesets: &mut Vec<GroupRowsChangesetPB>,
+    cell_data: &SelectOptionCellDataPB,
+    row_rev: &RowRevision,
+) {
+    cell_data.select_options.iter().for_each(|option| {
+        if option.id == group.id && group.contains_row(&row_rev.id) {
+            changesets.push(GroupRowsChangesetPB::delete(group.id.clone(), vec![row_rev.id.clone()]));
+            group.remove_row(&row_rev.id);
+        }
+    });
+}
+
+pub fn move_row(
+    group: &mut Group,
+    group_changeset: &mut Vec<GroupRowsChangesetPB>,
+    field_rev: &FieldRevision,
+    row_rev: &RowRevision,
+    row_changeset: &mut RowChangeset,
+    cell_data: &SelectOptionCellDataPB,
+    to_row_id: &str,
+) {
+    cell_data.select_options.iter().for_each(|option| {
+        // Remove the row in which group contains the row
+        let is_group_contains = group.contains_row(&row_rev.id);
+        let to_index = group.index_of_row(to_row_id);
+
+        if option.id == group.id && is_group_contains {
+            group_changeset.push(GroupRowsChangesetPB::delete(group.id.clone(), vec![row_rev.id.clone()]));
+            group.remove_row(&row_rev.id);
+        }
+
+        // Find the inserted group
+        if let Some(to_index) = to_index {
+            let row_pb = RowPB::from(row_rev);
+            let inserted_row = InsertedRowPB {
+                row: row_pb.clone(),
+                index: Some(to_index as i32),
+            };
+            group_changeset.push(GroupRowsChangesetPB::insert(group.id.clone(), vec![inserted_row]));
+            if group.number_of_row() == to_index {
+                group.add_row(row_pb);
+            } else {
+                group.insert_row(to_index, row_pb);
+            }
+        }
+
+        // If the inserted row comes from other group, it needs to update the corresponding cell content.
+        if to_index.is_some() && option.id != group.id {
+            // Update the corresponding row's cell content.
+            let cell_rev = insert_select_option_cell(group.id.clone(), field_rev);
+            row_changeset.cell_by_field_id.insert(field_rev.id.clone(), cell_rev);
+        }
+    });
+}
diff --git a/frontend/rust-lib/flowy-grid/src/services/group/controllers/select_option_controller.rs b/frontend/rust-lib/flowy-grid/src/services/group/controllers/select_option_controller.rs
deleted file mode 100644
index 29dc95891f..0000000000
--- a/frontend/rust-lib/flowy-grid/src/services/group/controllers/select_option_controller.rs
+++ /dev/null
@@ -1,286 +0,0 @@
-use crate::entities::{GroupRowsChangesetPB, InsertedRowPB, RowPB, SelectOptionGroupConfigurationPB};
-use crate::services::cell::insert_select_option_cell;
-use crate::services::field::{
-    MultiSelectTypeOptionPB, SelectOptionCellDataPB, SelectOptionCellDataParser, SingleSelectTypeOptionPB,
-};
-use crate::services::group::{GenericGroupController, Group, GroupController, GroupGenerator, Groupable};
-use flowy_grid_data_model::revision::{FieldRevision, RowChangeset, RowRevision};
-
-// SingleSelect
-pub type SingleSelectGroupController = GenericGroupController<
-    SelectOptionGroupConfigurationPB,
-    SingleSelectTypeOptionPB,
-    SingleSelectGroupGenerator,
-    SelectOptionCellDataParser,
->;
-
-impl Groupable for SingleSelectGroupController {
-    type CellDataType = SelectOptionCellDataPB;
-    fn can_group(&self, content: &str, cell_data: &SelectOptionCellDataPB) -> bool {
-        cell_data.select_options.iter().any(|option| option.id == content)
-    }
-
-    fn add_row_if_match(&mut self, row_rev: &RowRevision, cell_data: &Self::CellDataType) -> Vec<GroupRowsChangesetPB> {
-        let mut changesets = vec![];
-        self.groups_map.iter_mut().for_each(|(_, group): (_, &mut Group)| {
-            add_row(group, &mut changesets, cell_data, row_rev);
-        });
-        changesets
-    }
-
-    fn remove_row_if_match(
-        &mut self,
-        row_rev: &RowRevision,
-        cell_data: &Self::CellDataType,
-    ) -> Vec<GroupRowsChangesetPB> {
-        let mut changesets = vec![];
-        self.groups_map.iter_mut().for_each(|(_, group): (_, &mut Group)| {
-            remove_row(group, &mut changesets, cell_data, row_rev);
-        });
-        changesets
-    }
-
-    fn move_row_if_match(
-        &mut self,
-        field_rev: &FieldRevision,
-        row_rev: &RowRevision,
-        row_changeset: &mut RowChangeset,
-        cell_data: &Self::CellDataType,
-        to_row_id: &str,
-    ) -> Vec<GroupRowsChangesetPB> {
-        let mut group_changeset = vec![];
-        self.groups_map.iter_mut().for_each(|(_, group): (_, &mut Group)| {
-            move_row(
-                group,
-                &mut group_changeset,
-                field_rev,
-                row_rev,
-                row_changeset,
-                cell_data,
-                to_row_id,
-            );
-        });
-        group_changeset
-    }
-}
-
-impl GroupController for SingleSelectGroupController {
-    fn will_create_row(&mut self, row_rev: &mut RowRevision, field_rev: &FieldRevision, group_id: &str) {
-        let group: Option<&mut Group> = self.groups_map.get_mut(group_id);
-        match group {
-            None => {}
-            Some(group) => {
-                let cell_rev = insert_select_option_cell(group.id.clone(), field_rev);
-                row_rev.cells.insert(field_rev.id.clone(), cell_rev);
-                group.add_row(RowPB::from(row_rev));
-            }
-        }
-    }
-}
-
-pub struct SingleSelectGroupGenerator();
-impl GroupGenerator for SingleSelectGroupGenerator {
-    type ConfigurationType = SelectOptionGroupConfigurationPB;
-    type TypeOptionType = SingleSelectTypeOptionPB;
-    fn generate_groups(
-        field_id: &str,
-        _configuration: &Option<Self::ConfigurationType>,
-        type_option: &Option<Self::TypeOptionType>,
-    ) -> Vec<Group> {
-        match type_option {
-            None => vec![],
-            Some(type_option) => type_option
-                .options
-                .iter()
-                .map(|option| {
-                    Group::new(
-                        option.id.clone(),
-                        field_id.to_owned(),
-                        option.name.clone(),
-                        option.id.clone(),
-                    )
-                })
-                .collect(),
-        }
-    }
-}
-
-// MultiSelect
-pub type MultiSelectGroupController = GenericGroupController<
-    SelectOptionGroupConfigurationPB,
-    MultiSelectTypeOptionPB,
-    MultiSelectGroupGenerator,
-    SelectOptionCellDataParser,
->;
-
-impl Groupable for MultiSelectGroupController {
-    type CellDataType = SelectOptionCellDataPB;
-
-    fn can_group(&self, content: &str, cell_data: &SelectOptionCellDataPB) -> bool {
-        cell_data.select_options.iter().any(|option| option.id == content)
-    }
-
-    fn add_row_if_match(&mut self, row_rev: &RowRevision, cell_data: &Self::CellDataType) -> Vec<GroupRowsChangesetPB> {
-        let mut changesets = vec![];
-        self.groups_map.iter_mut().for_each(|(_, group): (_, &mut Group)| {
-            add_row(group, &mut changesets, cell_data, row_rev);
-        });
-        changesets
-    }
-
-    fn remove_row_if_match(
-        &mut self,
-        row_rev: &RowRevision,
-        cell_data: &Self::CellDataType,
-    ) -> Vec<GroupRowsChangesetPB> {
-        let mut changesets = vec![];
-        self.groups_map.iter_mut().for_each(|(_, group): (_, &mut Group)| {
-            remove_row(group, &mut changesets, cell_data, row_rev);
-        });
-        changesets
-    }
-
-    fn move_row_if_match(
-        &mut self,
-        field_rev: &FieldRevision,
-        row_rev: &RowRevision,
-        row_changeset: &mut RowChangeset,
-        cell_data: &Self::CellDataType,
-        to_row_id: &str,
-    ) -> Vec<GroupRowsChangesetPB> {
-        let mut group_changeset = vec![];
-        self.groups_map.iter_mut().for_each(|(_, group): (_, &mut Group)| {
-            move_row(
-                group,
-                &mut group_changeset,
-                field_rev,
-                row_rev,
-                row_changeset,
-                cell_data,
-                to_row_id,
-            );
-        });
-        group_changeset
-    }
-}
-
-impl GroupController for MultiSelectGroupController {
-    fn will_create_row(&mut self, row_rev: &mut RowRevision, field_rev: &FieldRevision, group_id: &str) {
-        let group: Option<&Group> = self.groups_map.get(group_id);
-        match group {
-            None => tracing::warn!("Can not find the group: {}", group_id),
-            Some(group) => {
-                let cell_rev = insert_select_option_cell(group.id.clone(), field_rev);
-                row_rev.cells.insert(field_rev.id.clone(), cell_rev);
-            }
-        }
-    }
-}
-
-pub struct MultiSelectGroupGenerator();
-impl GroupGenerator for MultiSelectGroupGenerator {
-    type ConfigurationType = SelectOptionGroupConfigurationPB;
-    type TypeOptionType = MultiSelectTypeOptionPB;
-
-    fn generate_groups(
-        field_id: &str,
-        _configuration: &Option<Self::ConfigurationType>,
-        type_option: &Option<Self::TypeOptionType>,
-    ) -> Vec<Group> {
-        match type_option {
-            None => vec![],
-            Some(type_option) => type_option
-                .options
-                .iter()
-                .map(|option| {
-                    Group::new(
-                        option.id.clone(),
-                        field_id.to_owned(),
-                        option.name.clone(),
-                        option.id.clone(),
-                    )
-                })
-                .collect(),
-        }
-    }
-}
-
-fn add_row(
-    group: &mut Group,
-    changesets: &mut Vec<GroupRowsChangesetPB>,
-    cell_data: &SelectOptionCellDataPB,
-    row_rev: &RowRevision,
-) {
-    cell_data.select_options.iter().for_each(|option| {
-        if option.id == group.id {
-            if !group.contains_row(&row_rev.id) {
-                let row_pb = RowPB::from(row_rev);
-                changesets.push(GroupRowsChangesetPB::insert(
-                    group.id.clone(),
-                    vec![InsertedRowPB::new(row_pb.clone())],
-                ));
-                group.add_row(row_pb);
-            }
-        } else if group.contains_row(&row_rev.id) {
-            changesets.push(GroupRowsChangesetPB::delete(group.id.clone(), vec![row_rev.id.clone()]));
-            group.remove_row(&row_rev.id);
-        }
-    });
-}
-
-fn remove_row(
-    group: &mut Group,
-    changesets: &mut Vec<GroupRowsChangesetPB>,
-    cell_data: &SelectOptionCellDataPB,
-    row_rev: &RowRevision,
-) {
-    cell_data.select_options.iter().for_each(|option| {
-        if option.id == group.id && group.contains_row(&row_rev.id) {
-            changesets.push(GroupRowsChangesetPB::delete(group.id.clone(), vec![row_rev.id.clone()]));
-            group.remove_row(&row_rev.id);
-        }
-    });
-}
-
-fn move_row(
-    group: &mut Group,
-    group_changeset: &mut Vec<GroupRowsChangesetPB>,
-    field_rev: &FieldRevision,
-    row_rev: &RowRevision,
-    row_changeset: &mut RowChangeset,
-    cell_data: &SelectOptionCellDataPB,
-    to_row_id: &str,
-) {
-    cell_data.select_options.iter().for_each(|option| {
-        // Remove the row in which group contains the row
-        let is_group_contains = group.contains_row(&row_rev.id);
-        let to_index = group.index_of_row(to_row_id);
-
-        if option.id == group.id && is_group_contains {
-            group_changeset.push(GroupRowsChangesetPB::delete(group.id.clone(), vec![row_rev.id.clone()]));
-            group.remove_row(&row_rev.id);
-        }
-
-        // Find the inserted group
-        if let Some(to_index) = to_index {
-            let row_pb = RowPB::from(row_rev);
-            let inserted_row = InsertedRowPB {
-                row: row_pb.clone(),
-                index: Some(to_index as i32),
-            };
-            group_changeset.push(GroupRowsChangesetPB::insert(group.id.clone(), vec![inserted_row]));
-            if group.number_of_row() == to_index {
-                group.add_row(row_pb);
-            } else {
-                group.insert_row(to_index, row_pb);
-            }
-        }
-
-        // If the inserted row comes from other group, it needs to update the corresponding cell content.
-        if to_index.is_some() && option.id != group.id {
-            // Update the corresponding row's cell content.
-            let cell_rev = insert_select_option_cell(group.id.clone(), field_rev);
-            row_changeset.cell_by_field_id.insert(field_rev.id.clone(), cell_rev);
-        }
-    });
-}
diff --git a/frontend/rust-lib/flowy-grid/src/services/group/entities.rs b/frontend/rust-lib/flowy-grid/src/services/group/entities.rs
new file mode 100644
index 0000000000..dd4171afb0
--- /dev/null
+++ b/frontend/rust-lib/flowy-grid/src/services/group/entities.rs
@@ -0,0 +1,73 @@
+use crate::entities::{GroupPB, RowPB};
+
+#[derive(Clone)]
+pub struct Group {
+    pub id: String,
+    pub field_id: String,
+    pub desc: String,
+    rows: Vec<RowPB>,
+
+    /// [content] is used to determine which group the cell belongs to.
+    pub content: String,
+}
+
+impl std::convert::From<Group> for GroupPB {
+    fn from(group: Group) -> Self {
+        Self {
+            field_id: group.field_id,
+            group_id: group.id,
+            desc: group.desc,
+            rows: group.rows,
+        }
+    }
+}
+
+impl Group {
+    pub fn new(id: String, field_id: String, desc: String, content: String) -> Self {
+        Self {
+            id,
+            field_id,
+            desc,
+            rows: vec![],
+            content,
+        }
+    }
+
+    pub fn contains_row(&self, row_id: &str) -> bool {
+        self.rows.iter().any(|row| row.id == row_id)
+    }
+
+    pub fn remove_row(&mut self, row_id: &str) {
+        match self.rows.iter().position(|row| row.id == row_id) {
+            None => {}
+            Some(pos) => {
+                self.rows.remove(pos);
+            }
+        }
+    }
+
+    pub fn add_row(&mut self, row_pb: RowPB) {
+        match self.rows.iter().find(|row| row.id == row_pb.id) {
+            None => {
+                self.rows.push(row_pb);
+            }
+            Some(_) => {}
+        }
+    }
+
+    pub fn insert_row(&mut self, index: usize, row_pb: RowPB) {
+        if index < self.rows.len() {
+            self.rows.insert(index, row_pb);
+        } else {
+            tracing::error!("Insert row index:{} beyond the bounds:{},", index, self.rows.len());
+        }
+    }
+
+    pub fn index_of_row(&self, row_id: &str) -> Option<usize> {
+        self.rows.iter().position(|row| row.id == row_id)
+    }
+
+    pub fn number_of_row(&self) -> usize {
+        self.rows.len()
+    }
+}
diff --git a/frontend/rust-lib/flowy-grid/src/services/group/controllers/group_controller.rs b/frontend/rust-lib/flowy-grid/src/services/group/group_controller.rs
similarity index 57%
rename from frontend/rust-lib/flowy-grid/src/services/group/controllers/group_controller.rs
rename to frontend/rust-lib/flowy-grid/src/services/group/group_controller.rs
index 07dcff3f77..fb2c0aaa6e 100644
--- a/frontend/rust-lib/flowy-grid/src/services/group/controllers/group_controller.rs
+++ b/frontend/rust-lib/flowy-grid/src/services/group/group_controller.rs
@@ -1,54 +1,43 @@
-use crate::entities::{GroupPB, GroupRowsChangesetPB, RowPB};
+use crate::entities::{GroupRowsChangesetPB, RowPB};
 use crate::services::cell::{decode_any_cell_data, CellBytesParser};
-use bytes::Bytes;
+use crate::services::group::action::GroupAction;
+use crate::services::group::configuration::{GenericGroupConfiguration, GroupConfigurationReader};
+use crate::services::group::entities::Group;
 use flowy_error::FlowyResult;
 use flowy_grid_data_model::revision::{
-    FieldRevision, GroupConfigurationRevision, RowChangeset, RowRevision, TypeOptionDataDeserializer,
+    FieldRevision, GroupConfigurationContentSerde, GroupConfigurationRevision, RowChangeset, RowRevision,
+    TypeOptionDataDeserializer,
 };
 use indexmap::IndexMap;
+use lib_infra::future::AFFuture;
 use std::marker::PhantomData;
 use std::sync::Arc;
 
+const DEFAULT_GROUP_ID: &str = "default_group";
+
+// Each kind of group must implement this trait to provide custom group
+// operations. For example, insert cell data to the row_rev when creating
+// a new row.
+pub trait GroupController: GroupControllerSharedAction + Send + Sync {
+    fn will_create_row(&mut self, row_rev: &mut RowRevision, field_rev: &FieldRevision, group_id: &str);
+}
+
 pub trait GroupGenerator {
     type ConfigurationType;
     type TypeOptionType;
 
     fn generate_groups(
         field_id: &str,
-        configuration: &Option<Self::ConfigurationType>,
+        configuration: &Self::ConfigurationType,
         type_option: &Option<Self::TypeOptionType>,
     ) -> Vec<Group>;
 }
 
-pub trait Groupable: Send + Sync {
-    type CellDataType;
-    fn can_group(&self, content: &str, cell_data: &Self::CellDataType) -> bool;
-    fn add_row_if_match(&mut self, row_rev: &RowRevision, cell_data: &Self::CellDataType) -> Vec<GroupRowsChangesetPB>;
-    fn remove_row_if_match(
-        &mut self,
-        row_rev: &RowRevision,
-        cell_data: &Self::CellDataType,
-    ) -> Vec<GroupRowsChangesetPB>;
-
-    fn move_row_if_match(
-        &mut self,
-        field_rev: &FieldRevision,
-        row_rev: &RowRevision,
-        row_changeset: &mut RowChangeset,
-        cell_data: &Self::CellDataType,
-        to_row_id: &str,
-    ) -> Vec<GroupRowsChangesetPB>;
-}
-
-pub trait GroupController: GroupControllerSharedAction + Send + Sync {
-    fn will_create_row(&mut self, row_rev: &mut RowRevision, field_rev: &FieldRevision, group_id: &str);
-}
-
+// Defines the shared actions each group controller can perform.
 pub trait GroupControllerSharedAction: Send + Sync {
     // The field that is used for grouping the rows
     fn field_id(&self) -> &str;
-    fn groups(&self) -> Vec<Group>;
-    fn group_rows(&mut self, row_revs: &[Arc<RowRevision>], field_rev: &FieldRevision) -> FlowyResult<()>;
+    fn fill_groups(&mut self, row_revs: &[Arc<RowRevision>], field_rev: &FieldRevision) -> FlowyResult<Vec<Group>>;
     fn did_update_row(
         &mut self,
         row_rev: &RowRevision,
@@ -70,105 +59,35 @@ pub trait GroupControllerSharedAction: Send + Sync {
     ) -> FlowyResult<Vec<GroupRowsChangesetPB>>;
 }
 
-const DEFAULT_GROUP_ID: &str = "default_group";
-
-/// C: represents the group configuration structure
+/// C: represents the group configuration that impl [GroupConfigurationSerde]
 /// T: the type option data deserializer that impl [TypeOptionDataDeserializer]
 /// G: the group generator, [GroupGenerator]
 /// P: the parser that impl [CellBytesParser] for the CellBytes
 pub struct GenericGroupController<C, T, G, P> {
     pub field_id: String,
     pub groups_map: IndexMap<String, Group>,
+
+    /// default_group is used to store the rows that don't belong to any groups.
     default_group: Group,
     pub type_option: Option<T>,
-    pub configuration: Option<C>,
+    pub configuration: GenericGroupConfiguration<C>,
     group_action_phantom: PhantomData<G>,
     cell_parser_phantom: PhantomData<P>,
 }
 
-#[derive(Clone)]
-pub struct Group {
-    pub id: String,
-    pub field_id: String,
-    pub desc: String,
-    rows: Vec<RowPB>,
-    pub content: String,
-}
-
-impl std::convert::From<Group> for GroupPB {
-    fn from(group: Group) -> Self {
-        Self {
-            field_id: group.field_id,
-            group_id: group.id,
-            desc: group.desc,
-            rows: group.rows,
-        }
-    }
-}
-
-impl Group {
-    pub fn new(id: String, field_id: String, desc: String, content: String) -> Self {
-        Self {
-            id,
-            field_id,
-            desc,
-            rows: vec![],
-            content,
-        }
-    }
-
-    pub fn contains_row(&self, row_id: &str) -> bool {
-        self.rows.iter().any(|row| row.id == row_id)
-    }
-
-    pub fn remove_row(&mut self, row_id: &str) {
-        match self.rows.iter().position(|row| row.id == row_id) {
-            None => {}
-            Some(pos) => {
-                self.rows.remove(pos);
-            }
-        }
-    }
-
-    pub fn add_row(&mut self, row_pb: RowPB) {
-        match self.rows.iter().find(|row| row.id == row_pb.id) {
-            None => {
-                self.rows.push(row_pb);
-            }
-            Some(_) => {}
-        }
-    }
-
-    pub fn insert_row(&mut self, index: usize, row_pb: RowPB) {
-        if index < self.rows.len() {
-            self.rows.insert(index, row_pb);
-        } else {
-            tracing::error!("Insert row index:{} beyond the bounds:{},", index, self.rows.len());
-        }
-    }
-
-    pub fn index_of_row(&self, row_id: &str) -> Option<usize> {
-        self.rows.iter().position(|row| row.id == row_id)
-    }
-
-    pub fn number_of_row(&self) -> usize {
-        self.rows.len()
-    }
-}
-
 impl<C, T, G, P> GenericGroupController<C, T, G, P>
 where
-    C: TryFrom<Bytes, Error = protobuf::ProtobufError>,
+    C: GroupConfigurationContentSerde,
     T: TypeOptionDataDeserializer,
-    G: GroupGenerator<ConfigurationType = C, TypeOptionType = T>,
+    G: GroupGenerator<ConfigurationType = GenericGroupConfiguration<C>, TypeOptionType = T>,
 {
-    pub fn new(field_rev: &Arc<FieldRevision>, configuration: GroupConfigurationRevision) -> FlowyResult<Self> {
-        // let configuration = match configuration.content {
-        //     None => None,
-        //     Some(content) => Some(C::try_from(Bytes::from(content))?),
-        // };
-
-        let configuration = None;
+    pub async fn new(
+        field_rev: &Arc<FieldRevision>,
+        configuration_reader: Arc<dyn GroupConfigurationReader>,
+        configuration_writer: Arc<dyn GroupConfigurationReader>,
+    ) -> FlowyResult<Self> {
+        let configuration =
+            GenericGroupConfiguration::<C>::new(field_rev.clone(), configuration_reader, configuration_writer).await?;
         let field_type_rev = field_rev.ty;
         let type_option = field_rev.get_type_option_entry::<T>(field_type_rev);
         let groups = G::generate_groups(&field_rev.id, &configuration, &type_option);
@@ -195,55 +114,52 @@ where
 impl<C, T, G, P> GroupControllerSharedAction for GenericGroupController<C, T, G, P>
 where
     P: CellBytesParser,
-    Self: Groupable<CellDataType = P::Object>,
+    Self: GroupAction<CellDataType = P::Object>,
 {
     fn field_id(&self) -> &str {
         &self.field_id
     }
 
-    fn groups(&self) -> Vec<Group> {
-        let default_group = self.default_group.clone();
-        let mut groups: Vec<Group> = self.groups_map.values().cloned().collect();
-        if !default_group.rows.is_empty() {
-            groups.push(default_group);
-        }
-        groups
-    }
-
-    fn group_rows(&mut self, row_revs: &[Arc<RowRevision>], field_rev: &FieldRevision) -> FlowyResult<()> {
-        if self.configuration.is_none() {
-            return Ok(());
-        }
+    fn fill_groups(&mut self, row_revs: &[Arc<RowRevision>], field_rev: &FieldRevision) -> FlowyResult<Vec<Group>> {
+        // if self.configuration.is_none() {
+        //     return Ok(vec![]);
+        // }
 
         for row_rev in row_revs {
             if let Some(cell_rev) = row_rev.cells.get(&self.field_id) {
-                let mut records: Vec<GroupRecord> = vec![];
+                let mut group_rows: Vec<GroupRow> = vec![];
                 let cell_bytes = decode_any_cell_data(cell_rev.data.clone(), field_rev);
                 let cell_data = cell_bytes.parser::<P>()?;
                 for group in self.groups_map.values() {
                     if self.can_group(&group.content, &cell_data) {
-                        records.push(GroupRecord {
+                        group_rows.push(GroupRow {
                             row: row_rev.into(),
                             group_id: group.id.clone(),
                         });
                     }
                 }
 
-                if records.is_empty() {
-                    self.default_group.rows.push(row_rev.into());
+                if group_rows.is_empty() {
+                    self.default_group.add_row(row_rev.into());
                 } else {
-                    for record in records {
-                        if let Some(group) = self.groups_map.get_mut(&record.group_id) {
-                            group.rows.push(record.row);
+                    for group_row in group_rows {
+                        if let Some(group) = self.groups_map.get_mut(&group_row.group_id) {
+                            group.add_row(group_row.row);
                         }
                     }
                 }
             } else {
-                self.default_group.rows.push(row_rev.into());
+                self.default_group.add_row(row_rev.into());
             }
         }
 
-        Ok(())
+        let default_group = self.default_group.clone();
+        let mut groups: Vec<Group> = self.groups_map.values().cloned().collect();
+        if !default_group.number_of_row() == 0 {
+            groups.push(default_group);
+        }
+
+        Ok(groups)
     }
 
     fn did_update_row(
@@ -292,7 +208,7 @@ where
     }
 }
 
-struct GroupRecord {
+struct GroupRow {
     row: RowPB,
     group_id: String,
 }
diff --git a/frontend/rust-lib/flowy-grid/src/services/group/group_service.rs b/frontend/rust-lib/flowy-grid/src/services/group/group_service.rs
index c07b3acec4..42e687445d 100644
--- a/frontend/rust-lib/flowy-grid/src/services/group/group_service.rs
+++ b/frontend/rust-lib/flowy-grid/src/services/group/group_service.rs
@@ -2,44 +2,48 @@ use crate::entities::{
     CheckboxGroupConfigurationPB, DateGroupConfigurationPB, FieldType, GroupRowsChangesetPB,
     NumberGroupConfigurationPB, SelectOptionGroupConfigurationPB, TextGroupConfigurationPB, UrlGroupConfigurationPB,
 };
+use crate::services::group::configuration::GroupConfigurationReader;
+use crate::services::group::group_controller::GroupController;
 use crate::services::group::{
-    CheckboxGroupController, Group, GroupController, MultiSelectGroupController, SingleSelectGroupController,
+    CheckboxGroupController, Group, GroupConfigurationWriter, MultiSelectGroupController, SingleSelectGroupController,
 };
-use bytes::Bytes;
 use flowy_error::FlowyResult;
 use flowy_grid_data_model::revision::{
-    gen_grid_group_id, CheckboxGroupConfigurationRevision, DateGroupConfigurationRevision, FieldRevision,
-    GroupConfigurationRevision, NumberGroupConfigurationRevision, RowChangeset, RowRevision,
-    SelectOptionGroupConfigurationRevision, TextGroupConfigurationRevision, UrlGroupConfigurationRevision,
+    CheckboxGroupConfigurationRevision, DateGroupConfigurationRevision, FieldRevision, GroupConfigurationRevision,
+    NumberGroupConfigurationRevision, RowChangeset, RowRevision, SelectOptionGroupConfigurationRevision,
+    TextGroupConfigurationRevision, UrlGroupConfigurationRevision,
 };
-use lib_infra::future::AFFuture;
+
 use std::future::Future;
 use std::sync::Arc;
 use tokio::sync::RwLock;
 
-pub trait GroupConfigurationDelegate: Send + Sync + 'static {
-    fn get_group_configuration(&self, field_rev: Arc<FieldRevision>) -> AFFuture<GroupConfigurationRevision>;
-}
-
 pub(crate) struct GroupService {
-    delegate: Box<dyn GroupConfigurationDelegate>,
+    configuration_reader: Arc<dyn GroupConfigurationReader>,
+    configuration_writer: Arc<dyn GroupConfigurationWriter>,
     group_controller: Option<Arc<RwLock<dyn GroupController>>>,
 }
 
 impl GroupService {
-    pub(crate) async fn new(delegate: Box<dyn GroupConfigurationDelegate>) -> Self {
+    pub(crate) async fn new<R, W>(configuration_reader: R, configuration_writer: W) -> Self
+    where
+        R: GroupConfigurationReader,
+        W: GroupConfigurationWriter,
+    {
         Self {
-            delegate,
+            configuration_reader: Arc::new(configuration_reader),
+            configuration_writer: Arc::new(configuration_writer),
             group_controller: None,
         }
     }
 
     pub(crate) async fn groups(&self) -> Vec<Group> {
-        if let Some(group_action_handler) = self.group_controller.as_ref() {
-            group_action_handler.read().await.groups()
-        } else {
-            vec![]
-        }
+        // if let Some(group_action_handler) = self.group_controller.as_ref() {
+        //     group_action_handler.read().await.groups()
+        // } else {
+        //     vec![]
+        // }
+        todo!()
     }
 
     pub(crate) async fn load_groups(
@@ -49,13 +53,25 @@ impl GroupService {
     ) -> Option<Vec<Group>> {
         let field_rev = find_group_field(field_revs)?;
         let field_type: FieldType = field_rev.ty.into();
-        let configuration = self.delegate.get_group_configuration(field_rev.clone()).await;
-        match self
-            .build_groups(&field_type, &field_rev, row_revs, configuration)
-            .await
-        {
-            Ok(groups) => Some(groups),
-            Err(_) => None,
+        match self.make_group_controller(&field_type, &field_rev).await {
+            Ok(group_controller) => {
+                self.group_controller = group_controller;
+                let mut groups = vec![];
+                if let Some(group_action_handler) = self.group_controller.as_ref() {
+                    let mut write_guard = group_action_handler.write().await;
+                    groups = match write_guard.fill_groups(&row_revs, &field_rev) {
+                        Ok(groups) => groups,
+                        Err(e) => {
+                            tracing::error!("Fill groups failed:{:?}", e);
+                            vec![]
+                        }
+                    };
+
+                    drop(write_guard);
+                }
+                Some(groups)
+            }
+            Err(_) => Some(vec![]),
         }
     }
 
@@ -151,14 +167,13 @@ impl GroupService {
         }
     }
 
-    #[tracing::instrument(level = "trace", skip_all, err)]
-    async fn build_groups(
+    #[tracing::instrument(level = "trace", skip_all)]
+    async fn make_group_controller(
         &mut self,
         field_type: &FieldType,
         field_rev: &Arc<FieldRevision>,
-        row_revs: Vec<Arc<RowRevision>>,
-        configuration: GroupConfigurationRevision,
-    ) -> FlowyResult<Vec<Group>> {
+    ) -> FlowyResult<Option<Arc<RwLock<dyn GroupController>>>> {
+        let mut group_controller: Option<Arc<RwLock<dyn GroupController>>> = None;
         match field_type {
             FieldType::RichText => {
                 // let generator = GroupGenerator::<TextGroupConfigurationPB>::from_configuration(configuration);
@@ -170,31 +185,37 @@ impl GroupService {
                 // let generator = GroupGenerator::<DateGroupConfigurationPB>::from_configuration(configuration);
             }
             FieldType::SingleSelect => {
-                let controller = SingleSelectGroupController::new(field_rev, configuration)?;
-                self.group_controller = Some(Arc::new(RwLock::new(controller)));
+                let controller = SingleSelectGroupController::new(
+                    field_rev,
+                    self.configuration_reader.clone(),
+                    self.configuration_writer.clone(),
+                )
+                .await?;
+                group_controller = Some(Arc::new(RwLock::new(controller)));
             }
             FieldType::MultiSelect => {
-                let controller = MultiSelectGroupController::new(field_rev, configuration)?;
-                self.group_controller = Some(Arc::new(RwLock::new(controller)));
+                let controller = MultiSelectGroupController::new(
+                    field_rev,
+                    self.configuration_reader.clone(),
+                    self.configuration_writer.clone(),
+                )
+                .await?;
+                group_controller = Some(Arc::new(RwLock::new(controller)));
             }
             FieldType::Checkbox => {
-                let controller = CheckboxGroupController::new(field_rev, configuration)?;
-                self.group_controller = Some(Arc::new(RwLock::new(controller)));
+                let controller = CheckboxGroupController::new(
+                    field_rev,
+                    self.configuration_reader.clone(),
+                    self.configuration_writer.clone(),
+                )
+                .await?;
+                group_controller = Some(Arc::new(RwLock::new(controller)))
             }
             FieldType::URL => {
                 // let generator = GroupGenerator::<UrlGroupConfigurationPB>::from_configuration(configuration);
             }
-        };
-
-        let mut groups = vec![];
-        if let Some(group_action_handler) = self.group_controller.as_ref() {
-            let mut write_guard = group_action_handler.write().await;
-            let _ = write_guard.group_rows(&row_revs, field_rev)?;
-            groups = write_guard.groups();
-            drop(write_guard);
         }
-
-        Ok(groups)
+        Ok(group_controller)
     }
 }
 
diff --git a/frontend/rust-lib/flowy-grid/src/services/group/mod.rs b/frontend/rust-lib/flowy-grid/src/services/group/mod.rs
index f8b96c8bab..19536b8c5b 100644
--- a/frontend/rust-lib/flowy-grid/src/services/group/mod.rs
+++ b/frontend/rust-lib/flowy-grid/src/services/group/mod.rs
@@ -1,5 +1,11 @@
-mod controllers;
+mod action;
+mod configuration;
+mod controller_impls;
+mod entities;
+mod group_controller;
 mod group_service;
 
-pub(crate) use controllers::*;
+pub(crate) use configuration::*;
+pub(crate) use controller_impls::*;
+pub(crate) use entities::*;
 pub(crate) use group_service::*;
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 1cc16f7da7..16ee630cc7 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
@@ -1,11 +1,4 @@
-use crate::entities::{
-    GridLayout, GridLayoutPB, GridSettingPB, RepeatedGridConfigurationFilterPB, RepeatedGridGroupConfigurationPB,
-    RepeatedGridSortPB,
-};
-use flowy_grid_data_model::revision::{FieldRevision, SettingRevision};
-use flowy_sync::entities::grid::{CreateFilterParams, DeleteFilterParams, GridSettingChangesetParams};
-use std::collections::HashMap;
-use std::sync::Arc;
+use crate::entities::{CreateFilterParams, DeleteFilterParams, GridLayout, GridSettingChangesetParams};
 
 pub struct GridSettingChangesetBuilder {
     params: GridSettingChangesetParams,
@@ -20,8 +13,6 @@ impl GridSettingChangesetBuilder {
             delete_filter: None,
             insert_group: None,
             delete_group: None,
-            insert_sort: None,
-            delete_sort: None,
         };
         Self { params }
     }
@@ -40,42 +31,3 @@ impl GridSettingChangesetBuilder {
         self.params
     }
 }
-
-pub fn make_grid_setting(grid_setting_rev: &SettingRevision, field_revs: &[Arc<FieldRevision>]) -> GridSettingPB {
-    let current_layout_type: GridLayout = grid_setting_rev.layout.clone().into();
-    let filters_by_field_id = grid_setting_rev
-        .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, RepeatedGridConfigurationFilterPB>>()
-        })
-        .unwrap_or_default();
-    let groups_by_field_id = grid_setting_rev
-        .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, RepeatedGridGroupConfigurationPB>>()
-        })
-        .unwrap_or_default();
-    let sorts_by_field_id = grid_setting_rev
-        .get_all_sort()
-        .map(|sorts_by_field_id| {
-            sorts_by_field_id
-                .into_iter()
-                .map(|(k, v)| (k, v.into()))
-                .collect::<HashMap<String, RepeatedGridSortPB>>()
-        })
-        .unwrap_or_default();
-
-    GridSettingPB {
-        layouts: GridLayoutPB::all(),
-        current_layout_type,
-        filter_configuration_by_field_id: filters_by_field_id,
-        group_configuration_by_field_id: groups_by_field_id,
-        sorts_by_field_id,
-    }
-}
diff --git a/shared-lib/flowy-grid-data-model/src/revision/filter_rev.rs b/shared-lib/flowy-grid-data-model/src/revision/filter_rev.rs
new file mode 100644
index 0000000000..7079b52229
--- /dev/null
+++ b/shared-lib/flowy-grid-data-model/src/revision/filter_rev.rs
@@ -0,0 +1,9 @@
+use serde::{Deserialize, Serialize};
+
+#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq, Hash)]
+pub struct FilterConfigurationRevision {
+    pub id: String,
+    pub field_id: String,
+    pub condition: u8,
+    pub content: Option<String>,
+}
diff --git a/shared-lib/flowy-grid-data-model/src/revision/grid_setting_rev.rs b/shared-lib/flowy-grid-data-model/src/revision/grid_setting_rev.rs
index ff15170932..01ca80a380 100644
--- a/shared-lib/flowy-grid-data-model/src/revision/grid_setting_rev.rs
+++ b/shared-lib/flowy-grid-data-model/src/revision/grid_setting_rev.rs
@@ -1,8 +1,7 @@
-use crate::revision::{FieldRevision, FieldTypeRevision};
+use crate::revision::{FieldRevision, FieldTypeRevision, FilterConfigurationRevision, GroupConfigurationRevision};
 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;
@@ -15,6 +14,7 @@ pub fn gen_grid_group_id() -> String {
     nanoid!(6)
 }
 
+#[allow(dead_code)]
 pub fn gen_grid_sort_id() -> String {
     nanoid!(6)
 }
@@ -24,114 +24,6 @@ pub type FilterConfigurationsByFieldId = HashMap<String, Vec<Arc<FilterConfigura
 //
 pub type GroupConfiguration = Configuration<GroupConfigurationRevision>;
 pub type GroupConfigurationsByFieldId = HashMap<String, Vec<Arc<GroupConfigurationRevision>>>;
-//
-pub type SortConfiguration = Configuration<SortConfigurationRevision>;
-pub type SortConfigurationsByFieldId = HashMap<String, Vec<Arc<SortConfigurationRevision>>>;
-
-#[derive(Debug, Clone, Serialize, Deserialize, Default, Eq, PartialEq)]
-pub struct SettingRevision {
-    pub layout: LayoutRevision,
-
-    pub filters: FilterConfiguration,
-
-    #[serde(default)]
-    pub groups: GroupConfiguration,
-
-    #[serde(skip)]
-    pub sorts: SortConfiguration,
-}
-
-#[derive(Debug, PartialEq, Eq, Hash, Clone, Serialize_repr, Deserialize_repr)]
-#[repr(u8)]
-pub enum LayoutRevision {
-    Table = 0,
-    Board = 1,
-}
-
-impl ToString for LayoutRevision {
-    fn to_string(&self) -> String {
-        let layout_rev = self.clone() as u8;
-        layout_rev.to_string()
-    }
-}
-
-impl std::default::Default for LayoutRevision {
-    fn default() -> Self {
-        LayoutRevision::Table
-    }
-}
-
-impl SettingRevision {
-    pub fn get_all_groups(&self, field_revs: &[Arc<FieldRevision>]) -> Option<GroupConfigurationsByFieldId> {
-        self.groups.get_all_objects(field_revs)
-    }
-
-    pub fn get_groups(
-        &self,
-        field_id: &str,
-        field_type_rev: &FieldTypeRevision,
-    ) -> Option<Vec<Arc<GroupConfigurationRevision>>> {
-        self.groups.get_objects(field_id, field_type_rev)
-    }
-
-    pub fn get_mut_groups(
-        &mut self,
-        field_id: &str,
-        field_type: &FieldTypeRevision,
-    ) -> Option<&mut Vec<Arc<GroupConfigurationRevision>>> {
-        self.groups.get_mut_objects(field_id, field_type)
-    }
-
-    pub fn insert_group(
-        &mut self,
-        field_id: &str,
-        field_type: &FieldTypeRevision,
-        group_rev: GroupConfigurationRevision,
-    ) {
-        // only one group can be set
-        self.groups.remove_all();
-        self.groups.insert_object(field_id, field_type, group_rev);
-    }
-
-    pub fn get_all_filters(&self, field_revs: &[Arc<FieldRevision>]) -> Option<FilterConfigurationsByFieldId> {
-        self.filters.get_all_objects(field_revs)
-    }
-
-    pub fn get_filters(
-        &self,
-        field_id: &str,
-        field_type_rev: &FieldTypeRevision,
-    ) -> Option<Vec<Arc<FilterConfigurationRevision>>> {
-        self.filters.get_objects(field_id, field_type_rev)
-    }
-
-    pub fn get_mut_filters(
-        &mut self,
-        field_id: &str,
-        field_type: &FieldTypeRevision,
-    ) -> Option<&mut Vec<Arc<FilterConfigurationRevision>>> {
-        self.filters.get_mut_objects(field_id, field_type)
-    }
-
-    pub fn insert_filter(
-        &mut self,
-        field_id: &str,
-        field_type: &FieldTypeRevision,
-        filter_rev: FilterConfigurationRevision,
-    ) {
-        self.filters.insert_object(field_id, field_type, filter_rev);
-    }
-
-    pub fn get_all_sort(&self) -> Option<SortConfigurationsByFieldId> {
-        None
-    }
-}
-
-#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq)]
-pub struct SortConfigurationRevision {
-    pub id: String,
-    pub field_id: Option<String>,
-}
 
 #[derive(Debug, Clone, Serialize, Deserialize, Default, Eq, PartialEq)]
 #[serde(transparent)]
@@ -239,38 +131,3 @@ where
         &mut self.object_by_field_type
     }
 }
-
-pub trait GroupConfigurationSerde {
-    fn from_configuration(s: &str) -> Result<Self, serde_json::Error>;
-}
-
-#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq)]
-pub struct GroupConfigurationRevision {
-    pub id: String,
-    pub field_id: String,
-    pub field_type_rev: FieldTypeRevision,
-    pub content: String,
-}
-
-impl GroupConfigurationRevision {
-    pub fn new<T>(field_id: String, field_type: FieldTypeRevision, content: T) -> Result<Self, serde_json::Error>
-    where
-        T: serde::Serialize,
-    {
-        let content = serde_json::to_string(&content)?;
-        Ok(Self {
-            id: gen_grid_group_id(),
-            field_id,
-            field_type_rev: field_type,
-            content,
-        })
-    }
-}
-
-#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq, Hash)]
-pub struct FilterConfigurationRevision {
-    pub id: String,
-    pub field_id: String,
-    pub condition: u8,
-    pub content: Option<String>,
-}
diff --git a/shared-lib/flowy-grid-data-model/src/revision/grid_view.rs b/shared-lib/flowy-grid-data-model/src/revision/grid_view.rs
index 2fcc2fc4eb..9d4df3067e 100644
--- a/shared-lib/flowy-grid-data-model/src/revision/grid_view.rs
+++ b/shared-lib/flowy-grid-data-model/src/revision/grid_view.rs
@@ -1,19 +1,49 @@
-use crate::revision::SettingRevision;
+use crate::revision::{
+    FieldRevision, FieldTypeRevision, FilterConfiguration, FilterConfigurationRevision, FilterConfigurationsByFieldId,
+    GroupConfiguration, GroupConfigurationRevision, GroupConfigurationsByFieldId,
+};
 use nanoid::nanoid;
 use serde::{Deserialize, Serialize};
+use serde_repr::*;
+use std::sync::Arc;
 
 #[allow(dead_code)]
 pub fn gen_grid_view_id() -> String {
     nanoid!(6)
 }
 
+#[derive(Debug, PartialEq, Eq, Hash, Clone, Serialize_repr, Deserialize_repr)]
+#[repr(u8)]
+pub enum LayoutRevision {
+    Table = 0,
+    Board = 1,
+}
+
+impl ToString for LayoutRevision {
+    fn to_string(&self) -> String {
+        let layout_rev = self.clone() as u8;
+        layout_rev.to_string()
+    }
+}
+
+impl std::default::Default for LayoutRevision {
+    fn default() -> Self {
+        LayoutRevision::Table
+    }
+}
+
 #[derive(Debug, Clone, Default, Serialize, Deserialize)]
 pub struct GridViewRevision {
     pub view_id: String,
 
     pub grid_id: String,
 
-    pub setting: SettingRevision,
+    pub layout: LayoutRevision,
+
+    pub filters: FilterConfiguration,
+
+    #[serde(default)]
+    pub groups: GroupConfiguration,
 
     // For the moment, we just use the order returned from the GridRevision
     #[allow(dead_code)]
@@ -26,10 +56,78 @@ impl GridViewRevision {
         GridViewRevision {
             view_id,
             grid_id,
-            setting: Default::default(),
+            layout: Default::default(),
+            filters: Default::default(),
+            groups: Default::default(),
             row_orders: vec![],
         }
     }
+
+    pub fn get_all_groups(&self, field_revs: &[Arc<FieldRevision>]) -> Option<GroupConfigurationsByFieldId> {
+        self.groups.get_all_objects(field_revs)
+    }
+
+    pub fn get_groups(
+        &self,
+        field_id: &str,
+        field_type_rev: &FieldTypeRevision,
+    ) -> Option<Arc<GroupConfigurationRevision>> {
+        let mut groups = self.groups.get_objects(field_id, field_type_rev)?;
+        if groups.is_empty() {
+            debug_assert_eq!(groups.len(), 1);
+            Some(groups.pop().unwrap())
+        } else {
+            None
+        }
+    }
+
+    pub fn get_mut_groups(
+        &mut self,
+        field_id: &str,
+        field_type: &FieldTypeRevision,
+    ) -> Option<&mut Vec<Arc<GroupConfigurationRevision>>> {
+        self.groups.get_mut_objects(field_id, field_type)
+    }
+
+    pub fn insert_group(
+        &mut self,
+        field_id: &str,
+        field_type: &FieldTypeRevision,
+        group_rev: GroupConfigurationRevision,
+    ) {
+        // only one group can be set
+        self.groups.remove_all();
+        self.groups.insert_object(field_id, field_type, group_rev);
+    }
+
+    pub fn get_all_filters(&self, field_revs: &[Arc<FieldRevision>]) -> Option<FilterConfigurationsByFieldId> {
+        self.filters.get_all_objects(field_revs)
+    }
+
+    pub fn get_filters(
+        &self,
+        field_id: &str,
+        field_type_rev: &FieldTypeRevision,
+    ) -> Option<Vec<Arc<FilterConfigurationRevision>>> {
+        self.filters.get_objects(field_id, field_type_rev)
+    }
+
+    pub fn get_mut_filters(
+        &mut self,
+        field_id: &str,
+        field_type: &FieldTypeRevision,
+    ) -> Option<&mut Vec<Arc<FilterConfigurationRevision>>> {
+        self.filters.get_mut_objects(field_id, field_type)
+    }
+
+    pub fn insert_filter(
+        &mut self,
+        field_id: &str,
+        field_type: &FieldTypeRevision,
+        filter_rev: FilterConfigurationRevision,
+    ) {
+        self.filters.insert_object(field_id, field_type, filter_rev);
+    }
 }
 
 #[derive(Debug, Clone, Default, Serialize, Deserialize)]
diff --git a/shared-lib/flowy-grid-data-model/src/revision/group_rev.rs b/shared-lib/flowy-grid-data-model/src/revision/group_rev.rs
index 932cc60033..83deeb2735 100644
--- a/shared-lib/flowy-grid-data-model/src/revision/group_rev.rs
+++ b/shared-lib/flowy-grid-data-model/src/revision/group_rev.rs
@@ -1,32 +1,91 @@
+use crate::revision::{gen_grid_group_id, FieldTypeRevision};
 use serde::{Deserialize, Serialize};
+use serde_json::Error;
 use serde_repr::*;
 
+pub trait GroupConfigurationContentSerde: Sized {
+    fn from_configuration(s: &str) -> Result<Self, serde_json::Error>;
+}
+
+#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq)]
+pub struct GroupConfigurationRevision {
+    pub id: String,
+    pub field_id: String,
+    pub field_type_rev: FieldTypeRevision,
+    pub content: String,
+}
+
+impl GroupConfigurationRevision {
+    pub fn new<T>(field_id: String, field_type: FieldTypeRevision, content: T) -> Result<Self, serde_json::Error>
+    where
+        T: serde::Serialize,
+    {
+        let content = serde_json::to_string(&content)?;
+        Ok(Self {
+            id: gen_grid_group_id(),
+            field_id,
+            field_type_rev: field_type,
+            content,
+        })
+    }
+}
+
 #[derive(Default, Serialize, Deserialize)]
 pub struct TextGroupConfigurationRevision {
     pub hide_empty: bool,
 }
 
+impl GroupConfigurationContentSerde for TextGroupConfigurationRevision {
+    fn from_configuration(s: &str) -> Result<Self, Error> {
+        serde_json::from_str(s)
+    }
+}
+
 #[derive(Default, Serialize, Deserialize)]
 pub struct NumberGroupConfigurationRevision {
     pub hide_empty: bool,
 }
 
+impl GroupConfigurationContentSerde for NumberGroupConfigurationRevision {
+    fn from_configuration(s: &str) -> Result<Self, Error> {
+        serde_json::from_str(s)
+    }
+}
+
 #[derive(Default, Serialize, Deserialize)]
 pub struct UrlGroupConfigurationRevision {
     pub hide_empty: bool,
 }
 
+impl GroupConfigurationContentSerde for UrlGroupConfigurationRevision {
+    fn from_configuration(s: &str) -> Result<Self, Error> {
+        serde_json::from_str(s)
+    }
+}
+
 #[derive(Default, Serialize, Deserialize)]
 pub struct CheckboxGroupConfigurationRevision {
     pub hide_empty: bool,
 }
 
+impl GroupConfigurationContentSerde for CheckboxGroupConfigurationRevision {
+    fn from_configuration(s: &str) -> Result<Self, Error> {
+        serde_json::from_str(s)
+    }
+}
+
 #[derive(Default, Serialize, Deserialize)]
 pub struct SelectOptionGroupConfigurationRevision {
     pub hide_empty: bool,
     pub groups: Vec<GroupRecordRevision>,
 }
 
+impl GroupConfigurationContentSerde for SelectOptionGroupConfigurationRevision {
+    fn from_configuration(s: &str) -> Result<Self, Error> {
+        serde_json::from_str(s)
+    }
+}
+
 #[derive(Default, Serialize, Deserialize)]
 pub struct GroupRecordRevision {
     pub group_id: String,
@@ -42,6 +101,12 @@ pub struct DateGroupConfigurationRevision {
     pub condition: DateCondition,
 }
 
+impl GroupConfigurationContentSerde for DateGroupConfigurationRevision {
+    fn from_configuration(s: &str) -> Result<Self, Error> {
+        serde_json::from_str(s)
+    }
+}
+
 #[derive(Serialize_repr, Deserialize_repr)]
 #[repr(u8)]
 pub enum DateCondition {
diff --git a/shared-lib/flowy-grid-data-model/src/revision/mod.rs b/shared-lib/flowy-grid-data-model/src/revision/mod.rs
index d9df0910bd..460370b86b 100644
--- a/shared-lib/flowy-grid-data-model/src/revision/mod.rs
+++ b/shared-lib/flowy-grid-data-model/src/revision/mod.rs
@@ -1,9 +1,11 @@
+mod filter_rev;
 mod grid_block;
 mod grid_rev;
 mod grid_setting_rev;
 mod grid_view;
 mod group_rev;
 
+pub use filter_rev::*;
 pub use grid_block::*;
 pub use grid_rev::*;
 pub use grid_setting_rev::*;
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 db52d0b38b..5ec4a87ef9 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
@@ -3,7 +3,7 @@ use crate::errors::{internal_error, CollaborateError, CollaborateResult};
 use crate::util::{cal_diff, make_text_delta_from_revisions};
 use flowy_grid_data_model::revision::{
     FieldRevision, FieldTypeRevision, FilterConfigurationRevision, FilterConfigurationsByFieldId, GridViewRevision,
-    GroupConfigurationRevision, GroupConfigurationsByFieldId, SettingRevision, SortConfigurationsByFieldId,
+    GroupConfigurationRevision, GroupConfigurationsByFieldId,
 };
 use lib_ot::core::{OperationTransform, PhantomAttributes, TextDelta, TextDeltaBuilder};
 use std::sync::Arc;
@@ -48,23 +48,11 @@ impl GridViewRevisionPad {
         Self::from_delta(delta)
     }
 
-    pub fn get_setting_rev(&self) -> &SettingRevision {
-        &self.view.setting
-    }
-
     pub fn get_all_groups(&self, field_revs: &[Arc<FieldRevision>]) -> Option<GroupConfigurationsByFieldId> {
-        self.setting.groups.get_all_objects(field_revs)
+        self.groups.get_all_objects(field_revs)
     }
 
-    pub fn get_groups(
-        &self,
-        field_id: &str,
-        field_type_rev: &FieldTypeRevision,
-    ) -> Option<Vec<Arc<GroupConfigurationRevision>>> {
-        self.setting.groups.get_objects(field_id, field_type_rev)
-    }
-
-    pub fn insert_group(
+    pub fn insert_group_configuration(
         &mut self,
         field_id: &str,
         field_type: &FieldTypeRevision,
@@ -72,8 +60,8 @@ impl GridViewRevisionPad {
     ) -> CollaborateResult<Option<GridViewRevisionChangeset>> {
         self.modify(|view| {
             // only one group can be set
-            view.setting.groups.remove_all();
-            view.setting.groups.insert_object(field_id, field_type, group_rev);
+            view.groups.remove_all();
+            view.groups.insert_object(field_id, field_type, group_rev);
             Ok(Some(()))
         })
     }
@@ -85,7 +73,7 @@ impl GridViewRevisionPad {
         group_id: &str,
     ) -> CollaborateResult<Option<GridViewRevisionChangeset>> {
         self.modify(|view| {
-            if let Some(groups) = view.setting.groups.get_mut_objects(field_id, field_type) {
+            if let Some(groups) = view.groups.get_mut_objects(field_id, field_type) {
                 groups.retain(|group| group.id != group_id);
                 Ok(Some(()))
             } else {
@@ -95,7 +83,7 @@ impl GridViewRevisionPad {
     }
 
     pub fn get_all_filters(&self, field_revs: &[Arc<FieldRevision>]) -> Option<FilterConfigurationsByFieldId> {
-        self.setting.filters.get_all_objects(field_revs)
+        self.filters.get_all_objects(field_revs)
     }
 
     pub fn get_filters(
@@ -103,7 +91,7 @@ impl GridViewRevisionPad {
         field_id: &str,
         field_type_rev: &FieldTypeRevision,
     ) -> Option<Vec<Arc<FilterConfigurationRevision>>> {
-        self.setting.filters.get_objects(field_id, field_type_rev)
+        self.filters.get_objects(field_id, field_type_rev)
     }
 
     pub fn insert_filter(
@@ -113,7 +101,7 @@ impl GridViewRevisionPad {
         filter_rev: FilterConfigurationRevision,
     ) -> CollaborateResult<Option<GridViewRevisionChangeset>> {
         self.modify(|view| {
-            view.setting.filters.insert_object(field_id, field_type, filter_rev);
+            view.filters.insert_object(field_id, field_type, filter_rev);
             Ok(Some(()))
         })
     }
@@ -125,7 +113,7 @@ impl GridViewRevisionPad {
         filter_id: &str,
     ) -> CollaborateResult<Option<GridViewRevisionChangeset>> {
         self.modify(|view| {
-            if let Some(filters) = view.setting.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 {
@@ -134,10 +122,6 @@ impl GridViewRevisionPad {
         })
     }
 
-    pub fn get_all_sort(&self) -> Option<SortConfigurationsByFieldId> {
-        None
-    }
-
     pub fn json_str(&self) -> CollaborateResult<String> {
         make_grid_view_rev_json_str(&self.view)
     }