Explorar o código

chore: add edit field type option helper

appflowy %!s(int64=2) %!d(string=hai) anos
pai
achega
e75d8f22c8
Modificáronse 27 ficheiros con 158 adicións e 75 borrados
  1. 3 3
      frontend/rust-lib/flowy-grid/src/entities/group_entities/group_changeset.rs
  2. 7 5
      frontend/rust-lib/flowy-grid/src/event_handler.rs
  3. 3 3
      frontend/rust-lib/flowy-grid/src/macros.rs
  4. 7 7
      frontend/rust-lib/flowy-grid/src/services/cell/cell_operation.rs
  5. 3 3
      frontend/rust-lib/flowy-grid/src/services/field/field_builder.rs
  6. 47 0
      frontend/rust-lib/flowy-grid/src/services/field/field_operation.rs
  7. 2 0
      frontend/rust-lib/flowy-grid/src/services/field/mod.rs
  8. 2 2
      frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option/checkbox_type_option.rs
  9. 2 2
      frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/date_type_option.rs
  10. 2 2
      frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option/number_type_option.rs
  11. 2 2
      frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/multi_select_type_option.rs
  12. 2 2
      frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/select_option.rs
  13. 2 2
      frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/single_select_type_option.rs
  14. 2 2
      frontend/rust-lib/flowy-grid/src/services/field/type_options/text_type_option/text_type_option.rs
  15. 2 2
      frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option/url_type_option.rs
  16. 7 7
      frontend/rust-lib/flowy-grid/src/services/filter/filter_service.rs
  17. 8 2
      frontend/rust-lib/flowy-grid/src/services/grid_editor.rs
  18. 14 15
      frontend/rust-lib/flowy-grid/src/services/group/configuration.rs
  19. 2 2
      frontend/rust-lib/flowy-grid/src/services/group/controller.rs
  20. 1 1
      frontend/rust-lib/flowy-grid/tests/grid/block_test/script.rs
  21. 2 2
      frontend/rust-lib/flowy-grid/tests/grid/field_test/test.rs
  22. 2 2
      frontend/rust-lib/flowy-grid/tests/grid/field_test/util.rs
  23. 1 1
      frontend/rust-lib/flowy-grid/tests/grid/grid_test.rs
  24. 23 0
      frontend/rust-lib/flowy-grid/tests/grid/group_test/script.rs
  25. 1 1
      frontend/rust-lib/flowy-grid/tests/grid/script.rs
  26. 5 5
      shared-lib/flowy-grid-data-model/src/revision/grid_rev.rs
  27. 4 0
      shared-lib/flowy-grid-data-model/src/revision/group_rev.rs

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

@@ -133,13 +133,13 @@ pub struct GroupViewChangesetPB {
     #[pb(index = 2)]
     pub inserted_groups: Vec<InsertedGroupPB>,
 
-    #[pb(index = 2)]
+    #[pb(index = 3)]
     pub new_groups: Vec<GroupPB>,
 
-    #[pb(index = 3)]
+    #[pb(index = 4)]
     pub deleted_groups: Vec<String>,
 
-    #[pb(index = 4)]
+    #[pb(index = 5)]
     pub update_groups: Vec<GroupPB>,
 }
 

+ 7 - 5
frontend/rust-lib/flowy-grid/src/event_handler.rs

@@ -203,12 +203,14 @@ pub(crate) async fn move_field_handler(
 
 /// The FieldMeta contains multiple data, each of them belongs to a specific FieldType.
 async fn get_type_option_data(field_rev: &FieldRevision, field_type: &FieldType) -> FlowyResult<Vec<u8>> {
-    let s = field_rev
-        .get_type_option_str(field_type)
-        .unwrap_or_else(|| default_type_option_builder_from_type(field_type).entry().json_str());
+    let s = field_rev.get_type_option_str(field_type).unwrap_or_else(|| {
+        default_type_option_builder_from_type(field_type)
+            .data_format()
+            .json_str()
+    });
     let field_type: FieldType = field_rev.ty.into();
     let builder = type_option_builder_from_json_str(&s, &field_type);
-    let type_option_data = builder.entry().protobuf_bytes().to_vec();
+    let type_option_data = builder.data_format().protobuf_bytes().to_vec();
 
     Ok(type_option_data)
 }
@@ -337,7 +339,7 @@ pub(crate) async fn update_select_option_handler(
             type_option.delete_option(option);
         }
 
-        mut_field_rev.insert_type_option_entry(&*type_option);
+        mut_field_rev.insert_type_option(&*type_option);
         let _ = editor.replace_field(field_rev).await?;
 
         if let Some(cell_content_changeset) = cell_content_changeset {

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

@@ -30,7 +30,7 @@ macro_rules! impl_type_option {
     ($target: ident, $field_type:expr) => {
         impl std::convert::From<&FieldRevision> for $target {
             fn from(field_rev: &FieldRevision) -> $target {
-                match field_rev.get_type_option_entry::<$target>($field_type.into()) {
+                match field_rev.get_type_option::<$target>($field_type.into()) {
                     None => $target::default(),
                     Some(target) => target,
                 }
@@ -39,7 +39,7 @@ macro_rules! impl_type_option {
 
         impl std::convert::From<&std::sync::Arc<FieldRevision>> for $target {
             fn from(field_rev: &std::sync::Arc<FieldRevision>) -> $target {
-                match field_rev.get_type_option_entry::<$target>($field_type.into()) {
+                match field_rev.get_type_option::<$target>($field_type.into()) {
                     None => $target::default(),
                     Some(target) => target,
                 }
@@ -52,7 +52,7 @@ macro_rules! impl_type_option {
             }
         }
 
-        impl TypeOptionDataEntry for $target {
+        impl TypeOptionDataFormat for $target {
             fn json_str(&self) -> String {
                 match serde_json::to_string(&self) {
                     Ok(s) => s,

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

@@ -101,25 +101,25 @@ 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::<RichTextTypeOptionPB>(field_type)?
+                .get_type_option::<RichTextTypeOptionPB>(field_type)?
                 .decode_cell_data(cell_data.into(), s_field_type, field_rev),
             FieldType::Number => field_rev
-                .get_type_option_entry::<NumberTypeOptionPB>(field_type)?
+                .get_type_option::<NumberTypeOptionPB>(field_type)?
                 .decode_cell_data(cell_data.into(), s_field_type, field_rev),
             FieldType::DateTime => field_rev
-                .get_type_option_entry::<DateTypeOptionPB>(field_type)?
+                .get_type_option::<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)?
+                .get_type_option::<SingleSelectTypeOptionPB>(field_type)?
                 .decode_cell_data(cell_data.into(), s_field_type, field_rev),
             FieldType::MultiSelect => field_rev
-                .get_type_option_entry::<MultiSelectTypeOptionPB>(field_type)?
+                .get_type_option::<MultiSelectTypeOptionPB>(field_type)?
                 .decode_cell_data(cell_data.into(), s_field_type, field_rev),
             FieldType::Checkbox => field_rev
-                .get_type_option_entry::<CheckboxTypeOptionPB>(field_type)?
+                .get_type_option::<CheckboxTypeOptionPB>(field_type)?
                 .decode_cell_data(cell_data.into(), s_field_type, field_rev),
             FieldType::URL => field_rev
-                .get_type_option_entry::<URLTypeOptionPB>(field_type)?
+                .get_type_option::<URLTypeOptionPB>(field_type)?
                 .decode_cell_data(cell_data.into(), s_field_type, field_rev),
         };
         Some(data)

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

@@ -1,7 +1,7 @@
 use crate::entities::{FieldPB, FieldType};
 use crate::services::field::type_options::*;
 use bytes::Bytes;
-use flowy_grid_data_model::revision::{FieldRevision, TypeOptionDataEntry};
+use flowy_grid_data_model::revision::{FieldRevision, TypeOptionDataFormat};
 use indexmap::IndexMap;
 
 pub struct FieldBuilder {
@@ -78,14 +78,14 @@ impl FieldBuilder {
 
     pub fn build(self) -> FieldRevision {
         let mut field_rev = self.field_rev;
-        field_rev.insert_type_option_entry(self.type_option_builder.entry());
+        field_rev.insert_type_option(self.type_option_builder.data_format());
         field_rev
     }
 }
 
 pub trait TypeOptionBuilder {
     fn field_type(&self) -> FieldType;
-    fn entry(&self) -> &dyn TypeOptionDataEntry;
+    fn data_format(&self) -> &dyn TypeOptionDataFormat;
 }
 
 pub fn default_type_option_builder_from_type(field_type: &FieldType) -> Box<dyn TypeOptionBuilder> {

+ 47 - 0
frontend/rust-lib/flowy-grid/src/services/field/field_operation.rs

@@ -0,0 +1,47 @@
+use crate::entities::{FieldChangesetParams, FieldType};
+use crate::services::field::{select_option_operation, SelectOptionPB};
+use crate::services::grid_editor::GridRevisionEditor;
+use flowy_error::FlowyResult;
+use flowy_grid_data_model::revision::{FieldRevision, TypeOptionDataDeserializer, TypeOptionDataFormat};
+use std::sync::Arc;
+
+pub async fn edit_field<T>(
+    field_id: &str,
+    editor: Arc<GridRevisionEditor>,
+    action: impl FnOnce(&mut T) -> bool,
+) -> FlowyResult<()>
+where
+    T: TypeOptionDataDeserializer + TypeOptionDataFormat,
+{
+    let get_type_option = async {
+        let field_rev = editor.get_field_rev(field_id).await?;
+        field_rev.get_type_option::<T>(field_rev.ty)
+    };
+
+    if let Some(mut type_option) = get_type_option.await {
+        if action(&mut type_option) {
+            let changeset = FieldChangesetParams { ..Default::default() };
+            let _ = editor.update_field(changeset).await?;
+        }
+    }
+
+    Ok(())
+}
+
+pub fn insert_single_select_option(field_rev: &mut FieldRevision, options: Vec<SelectOptionPB>) -> FlowyResult<()> {
+    if options.is_empty() {
+        return Ok(());
+    }
+    let mut type_option = select_option_operation(field_rev)?;
+    options.into_iter().for_each(|option| type_option.insert_option(option));
+    Ok(())
+}
+
+pub fn insert_multi_select_option(field_rev: &mut FieldRevision, options: Vec<SelectOptionPB>) -> FlowyResult<()> {
+    if options.is_empty() {
+        return Ok(());
+    }
+    let mut type_option = select_option_operation(field_rev)?;
+    options.into_iter().for_each(|option| type_option.insert_option(option));
+    Ok(())
+}

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

@@ -1,5 +1,7 @@
 mod field_builder;
+mod field_operation;
 pub(crate) mod type_options;
 
 pub use field_builder::*;
+pub use field_operation::*;
 pub use type_options::*;

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

@@ -5,7 +5,7 @@ use crate::services::field::{BoxTypeOptionBuilder, CheckboxCellData, TypeOptionB
 use bytes::Bytes;
 use flowy_derive::ProtoBuf;
 use flowy_error::{FlowyError, FlowyResult};
-use flowy_grid_data_model::revision::{CellRevision, FieldRevision, TypeOptionDataDeserializer, TypeOptionDataEntry};
+use flowy_grid_data_model::revision::{CellRevision, FieldRevision, TypeOptionDataDeserializer, TypeOptionDataFormat};
 use serde::{Deserialize, Serialize};
 use std::str::FromStr;
 
@@ -26,7 +26,7 @@ impl TypeOptionBuilder for CheckboxTypeOptionBuilder {
         FieldType::Checkbox
     }
 
-    fn entry(&self) -> &dyn TypeOptionDataEntry {
+    fn data_format(&self) -> &dyn TypeOptionDataFormat {
         &self.0
     }
 }

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

@@ -9,7 +9,7 @@ use chrono::format::strftime::StrftimeItems;
 use chrono::{NaiveDateTime, Timelike};
 use flowy_derive::ProtoBuf;
 use flowy_error::{ErrorCode, FlowyError, FlowyResult};
-use flowy_grid_data_model::revision::{CellRevision, FieldRevision, TypeOptionDataDeserializer, TypeOptionDataEntry};
+use flowy_grid_data_model::revision::{CellRevision, FieldRevision, TypeOptionDataDeserializer, TypeOptionDataFormat};
 use serde::{Deserialize, Serialize};
 
 // Date
@@ -189,7 +189,7 @@ impl TypeOptionBuilder for DateTypeOptionBuilder {
         FieldType::DateTime
     }
 
-    fn entry(&self) -> &dyn TypeOptionDataEntry {
+    fn data_format(&self) -> &dyn TypeOptionDataFormat {
         &self.0
     }
 }

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

@@ -6,7 +6,7 @@ use crate::services::field::{BoxTypeOptionBuilder, NumberCellData, TypeOptionBui
 use bytes::Bytes;
 use flowy_derive::ProtoBuf;
 use flowy_error::{FlowyError, FlowyResult};
-use flowy_grid_data_model::revision::{CellRevision, FieldRevision, TypeOptionDataDeserializer, TypeOptionDataEntry};
+use flowy_grid_data_model::revision::{CellRevision, FieldRevision, TypeOptionDataDeserializer, TypeOptionDataFormat};
 
 use rust_decimal::Decimal;
 
@@ -45,7 +45,7 @@ impl TypeOptionBuilder for NumberTypeOptionBuilder {
         FieldType::Number
     }
 
-    fn entry(&self) -> &dyn TypeOptionDataEntry {
+    fn data_format(&self) -> &dyn TypeOptionDataFormat {
         &self.0
     }
 }

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

@@ -9,7 +9,7 @@ use crate::services::field::{
 use bytes::Bytes;
 use flowy_derive::ProtoBuf;
 use flowy_error::{FlowyError, FlowyResult};
-use flowy_grid_data_model::revision::{CellRevision, FieldRevision, TypeOptionDataDeserializer, TypeOptionDataEntry};
+use flowy_grid_data_model::revision::{CellRevision, FieldRevision, TypeOptionDataDeserializer, TypeOptionDataFormat};
 use serde::{Deserialize, Serialize};
 
 // Multiple select
@@ -108,7 +108,7 @@ impl TypeOptionBuilder for MultiSelectTypeOptionBuilder {
         FieldType::MultiSelect
     }
 
-    fn entry(&self) -> &dyn TypeOptionDataEntry {
+    fn data_format(&self) -> &dyn TypeOptionDataFormat {
         &self.0
     }
 }

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

@@ -5,7 +5,7 @@ use bytes::Bytes;
 use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
 use flowy_error::{internal_error, ErrorCode, FlowyResult};
 use flowy_grid_data_model::parser::NotEmptyStr;
-use flowy_grid_data_model::revision::{FieldRevision, TypeOptionDataEntry};
+use flowy_grid_data_model::revision::{FieldRevision, TypeOptionDataFormat};
 use nanoid::nanoid;
 use serde::{Deserialize, Serialize};
 
@@ -75,7 +75,7 @@ pub fn make_selected_select_options(
     }
 }
 
-pub trait SelectOptionOperation: TypeOptionDataEntry + Send + Sync {
+pub trait SelectOptionOperation: TypeOptionDataFormat + Send + Sync {
     fn insert_option(&mut self, new_option: SelectOptionPB) {
         let options = self.mut_options();
         if let Some(index) = options

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

@@ -9,7 +9,7 @@ use crate::services::field::{BoxTypeOptionBuilder, TypeOptionBuilder};
 use bytes::Bytes;
 use flowy_derive::ProtoBuf;
 use flowy_error::{FlowyError, FlowyResult};
-use flowy_grid_data_model::revision::{CellRevision, FieldRevision, TypeOptionDataDeserializer, TypeOptionDataEntry};
+use flowy_grid_data_model::revision::{CellRevision, FieldRevision, TypeOptionDataDeserializer, TypeOptionDataFormat};
 use serde::{Deserialize, Serialize};
 
 // Single select
@@ -91,7 +91,7 @@ impl TypeOptionBuilder for SingleSelectTypeOptionBuilder {
         FieldType::SingleSelect
     }
 
-    fn entry(&self) -> &dyn TypeOptionDataEntry {
+    fn data_format(&self) -> &dyn TypeOptionDataFormat {
         &self.0
     }
 }

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

@@ -8,7 +8,7 @@ use crate::services::field::{BoxTypeOptionBuilder, TypeOptionBuilder};
 use bytes::Bytes;
 use flowy_derive::ProtoBuf;
 use flowy_error::{FlowyError, FlowyResult};
-use flowy_grid_data_model::revision::{CellRevision, FieldRevision, TypeOptionDataDeserializer, TypeOptionDataEntry};
+use flowy_grid_data_model::revision::{CellRevision, FieldRevision, TypeOptionDataDeserializer, TypeOptionDataFormat};
 use serde::{Deserialize, Serialize};
 
 #[derive(Default)]
@@ -21,7 +21,7 @@ impl TypeOptionBuilder for RichTextTypeOptionBuilder {
         FieldType::RichText
     }
 
-    fn entry(&self) -> &dyn TypeOptionDataEntry {
+    fn data_format(&self) -> &dyn TypeOptionDataFormat {
         &self.0
     }
 }

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

@@ -6,7 +6,7 @@ use bytes::Bytes;
 use fancy_regex::Regex;
 use flowy_derive::ProtoBuf;
 use flowy_error::{FlowyError, FlowyResult};
-use flowy_grid_data_model::revision::{CellRevision, FieldRevision, TypeOptionDataDeserializer, TypeOptionDataEntry};
+use flowy_grid_data_model::revision::{CellRevision, FieldRevision, TypeOptionDataDeserializer, TypeOptionDataFormat};
 use lazy_static::lazy_static;
 use serde::{Deserialize, Serialize};
 
@@ -20,7 +20,7 @@ impl TypeOptionBuilder for URLTypeOptionBuilder {
         FieldType::URL
     }
 
-    fn entry(&self) -> &dyn TypeOptionDataEntry {
+    fn data_format(&self) -> &dyn TypeOptionDataFormat {
         &self.0
     }
 }

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

@@ -188,7 +188,7 @@ fn filter_cell(
         FieldType::RichText => filter_cache.text_filter.get(&filter_id).and_then(|filter| {
             Some(
                 field_rev
-                    .get_type_option_entry::<RichTextTypeOptionPB>(field_type_rev)?
+                    .get_type_option::<RichTextTypeOptionPB>(field_type_rev)?
                     .apply_filter(any_cell_data, filter.value())
                     .ok(),
             )
@@ -196,7 +196,7 @@ fn filter_cell(
         FieldType::Number => filter_cache.number_filter.get(&filter_id).and_then(|filter| {
             Some(
                 field_rev
-                    .get_type_option_entry::<NumberTypeOptionPB>(field_type_rev)?
+                    .get_type_option::<NumberTypeOptionPB>(field_type_rev)?
                     .apply_filter(any_cell_data, filter.value())
                     .ok(),
             )
@@ -204,7 +204,7 @@ fn filter_cell(
         FieldType::DateTime => filter_cache.date_filter.get(&filter_id).and_then(|filter| {
             Some(
                 field_rev
-                    .get_type_option_entry::<DateTypeOptionPB>(field_type_rev)?
+                    .get_type_option::<DateTypeOptionPB>(field_type_rev)?
                     .apply_filter(any_cell_data, filter.value())
                     .ok(),
             )
@@ -212,7 +212,7 @@ fn filter_cell(
         FieldType::SingleSelect => filter_cache.select_option_filter.get(&filter_id).and_then(|filter| {
             Some(
                 field_rev
-                    .get_type_option_entry::<SingleSelectTypeOptionPB>(field_type_rev)?
+                    .get_type_option::<SingleSelectTypeOptionPB>(field_type_rev)?
                     .apply_filter(any_cell_data, filter.value())
                     .ok(),
             )
@@ -220,7 +220,7 @@ fn filter_cell(
         FieldType::MultiSelect => filter_cache.select_option_filter.get(&filter_id).and_then(|filter| {
             Some(
                 field_rev
-                    .get_type_option_entry::<MultiSelectTypeOptionPB>(field_type_rev)?
+                    .get_type_option::<MultiSelectTypeOptionPB>(field_type_rev)?
                     .apply_filter(any_cell_data, filter.value())
                     .ok(),
             )
@@ -228,7 +228,7 @@ fn filter_cell(
         FieldType::Checkbox => filter_cache.checkbox_filter.get(&filter_id).and_then(|filter| {
             Some(
                 field_rev
-                    .get_type_option_entry::<CheckboxTypeOptionPB>(field_type_rev)?
+                    .get_type_option::<CheckboxTypeOptionPB>(field_type_rev)?
                     .apply_filter(any_cell_data, filter.value())
                     .ok(),
             )
@@ -236,7 +236,7 @@ fn filter_cell(
         FieldType::URL => filter_cache.url_filter.get(&filter_id).and_then(|filter| {
             Some(
                 field_rev
-                    .get_type_option_entry::<URLTypeOptionPB>(field_type_rev)?
+                    .get_type_option::<URLTypeOptionPB>(field_type_rev)?
                     .apply_filter(any_cell_data, filter.value())
                     .ok(),
             )

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

@@ -179,6 +179,10 @@ impl GridRevisionEditor {
             None => Err(ErrorCode::FieldDoesNotExist.into()),
             Some(field_type) => {
                 let _ = self.update_field_rev(params, field_type).await?;
+                match self.view_manager.did_update_field(&field_id).await {
+                    Ok(_) => {}
+                    Err(e) => tracing::error!("View manager update field failed: {:?}", e),
+                }
                 let _ = self.notify_did_update_grid_field(&field_id).await?;
                 Ok(())
             }
@@ -225,7 +229,9 @@ impl GridRevisionEditor {
 
         let type_option_json_builder = |field_type: &FieldTypeRevision| -> String {
             let field_type: FieldType = field_type.into();
-            return default_type_option_builder_from_type(&field_type).entry().json_str();
+            return default_type_option_builder_from_type(&field_type)
+                .data_format()
+                .json_str();
         };
 
         let _ = self
@@ -828,7 +834,7 @@ impl JsonDeserializer for TypeOptionJsonDeserializer {
     fn deserialize(&self, type_option_data: Vec<u8>) -> CollaborateResult<String> {
         // The type_option_data sent from Dart is serialized by protobuf.
         let builder = type_option_builder_from_bytes(type_option_data, &self.0);
-        let json = builder.entry().json_str();
+        let json = builder.data_format().json_str();
         tracing::trace!("Deserialize type option data to: {}", json);
         Ok(json)
     }

+ 14 - 15
frontend/rust-lib/flowy-grid/src/services/group/configuration.rs

@@ -152,7 +152,7 @@ where
         } = merge_groups(&self.configuration.groups, new_groups);
 
         let deleted_group_ids = deleted_group_revs
-            .iter()
+            .into_iter()
             .map(|group_rev| group_rev.id)
             .collect::<Vec<String>>();
 
@@ -165,7 +165,7 @@ where
                 is_changed = true;
             }
 
-            for mut group_rev in &mut all_group_revs {
+            for group_rev in &mut all_group_revs {
                 match configuration
                     .groups
                     .iter()
@@ -177,8 +177,7 @@ where
                     }
                     Some(pos) => {
                         let mut old_group = configuration.groups.remove(pos);
-                        // Update the group configuration base on the GroupRevision
-                        group_rev.visible = old_group.visible;
+                        group_rev.update_with_other(&old_group);
 
                         // Take the GroupRevision if the name has changed
                         if is_group_changed(&group_rev, &old_group) {
@@ -192,6 +191,7 @@ where
             is_changed
         })?;
 
+        // The len of the filter_content_map should equal to the len of the all_group_revs
         debug_assert_eq!(filter_content_map.len(), all_group_revs.len());
         all_group_revs.into_iter().for_each(|group_rev| {
             if let Some(filter_content) = filter_content_map.get(&group_rev.id) {
@@ -207,21 +207,20 @@ where
 
         let new_groups = new_group_revs
             .into_iter()
-            .map(|group_rev| {
-                if let Some(filter_content) = filter_content_map.get(&group_rev.id) {
-                    let group = Group::new(
-                        group_rev.id,
-                        self.field_rev.id.clone(),
-                        group_rev.name,
-                        filter_content.clone(),
-                    );
-                    GroupPB::from(group)
-                }
+            .flat_map(|group_rev| {
+                let filter_content = filter_content_map.get(&group_rev.id)?;
+                let group = Group::new(
+                    group_rev.id,
+                    self.field_rev.id.clone(),
+                    group_rev.name,
+                    filter_content.clone(),
+                );
+                Some(GroupPB::from(group))
             })
             .collect();
 
         let changeset = GroupViewChangesetPB {
-            view_id,
+            view_id: self.view_id.clone(),
             new_groups,
             deleted_groups: deleted_group_ids,
             update_groups: vec![],

+ 2 - 2
frontend/rust-lib/flowy-grid/src/services/group/controller.rs

@@ -87,7 +87,7 @@ where
 {
     pub async fn new(field_rev: &Arc<FieldRevision>, mut configuration: GroupContext<C>) -> FlowyResult<Self> {
         let field_type_rev = field_rev.ty;
-        let type_option = field_rev.get_type_option_entry::<T>(field_type_rev);
+        let type_option = field_rev.get_type_option::<T>(field_type_rev);
         let groups = G::generate_groups(&field_rev.id, &configuration, &type_option);
         let _ = configuration.init_group_revs(groups)?;
 
@@ -274,7 +274,7 @@ where
 
     fn did_update_field(&mut self, field_rev: &FieldRevision) -> FlowyResult<Option<GroupViewChangesetPB>> {
         let field_type_rev = field_rev.ty;
-        let type_option = field_rev.get_type_option_entry::<T>(field_type_rev);
+        let type_option = field_rev.get_type_option::<T>(field_type_rev);
         let groups = G::generate_groups(&field_rev.id, &self.configuration, &type_option);
         let changeset = self.configuration.init_group_revs(groups)?;
         Ok(changeset)

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

@@ -176,7 +176,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::<NumberTypeOptionPB>(FieldType::Number.into())
+                    .get_type_option::<NumberTypeOptionPB>(FieldType::Number.into())
                     .unwrap();
                 let cell_data = self
                     .editor

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

@@ -4,7 +4,7 @@ use crate::grid::field_test::util::*;
 use flowy_grid::entities::FieldChangesetParams;
 use flowy_grid::services::field::selection_type_option::SelectOptionPB;
 use flowy_grid::services::field::SingleSelectTypeOptionPB;
-use flowy_grid_data_model::revision::TypeOptionDataEntry;
+use flowy_grid_data_model::revision::TypeOptionDataFormat;
 
 #[tokio::test]
 async fn grid_create_field() {
@@ -86,7 +86,7 @@ async fn grid_update_field() {
     let mut expected_field_rev = single_select_field.clone();
     expected_field_rev.frozen = true;
     expected_field_rev.width = 1000;
-    expected_field_rev.insert_type_option_entry(&single_select_type_option);
+    expected_field_rev.insert_type_option(&single_select_type_option);
 
     let scripts = vec![
         CreateField { params },

+ 2 - 2
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::<RichTextTypeOptionPB>(field_rev.ty)
+        .get_type_option::<RichTextTypeOptionPB>(field_rev.ty)
         .unwrap()
         .protobuf_bytes()
         .to_vec();
@@ -45,7 +45,7 @@ pub fn create_single_select_field(grid_id: &str) -> (InsertFieldParams, FieldRev
     let field_rev = FieldBuilder::new(single_select).name("Name").visibility(true).build();
     let cloned_field_rev = field_rev.clone();
     let type_option_data = field_rev
-        .get_type_option_entry::<SingleSelectTypeOptionPB>(field_rev.ty)
+        .get_type_option::<SingleSelectTypeOptionPB>(field_rev.ty)
         .unwrap()
         .protobuf_bytes()
         .to_vec();

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

@@ -8,7 +8,7 @@ use flowy_grid::services::field::{
 use flowy_grid::services::row::{decode_cell_data_from_type_option_cell_data, CreateRowMetaBuilder};
 use flowy_grid_data_model::entities::{
     CellChangeset, FieldChangesetParams, FieldType, GridBlockInfoChangeset, GridBlockMetaSnapshot, RowMetaChangeset,
-    TypeOptionDataEntry,
+    TypeOptionDataFormat,
 };
 
 #[tokio::test]

+ 23 - 0
frontend/rust-lib/flowy-grid/tests/grid/group_test/script.rs

@@ -3,6 +3,7 @@ use flowy_grid::entities::{
     CreateRowParams, FieldChangesetParams, FieldType, GridLayout, GroupPB, MoveGroupParams, MoveGroupRowParams, RowPB,
 };
 use flowy_grid::services::cell::{delete_select_option_cell, insert_select_option_cell};
+use flowy_grid::services::field::{select_option_operation, SelectOptionOperation};
 use flowy_grid_data_model::revision::{FieldRevision, RowChangeset};
 use std::sync::Arc;
 use std::time::Duration;
@@ -212,6 +213,28 @@ impl GridGroupTest {
             .clone();
         return field;
     }
+
+    pub async fn get_single_select_field(&self) -> Arc<FieldRevision> {
+        self.inner
+            .field_revs
+            .iter()
+            .find(|field_rev| {
+                let field_type: FieldType = field_rev.ty.into();
+                field_type.is_single_select()
+            })
+            .unwrap()
+            .clone()
+    }
+
+    pub async fn edit_single_select_type_option(&self, f: impl FnOnce(Box<dyn SelectOptionOperation>)) {
+        let single_select = self.get_single_select_field().await;
+        let mut field_rev = self.editor.get_field_rev(&single_select.id).await.unwrap();
+        let mut_field_rev = Arc::make_mut(&mut field_rev);
+        let mut type_option = select_option_operation(mut_field_rev)?;
+        f(type_option);
+        mut_field_rev.insert_type_option(&*type_option);
+        let _ = self.editor.replace_field(field_rev).await?;
+    }
 }
 
 impl std::ops::Deref for GridGroupTest {

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

@@ -5,7 +5,7 @@ use flowy_grid::services::row::CreateRowMetaPayload;
 use flowy_grid_data_model::entities::{
     BuildGridContext, CellChangeset, Field, FieldChangesetParams, FieldMeta, FieldOrder, FieldType,
     GridBlockInfoChangeset, GridBlockMetaSnapshot, InsertFieldParams, RowMeta, RowMetaChangeset, RowOrder,
-    TypeOptionDataEntry,
+    TypeOptionDataFormat,
 };
 use flowy_revision::REVISION_WRITE_INTERVAL_IN_MILLIS;
 use flowy_sync::client_grid::GridBuilder;

+ 5 - 5
shared-lib/flowy-grid-data-model/src/revision/grid_rev.rs

@@ -143,15 +143,15 @@ impl FieldRevision {
         }
     }
 
-    pub fn insert_type_option_entry<T>(&mut self, entry: &T)
+    pub fn insert_type_option<T>(&mut self, type_option: &T)
     where
-        T: TypeOptionDataEntry + ?Sized,
+        T: TypeOptionDataFormat + ?Sized,
     {
         let id = self.ty.to_string();
-        self.type_options.insert(id, entry.json_str());
+        self.type_options.insert(id, type_option.json_str());
     }
 
-    pub fn get_type_option_entry<T: TypeOptionDataDeserializer>(&self, field_type_rev: FieldTypeRevision) -> Option<T> {
+    pub fn get_type_option<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))
@@ -171,7 +171,7 @@ impl FieldRevision {
 
 /// The macro [impl_type_option] will implement the [TypeOptionDataEntry] for the type that
 /// supports the serde trait and the TryInto<Bytes> trait.
-pub trait TypeOptionDataEntry {
+pub trait TypeOptionDataFormat {
     fn json_str(&self) -> String;
     fn protobuf_bytes(&self) -> Bytes;
 }

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

@@ -135,6 +135,10 @@ impl GroupRevision {
             visible: true,
         }
     }
+
+    pub fn update_with_other(&mut self, other: &GroupRevision) {
+        self.visible = other.visible
+    }
 }
 
 #[derive(Default, Serialize, Deserialize)]