diff --git a/frontend/app_flowy/lib/plugins/board/application/board_bloc.dart b/frontend/app_flowy/lib/plugins/board/application/board_bloc.dart
index 581387e5ac..cbfd0500fb 100644
--- a/frontend/app_flowy/lib/plugins/board/application/board_bloc.dart
+++ b/frontend/app_flowy/lib/plugins/board/application/board_bloc.dart
@@ -1,7 +1,6 @@
 import 'dart:async';
 import 'package:app_flowy/plugins/grid/application/block/block_cache.dart';
 import 'package:app_flowy/plugins/grid/application/row/row_cache.dart';
-import 'package:app_flowy/plugins/grid/presentation/widgets/header/type_option/builder.dart';
 import 'package:appflowy_board/appflowy_board.dart';
 import 'package:dartz/dartz.dart';
 import 'package:equatable/equatable.dart';
@@ -57,8 +56,8 @@ class BoardBloc extends Bloc<BoardEvent, BoardState> {
           didReceiveGridUpdate: (GridPB grid) {
             emit(state.copyWith(grid: Some(grid)));
           },
-          groupByField: (FieldPB field) {
-            emit(state.copyWith(groupField: Some(field)));
+          didReceiveGroups: (List<GroupPB> groups) {
+            emit(state.copyWith(groups: groups));
           },
         );
       },
@@ -83,50 +82,20 @@ class BoardBloc extends Bloc<BoardEvent, BoardState> {
           add(BoardEvent.didReceiveGridUpdate(grid));
         }
       },
-      onFieldsChanged: (fields) {
-        if (!isClosed) {
-          _buildColumns(fields);
-        }
-      },
-      onGroupChanged: (groups) {},
-      onError: (err) {
-        Log.error(err);
-      },
-    );
-  }
-
-  void _buildColumns(UnmodifiableListView<FieldPB> fields) {
-    FieldPB? groupField;
-    for (final field in fields) {
-      if (field.fieldType == FieldType.SingleSelect) {
-        groupField = field;
-        _buildColumnsFromSingleSelect(field);
-      }
-    }
-
-    assert(groupField != null);
-    add(BoardEvent.groupByField(groupField!));
-  }
-
-  void _buildColumnsFromSingleSelect(FieldPB field) {
-    final typeOptionContext = makeTypeOptionContext<SingleSelectTypeOptionPB>(
-      gridId: _dataController.gridId,
-      field: field,
-    );
-
-    typeOptionContext.loadTypeOptionData(
-      onCompleted: (singleSelect) {
-        List<AFBoardColumnData> columns = singleSelect.options.map((option) {
+      onGroupChanged: (groups) {
+        List<AFBoardColumnData> columns = groups.map((group) {
           return AFBoardColumnData(
-            id: option.id,
-            desc: option.name,
-            customData: option,
+            id: group.groupId,
+            desc: group.desc,
+            customData: group,
           );
         }).toList();
 
         boardDataController.addColumns(columns);
       },
-      onError: (err) => Log.error(err),
+      onError: (err) {
+        Log.error(err);
+      },
     );
   }
 
@@ -147,7 +116,8 @@ class BoardBloc extends Bloc<BoardEvent, BoardState> {
 class BoardEvent with _$BoardEvent {
   const factory BoardEvent.initial() = InitialGrid;
   const factory BoardEvent.createRow() = _CreateRow;
-  const factory BoardEvent.groupByField(FieldPB field) = _GroupByField;
+  const factory BoardEvent.didReceiveGroups(List<GroupPB> groups) =
+      _DidReceiveGroup;
   const factory BoardEvent.didReceiveGridUpdate(
     GridPB grid,
   ) = _DidReceiveGridUpdate;
@@ -158,14 +128,14 @@ class BoardState with _$BoardState {
   const factory BoardState({
     required String gridId,
     required Option<GridPB> grid,
-    required Option<FieldPB> groupField,
+    required List<GroupPB> groups,
     required List<RowInfo> rowInfos,
     required GridLoadingState loadingState,
   }) = _BoardState;
 
   factory BoardState.initial(String gridId) => BoardState(
         rowInfos: [],
-        groupField: none(),
+        groups: [],
         grid: none(),
         gridId: gridId,
         loadingState: const _Loading(),
diff --git a/frontend/rust-lib/flowy-folder/tests/workspace/script.rs b/frontend/rust-lib/flowy-folder/tests/workspace/script.rs
index 3292d6deea..5fb0be874c 100644
--- a/frontend/rust-lib/flowy-folder/tests/workspace/script.rs
+++ b/frontend/rust-lib/flowy-folder/tests/workspace/script.rs
@@ -5,6 +5,7 @@ use flowy_folder::entities::{
     trash::{RepeatedTrashPB, TrashIdPB, TrashType},
     view::{CreateViewPayloadPB, UpdateViewPayloadPB},
     workspace::{CreateWorkspacePayloadPB, RepeatedWorkspacePB},
+    SubViewDataTypePB,
 };
 use flowy_folder::entities::{
     app::{AppPB, RepeatedAppPB},
@@ -353,13 +354,18 @@ pub async fn create_view(
     desc: &str,
     data_type: ViewDataTypePB,
 ) -> ViewPB {
+    let sub_data_type = match data_type {
+        ViewDataTypePB::TextBlock => None,
+        ViewDataTypePB::Database => Some(SubViewDataTypePB::Grid),
+    };
+
     let request = CreateViewPayloadPB {
         belong_to_id: app_id.to_string(),
         name: name.to_string(),
         desc: desc.to_string(),
         thumbnail: None,
         data_type,
-        sub_data_type: None,
+        sub_data_type,
         plugin_type: 0,
         data: vec![],
     };
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 468b216b5b..3dc296f34e 100644
--- a/frontend/rust-lib/flowy-grid/src/entities/field_entities.rs
+++ b/frontend/rust-lib/flowy-grid/src/entities/field_entities.rs
@@ -518,6 +518,14 @@ pub enum FieldType {
     URL = 6,
 }
 
+pub const RICH_TEXT_FIELD: FieldType = FieldType::RichText;
+pub const NUMBER_FIELD: FieldType = FieldType::Number;
+pub const DATE_FIELD: FieldType = FieldType::DateTime;
+pub const SINGLE_SELECT_FIELD: FieldType = FieldType::SingleSelect;
+pub const MULTI_SELECT_FIELD: FieldType = FieldType::MultiSelect;
+pub const CHECKBOX_FIELD: FieldType = FieldType::Checkbox;
+pub const URL_FIELD: FieldType = FieldType::URL;
+
 impl std::default::Default for FieldType {
     fn default() -> Self {
         FieldType::RichText
@@ -549,35 +557,39 @@ impl FieldType {
     }
 
     pub fn is_number(&self) -> bool {
-        self == &FieldType::Number
+        self == &NUMBER_FIELD
     }
 
     pub fn is_text(&self) -> bool {
-        self == &FieldType::RichText
+        self == &RICH_TEXT_FIELD
     }
 
     pub fn is_checkbox(&self) -> bool {
-        self == &FieldType::Checkbox
+        self == &CHECKBOX_FIELD
     }
 
     pub fn is_date(&self) -> bool {
-        self == &FieldType::DateTime
+        self == &DATE_FIELD
     }
 
     pub fn is_single_select(&self) -> bool {
-        self == &FieldType::SingleSelect
+        self == &SINGLE_SELECT_FIELD
     }
 
     pub fn is_multi_select(&self) -> bool {
-        self == &FieldType::MultiSelect
+        self == &MULTI_SELECT_FIELD
     }
 
     pub fn is_url(&self) -> bool {
-        self == &FieldType::URL
+        self == &URL_FIELD
     }
 
     pub fn is_select_option(&self) -> bool {
-        self == &FieldType::MultiSelect || self == &FieldType::SingleSelect
+        self == &MULTI_SELECT_FIELD || self == &SINGLE_SELECT_FIELD
+    }
+
+    pub fn can_be_group(&self) -> bool {
+        self.is_select_option()
     }
 }
 
diff --git a/frontend/rust-lib/flowy-grid/src/entities/filter_entities/checkbox_filter.rs b/frontend/rust-lib/flowy-grid/src/entities/filter_entities/checkbox_filter.rs
index bb31b7a3be..45a64af245 100644
--- a/frontend/rust-lib/flowy-grid/src/entities/filter_entities/checkbox_filter.rs
+++ b/frontend/rust-lib/flowy-grid/src/entities/filter_entities/checkbox_filter.rs
@@ -1,10 +1,10 @@
 use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
 use flowy_error::ErrorCode;
-use flowy_grid_data_model::revision::GridFilterRevision;
+use flowy_grid_data_model::revision::FilterConfigurationRevision;
 use std::sync::Arc;
 
 #[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)]
-pub struct GridCheckboxFilter {
+pub struct CheckboxFilterConfigurationPB {
     #[pb(index = 1)]
     pub condition: CheckboxCondition,
 }
@@ -40,9 +40,9 @@ impl std::convert::TryFrom<u8> for CheckboxCondition {
     }
 }
 
-impl std::convert::From<Arc<GridFilterRevision>> for GridCheckboxFilter {
-    fn from(rev: Arc<GridFilterRevision>) -> Self {
-        GridCheckboxFilter {
+impl std::convert::From<Arc<FilterConfigurationRevision>> for CheckboxFilterConfigurationPB {
+    fn from(rev: Arc<FilterConfigurationRevision>) -> Self {
+        CheckboxFilterConfigurationPB {
             condition: CheckboxCondition::try_from(rev.condition).unwrap_or(CheckboxCondition::IsChecked),
         }
     }
diff --git a/frontend/rust-lib/flowy-grid/src/entities/filter_entities/date_filter.rs b/frontend/rust-lib/flowy-grid/src/entities/filter_entities/date_filter.rs
index 936b95216c..72be45a655 100644
--- a/frontend/rust-lib/flowy-grid/src/entities/filter_entities/date_filter.rs
+++ b/frontend/rust-lib/flowy-grid/src/entities/filter_entities/date_filter.rs
@@ -2,13 +2,13 @@ use crate::entities::FieldType;
 use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
 use flowy_error::ErrorCode;
 use flowy_grid_data_model::parser::NotEmptyStr;
-use flowy_grid_data_model::revision::GridFilterRevision;
+use flowy_grid_data_model::revision::FilterConfigurationRevision;
 use serde::{Deserialize, Serialize};
 use std::str::FromStr;
 use std::sync::Arc;
 
 #[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)]
-pub struct GridDateFilter {
+pub struct DateFilterConfigurationPB {
     #[pb(index = 1)]
     pub condition: DateFilterCondition,
 
@@ -120,10 +120,10 @@ impl std::convert::TryFrom<u8> for DateFilterCondition {
         }
     }
 }
-impl std::convert::From<Arc<GridFilterRevision>> for GridDateFilter {
-    fn from(rev: Arc<GridFilterRevision>) -> Self {
+impl std::convert::From<Arc<FilterConfigurationRevision>> for DateFilterConfigurationPB {
+    fn from(rev: Arc<FilterConfigurationRevision>) -> Self {
         let condition = DateFilterCondition::try_from(rev.condition).unwrap_or(DateFilterCondition::DateIs);
-        let mut filter = GridDateFilter {
+        let mut filter = DateFilterConfigurationPB {
             condition,
             ..Default::default()
         };
diff --git a/frontend/rust-lib/flowy-grid/src/entities/filter_entities/number_filter.rs b/frontend/rust-lib/flowy-grid/src/entities/filter_entities/number_filter.rs
index 097ff5330a..68c7474b8f 100644
--- a/frontend/rust-lib/flowy-grid/src/entities/filter_entities/number_filter.rs
+++ b/frontend/rust-lib/flowy-grid/src/entities/filter_entities/number_filter.rs
@@ -1,11 +1,11 @@
 use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
 use flowy_error::ErrorCode;
-use flowy_grid_data_model::revision::GridFilterRevision;
+use flowy_grid_data_model::revision::FilterConfigurationRevision;
 
 use std::sync::Arc;
 
 #[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)]
-pub struct GridNumberFilter {
+pub struct NumberFilterConfigurationPB {
     #[pb(index = 1)]
     pub condition: NumberFilterCondition,
 
@@ -55,9 +55,9 @@ impl std::convert::TryFrom<u8> for NumberFilterCondition {
     }
 }
 
-impl std::convert::From<Arc<GridFilterRevision>> for GridNumberFilter {
-    fn from(rev: Arc<GridFilterRevision>) -> Self {
-        GridNumberFilter {
+impl std::convert::From<Arc<FilterConfigurationRevision>> for NumberFilterConfigurationPB {
+    fn from(rev: Arc<FilterConfigurationRevision>) -> Self {
+        NumberFilterConfigurationPB {
             condition: NumberFilterCondition::try_from(rev.condition).unwrap_or(NumberFilterCondition::Equal),
             content: rev.content.clone(),
         }
diff --git a/frontend/rust-lib/flowy-grid/src/entities/filter_entities/select_option_filter.rs b/frontend/rust-lib/flowy-grid/src/entities/filter_entities/select_option_filter.rs
index 9eb4ff3fe9..47e07c0b73 100644
--- a/frontend/rust-lib/flowy-grid/src/entities/filter_entities/select_option_filter.rs
+++ b/frontend/rust-lib/flowy-grid/src/entities/filter_entities/select_option_filter.rs
@@ -1,11 +1,11 @@
 use crate::services::field::SelectOptionIds;
 use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
 use flowy_error::ErrorCode;
-use flowy_grid_data_model::revision::GridFilterRevision;
+use flowy_grid_data_model::revision::FilterConfigurationRevision;
 use std::sync::Arc;
 
 #[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)]
-pub struct GridSelectOptionFilter {
+pub struct SelectOptionFilterConfigurationPB {
     #[pb(index = 1)]
     pub condition: SelectOptionCondition,
 
@@ -47,10 +47,10 @@ impl std::convert::TryFrom<u8> for SelectOptionCondition {
     }
 }
 
-impl std::convert::From<Arc<GridFilterRevision>> for GridSelectOptionFilter {
-    fn from(rev: Arc<GridFilterRevision>) -> Self {
+impl std::convert::From<Arc<FilterConfigurationRevision>> for SelectOptionFilterConfigurationPB {
+    fn from(rev: Arc<FilterConfigurationRevision>) -> Self {
         let ids = SelectOptionIds::from(rev.content.clone());
-        GridSelectOptionFilter {
+        SelectOptionFilterConfigurationPB {
             condition: SelectOptionCondition::try_from(rev.condition).unwrap_or(SelectOptionCondition::OptionIs),
             option_ids: ids.into_inner(),
         }
diff --git a/frontend/rust-lib/flowy-grid/src/entities/filter_entities/text_filter.rs b/frontend/rust-lib/flowy-grid/src/entities/filter_entities/text_filter.rs
index 7335e89129..802941516d 100644
--- a/frontend/rust-lib/flowy-grid/src/entities/filter_entities/text_filter.rs
+++ b/frontend/rust-lib/flowy-grid/src/entities/filter_entities/text_filter.rs
@@ -1,10 +1,10 @@
 use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
 use flowy_error::ErrorCode;
-use flowy_grid_data_model::revision::GridFilterRevision;
+use flowy_grid_data_model::revision::FilterConfigurationRevision;
 use std::sync::Arc;
 
 #[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)]
-pub struct GridTextFilter {
+pub struct TextFilterConfigurationPB {
     #[pb(index = 1)]
     pub condition: TextFilterCondition,
 
@@ -54,9 +54,9 @@ impl std::convert::TryFrom<u8> for TextFilterCondition {
     }
 }
 
-impl std::convert::From<Arc<GridFilterRevision>> for GridTextFilter {
-    fn from(rev: Arc<GridFilterRevision>) -> Self {
-        GridTextFilter {
+impl std::convert::From<Arc<FilterConfigurationRevision>> for TextFilterConfigurationPB {
+    fn from(rev: Arc<FilterConfigurationRevision>) -> Self {
+        TextFilterConfigurationPB {
             condition: TextFilterCondition::try_from(rev.condition).unwrap_or(TextFilterCondition::Is),
             content: rev.content.clone(),
         }
diff --git a/frontend/rust-lib/flowy-grid/src/entities/filter_entities/util.rs b/frontend/rust-lib/flowy-grid/src/entities/filter_entities/util.rs
index b085f6bdd3..687b371345 100644
--- a/frontend/rust-lib/flowy-grid/src/entities/filter_entities/util.rs
+++ b/frontend/rust-lib/flowy-grid/src/entities/filter_entities/util.rs
@@ -5,7 +5,7 @@ use crate::entities::{
 use flowy_derive::ProtoBuf;
 use flowy_error::ErrorCode;
 use flowy_grid_data_model::parser::NotEmptyStr;
-use flowy_grid_data_model::revision::{FieldRevision, GridFilterRevision};
+use flowy_grid_data_model::revision::{FieldRevision, FilterConfigurationRevision};
 use flowy_sync::entities::grid::{CreateGridFilterParams, DeleteFilterParams};
 use std::convert::TryInto;
 use std::sync::Arc;
@@ -22,14 +22,14 @@ pub struct RepeatedGridConfigurationFilterPB {
     pub items: Vec<GridFilterConfiguration>,
 }
 
-impl std::convert::From<&GridFilterRevision> for GridFilterConfiguration {
-    fn from(rev: &GridFilterRevision) -> Self {
+impl std::convert::From<&FilterConfigurationRevision> for GridFilterConfiguration {
+    fn from(rev: &FilterConfigurationRevision) -> Self {
         Self { id: rev.id.clone() }
     }
 }
 
-impl std::convert::From<Vec<Arc<GridFilterRevision>>> for RepeatedGridConfigurationFilterPB {
-    fn from(revs: Vec<Arc<GridFilterRevision>>) -> Self {
+impl std::convert::From<Vec<Arc<FilterConfigurationRevision>>> for RepeatedGridConfigurationFilterPB {
+    fn from(revs: Vec<Arc<FilterConfigurationRevision>>) -> Self {
         RepeatedGridConfigurationFilterPB {
             items: revs.into_iter().map(|rev| rev.as_ref().into()).collect(),
         }
diff --git a/frontend/rust-lib/flowy-grid/src/entities/group_entities/checkbox_group.rs b/frontend/rust-lib/flowy-grid/src/entities/group_entities/checkbox_group.rs
new file mode 100644
index 0000000000..ba121694a7
--- /dev/null
+++ b/frontend/rust-lib/flowy-grid/src/entities/group_entities/checkbox_group.rs
@@ -0,0 +1,7 @@
+use flowy_derive::ProtoBuf;
+
+#[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)]
+pub struct CheckboxGroupConfigurationPB {
+    #[pb(index = 1)]
+    pub(crate) hide_empty: bool,
+}
diff --git a/frontend/rust-lib/flowy-grid/src/entities/group_entities/date_group.rs b/frontend/rust-lib/flowy-grid/src/entities/group_entities/date_group.rs
new file mode 100644
index 0000000000..c117b22f8b
--- /dev/null
+++ b/frontend/rust-lib/flowy-grid/src/entities/group_entities/date_group.rs
@@ -0,0 +1,26 @@
+use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
+
+#[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)]
+pub struct DateGroupConfigurationPB {
+    #[pb(index = 1)]
+    pub condition: DateCondition,
+
+    #[pb(index = 2)]
+    hide_empty: bool,
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, ProtoBuf_Enum)]
+#[repr(u8)]
+pub enum DateCondition {
+    Relative = 0,
+    Day = 1,
+    Week = 2,
+    Month = 3,
+    Year = 4,
+}
+
+impl std::default::Default for DateCondition {
+    fn default() -> Self {
+        DateCondition::Relative
+    }
+}
diff --git a/frontend/rust-lib/flowy-grid/src/entities/group_entities/group.rs b/frontend/rust-lib/flowy-grid/src/entities/group_entities/group.rs
index c27b4aaa93..4a0f56e425 100644
--- a/frontend/rust-lib/flowy-grid/src/entities/group_entities/group.rs
+++ b/frontend/rust-lib/flowy-grid/src/entities/group_entities/group.rs
@@ -2,7 +2,7 @@ use crate::entities::{FieldType, RowPB};
 use flowy_derive::ProtoBuf;
 use flowy_error::ErrorCode;
 use flowy_grid_data_model::parser::NotEmptyStr;
-use flowy_grid_data_model::revision::GridGroupRevision;
+use flowy_grid_data_model::revision::GroupConfigurationRevision;
 use flowy_sync::entities::grid::{CreateGridGroupParams, DeleteGroupParams};
 use std::convert::TryInto;
 use std::sync::Arc;
@@ -14,17 +14,13 @@ pub struct GridGroupConfigurationPB {
 
     #[pb(index = 2)]
     pub group_field_id: String,
-
-    #[pb(index = 3, one_of)]
-    pub sub_group_field_id: Option<String>,
 }
 
-impl std::convert::From<&GridGroupRevision> for GridGroupConfigurationPB {
-    fn from(rev: &GridGroupRevision) -> Self {
+impl std::convert::From<&GroupConfigurationRevision> for GridGroupConfigurationPB {
+    fn from(rev: &GroupConfigurationRevision) -> Self {
         GridGroupConfigurationPB {
             id: rev.id.clone(),
             group_field_id: rev.field_id.clone(),
-            sub_group_field_id: rev.sub_field_id.clone(),
         }
     }
 }
@@ -32,7 +28,7 @@ impl std::convert::From<&GridGroupRevision> for GridGroupConfigurationPB {
 #[derive(ProtoBuf, Debug, Default, Clone)]
 pub struct RepeatedGridGroupPB {
     #[pb(index = 1)]
-    items: Vec<GroupPB>,
+    pub(crate) items: Vec<GroupPB>,
 }
 
 #[derive(ProtoBuf, Debug, Default, Clone)]
@@ -59,8 +55,8 @@ impl std::convert::From<Vec<GridGroupConfigurationPB>> for RepeatedGridGroupConf
     }
 }
 
-impl std::convert::From<Vec<Arc<GridGroupRevision>>> for RepeatedGridGroupConfigurationPB {
-    fn from(revs: Vec<Arc<GridGroupRevision>>) -> Self {
+impl std::convert::From<Vec<Arc<GroupConfigurationRevision>>> for RepeatedGridGroupConfigurationPB {
+    fn from(revs: Vec<Arc<GroupConfigurationRevision>>) -> Self {
         RepeatedGridGroupConfigurationPB {
             items: revs.iter().map(|rev| rev.as_ref().into()).collect(),
         }
@@ -72,11 +68,11 @@ pub struct CreateGridGroupPayloadPB {
     #[pb(index = 1)]
     pub field_id: String,
 
-    #[pb(index = 2, one_of)]
-    pub sub_field_id: Option<String>,
-
-    #[pb(index = 3)]
+    #[pb(index = 2)]
     pub field_type: FieldType,
+
+    #[pb(index = 3, one_of)]
+    pub content: Option<Vec<u8>>,
 }
 
 impl TryInto<CreateGridGroupParams> for CreateGridGroupPayloadPB {
@@ -87,15 +83,10 @@ impl TryInto<CreateGridGroupParams> for CreateGridGroupPayloadPB {
             .map_err(|_| ErrorCode::FieldIdIsEmpty)?
             .0;
 
-        let sub_field_id = match self.sub_field_id {
-            None => None,
-            Some(field_id) => Some(NotEmptyStr::parse(field_id).map_err(|_| ErrorCode::FieldIdIsEmpty)?.0),
-        };
-
         Ok(CreateGridGroupParams {
             field_id,
-            sub_field_id,
             field_type_rev: self.field_type.into(),
+            content: self.content,
         })
     }
 }
diff --git a/frontend/rust-lib/flowy-grid/src/entities/group_entities/mod.rs b/frontend/rust-lib/flowy-grid/src/entities/group_entities/mod.rs
index b50e59f6d6..1ededd3188 100644
--- a/frontend/rust-lib/flowy-grid/src/entities/group_entities/mod.rs
+++ b/frontend/rust-lib/flowy-grid/src/entities/group_entities/mod.rs
@@ -1,3 +1,15 @@
+mod checkbox_group;
+mod date_group;
 mod group;
+mod number_group;
+mod select_option_group;
+mod text_group;
+mod url_group;
 
+pub use checkbox_group::*;
+pub use date_group::*;
 pub use group::*;
+pub use number_group::*;
+pub use select_option_group::*;
+pub use text_group::*;
+pub use url_group::*;
diff --git a/frontend/rust-lib/flowy-grid/src/entities/group_entities/number_group.rs b/frontend/rust-lib/flowy-grid/src/entities/group_entities/number_group.rs
new file mode 100644
index 0000000000..ddb63a6ce5
--- /dev/null
+++ b/frontend/rust-lib/flowy-grid/src/entities/group_entities/number_group.rs
@@ -0,0 +1,7 @@
+use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
+
+#[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)]
+pub struct NumberGroupConfigurationPB {
+    #[pb(index = 1)]
+    hide_empty: bool,
+}
diff --git a/frontend/rust-lib/flowy-grid/src/entities/group_entities/select_option_group.rs b/frontend/rust-lib/flowy-grid/src/entities/group_entities/select_option_group.rs
new file mode 100644
index 0000000000..67dfe8d1b7
--- /dev/null
+++ b/frontend/rust-lib/flowy-grid/src/entities/group_entities/select_option_group.rs
@@ -0,0 +1,7 @@
+use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
+
+#[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)]
+pub struct SelectOptionGroupConfigurationPB {
+    #[pb(index = 1)]
+    hide_empty: bool,
+}
diff --git a/frontend/rust-lib/flowy-grid/src/entities/group_entities/text_group.rs b/frontend/rust-lib/flowy-grid/src/entities/group_entities/text_group.rs
new file mode 100644
index 0000000000..b349850843
--- /dev/null
+++ b/frontend/rust-lib/flowy-grid/src/entities/group_entities/text_group.rs
@@ -0,0 +1,7 @@
+use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
+
+#[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)]
+pub struct TextGroupConfigurationPB {
+    #[pb(index = 1)]
+    hide_empty: bool,
+}
diff --git a/frontend/rust-lib/flowy-grid/src/entities/group_entities/url_group.rs b/frontend/rust-lib/flowy-grid/src/entities/group_entities/url_group.rs
new file mode 100644
index 0000000000..955cb60ae3
--- /dev/null
+++ b/frontend/rust-lib/flowy-grid/src/entities/group_entities/url_group.rs
@@ -0,0 +1,7 @@
+use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
+
+#[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)]
+pub struct UrlGroupConfigurationPB {
+    #[pb(index = 1)]
+    hide_empty: bool,
+}
diff --git a/frontend/rust-lib/flowy-grid/src/entities/sort_entities.rs b/frontend/rust-lib/flowy-grid/src/entities/sort_entities.rs
index b630b000c5..f844b75066 100644
--- a/frontend/rust-lib/flowy-grid/src/entities/sort_entities.rs
+++ b/frontend/rust-lib/flowy-grid/src/entities/sort_entities.rs
@@ -1,7 +1,7 @@
 use flowy_derive::ProtoBuf;
 use flowy_error::ErrorCode;
 use flowy_grid_data_model::parser::NotEmptyStr;
-use flowy_grid_data_model::revision::GridSortRevision;
+use flowy_grid_data_model::revision::SortConfigurationRevision;
 use flowy_sync::entities::grid::CreateGridSortParams;
 use std::convert::TryInto;
 use std::sync::Arc;
@@ -15,8 +15,8 @@ pub struct GridSort {
     pub field_id: Option<String>,
 }
 
-impl std::convert::From<&GridSortRevision> for GridSort {
-    fn from(rev: &GridSortRevision) -> Self {
+impl std::convert::From<&SortConfigurationRevision> for GridSort {
+    fn from(rev: &SortConfigurationRevision) -> Self {
         GridSort {
             id: rev.id.clone(),
 
@@ -31,8 +31,8 @@ pub struct RepeatedGridSortPB {
     pub items: Vec<GridSort>,
 }
 
-impl std::convert::From<Vec<Arc<GridSortRevision>>> for RepeatedGridSortPB {
-    fn from(revs: Vec<Arc<GridSortRevision>>) -> Self {
+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(),
         }
diff --git a/frontend/rust-lib/flowy-grid/src/event_handler.rs b/frontend/rust-lib/flowy-grid/src/event_handler.rs
index 4721e70bca..86b8e8892c 100644
--- a/frontend/rust-lib/flowy-grid/src/event_handler.rs
+++ b/frontend/rust-lib/flowy-grid/src/event_handler.rs
@@ -407,12 +407,12 @@ pub(crate) async fn update_date_cell_handler(
 }
 
 #[tracing::instrument(level = "trace", skip_all, err)]
-pub(crate) async fn get_group_handler(
+pub(crate) async fn get_groups_handler(
     data: Data<GridIdPB>,
     manager: AppData<Arc<GridManager>>,
 ) -> DataResult<RepeatedGridGroupPB, FlowyError> {
     let params: GridIdPB = data.into_inner();
     let editor = manager.get_grid_editor(&params.value)?;
-    let group = editor.get_group().await?;
+    let group = editor.load_groups().await?;
     data_result(group)
 }
diff --git a/frontend/rust-lib/flowy-grid/src/event_map.rs b/frontend/rust-lib/flowy-grid/src/event_map.rs
index 0852deade2..9e0b2ef5dd 100644
--- a/frontend/rust-lib/flowy-grid/src/event_map.rs
+++ b/frontend/rust-lib/flowy-grid/src/event_map.rs
@@ -39,7 +39,7 @@ pub fn create(grid_manager: Arc<GridManager>) -> Module {
         // Date
         .event(GridEvent::UpdateDateCell, update_date_cell_handler)
         // Group
-        .event(GridEvent::GetGroup, update_date_cell_handler);
+        .event(GridEvent::GetGroup, get_groups_handler);
 
     module
 }
diff --git a/frontend/rust-lib/flowy-grid/src/services/cell/cell_operation.rs b/frontend/rust-lib/flowy-grid/src/services/cell/cell_operation.rs
index e73dbb8bc3..7ebee15d53 100644
--- a/frontend/rust-lib/flowy-grid/src/services/cell/cell_operation.rs
+++ b/frontend/rust-lib/flowy-grid/src/services/cell/cell_operation.rs
@@ -11,6 +11,10 @@ pub trait CellFilterOperation<T> {
     fn apply_filter(&self, any_cell_data: AnyCellData, filter: &T) -> FlowyResult<bool>;
 }
 
+pub trait CellGroupOperation {
+    fn apply_group(&self, any_cell_data: AnyCellData, group_content: &str) -> FlowyResult<bool>;
+}
+
 /// Return object that describes the cell.
 pub trait CellDisplayable<CD> {
     fn display_data(
@@ -55,15 +59,15 @@ pub fn apply_cell_data_changeset<C: ToString, T: AsRef<FieldRevision>>(
     let changeset = changeset.to_string();
     let field_type = field_rev.field_type_rev.into();
     let s = match field_type {
-        FieldType::RichText => RichTextTypeOption::from(field_rev).apply_changeset(changeset.into(), cell_rev),
-        FieldType::Number => NumberTypeOption::from(field_rev).apply_changeset(changeset.into(), cell_rev),
-        FieldType::DateTime => DateTypeOption::from(field_rev).apply_changeset(changeset.into(), cell_rev),
+        FieldType::RichText => RichTextTypeOptionPB::from(field_rev).apply_changeset(changeset.into(), cell_rev),
+        FieldType::Number => NumberTypeOptionPB::from(field_rev).apply_changeset(changeset.into(), cell_rev),
+        FieldType::DateTime => DateTypeOptionPB::from(field_rev).apply_changeset(changeset.into(), cell_rev),
         FieldType::SingleSelect => {
             SingleSelectTypeOptionPB::from(field_rev).apply_changeset(changeset.into(), cell_rev)
         }
         FieldType::MultiSelect => MultiSelectTypeOptionPB::from(field_rev).apply_changeset(changeset.into(), cell_rev),
         FieldType::Checkbox => CheckboxTypeOption::from(field_rev).apply_changeset(changeset.into(), cell_rev),
-        FieldType::URL => URLTypeOption::from(field_rev).apply_changeset(changeset.into(), cell_rev),
+        FieldType::URL => URLTypeOptionPB::from(field_rev).apply_changeset(changeset.into(), cell_rev),
     }?;
 
     Ok(AnyCellData::new(s, field_type).json())
@@ -97,13 +101,13 @@ pub fn try_decode_cell_data(
         let field_type: FieldTypeRevision = t_field_type.into();
         let data = match t_field_type {
             FieldType::RichText => field_rev
-                .get_type_option_entry::<RichTextTypeOption>(field_type)?
+                .get_type_option_entry::<RichTextTypeOptionPB>(field_type)?
                 .decode_cell_data(cell_data.into(), s_field_type, field_rev),
             FieldType::Number => field_rev
-                .get_type_option_entry::<NumberTypeOption>(field_type)?
+                .get_type_option_entry::<NumberTypeOptionPB>(field_type)?
                 .decode_cell_data(cell_data.into(), s_field_type, field_rev),
             FieldType::DateTime => field_rev
-                .get_type_option_entry::<DateTypeOption>(field_type)?
+                .get_type_option_entry::<DateTypeOptionPB>(field_type)?
                 .decode_cell_data(cell_data.into(), s_field_type, field_rev),
             FieldType::SingleSelect => field_rev
                 .get_type_option_entry::<SingleSelectTypeOptionPB>(field_type)?
@@ -115,7 +119,7 @@ pub fn try_decode_cell_data(
                 .get_type_option_entry::<CheckboxTypeOption>(field_type)?
                 .decode_cell_data(cell_data.into(), s_field_type, field_rev),
             FieldType::URL => field_rev
-                .get_type_option_entry::<URLTypeOption>(field_type)?
+                .get_type_option_entry::<URLTypeOptionPB>(field_type)?
                 .decode_cell_data(cell_data.into(), s_field_type, field_rev),
         };
         Some(data)
diff --git a/frontend/rust-lib/flowy-grid/src/services/field/field_builder.rs b/frontend/rust-lib/flowy-grid/src/services/field/field_builder.rs
index ccd16a019e..52f23d4906 100644
--- a/frontend/rust-lib/flowy-grid/src/services/field/field_builder.rs
+++ b/frontend/rust-lib/flowy-grid/src/services/field/field_builder.rs
@@ -90,13 +90,13 @@ pub trait TypeOptionBuilder {
 
 pub fn default_type_option_builder_from_type(field_type: &FieldType) -> Box<dyn TypeOptionBuilder> {
     let s: String = match field_type {
-        FieldType::RichText => RichTextTypeOption::default().into(),
-        FieldType::Number => NumberTypeOption::default().into(),
-        FieldType::DateTime => DateTypeOption::default().into(),
+        FieldType::RichText => RichTextTypeOptionPB::default().into(),
+        FieldType::Number => NumberTypeOptionPB::default().into(),
+        FieldType::DateTime => DateTypeOptionPB::default().into(),
         FieldType::SingleSelect => SingleSelectTypeOptionPB::default().into(),
         FieldType::MultiSelect => MultiSelectTypeOptionPB::default().into(),
         FieldType::Checkbox => CheckboxTypeOption::default().into(),
-        FieldType::URL => URLTypeOption::default().into(),
+        FieldType::URL => URLTypeOptionPB::default().into(),
     };
 
     type_option_builder_from_json_str(&s, field_type)
diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/date_tests.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/date_tests.rs
index 1229a8f5e1..5bdc39ed71 100644
--- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/date_tests.rs
+++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/date_tests.rs
@@ -9,7 +9,7 @@ mod tests {
 
     #[test]
     fn date_type_option_date_format_test() {
-        let mut type_option = DateTypeOption::default();
+        let mut type_option = DateTypeOptionPB::default();
         let field_rev = FieldBuilder::from_field_type(&FieldType::DateTime).build();
         for date_format in DateFormat::iter() {
             type_option.date_format = date_format;
@@ -32,7 +32,7 @@ mod tests {
 
     #[test]
     fn date_type_option_different_time_format_test() {
-        let mut type_option = DateTypeOption::default();
+        let mut type_option = DateTypeOptionPB::default();
         let field_type = FieldType::DateTime;
         let field_rev = FieldBuilder::from_field_type(&field_type).build();
 
@@ -66,7 +66,7 @@ mod tests {
 
     #[test]
     fn date_type_option_invalid_date_str_test() {
-        let type_option = DateTypeOption::default();
+        let type_option = DateTypeOptionPB::default();
         let field_type = FieldType::DateTime;
         let field_rev = FieldBuilder::from_field_type(&field_type).build();
         assert_date(&type_option, "abc", None, "", &field_rev);
@@ -75,7 +75,7 @@ mod tests {
     #[test]
     #[should_panic]
     fn date_type_option_invalid_include_time_str_test() {
-        let mut type_option = DateTypeOption::new();
+        let mut type_option = DateTypeOptionPB::new();
         type_option.include_time = true;
         let field_rev = FieldBuilder::from_field_type(&FieldType::DateTime).build();
 
@@ -90,7 +90,7 @@ mod tests {
 
     #[test]
     fn date_type_option_empty_include_time_str_test() {
-        let mut type_option = DateTypeOption::new();
+        let mut type_option = DateTypeOptionPB::new();
         type_option.include_time = true;
         let field_rev = FieldBuilder::from_field_type(&FieldType::DateTime).build();
 
@@ -101,7 +101,7 @@ mod tests {
     #[test]
     #[should_panic]
     fn date_type_option_twelve_hours_include_time_str_in_twenty_four_hours_format() {
-        let mut type_option = DateTypeOption::new();
+        let mut type_option = DateTypeOptionPB::new();
         type_option.include_time = true;
         let field_rev = FieldBuilder::from_field_type(&FieldType::DateTime).build();
 
@@ -114,7 +114,7 @@ mod tests {
         );
     }
     fn assert_date<T: ToString>(
-        type_option: &DateTypeOption,
+        type_option: &DateTypeOptionPB,
         timestamp: T,
         include_time_str: Option<String>,
         expected_str: &str,
@@ -133,7 +133,7 @@ mod tests {
         );
     }
 
-    fn decode_cell_data(encoded_data: String, type_option: &DateTypeOption, field_rev: &FieldRevision) -> String {
+    fn decode_cell_data(encoded_data: String, type_option: &DateTypeOptionPB, field_rev: &FieldRevision) -> String {
         let decoded_data = type_option
             .decode_cell_data(encoded_data.into(), &FieldType::DateTime, field_rev)
             .unwrap()
diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/date_type_option.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/date_type_option.rs
index 17b897b1f0..729ae1958a 100644
--- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/date_type_option.rs
+++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/date_type_option.rs
@@ -14,7 +14,7 @@ use serde::{Deserialize, Serialize};
 
 // Date
 #[derive(Clone, Debug, Default, Serialize, Deserialize, ProtoBuf)]
-pub struct DateTypeOption {
+pub struct DateTypeOptionPB {
     #[pb(index = 1)]
     pub date_format: DateFormat,
 
@@ -24,9 +24,9 @@ pub struct DateTypeOption {
     #[pb(index = 3)]
     pub include_time: bool,
 }
-impl_type_option!(DateTypeOption, FieldType::DateTime);
+impl_type_option!(DateTypeOptionPB, FieldType::DateTime);
 
-impl DateTypeOption {
+impl DateTypeOptionPB {
     #[allow(dead_code)]
     pub fn new() -> Self {
         Self::default()
@@ -116,7 +116,7 @@ impl DateTypeOption {
     }
 }
 
-impl CellDisplayable<DateTimestamp> for DateTypeOption {
+impl CellDisplayable<DateTimestamp> for DateTypeOptionPB {
     fn display_data(
         &self,
         cell_data: CellData<DateTimestamp>,
@@ -129,7 +129,7 @@ impl CellDisplayable<DateTimestamp> for DateTypeOption {
     }
 }
 
-impl CellDataOperation<DateTimestamp, DateCellChangesetPB> for DateTypeOption {
+impl CellDataOperation<DateTimestamp, DateCellChangesetPB> for DateTypeOptionPB {
     fn decode_cell_data(
         &self,
         cell_data: CellData<DateTimestamp>,
@@ -169,9 +169,9 @@ impl CellDataOperation<DateTimestamp, DateCellChangesetPB> for DateTypeOption {
 }
 
 #[derive(Default)]
-pub struct DateTypeOptionBuilder(DateTypeOption);
+pub struct DateTypeOptionBuilder(DateTypeOptionPB);
 impl_into_box_type_option_builder!(DateTypeOptionBuilder);
-impl_builder_from_json_str_and_from_bytes!(DateTypeOptionBuilder, DateTypeOption);
+impl_builder_from_json_str_and_from_bytes!(DateTypeOptionBuilder, DateTypeOptionPB);
 
 impl DateTypeOptionBuilder {
     pub fn date_format(mut self, date_format: DateFormat) -> Self {
diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option/number_tests.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option/number_tests.rs
index 41132ecfe4..41d4cb212c 100644
--- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option/number_tests.rs
+++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option/number_tests.rs
@@ -3,14 +3,14 @@ mod tests {
     use crate::entities::FieldType;
     use crate::services::cell::CellDataOperation;
     use crate::services::field::FieldBuilder;
-    use crate::services::field::{strip_currency_symbol, NumberFormat, NumberTypeOption};
+    use crate::services::field::{strip_currency_symbol, NumberFormat, NumberTypeOptionPB};
     use flowy_grid_data_model::revision::FieldRevision;
     use strum::IntoEnumIterator;
 
     /// Testing when the input is not a number.
     #[test]
     fn number_type_option_invalid_input_test() {
-        let type_option = NumberTypeOption::default();
+        let type_option = NumberTypeOptionPB::default();
         let field_type = FieldType::Number;
         let field_rev = FieldBuilder::from_field_type(&field_type).build();
 
@@ -33,7 +33,7 @@ mod tests {
     /// Format the input number to the corresponding format string.
     #[test]
     fn number_type_option_format_number_test() {
-        let mut type_option = NumberTypeOption::default();
+        let mut type_option = NumberTypeOptionPB::default();
         let field_type = FieldType::Number;
         let field_rev = FieldBuilder::from_field_type(&field_type).build();
 
@@ -63,7 +63,7 @@ mod tests {
     /// Format the input String to the corresponding format string.
     #[test]
     fn number_type_option_format_str_test() {
-        let mut type_option = NumberTypeOption::default();
+        let mut type_option = NumberTypeOptionPB::default();
         let field_type = FieldType::Number;
         let field_rev = FieldBuilder::from_field_type(&field_type).build();
 
@@ -101,7 +101,7 @@ mod tests {
     /// Carry out the sign positive to input number
     #[test]
     fn number_description_sign_test() {
-        let mut type_option = NumberTypeOption {
+        let mut type_option = NumberTypeOptionPB {
             sign_positive: false,
             ..Default::default()
         };
@@ -129,7 +129,7 @@ mod tests {
     }
 
     fn assert_number(
-        type_option: &NumberTypeOption,
+        type_option: &NumberTypeOptionPB,
         input_str: &str,
         expected_str: &str,
         field_type: &FieldType,
diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option/number_type_option.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option/number_type_option.rs
index 26d1d64248..cdb1118385 100644
--- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option/number_type_option.rs
+++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option/number_type_option.rs
@@ -14,9 +14,9 @@ use serde::{Deserialize, Serialize};
 use std::str::FromStr;
 
 #[derive(Default)]
-pub struct NumberTypeOptionBuilder(NumberTypeOption);
+pub struct NumberTypeOptionBuilder(NumberTypeOptionPB);
 impl_into_box_type_option_builder!(NumberTypeOptionBuilder);
-impl_builder_from_json_str_and_from_bytes!(NumberTypeOptionBuilder, NumberTypeOption);
+impl_builder_from_json_str_and_from_bytes!(NumberTypeOptionBuilder, NumberTypeOptionPB);
 
 impl NumberTypeOptionBuilder {
     pub fn name(mut self, name: &str) -> Self {
@@ -52,7 +52,7 @@ impl TypeOptionBuilder for NumberTypeOptionBuilder {
 
 // Number
 #[derive(Clone, Debug, Serialize, Deserialize, ProtoBuf)]
-pub struct NumberTypeOption {
+pub struct NumberTypeOptionPB {
     #[pb(index = 1)]
     pub format: NumberFormat,
 
@@ -68,9 +68,9 @@ pub struct NumberTypeOption {
     #[pb(index = 5)]
     pub name: String,
 }
-impl_type_option!(NumberTypeOption, FieldType::Number);
+impl_type_option!(NumberTypeOptionPB, FieldType::Number);
 
-impl NumberTypeOption {
+impl NumberTypeOptionPB {
     pub fn new() -> Self {
         Self::default()
     }
@@ -102,7 +102,7 @@ pub(crate) fn strip_currency_symbol<T: ToString>(s: T) -> String {
     s
 }
 
-impl CellDataOperation<String, String> for NumberTypeOption {
+impl CellDataOperation<String, String> for NumberTypeOptionPB {
     fn decode_cell_data(
         &self,
         cell_data: CellData<String>,
@@ -132,11 +132,11 @@ impl CellDataOperation<String, String> for NumberTypeOption {
     }
 }
 
-impl std::default::Default for NumberTypeOption {
+impl std::default::Default for NumberTypeOptionPB {
     fn default() -> Self {
         let format = NumberFormat::default();
         let symbol = format.symbol();
-        NumberTypeOption {
+        NumberTypeOptionPB {
             format,
             scale: 0,
             symbol,
diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/text_type_option/text_type_option.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/text_type_option/text_type_option.rs
index 44ae81315d..00ea95125f 100644
--- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/text_type_option/text_type_option.rs
+++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/text_type_option/text_type_option.rs
@@ -12,9 +12,9 @@ use flowy_grid_data_model::revision::{CellRevision, FieldRevision, TypeOptionDat
 use serde::{Deserialize, Serialize};
 
 #[derive(Default)]
-pub struct RichTextTypeOptionBuilder(RichTextTypeOption);
+pub struct RichTextTypeOptionBuilder(RichTextTypeOptionPB);
 impl_into_box_type_option_builder!(RichTextTypeOptionBuilder);
-impl_builder_from_json_str_and_from_bytes!(RichTextTypeOptionBuilder, RichTextTypeOption);
+impl_builder_from_json_str_and_from_bytes!(RichTextTypeOptionBuilder, RichTextTypeOptionPB);
 
 impl TypeOptionBuilder for RichTextTypeOptionBuilder {
     fn field_type(&self) -> FieldType {
@@ -27,13 +27,13 @@ impl TypeOptionBuilder for RichTextTypeOptionBuilder {
 }
 
 #[derive(Debug, Clone, Default, Serialize, Deserialize, ProtoBuf)]
-pub struct RichTextTypeOption {
+pub struct RichTextTypeOptionPB {
     #[pb(index = 1)]
     data: String, //It's not used yet
 }
-impl_type_option!(RichTextTypeOption, FieldType::RichText);
+impl_type_option!(RichTextTypeOptionPB, FieldType::RichText);
 
-impl CellDisplayable<String> for RichTextTypeOption {
+impl CellDisplayable<String> for RichTextTypeOptionPB {
     fn display_data(
         &self,
         cell_data: CellData<String>,
@@ -45,7 +45,7 @@ impl CellDisplayable<String> for RichTextTypeOption {
     }
 }
 
-impl CellDataOperation<String, String> for RichTextTypeOption {
+impl CellDataOperation<String, String> for RichTextTypeOptionPB {
     fn decode_cell_data(
         &self,
         cell_data: CellData<String>,
@@ -114,7 +114,7 @@ mod tests {
 
     #[test]
     fn text_description_test() {
-        let type_option = RichTextTypeOption::default();
+        let type_option = RichTextTypeOptionPB::default();
 
         // date
         let field_type = FieldType::DateTime;
diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option/url_tests.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option/url_tests.rs
index 3cf5d6f99b..ddccfdb606 100644
--- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option/url_tests.rs
+++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option/url_tests.rs
@@ -3,14 +3,14 @@ mod tests {
     use crate::entities::FieldType;
     use crate::services::cell::{CellData, CellDataOperation};
     use crate::services::field::{FieldBuilder, URLCellDataParser};
-    use crate::services::field::{URLCellDataPB, URLTypeOption};
+    use crate::services::field::{URLCellDataPB, URLTypeOptionPB};
     use flowy_grid_data_model::revision::FieldRevision;
 
     /// The expected_str will equal to the input string, but the expected_url will be empty if there's no
     /// http url in the input string.
     #[test]
     fn url_type_option_does_not_contain_url_test() {
-        let type_option = URLTypeOption::default();
+        let type_option = URLTypeOptionPB::default();
         let field_type = FieldType::URL;
         let field_rev = FieldBuilder::from_field_type(&field_type).build();
         assert_url(&type_option, "123", "123", "", &field_type, &field_rev);
@@ -21,7 +21,7 @@ mod tests {
     /// if there's a http url in the input string.
     #[test]
     fn url_type_option_contains_url_test() {
-        let type_option = URLTypeOption::default();
+        let type_option = URLTypeOptionPB::default();
         let field_type = FieldType::URL;
         let field_rev = FieldBuilder::from_field_type(&field_type).build();
         assert_url(
@@ -46,7 +46,7 @@ mod tests {
     /// if there's a http url and some words following it in the input string.
     #[test]
     fn url_type_option_contains_url_with_string_after_test() {
-        let type_option = URLTypeOption::default();
+        let type_option = URLTypeOptionPB::default();
         let field_type = FieldType::URL;
         let field_rev = FieldBuilder::from_field_type(&field_type).build();
         assert_url(
@@ -71,7 +71,7 @@ mod tests {
     /// if there's a http url and special words following it in the input string.
     #[test]
     fn url_type_option_contains_url_with_special_string_after_test() {
-        let type_option = URLTypeOption::default();
+        let type_option = URLTypeOptionPB::default();
         let field_type = FieldType::URL;
         let field_rev = FieldBuilder::from_field_type(&field_type).build();
         assert_url(
@@ -96,7 +96,7 @@ mod tests {
     /// if there's a level4 url in the input string.
     #[test]
     fn level4_url_type_test() {
-        let type_option = URLTypeOption::default();
+        let type_option = URLTypeOptionPB::default();
         let field_type = FieldType::URL;
         let field_rev = FieldBuilder::from_field_type(&field_type).build();
         assert_url(
@@ -121,7 +121,7 @@ mod tests {
     /// urls with different top level domains.
     #[test]
     fn different_top_level_domains_test() {
-        let type_option = URLTypeOption::default();
+        let type_option = URLTypeOptionPB::default();
         let field_type = FieldType::URL;
         let field_rev = FieldBuilder::from_field_type(&field_type).build();
         assert_url(
@@ -162,7 +162,7 @@ mod tests {
     }
 
     fn assert_url(
-        type_option: &URLTypeOption,
+        type_option: &URLTypeOptionPB,
         input_str: &str,
         expected_str: &str,
         expected_url: &str,
@@ -177,7 +177,7 @@ mod tests {
 
     fn decode_cell_data<T: Into<CellData<URLCellDataPB>>>(
         encoded_data: T,
-        type_option: &URLTypeOption,
+        type_option: &URLTypeOptionPB,
         field_rev: &FieldRevision,
         field_type: &FieldType,
     ) -> URLCellDataPB {
diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option/url_type_option.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option/url_type_option.rs
index 3fa49dac09..adbc91b4f0 100644
--- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option/url_type_option.rs
+++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option/url_type_option.rs
@@ -11,9 +11,9 @@ use lazy_static::lazy_static;
 use serde::{Deserialize, Serialize};
 
 #[derive(Default)]
-pub struct URLTypeOptionBuilder(URLTypeOption);
+pub struct URLTypeOptionBuilder(URLTypeOptionPB);
 impl_into_box_type_option_builder!(URLTypeOptionBuilder);
-impl_builder_from_json_str_and_from_bytes!(URLTypeOptionBuilder, URLTypeOption);
+impl_builder_from_json_str_and_from_bytes!(URLTypeOptionBuilder, URLTypeOptionPB);
 
 impl TypeOptionBuilder for URLTypeOptionBuilder {
     fn field_type(&self) -> FieldType {
@@ -26,13 +26,13 @@ impl TypeOptionBuilder for URLTypeOptionBuilder {
 }
 
 #[derive(Debug, Clone, Serialize, Deserialize, Default, ProtoBuf)]
-pub struct URLTypeOption {
+pub struct URLTypeOptionPB {
     #[pb(index = 1)]
     data: String, //It's not used yet.
 }
-impl_type_option!(URLTypeOption, FieldType::URL);
+impl_type_option!(URLTypeOptionPB, FieldType::URL);
 
-impl CellDisplayable<URLCellDataPB> for URLTypeOption {
+impl CellDisplayable<URLCellDataPB> for URLTypeOptionPB {
     fn display_data(
         &self,
         cell_data: CellData<URLCellDataPB>,
@@ -44,7 +44,7 @@ impl CellDisplayable<URLCellDataPB> for URLTypeOption {
     }
 }
 
-impl CellDataOperation<URLCellDataPB, String> for URLTypeOption {
+impl CellDataOperation<URLCellDataPB, String> for URLTypeOptionPB {
     fn decode_cell_data(
         &self,
         cell_data: CellData<URLCellDataPB>,
diff --git a/frontend/rust-lib/flowy-grid/src/services/filter/filter_cache.rs b/frontend/rust-lib/flowy-grid/src/services/filter/filter_cache.rs
index a1f6d4cbbf..1d3ed77389 100644
--- a/frontend/rust-lib/flowy-grid/src/services/filter/filter_cache.rs
+++ b/frontend/rust-lib/flowy-grid/src/services/filter/filter_cache.rs
@@ -1,5 +1,6 @@
 use crate::entities::{
-    FieldType, GridCheckboxFilter, GridDateFilter, GridNumberFilter, GridSelectOptionFilter, GridTextFilter,
+    CheckboxFilterConfigurationPB, DateFilterConfigurationPB, FieldType, NumberFilterConfigurationPB,
+    SelectOptionFilterConfigurationPB, TextFilterConfigurationPB,
 };
 use dashmap::DashMap;
 use flowy_grid_data_model::revision::{FieldRevision, RowRevision};
@@ -58,12 +59,12 @@ impl FilterResult {
 
 #[derive(Default)]
 pub(crate) struct FilterCache {
-    pub(crate) text_filter: DashMap<FilterId, GridTextFilter>,
-    pub(crate) url_filter: DashMap<FilterId, GridTextFilter>,
-    pub(crate) number_filter: DashMap<FilterId, GridNumberFilter>,
-    pub(crate) date_filter: DashMap<FilterId, GridDateFilter>,
-    pub(crate) select_option_filter: DashMap<FilterId, GridSelectOptionFilter>,
-    pub(crate) checkbox_filter: DashMap<FilterId, GridCheckboxFilter>,
+    pub(crate) text_filter: DashMap<FilterId, TextFilterConfigurationPB>,
+    pub(crate) url_filter: DashMap<FilterId, TextFilterConfigurationPB>,
+    pub(crate) number_filter: DashMap<FilterId, NumberFilterConfigurationPB>,
+    pub(crate) date_filter: DashMap<FilterId, DateFilterConfigurationPB>,
+    pub(crate) select_option_filter: DashMap<FilterId, SelectOptionFilterConfigurationPB>,
+    pub(crate) checkbox_filter: DashMap<FilterId, CheckboxFilterConfigurationPB>,
 }
 
 impl FilterCache {
@@ -117,28 +118,34 @@ pub(crate) async fn refresh_filter_cache(
                 let field_type: FieldType = field_rev.field_type_rev.into();
                 match &field_type {
                     FieldType::RichText => {
-                        let _ = cache.text_filter.insert(filter_id, GridTextFilter::from(filter_rev));
+                        let _ = cache
+                            .text_filter
+                            .insert(filter_id, TextFilterConfigurationPB::from(filter_rev));
                     }
                     FieldType::Number => {
                         let _ = cache
                             .number_filter
-                            .insert(filter_id, GridNumberFilter::from(filter_rev));
+                            .insert(filter_id, NumberFilterConfigurationPB::from(filter_rev));
                     }
                     FieldType::DateTime => {
-                        let _ = cache.date_filter.insert(filter_id, GridDateFilter::from(filter_rev));
+                        let _ = cache
+                            .date_filter
+                            .insert(filter_id, DateFilterConfigurationPB::from(filter_rev));
                     }
                     FieldType::SingleSelect | FieldType::MultiSelect => {
                         let _ = cache
                             .select_option_filter
-                            .insert(filter_id, GridSelectOptionFilter::from(filter_rev));
+                            .insert(filter_id, SelectOptionFilterConfigurationPB::from(filter_rev));
                     }
                     FieldType::Checkbox => {
                         let _ = cache
                             .checkbox_filter
-                            .insert(filter_id, GridCheckboxFilter::from(filter_rev));
+                            .insert(filter_id, CheckboxFilterConfigurationPB::from(filter_rev));
                     }
                     FieldType::URL => {
-                        let _ = cache.url_filter.insert(filter_id, GridTextFilter::from(filter_rev));
+                        let _ = cache
+                            .url_filter
+                            .insert(filter_id, TextFilterConfigurationPB::from(filter_rev));
                     }
                 }
             }
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 8ee5f6d99e..28f7f217e3 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
@@ -3,8 +3,8 @@ use crate::entities::{FieldType, GridBlockChangesetPB};
 use crate::services::block_manager::GridBlockManager;
 use crate::services::cell::{AnyCellData, CellFilterOperation};
 use crate::services::field::{
-    CheckboxTypeOption, DateTypeOption, MultiSelectTypeOptionPB, NumberTypeOption, RichTextTypeOption,
-    SingleSelectTypeOptionPB, URLTypeOption,
+    CheckboxTypeOption, DateTypeOptionPB, MultiSelectTypeOptionPB, NumberTypeOptionPB, RichTextTypeOptionPB,
+    SingleSelectTypeOptionPB, URLTypeOptionPB,
 };
 use crate::services::filter::filter_cache::{
     refresh_filter_cache, FilterCache, FilterId, FilterResult, FilterResultCache,
@@ -182,7 +182,7 @@ fn filter_cell(
         FieldType::RichText => filter_cache.text_filter.get(&filter_id).and_then(|filter| {
             Some(
                 field_rev
-                    .get_type_option_entry::<RichTextTypeOption>(field_type_rev)?
+                    .get_type_option_entry::<RichTextTypeOptionPB>(field_type_rev)?
                     .apply_filter(any_cell_data, filter.value())
                     .ok(),
             )
@@ -190,7 +190,7 @@ fn filter_cell(
         FieldType::Number => filter_cache.number_filter.get(&filter_id).and_then(|filter| {
             Some(
                 field_rev
-                    .get_type_option_entry::<NumberTypeOption>(field_type_rev)?
+                    .get_type_option_entry::<NumberTypeOptionPB>(field_type_rev)?
                     .apply_filter(any_cell_data, filter.value())
                     .ok(),
             )
@@ -198,7 +198,7 @@ fn filter_cell(
         FieldType::DateTime => filter_cache.date_filter.get(&filter_id).and_then(|filter| {
             Some(
                 field_rev
-                    .get_type_option_entry::<DateTypeOption>(field_type_rev)?
+                    .get_type_option_entry::<DateTypeOptionPB>(field_type_rev)?
                     .apply_filter(any_cell_data, filter.value())
                     .ok(),
             )
@@ -230,7 +230,7 @@ fn filter_cell(
         FieldType::URL => filter_cache.url_filter.get(&filter_id).and_then(|filter| {
             Some(
                 field_rev
-                    .get_type_option_entry::<URLTypeOption>(field_type_rev)?
+                    .get_type_option_entry::<URLTypeOptionPB>(field_type_rev)?
                     .apply_filter(any_cell_data, filter.value())
                     .ok(),
             )
diff --git a/frontend/rust-lib/flowy-grid/src/services/filter/impls/checkbox_filter.rs b/frontend/rust-lib/flowy-grid/src/services/filter/impls/checkbox_filter.rs
index 24e21bbeb7..6ff2924e16 100644
--- a/frontend/rust-lib/flowy-grid/src/services/filter/impls/checkbox_filter.rs
+++ b/frontend/rust-lib/flowy-grid/src/services/filter/impls/checkbox_filter.rs
@@ -1,9 +1,9 @@
-use crate::entities::{CheckboxCondition, GridCheckboxFilter};
+use crate::entities::{CheckboxCondition, CheckboxFilterConfigurationPB};
 use crate::services::cell::{AnyCellData, CellData, CellFilterOperation};
 use crate::services::field::{CheckboxCellData, CheckboxTypeOption};
 use flowy_error::FlowyResult;
 
-impl GridCheckboxFilter {
+impl CheckboxFilterConfigurationPB {
     pub fn is_visible(&self, cell_data: &CheckboxCellData) -> bool {
         let is_check = cell_data.is_check();
         match self.condition {
@@ -13,8 +13,8 @@ impl GridCheckboxFilter {
     }
 }
 
-impl CellFilterOperation<GridCheckboxFilter> for CheckboxTypeOption {
-    fn apply_filter(&self, any_cell_data: AnyCellData, filter: &GridCheckboxFilter) -> FlowyResult<bool> {
+impl CellFilterOperation<CheckboxFilterConfigurationPB> for CheckboxTypeOption {
+    fn apply_filter(&self, any_cell_data: AnyCellData, filter: &CheckboxFilterConfigurationPB) -> FlowyResult<bool> {
         if !any_cell_data.is_checkbox() {
             return Ok(true);
         }
@@ -26,13 +26,13 @@ impl CellFilterOperation<GridCheckboxFilter> for CheckboxTypeOption {
 
 #[cfg(test)]
 mod tests {
-    use crate::entities::{CheckboxCondition, GridCheckboxFilter};
+    use crate::entities::{CheckboxCondition, CheckboxFilterConfigurationPB};
     use crate::services::field::CheckboxCellData;
     use std::str::FromStr;
 
     #[test]
     fn checkbox_filter_is_check_test() {
-        let checkbox_filter = GridCheckboxFilter {
+        let checkbox_filter = CheckboxFilterConfigurationPB {
             condition: CheckboxCondition::IsChecked,
         };
         for (value, visible) in [("true", true), ("yes", true), ("false", false), ("no", false)] {
@@ -43,7 +43,7 @@ mod tests {
 
     #[test]
     fn checkbox_filter_is_uncheck_test() {
-        let checkbox_filter = GridCheckboxFilter {
+        let checkbox_filter = CheckboxFilterConfigurationPB {
             condition: CheckboxCondition::IsUnChecked,
         };
         for (value, visible) in [("false", true), ("no", true), ("true", false), ("yes", false)] {
diff --git a/frontend/rust-lib/flowy-grid/src/services/filter/impls/date_filter.rs b/frontend/rust-lib/flowy-grid/src/services/filter/impls/date_filter.rs
index 46e2571438..18d968d2a4 100644
--- a/frontend/rust-lib/flowy-grid/src/services/filter/impls/date_filter.rs
+++ b/frontend/rust-lib/flowy-grid/src/services/filter/impls/date_filter.rs
@@ -1,9 +1,9 @@
-use crate::entities::{DateFilterCondition, GridDateFilter};
+use crate::entities::{DateFilterCondition, DateFilterConfigurationPB};
 use crate::services::cell::{AnyCellData, CellData, CellFilterOperation};
-use crate::services::field::{DateTimestamp, DateTypeOption};
+use crate::services::field::{DateTimestamp, DateTypeOptionPB};
 use flowy_error::FlowyResult;
 
-impl GridDateFilter {
+impl DateFilterConfigurationPB {
     pub fn is_visible<T: Into<i64>>(&self, cell_timestamp: T) -> bool {
         if self.start.is_none() {
             return false;
@@ -29,8 +29,8 @@ impl GridDateFilter {
     }
 }
 
-impl CellFilterOperation<GridDateFilter> for DateTypeOption {
-    fn apply_filter(&self, any_cell_data: AnyCellData, filter: &GridDateFilter) -> FlowyResult<bool> {
+impl CellFilterOperation<DateFilterConfigurationPB> for DateTypeOptionPB {
+    fn apply_filter(&self, any_cell_data: AnyCellData, filter: &DateFilterConfigurationPB) -> FlowyResult<bool> {
         if !any_cell_data.is_date() {
             return Ok(true);
         }
@@ -43,11 +43,11 @@ impl CellFilterOperation<GridDateFilter> for DateTypeOption {
 #[cfg(test)]
 mod tests {
     #![allow(clippy::all)]
-    use crate::entities::{DateFilterCondition, GridDateFilter};
+    use crate::entities::{DateFilterCondition, DateFilterConfigurationPB};
 
     #[test]
     fn date_filter_is_test() {
-        let filter = GridDateFilter {
+        let filter = DateFilterConfigurationPB {
             condition: DateFilterCondition::DateIs,
             start: Some(123),
             end: None,
@@ -59,7 +59,7 @@ mod tests {
     }
     #[test]
     fn date_filter_before_test() {
-        let filter = GridDateFilter {
+        let filter = DateFilterConfigurationPB {
             condition: DateFilterCondition::DateBefore,
             start: Some(123),
             end: None,
@@ -71,7 +71,7 @@ mod tests {
     }
     #[test]
     fn date_filter_before_or_on_test() {
-        let filter = GridDateFilter {
+        let filter = DateFilterConfigurationPB {
             condition: DateFilterCondition::DateOnOrBefore,
             start: Some(123),
             end: None,
@@ -83,7 +83,7 @@ mod tests {
     }
     #[test]
     fn date_filter_after_test() {
-        let filter = GridDateFilter {
+        let filter = DateFilterConfigurationPB {
             condition: DateFilterCondition::DateAfter,
             start: Some(123),
             end: None,
@@ -95,7 +95,7 @@ mod tests {
     }
     #[test]
     fn date_filter_within_test() {
-        let filter = GridDateFilter {
+        let filter = DateFilterConfigurationPB {
             condition: DateFilterCondition::DateWithIn,
             start: Some(123),
             end: Some(130),
diff --git a/frontend/rust-lib/flowy-grid/src/services/filter/impls/number_filter.rs b/frontend/rust-lib/flowy-grid/src/services/filter/impls/number_filter.rs
index f44c1d2d62..45ae0ac464 100644
--- a/frontend/rust-lib/flowy-grid/src/services/filter/impls/number_filter.rs
+++ b/frontend/rust-lib/flowy-grid/src/services/filter/impls/number_filter.rs
@@ -1,12 +1,12 @@
-use crate::entities::{GridNumberFilter, NumberFilterCondition};
+use crate::entities::{NumberFilterCondition, NumberFilterConfigurationPB};
 use crate::services::cell::{AnyCellData, CellFilterOperation};
-use crate::services::field::{NumberCellData, NumberTypeOption};
+use crate::services::field::{NumberCellData, NumberTypeOptionPB};
 use flowy_error::FlowyResult;
 use rust_decimal::prelude::Zero;
 use rust_decimal::Decimal;
 use std::str::FromStr;
 
-impl GridNumberFilter {
+impl NumberFilterConfigurationPB {
     pub fn is_visible(&self, num_cell_data: &NumberCellData) -> bool {
         if self.content.is_none() {
             return false;
@@ -31,8 +31,8 @@ impl GridNumberFilter {
     }
 }
 
-impl CellFilterOperation<GridNumberFilter> for NumberTypeOption {
-    fn apply_filter(&self, any_cell_data: AnyCellData, filter: &GridNumberFilter) -> FlowyResult<bool> {
+impl CellFilterOperation<NumberFilterConfigurationPB> for NumberTypeOptionPB {
+    fn apply_filter(&self, any_cell_data: AnyCellData, filter: &NumberFilterConfigurationPB) -> FlowyResult<bool> {
         if !any_cell_data.is_number() {
             return Ok(true);
         }
@@ -46,11 +46,11 @@ impl CellFilterOperation<GridNumberFilter> for NumberTypeOption {
 
 #[cfg(test)]
 mod tests {
-    use crate::entities::{GridNumberFilter, NumberFilterCondition};
+    use crate::entities::{NumberFilterCondition, NumberFilterConfigurationPB};
     use crate::services::field::{NumberCellData, NumberFormat};
     #[test]
     fn number_filter_equal_test() {
-        let number_filter = GridNumberFilter {
+        let number_filter = NumberFilterConfigurationPB {
             condition: NumberFilterCondition::Equal,
             content: Some("123".to_owned()),
         };
@@ -68,7 +68,7 @@ mod tests {
     }
     #[test]
     fn number_filter_greater_than_test() {
-        let number_filter = GridNumberFilter {
+        let number_filter = NumberFilterConfigurationPB {
             condition: NumberFilterCondition::GreaterThan,
             content: Some("12".to_owned()),
         };
@@ -80,7 +80,7 @@ mod tests {
 
     #[test]
     fn number_filter_less_than_test() {
-        let number_filter = GridNumberFilter {
+        let number_filter = NumberFilterConfigurationPB {
             condition: NumberFilterCondition::LessThan,
             content: Some("100".to_owned()),
         };
diff --git a/frontend/rust-lib/flowy-grid/src/services/filter/impls/select_option_filter.rs b/frontend/rust-lib/flowy-grid/src/services/filter/impls/select_option_filter.rs
index 5ae8210746..f48069911e 100644
--- a/frontend/rust-lib/flowy-grid/src/services/filter/impls/select_option_filter.rs
+++ b/frontend/rust-lib/flowy-grid/src/services/filter/impls/select_option_filter.rs
@@ -1,12 +1,12 @@
 #![allow(clippy::needless_collect)]
 
-use crate::entities::{GridSelectOptionFilter, SelectOptionCondition};
+use crate::entities::{SelectOptionCondition, SelectOptionFilterConfigurationPB};
 use crate::services::cell::{AnyCellData, CellFilterOperation};
 use crate::services::field::{MultiSelectTypeOptionPB, SingleSelectTypeOptionPB};
 use crate::services::field::{SelectOptionOperation, SelectedSelectOptions};
 use flowy_error::FlowyResult;
 
-impl GridSelectOptionFilter {
+impl SelectOptionFilterConfigurationPB {
     pub fn is_visible(&self, selected_options: &SelectedSelectOptions) -> bool {
         let selected_option_ids: Vec<&String> = selected_options.options.iter().map(|option| &option.id).collect();
         match self.condition {
@@ -39,8 +39,12 @@ impl GridSelectOptionFilter {
     }
 }
 
-impl CellFilterOperation<GridSelectOptionFilter> for MultiSelectTypeOptionPB {
-    fn apply_filter(&self, any_cell_data: AnyCellData, filter: &GridSelectOptionFilter) -> FlowyResult<bool> {
+impl CellFilterOperation<SelectOptionFilterConfigurationPB> for MultiSelectTypeOptionPB {
+    fn apply_filter(
+        &self,
+        any_cell_data: AnyCellData,
+        filter: &SelectOptionFilterConfigurationPB,
+    ) -> FlowyResult<bool> {
         if !any_cell_data.is_multi_select() {
             return Ok(true);
         }
@@ -50,8 +54,12 @@ impl CellFilterOperation<GridSelectOptionFilter> for MultiSelectTypeOptionPB {
     }
 }
 
-impl CellFilterOperation<GridSelectOptionFilter> for SingleSelectTypeOptionPB {
-    fn apply_filter(&self, any_cell_data: AnyCellData, filter: &GridSelectOptionFilter) -> FlowyResult<bool> {
+impl CellFilterOperation<SelectOptionFilterConfigurationPB> for SingleSelectTypeOptionPB {
+    fn apply_filter(
+        &self,
+        any_cell_data: AnyCellData,
+        filter: &SelectOptionFilterConfigurationPB,
+    ) -> FlowyResult<bool> {
         if !any_cell_data.is_single_select() {
             return Ok(true);
         }
@@ -63,7 +71,7 @@ impl CellFilterOperation<GridSelectOptionFilter> for SingleSelectTypeOptionPB {
 #[cfg(test)]
 mod tests {
     #![allow(clippy::all)]
-    use crate::entities::{GridSelectOptionFilter, SelectOptionCondition};
+    use crate::entities::{SelectOptionCondition, SelectOptionFilterConfigurationPB};
     use crate::services::field::selection_type_option::{SelectOptionPB, SelectedSelectOptions};
 
     #[test]
@@ -72,7 +80,7 @@ mod tests {
         let option_2 = SelectOptionPB::new("B");
         let option_3 = SelectOptionPB::new("C");
 
-        let filter_1 = GridSelectOptionFilter {
+        let filter_1 = SelectOptionFilterConfigurationPB {
             condition: SelectOptionCondition::OptionIs,
             option_ids: vec![option_1.id.clone(), option_2.id.clone()],
         };
diff --git a/frontend/rust-lib/flowy-grid/src/services/filter/impls/text_filter.rs b/frontend/rust-lib/flowy-grid/src/services/filter/impls/text_filter.rs
index 25f3902ceb..86cb2aadfa 100644
--- a/frontend/rust-lib/flowy-grid/src/services/filter/impls/text_filter.rs
+++ b/frontend/rust-lib/flowy-grid/src/services/filter/impls/text_filter.rs
@@ -1,9 +1,9 @@
-use crate::entities::{GridTextFilter, TextFilterCondition};
+use crate::entities::{TextFilterCondition, TextFilterConfigurationPB};
 use crate::services::cell::{AnyCellData, CellData, CellFilterOperation};
-use crate::services::field::{RichTextTypeOption, TextCellData};
+use crate::services::field::{RichTextTypeOptionPB, TextCellData};
 use flowy_error::FlowyResult;
 
-impl GridTextFilter {
+impl TextFilterConfigurationPB {
     pub fn is_visible<T: AsRef<str>>(&self, cell_data: T) -> bool {
         let cell_data = cell_data.as_ref();
         let s = cell_data.to_lowercase();
@@ -24,8 +24,8 @@ impl GridTextFilter {
     }
 }
 
-impl CellFilterOperation<GridTextFilter> for RichTextTypeOption {
-    fn apply_filter(&self, any_cell_data: AnyCellData, filter: &GridTextFilter) -> FlowyResult<bool> {
+impl CellFilterOperation<TextFilterConfigurationPB> for RichTextTypeOptionPB {
+    fn apply_filter(&self, any_cell_data: AnyCellData, filter: &TextFilterConfigurationPB) -> FlowyResult<bool> {
         if !any_cell_data.is_text() {
             return Ok(true);
         }
@@ -38,11 +38,11 @@ impl CellFilterOperation<GridTextFilter> for RichTextTypeOption {
 #[cfg(test)]
 mod tests {
     #![allow(clippy::all)]
-    use crate::entities::{GridTextFilter, TextFilterCondition};
+    use crate::entities::{TextFilterCondition, TextFilterConfigurationPB};
 
     #[test]
     fn text_filter_equal_test() {
-        let text_filter = GridTextFilter {
+        let text_filter = TextFilterConfigurationPB {
             condition: TextFilterCondition::Is,
             content: Some("appflowy".to_owned()),
         };
@@ -54,7 +54,7 @@ mod tests {
     }
     #[test]
     fn text_filter_start_with_test() {
-        let text_filter = GridTextFilter {
+        let text_filter = TextFilterConfigurationPB {
             condition: TextFilterCondition::StartsWith,
             content: Some("appflowy".to_owned()),
         };
@@ -66,7 +66,7 @@ mod tests {
 
     #[test]
     fn text_filter_end_with_test() {
-        let text_filter = GridTextFilter {
+        let text_filter = TextFilterConfigurationPB {
             condition: TextFilterCondition::EndsWith,
             content: Some("appflowy".to_owned()),
         };
@@ -77,7 +77,7 @@ mod tests {
     }
     #[test]
     fn text_filter_empty_test() {
-        let text_filter = GridTextFilter {
+        let text_filter = TextFilterConfigurationPB {
             condition: TextFilterCondition::TextIsEmpty,
             content: Some("appflowy".to_owned()),
         };
@@ -87,7 +87,7 @@ mod tests {
     }
     #[test]
     fn text_filter_contain_test() {
-        let text_filter = GridTextFilter {
+        let text_filter = TextFilterConfigurationPB {
             condition: TextFilterCondition::Contains,
             content: Some("appflowy".to_owned()),
         };
diff --git a/frontend/rust-lib/flowy-grid/src/services/filter/impls/url_filter.rs b/frontend/rust-lib/flowy-grid/src/services/filter/impls/url_filter.rs
index 15254d4713..4f0a7b93cd 100644
--- a/frontend/rust-lib/flowy-grid/src/services/filter/impls/url_filter.rs
+++ b/frontend/rust-lib/flowy-grid/src/services/filter/impls/url_filter.rs
@@ -1,10 +1,10 @@
-use crate::entities::GridTextFilter;
+use crate::entities::TextFilterConfigurationPB;
 use crate::services::cell::{AnyCellData, CellData, CellFilterOperation};
-use crate::services::field::{TextCellData, URLTypeOption};
+use crate::services::field::{TextCellData, URLTypeOptionPB};
 use flowy_error::FlowyResult;
 
-impl CellFilterOperation<GridTextFilter> for URLTypeOption {
-    fn apply_filter(&self, any_cell_data: AnyCellData, filter: &GridTextFilter) -> FlowyResult<bool> {
+impl CellFilterOperation<TextFilterConfigurationPB> for URLTypeOptionPB {
+    fn apply_filter(&self, any_cell_data: AnyCellData, filter: &TextFilterConfigurationPB) -> FlowyResult<bool> {
         if !any_cell_data.is_url() {
             return Ok(true);
         }
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 4654f8722c..b0cab2f5af 100644
--- a/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs
+++ b/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs
@@ -452,7 +452,7 @@ impl GridRevisionEditor {
 
     pub async fn get_grid_setting(&self) -> FlowyResult<GridSettingPB> {
         let read_guard = self.grid_pad.read().await;
-        let grid_setting_rev = read_guard.get_grid_setting_rev();
+        let grid_setting_rev = read_guard.get_setting_rev();
         let field_revs = read_guard.get_field_revs(None)?;
         let grid_setting = make_grid_setting(grid_setting_rev, &field_revs);
         Ok(grid_setting)
@@ -564,8 +564,9 @@ impl GridRevisionEditor {
         })
     }
 
-    pub async fn get_group(&self) -> FlowyResult<RepeatedGridGroupPB> {
-        todo!()
+    pub async fn load_groups(&self) -> FlowyResult<RepeatedGridGroupPB> {
+        let groups = self.group_service.load_groups().await.unwrap_or(vec![]);
+        Ok(RepeatedGridGroupPB { items: groups })
     }
 
     async fn modify<F>(&self, f: F) -> FlowyResult<()>
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 50d04febf4..5bafd5b841 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
@@ -1,5 +1,13 @@
+use crate::entities::{
+    CheckboxGroupConfigurationPB, DateGroupConfigurationPB, FieldType, GroupPB, NumberGroupConfigurationPB,
+    SelectOptionGroupConfigurationPB, TextGroupConfigurationPB, UrlGroupConfigurationPB,
+};
 use crate::services::block_manager::GridBlockManager;
+use crate::services::cell::{decode_any_cell_data, CellBytes};
 use crate::services::grid_editor_task::GridServiceTaskScheduler;
+use bytes::Bytes;
+use flowy_error::FlowyResult;
+use flowy_grid_data_model::revision::{CellRevision, FieldRevision, GroupConfigurationRevision, RowRevision};
 use flowy_sync::client_grid::GridRevisionPad;
 use std::sync::Arc;
 use tokio::sync::RwLock;
@@ -26,4 +34,116 @@ impl GridGroupService {
             block_manager,
         }
     }
+
+    pub(crate) async fn load_groups(&self) -> Option<Vec<GroupPB>> {
+        let grid_pad = self.grid_pad.read().await;
+        let field_rev = find_group_field(grid_pad.fields())?;
+        let field_type: FieldType = field_rev.field_type_rev.clone().into();
+        let setting = grid_pad.get_setting_rev();
+        let mut configurations = setting.get_groups(&setting.layout, &field_rev.id, &field_rev.field_type_rev)?;
+
+        if configurations.is_empty() {
+            return None;
+        }
+        assert_eq!(configurations.len(), 1);
+        let configuration = (&*configurations.pop().unwrap()).clone();
+
+        let blocks = self.block_manager.get_block_snapshots(None).await.unwrap();
+
+        let row_revs = blocks
+            .into_iter()
+            .map(|block| block.row_revs)
+            .flatten()
+            .collect::<Vec<Arc<RowRevision>>>();
+
+        let groups = match field_type {
+            FieldType::RichText => {
+                let generator = GroupGenerator::<TextGroupConfigurationPB>::from_configuration(configuration);
+            }
+            FieldType::Number => {
+                let generator = GroupGenerator::<NumberGroupConfigurationPB>::from_configuration(configuration);
+            }
+            FieldType::DateTime => {
+                let generator = GroupGenerator::<DateGroupConfigurationPB>::from_configuration(configuration);
+            }
+            FieldType::SingleSelect => {
+                let generator = GroupGenerator::<SelectOptionGroupConfigurationPB>::from_configuration(configuration);
+            }
+            FieldType::MultiSelect => {
+                let generator = GroupGenerator::<SelectOptionGroupConfigurationPB>::from_configuration(configuration);
+            }
+            FieldType::Checkbox => {
+                let generator = GroupGenerator::<CheckboxGroupConfigurationPB>::from_configuration(configuration);
+            }
+            FieldType::URL => {
+                let generator = GroupGenerator::<UrlGroupConfigurationPB>::from_configuration(configuration);
+            }
+        };
+        None
+    }
+}
+
+pub struct GroupGenerator<T> {
+    field_id: String,
+    groups: Vec<Group>,
+    configuration: Option<T>,
+}
+
+pub struct Group {
+    row_ids: Vec<String>,
+    content: String,
+}
+
+impl<T> GroupGenerator<T>
+where
+    T: TryFrom<Bytes, Error = protobuf::ProtobufError>,
+{
+    pub fn from_configuration(configuration: GroupConfigurationRevision) -> FlowyResult<Self> {
+        let bytes = Bytes::from(configuration.content.unwrap_or(vec![]));
+        Self::from_bytes(&configuration.field_id, bytes)
+    }
+
+    pub fn from_bytes(field_id: &str, bytes: Bytes) -> FlowyResult<Self> {
+        let configuration = if bytes.is_empty() {
+            None
+        } else {
+            Some(T::try_from(bytes)?)
+        };
+        Ok(Self {
+            field_id: field_id.to_owned(),
+            groups: vec![],
+            configuration,
+        })
+    }
+}
+pub trait GroupConfiguration {
+    fn should_group(&self, content: &str, cell_bytes: CellBytes) -> bool;
+}
+
+impl<T> GroupGenerator<T>
+where
+    T: GroupConfiguration,
+{
+    pub fn group_row(&mut self, field_rev: &Arc<FieldRevision>, row: &RowRevision) {
+        if self.configuration.is_none() {
+            return;
+        }
+        let configuration = self.configuration.as_ref().unwrap();
+        if let Some(cell_rev) = row.cells.get(&self.field_id) {
+            for group in self.groups.iter_mut() {
+                let cell_rev: CellRevision = cell_rev.clone();
+                let cell_bytes = decode_any_cell_data(cell_rev.data, field_rev);
+                if configuration.should_group(&group.content, cell_bytes) {
+                    group.row_ids.push(row.id.clone());
+                }
+            }
+        }
+    }
+}
+
+fn find_group_field(field_revs: &[Arc<FieldRevision>]) -> Option<&Arc<FieldRevision>> {
+    field_revs.iter().find(|field_rev| {
+        let field_type: FieldType = field_rev.field_type_rev.into();
+        field_type.can_be_group()
+    })
 }
diff --git a/frontend/rust-lib/flowy-grid/src/services/group/impls/checkbox_group.rs b/frontend/rust-lib/flowy-grid/src/services/group/impls/checkbox_group.rs
new file mode 100644
index 0000000000..19a79428c3
--- /dev/null
+++ b/frontend/rust-lib/flowy-grid/src/services/group/impls/checkbox_group.rs
@@ -0,0 +1,17 @@
+use crate::entities::CheckboxGroupConfigurationPB;
+use crate::services::cell::{AnyCellData, CellData, CellGroupOperation};
+use crate::services::field::{CheckboxCellData, CheckboxTypeOption};
+use flowy_error::FlowyResult;
+
+impl CellGroupOperation for CheckboxTypeOption {
+    fn apply_group(&self, any_cell_data: AnyCellData, content: &str) -> FlowyResult<bool> {
+        if !any_cell_data.is_checkbox() {
+            return Ok(true);
+        }
+        let cell_data: CellData<CheckboxCellData> = any_cell_data.into();
+        let checkbox_cell_data = cell_data.try_into_inner()?;
+
+        // Ok(checkbox_cell_data.as_ref() == content)
+        todo!()
+    }
+}
diff --git a/shared-lib/flowy-grid-data-model/src/revision/grid_sort.rs b/frontend/rust-lib/flowy-grid/src/services/group/impls/date_group.rs
similarity index 100%
rename from shared-lib/flowy-grid-data-model/src/revision/grid_sort.rs
rename to frontend/rust-lib/flowy-grid/src/services/group/impls/date_group.rs
diff --git a/frontend/rust-lib/flowy-grid/src/services/group/impls/mod.rs b/frontend/rust-lib/flowy-grid/src/services/group/impls/mod.rs
new file mode 100644
index 0000000000..37babdb470
--- /dev/null
+++ b/frontend/rust-lib/flowy-grid/src/services/group/impls/mod.rs
@@ -0,0 +1,11 @@
+mod checkbox_group;
+mod date_group;
+mod number_group;
+mod select_option_group;
+mod text_group;
+
+pub use checkbox_group::*;
+pub use date_group::*;
+pub use number_group::*;
+pub use select_option_group::*;
+pub use text_group::*;
diff --git a/frontend/rust-lib/flowy-grid/src/services/group/impls/number_group.rs b/frontend/rust-lib/flowy-grid/src/services/group/impls/number_group.rs
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/frontend/rust-lib/flowy-grid/src/services/group/impls/select_option_group.rs b/frontend/rust-lib/flowy-grid/src/services/group/impls/select_option_group.rs
new file mode 100644
index 0000000000..b9e8f5b53b
--- /dev/null
+++ b/frontend/rust-lib/flowy-grid/src/services/group/impls/select_option_group.rs
@@ -0,0 +1,8 @@
+use crate::entities::SelectOptionGroupConfigurationPB;
+use crate::services::field::SelectedSelectOptions;
+
+impl SelectOptionGroupConfigurationPB {
+    pub fn is_visible(&self, selected_options: &SelectedSelectOptions) -> bool {
+        return true;
+    }
+}
diff --git a/frontend/rust-lib/flowy-grid/src/services/group/impls/text_group.rs b/frontend/rust-lib/flowy-grid/src/services/group/impls/text_group.rs
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/frontend/rust-lib/flowy-grid/src/services/group/impls/url_group.rs b/frontend/rust-lib/flowy-grid/src/services/group/impls/url_group.rs
new file mode 100644
index 0000000000..e69de29bb2
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 9fe58d6fc1..f30f63b452 100644
--- a/frontend/rust-lib/flowy-grid/src/services/group/mod.rs
+++ b/frontend/rust-lib/flowy-grid/src/services/group/mod.rs
@@ -1,3 +1,5 @@
 mod group_service;
+mod impls;
 
 pub(crate) use group_service::*;
+pub(crate) use impls::*;
diff --git a/frontend/rust-lib/flowy-grid/tests/grid/block_test/script.rs b/frontend/rust-lib/flowy-grid/tests/grid/block_test/script.rs
index 900a41c6ed..b25bb044fc 100644
--- a/frontend/rust-lib/flowy-grid/tests/grid/block_test/script.rs
+++ b/frontend/rust-lib/flowy-grid/tests/grid/block_test/script.rs
@@ -170,7 +170,7 @@ impl GridRowTest {
             FieldType::Number => {
                 let field_rev = self.editor.get_field_rev(&cell_id.field_id).await.unwrap();
                 let number_type_option = field_rev
-                    .get_type_option_entry::<NumberTypeOption>(FieldType::Number.into())
+                    .get_type_option_entry::<NumberTypeOptionPB>(FieldType::Number.into())
                     .unwrap();
                 let cell_data = self
                     .editor
diff --git a/frontend/rust-lib/flowy-grid/tests/grid/field_test/util.rs b/frontend/rust-lib/flowy-grid/tests/grid/field_test/util.rs
index bfd8c92f0a..8615d868c2 100644
--- a/frontend/rust-lib/flowy-grid/tests/grid/field_test/util.rs
+++ b/frontend/rust-lib/flowy-grid/tests/grid/field_test/util.rs
@@ -12,7 +12,7 @@ pub fn create_text_field(grid_id: &str) -> (InsertFieldParams, FieldRevision) {
     let cloned_field_rev = field_rev.clone();
 
     let type_option_data = field_rev
-        .get_type_option_entry::<RichTextTypeOption>(field_rev.field_type_rev)
+        .get_type_option_entry::<RichTextTypeOptionPB>(field_rev.field_type_rev)
         .unwrap()
         .protobuf_bytes()
         .to_vec();
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
index 06e7971cf0..7079b52229 100644
--- a/shared-lib/flowy-grid-data-model/src/revision/filter_rev.rs
+++ b/shared-lib/flowy-grid-data-model/src/revision/filter_rev.rs
@@ -1,7 +1,7 @@
 use serde::{Deserialize, Serialize};
 
 #[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq, Hash)]
-pub struct GridFilterRevision {
+pub struct FilterConfigurationRevision {
     pub id: String,
     pub field_id: String,
     pub condition: u8,
diff --git a/shared-lib/flowy-grid-data-model/src/revision/grid_group.rs b/shared-lib/flowy-grid-data-model/src/revision/grid_group.rs
index 268682d552..dae56bd123 100644
--- a/shared-lib/flowy-grid-data-model/src/revision/grid_group.rs
+++ b/shared-lib/flowy-grid-data-model/src/revision/grid_group.rs
@@ -1,8 +1,10 @@
+use crate::revision::FieldTypeRevision;
 use serde::{Deserialize, Serialize};
 
 #[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq)]
-pub struct GridGroupRevision {
+pub struct GroupConfigurationRevision {
     pub id: String,
     pub field_id: String,
-    pub sub_field_id: Option<String>,
+    pub field_type_rev: FieldTypeRevision,
+    pub content: Option<Vec<u8>>,
 }
diff --git a/shared-lib/flowy-grid-data-model/src/revision/grid_rev.rs b/shared-lib/flowy-grid-data-model/src/revision/grid_rev.rs
index 09056f827d..b60baff811 100644
--- a/shared-lib/flowy-grid-data-model/src/revision/grid_rev.rs
+++ b/shared-lib/flowy-grid-data-model/src/revision/grid_rev.rs
@@ -171,6 +171,7 @@ impl FieldRevision {
 
     pub fn get_type_option_entry<T: TypeOptionDataDeserializer>(&self, field_type_rev: FieldTypeRevision) -> Option<T> {
         let id = field_type_rev.to_string();
+        // TODO: cache the deserialized type option
         self.type_options.get(&id).map(|s| T::from_json_str(s))
     }
 
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 277de36d62..6181ca8195 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,5 +1,5 @@
-use crate::revision::filter_rev::GridFilterRevision;
-use crate::revision::grid_group::GridGroupRevision;
+use crate::revision::filter_rev::FilterConfigurationRevision;
+use crate::revision::grid_group::GroupConfigurationRevision;
 use crate::revision::{FieldRevision, FieldTypeRevision};
 use indexmap::IndexMap;
 use nanoid::nanoid;
@@ -21,29 +21,29 @@ pub fn gen_grid_sort_id() -> String {
     nanoid!(6)
 }
 
-pub type GridFilters = SettingContainer<GridFilterRevision>;
-pub type GridFilterRevisionMap = GridObjectRevisionMap<GridFilterRevision>;
-pub type FiltersByFieldId = HashMap<String, Vec<Arc<GridFilterRevision>>>;
+pub type FilterConfigurations = SettingConfiguration<FilterConfigurationRevision>;
+pub type FilterConfigurationRevisionMap = GridObjectRevisionMap<FilterConfigurationRevision>;
+pub type FilterConfigurationsByFieldId = HashMap<String, Vec<Arc<FilterConfigurationRevision>>>;
 //
-pub type GridGroups = SettingContainer<GridGroupRevision>;
-pub type GridGroupRevisionMap = GridObjectRevisionMap<GridGroupRevision>;
-pub type GroupsByFieldId = HashMap<String, Vec<Arc<GridGroupRevision>>>;
+pub type GroupConfigurations = SettingConfiguration<GroupConfigurationRevision>;
+pub type GroupConfigurationRevisionMap = GridObjectRevisionMap<GroupConfigurationRevision>;
+pub type GroupConfigurationsByFieldId = HashMap<String, Vec<Arc<GroupConfigurationRevision>>>;
 //
-pub type GridSorts = SettingContainer<GridSortRevision>;
-pub type GridSortRevisionMap = GridObjectRevisionMap<GridSortRevision>;
-pub type SortsByFieldId = HashMap<String, Vec<Arc<GridSortRevision>>>;
+pub type SortConfigurations = SettingConfiguration<SortConfigurationRevision>;
+pub type SortConfigurationRevisionMap = GridObjectRevisionMap<SortConfigurationRevision>;
+pub type SortConfigurationsByFieldId = HashMap<String, Vec<Arc<SortConfigurationRevision>>>;
 
 #[derive(Debug, Clone, Serialize, Deserialize, Default, Eq, PartialEq)]
 pub struct GridSettingRevision {
     pub layout: GridLayoutRevision,
 
-    pub filters: GridFilters,
+    pub filters: FilterConfigurations,
 
     #[serde(default)]
-    pub groups: GridGroups,
+    pub groups: GroupConfigurations,
 
     #[serde(skip)]
-    pub sorts: GridSorts,
+    pub sorts: SortConfigurations,
 }
 
 #[derive(Debug, PartialEq, Eq, Hash, Clone, Serialize_repr, Deserialize_repr)]
@@ -67,7 +67,7 @@ impl std::default::Default for GridLayoutRevision {
 }
 
 impl GridSettingRevision {
-    pub fn get_all_groups(&self, field_revs: &[Arc<FieldRevision>]) -> Option<GroupsByFieldId> {
+    pub fn get_all_groups(&self, field_revs: &[Arc<FieldRevision>]) -> Option<GroupConfigurationsByFieldId> {
         self.groups.get_all_objects(&self.layout, field_revs)
     }
 
@@ -76,7 +76,7 @@ impl GridSettingRevision {
         layout: &GridLayoutRevision,
         field_id: &str,
         field_type_rev: &FieldTypeRevision,
-    ) -> Option<Vec<Arc<GridGroupRevision>>> {
+    ) -> Option<Vec<Arc<GroupConfigurationRevision>>> {
         self.groups.get_objects(layout, field_id, field_type_rev)
     }
 
@@ -85,7 +85,7 @@ impl GridSettingRevision {
         layout: &GridLayoutRevision,
         field_id: &str,
         field_type: &FieldTypeRevision,
-    ) -> Option<&mut Vec<Arc<GridGroupRevision>>> {
+    ) -> Option<&mut Vec<Arc<GroupConfigurationRevision>>> {
         self.groups.get_mut_objects(layout, field_id, field_type)
     }
 
@@ -94,12 +94,13 @@ impl GridSettingRevision {
         layout: &GridLayoutRevision,
         field_id: &str,
         field_type: &FieldTypeRevision,
-        group_rev: GridGroupRevision,
+        group_rev: GroupConfigurationRevision,
     ) {
+        self.groups.remove_all(layout);
         self.groups.insert_object(layout, field_id, field_type, group_rev);
     }
 
-    pub fn get_all_filters(&self, field_revs: &[Arc<FieldRevision>]) -> Option<FiltersByFieldId> {
+    pub fn get_all_filters(&self, field_revs: &[Arc<FieldRevision>]) -> Option<FilterConfigurationsByFieldId> {
         self.filters.get_all_objects(&self.layout, field_revs)
     }
 
@@ -108,7 +109,7 @@ impl GridSettingRevision {
         layout: &GridLayoutRevision,
         field_id: &str,
         field_type_rev: &FieldTypeRevision,
-    ) -> Option<Vec<Arc<GridFilterRevision>>> {
+    ) -> Option<Vec<Arc<FilterConfigurationRevision>>> {
         self.filters.get_objects(layout, field_id, field_type_rev)
     }
 
@@ -117,7 +118,7 @@ impl GridSettingRevision {
         layout: &GridLayoutRevision,
         field_id: &str,
         field_type: &FieldTypeRevision,
-    ) -> Option<&mut Vec<Arc<GridFilterRevision>>> {
+    ) -> Option<&mut Vec<Arc<FilterConfigurationRevision>>> {
         self.filters.get_mut_objects(layout, field_id, field_type)
     }
 
@@ -126,25 +127,25 @@ impl GridSettingRevision {
         layout: &GridLayoutRevision,
         field_id: &str,
         field_type: &FieldTypeRevision,
-        filter_rev: GridFilterRevision,
+        filter_rev: FilterConfigurationRevision,
     ) {
         self.filters.insert_object(layout, field_id, field_type, filter_rev);
     }
 
-    pub fn get_all_sort(&self) -> Option<SortsByFieldId> {
+    pub fn get_all_sort(&self) -> Option<SortConfigurationsByFieldId> {
         None
     }
 }
 
 #[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq)]
-pub struct GridSortRevision {
+pub struct SortConfigurationRevision {
     pub id: String,
     pub field_id: Option<String>,
 }
 
 #[derive(Debug, Clone, Serialize, Deserialize, Default, Eq, PartialEq)]
 #[serde(transparent)]
-pub struct SettingContainer<T>
+pub struct SettingConfiguration<T>
 where
     T: Debug + Clone + Default + Eq + PartialEq + serde::Serialize + serde::de::DeserializeOwned + 'static,
 {
@@ -157,7 +158,7 @@ where
     inner: IndexMap<GridLayoutRevision, IndexMap<String, GridObjectRevisionMap<T>>>,
 }
 
-impl<T> SettingContainer<T>
+impl<T> SettingConfiguration<T>
 where
     T: Debug + Clone + Default + Eq + PartialEq + serde::Serialize + serde::de::DeserializeOwned + 'static,
 {
@@ -229,6 +230,12 @@ where
             .or_insert_with(Vec::new)
             .push(Arc::new(object))
     }
+
+    pub fn remove_all(&mut self, layout: &GridLayoutRevision) {
+        if let Some(object_rev_map_by_field_id) = self.inner.get_mut(layout) {
+            object_rev_map_by_field_id.clear()
+        }
+    }
 }
 
 #[derive(Debug, Clone, Serialize, Deserialize, Default, Eq, PartialEq)]
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 9736442557..67b58978b5 100644
--- a/shared-lib/flowy-grid-data-model/src/revision/mod.rs
+++ b/shared-lib/flowy-grid-data-model/src/revision/mod.rs
@@ -2,10 +2,8 @@ mod filter_rev;
 mod grid_group;
 mod grid_rev;
 mod grid_setting_rev;
-mod grid_sort;
 
 pub use filter_rev::*;
 pub use grid_group::*;
 pub use grid_rev::*;
 pub use grid_setting_rev::*;
-pub use grid_sort::*;
diff --git a/shared-lib/flowy-grid-data-model/tests/serde_test.rs b/shared-lib/flowy-grid-data-model/tests/serde_test.rs
index 1dff913547..8a630a4651 100644
--- a/shared-lib/flowy-grid-data-model/tests/serde_test.rs
+++ b/shared-lib/flowy-grid-data-model/tests/serde_test.rs
@@ -8,6 +8,6 @@ fn grid_default_serde_test() {
     let json = serde_json::to_string(&grid).unwrap();
     assert_eq!(
         json,
-        r#"{"grid_id":"1","fields":[],"blocks":[],"setting":{"layout":0,"filters":[]}}"#
+        r#"{"grid_id":"1","fields":[],"blocks":[],"setting":{"layout":0,"filters":[],"groups":[]}}"#
     )
 }
diff --git a/shared-lib/flowy-sync/src/client_grid/grid_revision_pad.rs b/shared-lib/flowy-sync/src/client_grid/grid_revision_pad.rs
index 73c32834b1..a762103e57 100644
--- a/shared-lib/flowy-sync/src/client_grid/grid_revision_pad.rs
+++ b/shared-lib/flowy-sync/src/client_grid/grid_revision_pad.rs
@@ -6,9 +6,9 @@ use crate::errors::{internal_error, CollaborateError, CollaborateResult};
 use crate::util::{cal_diff, make_delta_from_revisions};
 use bytes::Bytes;
 use flowy_grid_data_model::revision::{
-    gen_block_id, gen_grid_filter_id, gen_grid_group_id, gen_grid_id, gen_grid_sort_id, FieldRevision,
-    FieldTypeRevision, GridBlockMetaRevision, GridBlockMetaRevisionChangeset, GridFilterRevision, GridGroupRevision,
-    GridLayoutRevision, GridRevision, GridSettingRevision, GridSortRevision,
+    gen_block_id, gen_grid_filter_id, gen_grid_group_id, gen_grid_id, FieldRevision, FieldTypeRevision,
+    FilterConfigurationRevision, GridBlockMetaRevision, GridBlockMetaRevisionChangeset, GridLayoutRevision,
+    GridRevision, GridSettingRevision, GroupConfigurationRevision,
 };
 use lib_infra::util::move_vec_element;
 use lib_ot::core::{OperationTransform, PhantomAttributes, TextDelta, TextDeltaBuilder};
@@ -341,7 +341,7 @@ impl GridRevisionPad {
         })
     }
 
-    pub fn get_grid_setting_rev(&self) -> &GridSettingRevision {
+    pub fn get_setting_rev(&self) -> &GridSettingRevision {
         &self.grid_rev.setting
     }
 
@@ -350,7 +350,7 @@ impl GridRevisionPad {
         &self,
         layout: Option<&GridLayoutRevision>,
         field_ids: Option<Vec<String>>,
-    ) -> Option<Vec<Arc<GridFilterRevision>>> {
+    ) -> Option<Vec<Arc<FilterConfigurationRevision>>> {
         let mut filter_revs = vec![];
         let layout_ty = layout.unwrap_or(&self.grid_rev.setting.layout);
         let field_revs = self.get_field_revs(None).ok()?;
@@ -419,7 +419,7 @@ impl GridRevisionPad {
                     groups.retain(|filter| filter.id != params.group_id);
                 }
             }
-            if let Some(sort) = changeset.insert_sort {
+            if let Some(_sort) = changeset.insert_sort {
                 // let rev = GridSortRevision {
                 //     id: gen_grid_sort_id(),
                 //     field_id: sort.field_id,
@@ -434,7 +434,7 @@ impl GridRevisionPad {
                 is_changed = Some(())
             }
 
-            if let Some(delete_sort_id) = changeset.delete_sort {
+            if let Some(_delete_sort_id) = changeset.delete_sort {
                 // match grid_rev.setting.sorts.get_mut(&layout_rev) {
                 //     Some(sorts) => sorts.retain(|sort| sort.id != delete_sort_id),
                 //     None => {
@@ -559,19 +559,20 @@ impl std::default::Default for GridRevisionPad {
     }
 }
 
-fn make_filter_revision(params: &CreateGridFilterParams) -> GridFilterRevision {
-    GridFilterRevision {
+fn make_filter_revision(params: &CreateGridFilterParams) -> FilterConfigurationRevision {
+    FilterConfigurationRevision {
         id: gen_grid_filter_id(),
         field_id: params.field_id.clone(),
-        condition: params.condition.clone(),
+        condition: params.condition,
         content: params.content.clone(),
     }
 }
 
-fn make_group_revision(params: &CreateGridGroupParams) -> GridGroupRevision {
-    GridGroupRevision {
+fn make_group_revision(params: &CreateGridGroupParams) -> GroupConfigurationRevision {
+    GroupConfigurationRevision {
         id: gen_grid_group_id(),
         field_id: params.field_id.clone(),
-        sub_field_id: params.sub_field_id.clone(),
+        field_type_rev: params.field_type_rev.clone(),
+        content: params.content.clone(),
     }
 }
diff --git a/shared-lib/flowy-sync/src/entities/grid.rs b/shared-lib/flowy-sync/src/entities/grid.rs
index 8b5e9d4629..23c8658839 100644
--- a/shared-lib/flowy-sync/src/entities/grid.rs
+++ b/shared-lib/flowy-sync/src/entities/grid.rs
@@ -31,8 +31,8 @@ pub struct DeleteFilterParams {
 
 pub struct CreateGridGroupParams {
     pub field_id: String,
-    pub sub_field_id: Option<String>,
     pub field_type_rev: FieldTypeRevision,
+    pub content: Option<Vec<u8>>,
 }
 
 pub struct DeleteGroupParams {