Selaa lähdekoodia

Merge pull request #1260 from AppFlowy-IO/refactor/switch_to_field

Nathan.fooo 2 vuotta sitten
vanhempi
commit
a20e92f08a
20 muutettua tiedostoa jossa 230 lisäystä ja 339 poistoa
  1. 0 19
      frontend/app_flowy/lib/plugins/grid/application/field/field_service.dart
  2. 1 1
      frontend/app_flowy/lib/plugins/grid/application/field/type_option/type_option_context.dart
  3. 16 39
      frontend/app_flowy/lib/plugins/grid/application/field/type_option/type_option_data_controller.dart
  4. 6 44
      frontend/rust-lib/flowy-grid/src/entities/field_entities.rs
  5. 55 52
      frontend/rust-lib/flowy-grid/src/event_handler.rs
  6. 1 7
      frontend/rust-lib/flowy-grid/src/event_map.rs
  7. 4 47
      frontend/rust-lib/flowy-grid/src/services/field/field_builder.rs
  8. 2 0
      frontend/rust-lib/flowy-grid/src/services/field/mod.rs
  9. 48 0
      frontend/rust-lib/flowy-grid/src/services/field/type_option_builder.rs
  10. 29 48
      frontend/rust-lib/flowy-grid/src/services/grid_editor.rs
  11. 2 9
      frontend/rust-lib/flowy-grid/src/services/grid_view_editor.rs
  12. 1 2
      frontend/rust-lib/flowy-grid/src/services/grid_view_manager.rs
  13. 1 1
      frontend/rust-lib/flowy-grid/src/services/group/configuration.rs
  14. 2 5
      frontend/rust-lib/flowy-grid/src/services/group/controller.rs
  15. 16 11
      frontend/rust-lib/flowy-grid/tests/grid/field_test/script.rs
  16. 30 18
      frontend/rust-lib/flowy-grid/tests/grid/field_test/test.rs
  17. 14 32
      frontend/rust-lib/flowy-grid/tests/grid/field_test/util.rs
  18. 0 1
      shared-lib/flowy-grid-data-model/src/revision/grid_rev.rs
  19. 1 1
      shared-lib/flowy-sync/src/client_folder/folder_pad.rs
  20. 1 2
      shared-lib/lib-ot/src/text_delta/delta.rs

+ 0 - 19
frontend/app_flowy/lib/plugins/grid/application/field/field_service.dart

@@ -67,25 +67,6 @@ class FieldService {
     return GridEventUpdateField(payload).send();
     return GridEventUpdateField(payload).send();
   }
   }
 
 
-  // Create the field if it does not exist. Otherwise, update the field.
-  static Future<Either<Unit, FlowyError>> insertField({
-    required String gridId,
-    required FieldPB field,
-    List<int>? typeOptionData,
-    String? startFieldId,
-  }) {
-    var payload = InsertFieldPayloadPB.create()
-      ..gridId = gridId
-      ..field_2 = field
-      ..typeOptionData = typeOptionData ?? [];
-
-    if (startFieldId != null) {
-      payload.startFieldId = startFieldId;
-    }
-
-    return GridEventInsertField(payload).send();
-  }
-
   static Future<Either<Unit, FlowyError>> updateFieldTypeOption({
   static Future<Either<Unit, FlowyError>> updateFieldTypeOption({
     required String gridId,
     required String gridId,
     required String fieldId,
     required String fieldId,

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

@@ -145,7 +145,7 @@ abstract class IFieldTypeOptionLoader {
   String get gridId;
   String get gridId;
   Future<Either<FieldTypeOptionDataPB, FlowyError>> load();
   Future<Either<FieldTypeOptionDataPB, FlowyError>> load();
 
 
-  Future<Either<FieldTypeOptionDataPB, FlowyError>> switchToField(
+  Future<Either<Unit, FlowyError>> switchToField(
       String fieldId, FieldType fieldType) {
       String fieldId, FieldType fieldType) {
     final payload = EditFieldPayloadPB.create()
     final payload = EditFieldPayloadPB.create()
       ..gridId = gridId
       ..gridId = gridId

+ 16 - 39
frontend/app_flowy/lib/plugins/grid/application/field/type_option/type_option_data_controller.dart

@@ -47,64 +47,41 @@ class TypeOptionDataController {
     return _data.field_2;
     return _data.field_2;
   }
   }
 
 
-  set field(FieldPB field) {
-    _updateData(newField: field);
-  }
-
   T getTypeOption<T>(TypeOptionDataParser<T> parser) {
   T getTypeOption<T>(TypeOptionDataParser<T> parser) {
     return parser.fromBuffer(_data.typeOptionData);
     return parser.fromBuffer(_data.typeOptionData);
   }
   }
 
 
   set fieldName(String name) {
   set fieldName(String name) {
-    _updateData(newName: name);
-  }
+    _data = _data.rebuild((rebuildData) {
+      rebuildData.field_2 = rebuildData.field_2.rebuild((rebuildField) {
+        rebuildField.name = name;
+      });
+    });
 
 
-  set typeOptionData(List<int> typeOptionData) {
-    _updateData(newTypeOptionData: typeOptionData);
+    _fieldNotifier.value = _data.field_2;
+
+    FieldService(gridId: gridId, fieldId: field.id).updateField(name: name);
   }
   }
 
 
-  void _updateData({
-    String? newName,
-    FieldPB? newField,
-    List<int>? newTypeOptionData,
-  }) {
+  set typeOptionData(List<int> typeOptionData) {
     _data = _data.rebuild((rebuildData) {
     _data = _data.rebuild((rebuildData) {
-      if (newName != null) {
-        rebuildData.field_2 = rebuildData.field_2.rebuild((rebuildField) {
-          rebuildField.name = newName;
-        });
-      }
-
-      if (newField != null) {
-        rebuildData.field_2 = newField;
-      }
-
-      if (newTypeOptionData != null) {
-        rebuildData.typeOptionData = newTypeOptionData;
+      if (typeOptionData.isNotEmpty) {
+        rebuildData.typeOptionData = typeOptionData;
       }
       }
     });
     });
 
 
-    _fieldNotifier.value = _data.field_2;
-
-    FieldService.insertField(
+    FieldService.updateFieldTypeOption(
       gridId: gridId,
       gridId: gridId,
-      field: field,
-      typeOptionData: _data.typeOptionData,
+      fieldId: field.id,
+      typeOptionData: typeOptionData,
     );
     );
   }
   }
 
 
   Future<void> switchToField(FieldType newFieldType) {
   Future<void> switchToField(FieldType newFieldType) {
     return loader.switchToField(field.id, newFieldType).then((result) {
     return loader.switchToField(field.id, newFieldType).then((result) {
       return result.fold(
       return result.fold(
-        (fieldTypeOptionData) {
-          _updateData(
-            newField: fieldTypeOptionData.field_2,
-            newTypeOptionData: fieldTypeOptionData.typeOptionData,
-          );
-        },
-        (err) {
-          Log.error(err);
-        },
+        (_) {},
+        (err) => Log.error(err),
       );
       );
     });
     });
   }
   }

+ 6 - 44
frontend/rust-lib/flowy-grid/src/entities/field_entities.rs

@@ -164,11 +164,16 @@ pub struct CreateFieldPayloadPB {
 
 
     #[pb(index = 2)]
     #[pb(index = 2)]
     pub field_type: FieldType,
     pub field_type: FieldType,
+
+    #[pb(index = 3, one_of)]
+    pub type_option_data: Option<Vec<u8>>,
 }
 }
 
 
+#[derive(Clone)]
 pub struct CreateFieldParams {
 pub struct CreateFieldParams {
     pub grid_id: String,
     pub grid_id: String,
     pub field_type: FieldType,
     pub field_type: FieldType,
+    pub type_option_data: Option<Vec<u8>>,
 }
 }
 
 
 impl TryInto<CreateFieldParams> for CreateFieldPayloadPB {
 impl TryInto<CreateFieldParams> for CreateFieldPayloadPB {
@@ -179,6 +184,7 @@ impl TryInto<CreateFieldParams> for CreateFieldPayloadPB {
         Ok(CreateFieldParams {
         Ok(CreateFieldParams {
             grid_id: grid_id.0,
             grid_id: grid_id.0,
             field_type: self.field_type,
             field_type: self.field_type,
+            type_option_data: self.type_option_data,
         })
         })
     }
     }
 }
 }
@@ -314,50 +320,6 @@ impl std::convert::From<String> for RepeatedFieldIdPB {
     }
     }
 }
 }
 
 
-#[derive(ProtoBuf, Default)]
-pub struct InsertFieldPayloadPB {
-    #[pb(index = 1)]
-    pub grid_id: String,
-
-    #[pb(index = 2)]
-    pub field: FieldPB,
-
-    #[pb(index = 3)]
-    pub type_option_data: Vec<u8>,
-
-    #[pb(index = 4, one_of)]
-    pub start_field_id: Option<String>,
-}
-
-#[derive(Clone)]
-pub struct InsertFieldParams {
-    pub grid_id: String,
-    pub field: FieldPB,
-    pub type_option_data: Vec<u8>,
-    pub start_field_id: Option<String>,
-}
-
-impl TryInto<InsertFieldParams> for InsertFieldPayloadPB {
-    type Error = ErrorCode;
-
-    fn try_into(self) -> Result<InsertFieldParams, Self::Error> {
-        let grid_id = NotEmptyStr::parse(self.grid_id).map_err(|_| ErrorCode::GridIdIsEmpty)?;
-        let _ = NotEmptyStr::parse(self.field.id.clone()).map_err(|_| ErrorCode::FieldIdIsEmpty)?;
-
-        let start_field_id = match self.start_field_id {
-            None => None,
-            Some(id) => Some(NotEmptyStr::parse(id).map_err(|_| ErrorCode::FieldIdIsEmpty)?.0),
-        };
-
-        Ok(InsertFieldParams {
-            grid_id: grid_id.0,
-            field: self.field,
-            type_option_data: self.type_option_data,
-            start_field_id,
-        })
-    }
-}
-
 /// [UpdateFieldTypeOptionPayloadPB] is used to update the type option data.
 /// [UpdateFieldTypeOptionPayloadPB] is used to update the type option data.
 #[derive(ProtoBuf, Default)]
 #[derive(ProtoBuf, Default)]
 pub struct UpdateFieldTypeOptionPayloadPB {
 pub struct UpdateFieldTypeOptionPayloadPB {

+ 55 - 52
frontend/rust-lib/flowy-grid/src/event_handler.rs

@@ -101,17 +101,6 @@ pub(crate) async fn update_field_handler(
     Ok(())
     Ok(())
 }
 }
 
 
-#[tracing::instrument(level = "trace", skip(data, manager), err)]
-pub(crate) async fn insert_field_handler(
-    data: Data<InsertFieldPayloadPB>,
-    manager: AppData<Arc<GridManager>>,
-) -> Result<(), FlowyError> {
-    let params: InsertFieldParams = data.into_inner().try_into()?;
-    let editor = manager.get_grid_editor(&params.grid_id)?;
-    let _ = editor.insert_field(params).await?;
-    Ok(())
-}
-
 #[tracing::instrument(level = "trace", skip(data, manager), err)]
 #[tracing::instrument(level = "trace", skip(data, manager), err)]
 pub(crate) async fn update_field_type_option_handler(
 pub(crate) async fn update_field_type_option_handler(
     data: Data<UpdateFieldTypeOptionPayloadPB>,
     data: Data<UpdateFieldTypeOptionPayloadPB>,
@@ -140,27 +129,25 @@ pub(crate) async fn delete_field_handler(
 pub(crate) async fn switch_to_field_handler(
 pub(crate) async fn switch_to_field_handler(
     data: Data<EditFieldPayloadPB>,
     data: Data<EditFieldPayloadPB>,
     manager: AppData<Arc<GridManager>>,
     manager: AppData<Arc<GridManager>>,
-) -> DataResult<FieldTypeOptionDataPB, FlowyError> {
+) -> Result<(), FlowyError> {
     let params: EditFieldParams = data.into_inner().try_into()?;
     let params: EditFieldParams = data.into_inner().try_into()?;
     let editor = manager.get_grid_editor(&params.grid_id)?;
     let editor = manager.get_grid_editor(&params.grid_id)?;
     editor
     editor
         .switch_to_field_type(&params.field_id, &params.field_type)
         .switch_to_field_type(&params.field_id, &params.field_type)
         .await?;
         .await?;
 
 
-    // Get the FieldMeta with field_id, if it doesn't exist, we create the default FieldMeta from the FieldType.
+    // Get the field_rev with field_id, if it doesn't exist, we create the default FieldMeta from the FieldType.
     let field_rev = editor
     let field_rev = editor
         .get_field_rev(&params.field_id)
         .get_field_rev(&params.field_id)
         .await
         .await
         .unwrap_or(Arc::new(editor.next_field_rev(&params.field_type).await?));
         .unwrap_or(Arc::new(editor.next_field_rev(&params.field_type).await?));
 
 
     let type_option_data = get_type_option_data(&field_rev, &params.field_type).await?;
     let type_option_data = get_type_option_data(&field_rev, &params.field_type).await?;
-    let data = FieldTypeOptionDataPB {
-        grid_id: params.grid_id,
-        field: field_rev.into(),
-        type_option_data,
-    };
+    let _ = editor
+        .update_field_type_option(&params.grid_id, &field_rev.id, type_option_data)
+        .await?;
 
 
-    data_result(data)
+    Ok(())
 }
 }
 
 
 #[tracing::instrument(level = "trace", skip(data, manager), err)]
 #[tracing::instrument(level = "trace", skip(data, manager), err)]
@@ -205,7 +192,9 @@ pub(crate) async fn create_field_type_option_data_handler(
 ) -> DataResult<FieldTypeOptionDataPB, FlowyError> {
 ) -> DataResult<FieldTypeOptionDataPB, FlowyError> {
     let params: CreateFieldParams = data.into_inner().try_into()?;
     let params: CreateFieldParams = data.into_inner().try_into()?;
     let editor = manager.get_grid_editor(&params.grid_id)?;
     let editor = manager.get_grid_editor(&params.grid_id)?;
-    let field_rev = editor.create_next_field_rev(&params.field_type).await?;
+    let field_rev = editor
+        .create_new_field_rev(&params.field_type, params.type_option_data)
+        .await?;
     let field_type: FieldType = field_rev.ty.into();
     let field_type: FieldType = field_rev.ty.into();
     let type_option_data = get_type_option_data(&field_rev, &field_type).await?;
     let type_option_data = get_type_option_data(&field_rev, &field_type).await?;
 
 
@@ -227,7 +216,7 @@ pub(crate) async fn move_field_handler(
     Ok(())
     Ok(())
 }
 }
 
 
-/// The FieldMeta contains multiple data, each of them belongs to a specific FieldType.
+/// The [FieldRevision] 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>> {
 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(|| {
     let s = field_rev.get_type_option_str(field_type).unwrap_or_else(|| {
         default_type_option_builder_from_type(field_type)
         default_type_option_builder_from_type(field_type)
@@ -346,38 +335,52 @@ pub(crate) async fn update_select_option_handler(
     let changeset: SelectOptionChangeset = data.into_inner().try_into()?;
     let changeset: SelectOptionChangeset = data.into_inner().try_into()?;
     let editor = manager.get_grid_editor(&changeset.cell_identifier.grid_id)?;
     let editor = manager.get_grid_editor(&changeset.cell_identifier.grid_id)?;
 
 
-    if let Some(mut field_rev) = editor.get_field_rev(&changeset.cell_identifier.field_id).await {
-        let mut_field_rev = Arc::make_mut(&mut field_rev);
-        let mut type_option = select_option_operation(mut_field_rev)?;
-        let mut cell_content_changeset = None;
-
-        if let Some(option) = changeset.insert_option {
-            cell_content_changeset = Some(SelectOptionCellChangeset::from_insert(&option.id).to_str());
-            type_option.insert_option(option);
-        }
-
-        if let Some(option) = changeset.update_option {
-            type_option.insert_option(option);
-        }
-
-        if let Some(option) = changeset.delete_option {
-            cell_content_changeset = Some(SelectOptionCellChangeset::from_delete(&option.id).to_str());
-            type_option.delete_option(option);
-        }
-
-        mut_field_rev.insert_type_option(&*type_option);
-        let _ = editor.replace_field(field_rev).await?;
+    let _ = editor
+        .modify_field_rev(&changeset.cell_identifier.field_id, |field_rev| {
+            let mut type_option = select_option_operation(field_rev)?;
+            let mut cell_content_changeset = None;
+            let mut is_changed = None;
+
+            if let Some(option) = changeset.insert_option {
+                cell_content_changeset = Some(SelectOptionCellChangeset::from_insert(&option.id).to_str());
+                type_option.insert_option(option);
+                is_changed = Some(());
+            }
+
+            if let Some(option) = changeset.update_option {
+                type_option.insert_option(option);
+                is_changed = Some(());
+            }
+
+            if let Some(option) = changeset.delete_option {
+                cell_content_changeset = Some(SelectOptionCellChangeset::from_delete(&option.id).to_str());
+                type_option.delete_option(option);
+                is_changed = Some(());
+            }
+
+            if is_changed.is_some() {
+                field_rev.insert_type_option(&*type_option);
+            }
+
+            if let Some(cell_content_changeset) = cell_content_changeset {
+                let changeset = CellChangesetPB {
+                    grid_id: changeset.cell_identifier.grid_id,
+                    row_id: changeset.cell_identifier.row_id,
+                    field_id: changeset.cell_identifier.field_id.clone(),
+                    content: cell_content_changeset,
+                };
+                let cloned_editor = editor.clone();
+                tokio::spawn(async move {
+                    match cloned_editor.update_cell(changeset).await {
+                        Ok(_) => {}
+                        Err(_) => {}
+                    }
+                });
+            }
+            Ok(is_changed)
+        })
+        .await?;
 
 
-        if let Some(cell_content_changeset) = cell_content_changeset {
-            let changeset = CellChangesetPB {
-                grid_id: changeset.cell_identifier.grid_id,
-                row_id: changeset.cell_identifier.row_id,
-                field_id: changeset.cell_identifier.field_id,
-                content: cell_content_changeset,
-            };
-            let _ = editor.update_cell(changeset).await?;
-        }
-    }
     Ok(())
     Ok(())
 }
 }
 
 

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

@@ -15,7 +15,6 @@ pub fn create(grid_manager: Arc<GridManager>) -> Module {
         // Field
         // Field
         .event(GridEvent::GetFields, get_fields_handler)
         .event(GridEvent::GetFields, get_fields_handler)
         .event(GridEvent::UpdateField, update_field_handler)
         .event(GridEvent::UpdateField, update_field_handler)
-        .event(GridEvent::InsertField, insert_field_handler)
         .event(GridEvent::UpdateFieldTypeOption, update_field_type_option_handler)
         .event(GridEvent::UpdateFieldTypeOption, update_field_type_option_handler)
         .event(GridEvent::DeleteField, delete_field_handler)
         .event(GridEvent::DeleteField, delete_field_handler)
         .event(GridEvent::SwitchToField, switch_to_field_handler)
         .event(GridEvent::SwitchToField, switch_to_field_handler)
@@ -106,11 +105,6 @@ pub enum GridEvent {
     #[event(input = "UpdateFieldTypeOptionPayloadPB")]
     #[event(input = "UpdateFieldTypeOptionPayloadPB")]
     UpdateFieldTypeOption = 12,
     UpdateFieldTypeOption = 12,
 
 
-    /// [InsertField] event is used to insert a new Field. If the Field already exists, the event
-    /// handler will replace the value with the new Field value.
-    #[event(input = "InsertFieldPayloadPB")]
-    InsertField = 13,
-
     /// [DeleteField] event is used to delete a Field. [DeleteFieldPayloadPB] is the context that
     /// [DeleteField] event is used to delete a Field. [DeleteFieldPayloadPB] is the context that
     /// is used to delete the field from the Grid.
     /// is used to delete the field from the Grid.
     #[event(input = "DeleteFieldPayloadPB")]
     #[event(input = "DeleteFieldPayloadPB")]
@@ -119,7 +113,7 @@ pub enum GridEvent {
     /// [SwitchToField] event is used to update the current Field's type.
     /// [SwitchToField] event is used to update the current Field's type.
     /// It will insert a new FieldTypeOptionData if the new FieldType doesn't exist before, otherwise
     /// It will insert a new FieldTypeOptionData if the new FieldType doesn't exist before, otherwise
     /// reuse the existing FieldTypeOptionData. You could check the [GridRevisionPad] for more details.
     /// reuse the existing FieldTypeOptionData. You could check the [GridRevisionPad] for more details.
-    #[event(input = "EditFieldPayloadPB", output = "FieldTypeOptionDataPB")]
+    #[event(input = "EditFieldPayloadPB")]
     SwitchToField = 20,
     SwitchToField = 20,
 
 
     /// [DuplicateField] event is used to duplicate a Field. The duplicated field data is kind of
     /// [DuplicateField] event is used to duplicate a Field. The duplicated field data is kind of

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

@@ -1,7 +1,8 @@
 use crate::entities::{FieldPB, FieldType};
 use crate::entities::{FieldPB, FieldType};
-use crate::services::field::type_options::*;
-use bytes::Bytes;
-use flowy_grid_data_model::revision::{FieldRevision, TypeOptionDataFormat};
+
+use crate::services::field::{default_type_option_builder_from_type, TypeOptionBuilder};
+
+use flowy_grid_data_model::revision::FieldRevision;
 use indexmap::IndexMap;
 use indexmap::IndexMap;
 
 
 pub struct FieldBuilder {
 pub struct FieldBuilder {
@@ -82,47 +83,3 @@ impl FieldBuilder {
         field_rev
         field_rev
     }
     }
 }
 }
-
-pub trait TypeOptionBuilder {
-    fn field_type(&self) -> FieldType;
-    fn data_format(&self) -> &dyn TypeOptionDataFormat;
-}
-
-pub fn default_type_option_builder_from_type(field_type: &FieldType) -> Box<dyn TypeOptionBuilder> {
-    let s: String = match field_type {
-        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 => CheckboxTypeOptionPB::default().into(),
-        FieldType::URL => URLTypeOptionPB::default().into(),
-    };
-
-    type_option_builder_from_json_str(&s, field_type)
-}
-
-pub fn type_option_builder_from_json_str(s: &str, field_type: &FieldType) -> Box<dyn TypeOptionBuilder> {
-    match field_type {
-        FieldType::RichText => Box::new(RichTextTypeOptionBuilder::from_json_str(s)),
-        FieldType::Number => Box::new(NumberTypeOptionBuilder::from_json_str(s)),
-        FieldType::DateTime => Box::new(DateTypeOptionBuilder::from_json_str(s)),
-        FieldType::SingleSelect => Box::new(SingleSelectTypeOptionBuilder::from_json_str(s)),
-        FieldType::MultiSelect => Box::new(MultiSelectTypeOptionBuilder::from_json_str(s)),
-        FieldType::Checkbox => Box::new(CheckboxTypeOptionBuilder::from_json_str(s)),
-        FieldType::URL => Box::new(URLTypeOptionBuilder::from_json_str(s)),
-    }
-}
-
-pub fn type_option_builder_from_bytes<T: Into<Bytes>>(bytes: T, field_type: &FieldType) -> Box<dyn TypeOptionBuilder> {
-    let bytes = bytes.into();
-    match field_type {
-        FieldType::RichText => Box::new(RichTextTypeOptionBuilder::from_protobuf_bytes(bytes)),
-        FieldType::Number => Box::new(NumberTypeOptionBuilder::from_protobuf_bytes(bytes)),
-        FieldType::DateTime => Box::new(DateTypeOptionBuilder::from_protobuf_bytes(bytes)),
-        FieldType::SingleSelect => Box::new(SingleSelectTypeOptionBuilder::from_protobuf_bytes(bytes)),
-        FieldType::MultiSelect => Box::new(MultiSelectTypeOptionBuilder::from_protobuf_bytes(bytes)),
-        FieldType::Checkbox => Box::new(CheckboxTypeOptionBuilder::from_protobuf_bytes(bytes)),
-        FieldType::URL => Box::new(URLTypeOptionBuilder::from_protobuf_bytes(bytes)),
-    }
-}

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

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

+ 48 - 0
frontend/rust-lib/flowy-grid/src/services/field/type_option_builder.rs

@@ -0,0 +1,48 @@
+use crate::entities::FieldType;
+use crate::services::field::type_options::*;
+use bytes::Bytes;
+use flowy_grid_data_model::revision::TypeOptionDataFormat;
+
+pub trait TypeOptionBuilder {
+    fn field_type(&self) -> FieldType;
+    fn data_format(&self) -> &dyn TypeOptionDataFormat;
+}
+
+pub fn default_type_option_builder_from_type(field_type: &FieldType) -> Box<dyn TypeOptionBuilder> {
+    let s: String = match field_type {
+        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 => CheckboxTypeOptionPB::default().into(),
+        FieldType::URL => URLTypeOptionPB::default().into(),
+    };
+
+    type_option_builder_from_json_str(&s, field_type)
+}
+
+pub fn type_option_builder_from_json_str(s: &str, field_type: &FieldType) -> Box<dyn TypeOptionBuilder> {
+    match field_type {
+        FieldType::RichText => Box::new(RichTextTypeOptionBuilder::from_json_str(s)),
+        FieldType::Number => Box::new(NumberTypeOptionBuilder::from_json_str(s)),
+        FieldType::DateTime => Box::new(DateTypeOptionBuilder::from_json_str(s)),
+        FieldType::SingleSelect => Box::new(SingleSelectTypeOptionBuilder::from_json_str(s)),
+        FieldType::MultiSelect => Box::new(MultiSelectTypeOptionBuilder::from_json_str(s)),
+        FieldType::Checkbox => Box::new(CheckboxTypeOptionBuilder::from_json_str(s)),
+        FieldType::URL => Box::new(URLTypeOptionBuilder::from_json_str(s)),
+    }
+}
+
+pub fn type_option_builder_from_bytes<T: Into<Bytes>>(bytes: T, field_type: &FieldType) -> Box<dyn TypeOptionBuilder> {
+    let bytes = bytes.into();
+    match field_type {
+        FieldType::RichText => Box::new(RichTextTypeOptionBuilder::from_protobuf_bytes(bytes)),
+        FieldType::Number => Box::new(NumberTypeOptionBuilder::from_protobuf_bytes(bytes)),
+        FieldType::DateTime => Box::new(DateTypeOptionBuilder::from_protobuf_bytes(bytes)),
+        FieldType::SingleSelect => Box::new(SingleSelectTypeOptionBuilder::from_protobuf_bytes(bytes)),
+        FieldType::MultiSelect => Box::new(MultiSelectTypeOptionBuilder::from_protobuf_bytes(bytes)),
+        FieldType::Checkbox => Box::new(CheckboxTypeOptionBuilder::from_protobuf_bytes(bytes)),
+        FieldType::URL => Box::new(URLTypeOptionBuilder::from_protobuf_bytes(bytes)),
+    }
+}

+ 29 - 48
frontend/rust-lib/flowy-grid/src/services/grid_editor.rs

@@ -16,7 +16,7 @@ use flowy_grid_data_model::revision::*;
 use flowy_revision::{RevisionCloudService, RevisionCompactor, RevisionManager, RevisionObjectBuilder};
 use flowy_revision::{RevisionCloudService, RevisionCompactor, RevisionManager, RevisionObjectBuilder};
 use flowy_sync::client_grid::{GridRevisionChangeset, GridRevisionPad, JsonDeserializer};
 use flowy_sync::client_grid::{GridRevisionChangeset, GridRevisionPad, JsonDeserializer};
 use flowy_sync::entities::revision::Revision;
 use flowy_sync::entities::revision::Revision;
-use flowy_sync::errors::CollaborateResult;
+use flowy_sync::errors::{CollaborateError, CollaborateResult};
 use flowy_sync::util::make_operations_from_revisions;
 use flowy_sync::util::make_operations_from_revisions;
 use lib_infra::future::{wrap_future, FutureResult};
 use lib_infra::future::{wrap_future, FutureResult};
 
 
@@ -87,43 +87,6 @@ impl GridRevisionEditor {
         Ok(editor)
         Ok(editor)
     }
     }
 
 
-    pub async fn insert_field(&self, params: InsertFieldParams) -> FlowyResult<()> {
-        let InsertFieldParams {
-            field,
-            type_option_data,
-            start_field_id,
-            grid_id,
-        } = params;
-        let field_id = field.id.clone();
-        if self.contain_field(&field_id).await {
-            let changeset = FieldChangesetParams {
-                field_id: field.id,
-                grid_id,
-                name: Some(field.name),
-                desc: Some(field.desc),
-                field_type: Some(field.field_type.clone().into()),
-                frozen: Some(field.frozen),
-                visibility: Some(field.visibility),
-                width: Some(field.width),
-                type_option_data: Some(type_option_data),
-            };
-
-            let _ = self.update_field_rev(changeset, field.field_type).await?;
-            let _ = self.notify_did_update_grid_field(&field_id).await?;
-        } else {
-            let _ = self
-                .modify(|grid| {
-                    let builder = type_option_builder_from_bytes(type_option_data, &field.field_type);
-                    let field_rev = FieldBuilder::from_field(field, builder).build();
-                    Ok(grid.create_field_rev(field_rev, start_field_id)?)
-                })
-                .await?;
-            let _ = self.notify_did_insert_grid_field(&field_id).await?;
-        }
-
-        Ok(())
-    }
-
     pub async fn update_field_type_option(
     pub async fn update_field_type_option(
         &self,
         &self,
         grid_id: &str,
         grid_id: &str,
@@ -153,8 +116,16 @@ impl GridRevisionEditor {
         Ok(field_rev)
         Ok(field_rev)
     }
     }
 
 
-    pub async fn create_next_field_rev(&self, field_type: &FieldType) -> FlowyResult<FieldRevision> {
-        let field_rev = self.next_field_rev(field_type).await?;
+    pub async fn create_new_field_rev(
+        &self,
+        field_type: &FieldType,
+        type_option_data: Option<Vec<u8>>,
+    ) -> FlowyResult<FieldRevision> {
+        let mut field_rev = self.next_field_rev(field_type).await?;
+        if let Some(type_option_data) = type_option_data {
+            let type_option_builder = type_option_builder_from_bytes(type_option_data, field_type);
+            field_rev.insert_type_option(type_option_builder.data_format());
+        }
         let _ = self
         let _ = self
             .modify(|grid| Ok(grid.create_field_rev(field_rev.clone(), None)?))
             .modify(|grid| Ok(grid.create_field_rev(field_rev.clone(), None)?))
             .await?;
             .await?;
@@ -186,18 +157,28 @@ impl GridRevisionEditor {
         }
         }
     }
     }
 
 
-    // Replaces the field revision with new field revision.
-    pub async fn replace_field(&self, field_rev: Arc<FieldRevision>) -> FlowyResult<()> {
-        let field_id = field_rev.id.clone();
+    pub async fn modify_field_rev<F>(&self, field_id: &str, f: F) -> FlowyResult<()>
+    where
+        F: for<'a> FnOnce(&'a mut FieldRevision) -> FlowyResult<Option<()>>,
+    {
+        let mut is_changed = false;
         let _ = self
         let _ = self
-            .modify(|grid_pad| Ok(grid_pad.replace_field_rev(field_rev.clone())?))
+            .modify(|grid| {
+                let changeset = grid.modify_field(field_id, |field_rev| {
+                    Ok(f(field_rev).map_err(|e| CollaborateError::internal().context(e))?)
+                })?;
+                is_changed = changeset.is_some();
+                Ok(changeset)
+            })
             .await?;
             .await?;
 
 
-        match self.view_manager.did_update_view_field(&field_rev.id).await {
-            Ok(_) => {}
-            Err(e) => tracing::error!("View manager update field failed: {:?}", e),
+        if is_changed {
+            match self.view_manager.did_update_view_field_type_option(field_id).await {
+                Ok(_) => {}
+                Err(e) => tracing::error!("View manager update field failed: {:?}", e),
+            }
+            let _ = self.notify_did_update_grid_field(field_id).await?;
         }
         }
-        let _ = self.notify_did_update_grid_field(&field_id).await?;
         Ok(())
         Ok(())
     }
     }
 
 

+ 2 - 9
frontend/rust-lib/flowy-grid/src/services/grid_view_editor.rs

@@ -283,15 +283,8 @@ impl GridViewRevisionEditor {
         .await
         .await
     }
     }
     #[tracing::instrument(level = "trace", skip_all, err)]
     #[tracing::instrument(level = "trace", skip_all, err)]
-    pub(crate) async fn did_update_view_field(&self, field_id: &str) -> FlowyResult<()> {
-        if let Some(field_rev) = self.field_delegate.get_field_rev(field_id).await {
-            match self.group_controller.write().await.did_update_group_field(&field_rev)? {
-                None => {}
-                Some(changeset) => {
-                    self.notify_did_update_view(changeset).await;
-                }
-            }
-        }
+    pub(crate) async fn did_update_view_field(&self, _field_id: &str) -> FlowyResult<()> {
+        // Do nothing
         Ok(())
         Ok(())
     }
     }
 
 

+ 1 - 2
frontend/rust-lib/flowy-grid/src/services/grid_view_manager.rs

@@ -179,8 +179,7 @@ impl GridViewManager {
     #[tracing::instrument(level = "trace", skip(self), err)]
     #[tracing::instrument(level = "trace", skip(self), err)]
     pub(crate) async fn did_update_view_field(&self, field_id: &str) -> FlowyResult<()> {
     pub(crate) async fn did_update_view_field(&self, field_id: &str) -> FlowyResult<()> {
         let view_editor = self.get_default_view_editor().await?;
         let view_editor = self.get_default_view_editor().await?;
-        // Only the field_id of the updated field is equal to the field_id of the group.
-        // Update the group
+        // Update the group if the group_id equal to the field_id
         if view_editor.group_id().await != field_id {
         if view_editor.group_id().await != field_id {
             return Ok(());
             return Ok(());
         }
         }

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

@@ -172,7 +172,7 @@ where
     /// [GroupConfigurationRevision] as old groups. The old groups and the new groups will be merged
     /// [GroupConfigurationRevision] as old groups. The old groups and the new groups will be merged
     /// while keeping the order of the old groups.
     /// while keeping the order of the old groups.
     ///
     ///
-    #[tracing::instrument(level = "debug", skip(self, generated_group_configs), err)]
+    #[tracing::instrument(level = "trace", skip(self, generated_group_configs), err)]
     pub(crate) fn init_groups(
     pub(crate) fn init_groups(
         &mut self,
         &mut self,
         generated_group_configs: Vec<GeneratedGroupConfig>,
         generated_group_configs: Vec<GeneratedGroupConfig>,

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

@@ -319,11 +319,8 @@ where
         }
         }
     }
     }
 
 
-    fn did_update_group_field(&mut self, field_rev: &FieldRevision) -> FlowyResult<Option<GroupViewChangesetPB>> {
-        let type_option = field_rev.get_type_option::<T>(field_rev.ty);
-        let groups = G::generate_groups(&field_rev.id, &self.group_ctx, &type_option);
-        let changeset = self.group_ctx.init_groups(groups)?;
-        Ok(changeset)
+    fn did_update_group_field(&mut self, _field_rev: &FieldRevision) -> FlowyResult<Option<GroupViewChangesetPB>> {
+        Ok(None)
     }
     }
 }
 }
 
 

+ 16 - 11
frontend/rust-lib/flowy-grid/tests/grid/field_test/script.rs

@@ -1,10 +1,10 @@
 use crate::grid::grid_editor::GridEditorTest;
 use crate::grid::grid_editor::GridEditorTest;
-use flowy_grid::entities::{FieldChangesetParams, InsertFieldParams};
+use flowy_grid::entities::{CreateFieldParams, FieldChangesetParams};
 use flowy_grid_data_model::revision::FieldRevision;
 use flowy_grid_data_model::revision::FieldRevision;
 
 
 pub enum FieldScript {
 pub enum FieldScript {
     CreateField {
     CreateField {
-        params: InsertFieldParams,
+        params: CreateFieldParams,
     },
     },
     UpdateField {
     UpdateField {
         changeset: FieldChangesetParams,
         changeset: FieldChangesetParams,
@@ -13,9 +13,9 @@ pub enum FieldScript {
         field_rev: FieldRevision,
         field_rev: FieldRevision,
     },
     },
     AssertFieldCount(usize),
     AssertFieldCount(usize),
-    AssertFieldEqual {
+    AssertFieldTypeOptionEqual {
         field_index: usize,
         field_index: usize,
-        field_rev: FieldRevision,
+        expected_type_option_data: String,
     },
     },
 }
 }
 
 
@@ -46,11 +46,11 @@ impl GridFieldTest {
     pub async fn run_script(&mut self, script: FieldScript) {
     pub async fn run_script(&mut self, script: FieldScript) {
         match script {
         match script {
             FieldScript::CreateField { params } => {
             FieldScript::CreateField { params } => {
-                if !self.editor.contain_field(&params.field.id).await {
-                    self.field_count += 1;
-                }
-
-                self.editor.insert_field(params).await.unwrap();
+                self.field_count += 1;
+                self.editor
+                    .create_new_field_rev(&params.field_type, params.type_option_data)
+                    .await
+                    .unwrap();
                 self.field_revs = self.editor.get_field_revs(None).await.unwrap();
                 self.field_revs = self.editor.get_field_revs(None).await.unwrap();
                 assert_eq!(self.field_count, self.field_revs.len());
                 assert_eq!(self.field_count, self.field_revs.len());
             }
             }
@@ -70,9 +70,14 @@ impl GridFieldTest {
             FieldScript::AssertFieldCount(count) => {
             FieldScript::AssertFieldCount(count) => {
                 assert_eq!(self.editor.get_field_revs(None).await.unwrap().len(), count);
                 assert_eq!(self.editor.get_field_revs(None).await.unwrap().len(), count);
             }
             }
-            FieldScript::AssertFieldEqual { field_index, field_rev } => {
+            FieldScript::AssertFieldTypeOptionEqual {
+                field_index,
+                expected_type_option_data,
+            } => {
                 let field_revs = self.editor.get_field_revs(None).await.unwrap();
                 let field_revs = self.editor.get_field_revs(None).await.unwrap();
-                assert_eq!(field_revs[field_index].as_ref(), &field_rev);
+                let field_rev = field_revs[field_index].as_ref();
+                let type_option_data = field_rev.get_type_option_str(field_rev.ty.clone()).unwrap();
+                assert_eq!(type_option_data, expected_type_option_data);
             }
             }
         }
         }
     }
     }

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

@@ -13,9 +13,9 @@ async fn grid_create_field() {
 
 
     let scripts = vec![
     let scripts = vec![
         CreateField { params },
         CreateField { params },
-        AssertFieldEqual {
+        AssertFieldTypeOptionEqual {
             field_index: test.field_count(),
             field_index: test.field_count(),
-            field_rev,
+            expected_type_option_data: field_rev.get_type_option_str(field_rev.ty.clone()).unwrap(),
         },
         },
     ];
     ];
     test.run_scripts(scripts).await;
     test.run_scripts(scripts).await;
@@ -23,9 +23,9 @@ async fn grid_create_field() {
     let (params, field_rev) = create_single_select_field(&test.grid_id());
     let (params, field_rev) = create_single_select_field(&test.grid_id());
     let scripts = vec![
     let scripts = vec![
         CreateField { params },
         CreateField { params },
-        AssertFieldEqual {
+        AssertFieldTypeOptionEqual {
             field_index: test.field_count(),
             field_index: test.field_count(),
-            field_rev,
+            expected_type_option_data: field_rev.get_type_option_str(field_rev.ty.clone()).unwrap(),
         },
         },
     ];
     ];
     test.run_scripts(scripts).await;
     test.run_scripts(scripts).await;
@@ -39,7 +39,6 @@ async fn grid_create_duplicate_field() {
     let expected_field_count = field_count + 1;
     let expected_field_count = field_count + 1;
     let scripts = vec![
     let scripts = vec![
         CreateField { params: params.clone() },
         CreateField { params: params.clone() },
-        CreateField { params },
         AssertFieldCount(expected_field_count),
         AssertFieldCount(expected_field_count),
     ];
     ];
     test.run_scripts(scripts).await;
     test.run_scripts(scripts).await;
@@ -48,7 +47,12 @@ async fn grid_create_duplicate_field() {
 #[tokio::test]
 #[tokio::test]
 async fn grid_update_field_with_empty_change() {
 async fn grid_update_field_with_empty_change() {
     let mut test = GridFieldTest::new().await;
     let mut test = GridFieldTest::new().await;
-    let (params, field_rev) = create_single_select_field(&test.grid_id());
+    let (params, _) = create_single_select_field(&test.grid_id());
+    let create_field_index = test.field_count();
+    let scripts = vec![CreateField { params }];
+    test.run_scripts(scripts).await;
+
+    let field_rev = (&*test.field_revs.clone().pop().unwrap()).clone();
     let changeset = FieldChangesetParams {
     let changeset = FieldChangesetParams {
         field_id: field_rev.id.clone(),
         field_id: field_rev.id.clone(),
         grid_id: test.grid_id(),
         grid_id: test.grid_id(),
@@ -56,11 +60,10 @@ async fn grid_update_field_with_empty_change() {
     };
     };
 
 
     let scripts = vec![
     let scripts = vec![
-        CreateField { params },
         UpdateField { changeset },
         UpdateField { changeset },
-        AssertFieldEqual {
-            field_index: test.field_count(),
-            field_rev,
+        AssertFieldTypeOptionEqual {
+            field_index: create_field_index,
+            expected_type_option_data: field_rev.get_type_option_str(field_rev.ty.clone()).unwrap(),
         },
         },
     ];
     ];
     test.run_scripts(scripts).await;
     test.run_scripts(scripts).await;
@@ -69,10 +72,15 @@ async fn grid_update_field_with_empty_change() {
 #[tokio::test]
 #[tokio::test]
 async fn grid_update_field() {
 async fn grid_update_field() {
     let mut test = GridFieldTest::new().await;
     let mut test = GridFieldTest::new().await;
-    let (params, single_select_field) = create_single_select_field(&test.grid_id());
-
+    let (params, _) = create_single_select_field(&test.grid_id());
+    let scripts = vec![CreateField { params }];
+    let create_field_index = test.field_count();
+    test.run_scripts(scripts).await;
+    //
+    let single_select_field = (&*test.field_revs.clone().pop().unwrap()).clone();
     let mut single_select_type_option = SingleSelectTypeOptionPB::from(&single_select_field);
     let mut single_select_type_option = SingleSelectTypeOptionPB::from(&single_select_field);
     single_select_type_option.options.push(SelectOptionPB::new("Unknown"));
     single_select_type_option.options.push(SelectOptionPB::new("Unknown"));
+
     let changeset = FieldChangesetParams {
     let changeset = FieldChangesetParams {
         field_id: single_select_field.id.clone(),
         field_id: single_select_field.id.clone(),
         grid_id: test.grid_id(),
         grid_id: test.grid_id(),
@@ -89,11 +97,12 @@ async fn grid_update_field() {
     expected_field_rev.insert_type_option(&single_select_type_option);
     expected_field_rev.insert_type_option(&single_select_type_option);
 
 
     let scripts = vec![
     let scripts = vec![
-        CreateField { params },
         UpdateField { changeset },
         UpdateField { changeset },
-        AssertFieldEqual {
-            field_index: test.field_count(),
-            field_rev: expected_field_rev,
+        AssertFieldTypeOptionEqual {
+            field_index: create_field_index,
+            expected_type_option_data: expected_field_rev
+                .get_type_option_str(expected_field_rev.ty.clone())
+                .unwrap(),
         },
         },
     ];
     ];
     test.run_scripts(scripts).await;
     test.run_scripts(scripts).await;
@@ -103,9 +112,12 @@ async fn grid_update_field() {
 async fn grid_delete_field() {
 async fn grid_delete_field() {
     let mut test = GridFieldTest::new().await;
     let mut test = GridFieldTest::new().await;
     let original_field_count = test.field_count();
     let original_field_count = test.field_count();
-    let (params, text_field_rev) = create_text_field(&test.grid_id());
+    let (params, _) = create_text_field(&test.grid_id());
+    let scripts = vec![CreateField { params }];
+    test.run_scripts(scripts).await;
+
+    let text_field_rev = (&*test.field_revs.clone().pop().unwrap()).clone();
     let scripts = vec![
     let scripts = vec![
-        CreateField { params },
         DeleteField {
         DeleteField {
             field_rev: text_field_rev,
             field_rev: text_field_rev,
         },
         },

+ 14 - 32
frontend/rust-lib/flowy-grid/tests/grid/field_test/util.rs

@@ -3,8 +3,8 @@ use flowy_grid::services::field::selection_type_option::SelectOptionPB;
 use flowy_grid::services::field::*;
 use flowy_grid::services::field::*;
 use flowy_grid_data_model::revision::*;
 use flowy_grid_data_model::revision::*;
 
 
-pub fn create_text_field(grid_id: &str) -> (InsertFieldParams, FieldRevision) {
-    let field_rev = FieldBuilder::new(RichTextTypeOptionBuilder::default())
+pub fn create_text_field(grid_id: &str) -> (CreateFieldParams, FieldRevision) {
+    let mut field_rev = FieldBuilder::new(RichTextTypeOptionBuilder::default())
         .name("Name")
         .name("Name")
         .visibility(true)
         .visibility(true)
         .build();
         .build();
@@ -17,32 +17,23 @@ pub fn create_text_field(grid_id: &str) -> (InsertFieldParams, FieldRevision) {
         .protobuf_bytes()
         .protobuf_bytes()
         .to_vec();
         .to_vec();
 
 
-    let field = FieldPB {
-        id: field_rev.id,
-        name: field_rev.name,
-        desc: field_rev.desc,
-        field_type: field_rev.ty.into(),
-        frozen: field_rev.frozen,
-        visibility: field_rev.visibility,
-        width: field_rev.width,
-        is_primary: false,
-    };
+    let type_option_builder = type_option_builder_from_bytes(type_option_data.clone(), &field_rev.ty.into());
+    field_rev.insert_type_option(type_option_builder.data_format());
 
 
-    let params = InsertFieldParams {
+    let params = CreateFieldParams {
         grid_id: grid_id.to_owned(),
         grid_id: grid_id.to_owned(),
-        field,
-        type_option_data,
-        start_field_id: None,
+        field_type: field_rev.ty.into(),
+        type_option_data: Some(type_option_data),
     };
     };
     (params, cloned_field_rev)
     (params, cloned_field_rev)
 }
 }
 
 
-pub fn create_single_select_field(grid_id: &str) -> (InsertFieldParams, FieldRevision) {
+pub fn create_single_select_field(grid_id: &str) -> (CreateFieldParams, FieldRevision) {
     let single_select = SingleSelectTypeOptionBuilder::default()
     let single_select = SingleSelectTypeOptionBuilder::default()
         .add_option(SelectOptionPB::new("Done"))
         .add_option(SelectOptionPB::new("Done"))
         .add_option(SelectOptionPB::new("Progress"));
         .add_option(SelectOptionPB::new("Progress"));
 
 
-    let field_rev = FieldBuilder::new(single_select).name("Name").visibility(true).build();
+    let mut field_rev = FieldBuilder::new(single_select).name("Name").visibility(true).build();
     let cloned_field_rev = field_rev.clone();
     let cloned_field_rev = field_rev.clone();
     let type_option_data = field_rev
     let type_option_data = field_rev
         .get_type_option::<SingleSelectTypeOptionPB>(field_rev.ty)
         .get_type_option::<SingleSelectTypeOptionPB>(field_rev.ty)
@@ -50,22 +41,13 @@ pub fn create_single_select_field(grid_id: &str) -> (InsertFieldParams, FieldRev
         .protobuf_bytes()
         .protobuf_bytes()
         .to_vec();
         .to_vec();
 
 
-    let field = FieldPB {
-        id: field_rev.id,
-        name: field_rev.name,
-        desc: field_rev.desc,
-        field_type: field_rev.ty.into(),
-        frozen: field_rev.frozen,
-        visibility: field_rev.visibility,
-        width: field_rev.width,
-        is_primary: false,
-    };
+    let type_option_builder = type_option_builder_from_bytes(type_option_data.clone(), &field_rev.ty.into());
+    field_rev.insert_type_option(type_option_builder.data_format());
 
 
-    let params = InsertFieldParams {
+    let params = CreateFieldParams {
         grid_id: grid_id.to_owned(),
         grid_id: grid_id.to_owned(),
-        field,
-        type_option_data,
-        start_field_id: None,
+        field_type: field_rev.ty.into(),
+        type_option_data: Some(type_option_data),
     };
     };
     (params, cloned_field_rev)
     (params, cloned_field_rev)
 }
 }

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

@@ -157,7 +157,6 @@ impl FieldRevision {
 
 
     pub fn get_type_option<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();
         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))
         self.type_options.get(&id).map(|s| T::from_json_str(s))
     }
     }
 
 

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

@@ -472,7 +472,7 @@ mod tests {
     use flowy_folder_data_model::revision::{
     use flowy_folder_data_model::revision::{
         AppRevision, FolderRevision, TrashRevision, ViewRevision, WorkspaceRevision,
         AppRevision, FolderRevision, TrashRevision, ViewRevision, WorkspaceRevision,
     };
     };
-    use lib_ot::core::{DeltaBuilder, OperationTransform};
+    use lib_ot::core::OperationTransform;
 
 
     #[test]
     #[test]
     fn folder_add_workspace() {
     fn folder_add_workspace() {

+ 1 - 2
shared-lib/lib-ot/src/text_delta/delta.rs

@@ -1,5 +1,4 @@
-use crate::core::{AttributeHashMap, DeltaOperation, DeltaOperations, OperationBuilder, OperationTransform};
-use std::fmt::Debug;
+use crate::core::{AttributeHashMap, DeltaOperation, DeltaOperations, OperationBuilder};
 
 
 pub type TextOperations = DeltaOperations<AttributeHashMap>;
 pub type TextOperations = DeltaOperations<AttributeHashMap>;
 pub type TextOperationBuilder = OperationBuilder<AttributeHashMap>;
 pub type TextOperationBuilder = OperationBuilder<AttributeHashMap>;