Quellcode durchsuchen

refactor: provide default type option transform (#1579)

Nathan.fooo vor 2 Jahren
Ursprung
Commit
67e350e797
15 geänderte Dateien mit 253 neuen und 144 gelöschten Zeilen
  1. 0 18
      frontend/rust-lib/flowy-grid/src/services/field/type_option_builder.rs
  2. 5 6
      frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option/checkbox_type_option.rs
  3. 1 1
      frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/date_tests.rs
  4. 5 6
      frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/date_type_option.rs
  5. 5 6
      frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option/number_type_option.rs
  6. 3 7
      frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/checklist_type_option.rs
  7. 15 18
      frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/multi_select_type_option.rs
  8. 30 10
      frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/select_type_option.rs
  9. 13 17
      frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/single_select_type_option.rs
  10. 11 15
      frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/type_option_transform.rs
  11. 5 5
      frontend/rust-lib/flowy-grid/src/services/field/type_options/text_type_option/text_type_option.rs
  12. 145 20
      frontend/rust-lib/flowy-grid/src/services/field/type_options/type_option.rs
  13. 6 8
      frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option/url_type_option.rs
  14. 8 7
      frontend/rust-lib/flowy-grid/src/services/grid_editor.rs
  15. 1 0
      shared-lib/grid-rev-model/src/grid_rev.rs

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

@@ -9,24 +9,6 @@ pub trait TypeOptionBuilder {
 
 
     /// Returns a serializer that can be used to serialize the type-option data
     /// Returns a serializer that can be used to serialize the type-option data
     fn serializer(&self) -> &dyn TypeOptionDataSerializer;
     fn serializer(&self) -> &dyn TypeOptionDataSerializer;
-
-    /// Transform the data from passed-in type-option to current type-option
-    ///
-    /// The current type-option data may be changed if it supports transform
-    /// the data from the other kind of type-option data.
-    ///
-    /// For example, when switching from `checkbox` type-option to `single-select`
-    /// type-option, adding the `Yes` option if the `single-select` type-option doesn't contain it.
-    /// But the cell content is a string, `Yes`, it's need to do the cell content transform.
-    /// The `Yes` string will be transformed to the `Yes` option id.
-    ///
-    ///
-    /// # Arguments
-    ///
-    /// * `field_type`: represents as the field type of the passed-in type-option data
-    /// * `type_option_data`: passed-in type-option data
-    //
-    fn transform(&mut self, field_type: &FieldType, type_option_data: String);
 }
 }
 
 
 pub fn default_type_option_builder_from_type(field_type: &FieldType) -> Box<dyn TypeOptionBuilder> {
 pub fn default_type_option_builder_from_type(field_type: &FieldType) -> Box<dyn TypeOptionBuilder> {

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

@@ -3,6 +3,7 @@ use crate::impl_type_option;
 use crate::services::cell::{AnyCellChangeset, CellDataChangeset, CellDataDecoder, FromCellString};
 use crate::services::cell::{AnyCellChangeset, CellDataChangeset, CellDataDecoder, FromCellString};
 use crate::services::field::{
 use crate::services::field::{
     BoxTypeOptionBuilder, CheckboxCellData, TypeOption, TypeOptionBuilder, TypeOptionCellData, TypeOptionConfiguration,
     BoxTypeOptionBuilder, CheckboxCellData, TypeOption, TypeOptionBuilder, TypeOptionCellData, TypeOptionConfiguration,
+    TypeOptionTransform,
 };
 };
 use bytes::Bytes;
 use bytes::Bytes;
 use flowy_derive::ProtoBuf;
 use flowy_derive::ProtoBuf;
@@ -31,10 +32,6 @@ impl TypeOptionBuilder for CheckboxTypeOptionBuilder {
     fn serializer(&self) -> &dyn TypeOptionDataSerializer {
     fn serializer(&self) -> &dyn TypeOptionDataSerializer {
         &self.0
         &self.0
     }
     }
-
-    fn transform(&mut self, _field_type: &FieldType, _type_option_data: String) {
-        // Do nothing
-    }
 }
 }
 
 
 #[derive(Debug, Clone, Serialize, Deserialize, Default, ProtoBuf)]
 #[derive(Debug, Clone, Serialize, Deserialize, Default, ProtoBuf)]
@@ -47,15 +44,17 @@ impl_type_option!(CheckboxTypeOptionPB, FieldType::Checkbox);
 impl TypeOption for CheckboxTypeOptionPB {
 impl TypeOption for CheckboxTypeOptionPB {
     type CellData = CheckboxCellData;
     type CellData = CheckboxCellData;
     type CellChangeset = CheckboxCellChangeset;
     type CellChangeset = CheckboxCellChangeset;
-    type CellPBType = CheckboxCellData;
+    type CellProtobufType = CheckboxCellData;
 }
 }
 
 
+impl TypeOptionTransform for CheckboxTypeOptionPB {}
+
 impl TypeOptionConfiguration for CheckboxTypeOptionPB {
 impl TypeOptionConfiguration for CheckboxTypeOptionPB {
     type CellFilterConfiguration = CheckboxFilterPB;
     type CellFilterConfiguration = CheckboxFilterPB;
 }
 }
 
 
 impl TypeOptionCellData for CheckboxTypeOptionPB {
 impl TypeOptionCellData for CheckboxTypeOptionPB {
-    fn convert_into_pb_type(&self, cell_data: <Self as TypeOption>::CellData) -> <Self as TypeOption>::CellPBType {
+    fn convert_to_protobuf(&self, cell_data: <Self as TypeOption>::CellData) -> <Self as TypeOption>::CellProtobufType {
         cell_data
         cell_data
     }
     }
 
 

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

@@ -165,7 +165,7 @@ mod tests {
         let decoded_data = type_option
         let decoded_data = type_option
             .try_decode_cell_data(encoded_data, &FieldType::DateTime, field_rev)
             .try_decode_cell_data(encoded_data, &FieldType::DateTime, field_rev)
             .unwrap();
             .unwrap();
-        let decoded_data = type_option.convert_into_pb_type(decoded_data);
+        let decoded_data = type_option.convert_to_protobuf(decoded_data);
         if type_option.include_time {
         if type_option.include_time {
             format!("{} {}", decoded_data.date, decoded_data.time)
             format!("{} {}", decoded_data.date, decoded_data.time)
                 .trim_end()
                 .trim_end()

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

@@ -3,7 +3,7 @@ use crate::impl_type_option;
 use crate::services::cell::{AnyCellChangeset, CellDataChangeset, CellDataDecoder, FromCellString};
 use crate::services::cell::{AnyCellChangeset, CellDataChangeset, CellDataDecoder, FromCellString};
 use crate::services::field::{
 use crate::services::field::{
     BoxTypeOptionBuilder, DateCellChangeset, DateCellData, DateCellDataPB, DateFormat, TimeFormat, TypeOption,
     BoxTypeOptionBuilder, DateCellChangeset, DateCellData, DateCellDataPB, DateFormat, TimeFormat, TypeOption,
-    TypeOptionBuilder, TypeOptionCellData, TypeOptionConfiguration,
+    TypeOptionBuilder, TypeOptionCellData, TypeOptionConfiguration, TypeOptionTransform,
 };
 };
 use bytes::Bytes;
 use bytes::Bytes;
 use chrono::format::strftime::StrftimeItems;
 use chrono::format::strftime::StrftimeItems;
@@ -30,7 +30,7 @@ impl_type_option!(DateTypeOptionPB, FieldType::DateTime);
 impl TypeOption for DateTypeOptionPB {
 impl TypeOption for DateTypeOptionPB {
     type CellData = DateCellData;
     type CellData = DateCellData;
     type CellChangeset = DateCellChangeset;
     type CellChangeset = DateCellChangeset;
-    type CellPBType = DateCellDataPB;
+    type CellProtobufType = DateCellDataPB;
 }
 }
 
 
 impl TypeOptionConfiguration for DateTypeOptionPB {
 impl TypeOptionConfiguration for DateTypeOptionPB {
@@ -38,7 +38,7 @@ impl TypeOptionConfiguration for DateTypeOptionPB {
 }
 }
 
 
 impl TypeOptionCellData for DateTypeOptionPB {
 impl TypeOptionCellData for DateTypeOptionPB {
-    fn convert_into_pb_type(&self, cell_data: <Self as TypeOption>::CellData) -> <Self as TypeOption>::CellPBType {
+    fn convert_to_protobuf(&self, cell_data: <Self as TypeOption>::CellData) -> <Self as TypeOption>::CellProtobufType {
         self.today_desc_from_timestamp(cell_data)
         self.today_desc_from_timestamp(cell_data)
     }
     }
 
 
@@ -128,6 +128,8 @@ impl DateTypeOptionPB {
     }
     }
 }
 }
 
 
+impl TypeOptionTransform for DateTypeOptionPB {}
+
 impl CellDataDecoder for DateTypeOptionPB {
 impl CellDataDecoder for DateTypeOptionPB {
     fn try_decode_cell_data(
     fn try_decode_cell_data(
         &self,
         &self,
@@ -207,7 +209,4 @@ impl TypeOptionBuilder for DateTypeOptionBuilder {
     fn serializer(&self) -> &dyn TypeOptionDataSerializer {
     fn serializer(&self) -> &dyn TypeOptionDataSerializer {
         &self.0
         &self.0
     }
     }
-    fn transform(&mut self, _field_type: &FieldType, _type_option_data: String) {
-        // Do nothing
-    }
 }
 }

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

@@ -4,7 +4,7 @@ use crate::services::cell::{AnyCellChangeset, CellComparable, CellDataChangeset,
 use crate::services::field::type_options::number_type_option::format::*;
 use crate::services::field::type_options::number_type_option::format::*;
 use crate::services::field::{
 use crate::services::field::{
     BoxTypeOptionBuilder, NumberCellData, StrCellData, TypeOption, TypeOptionBuilder, TypeOptionCellData,
     BoxTypeOptionBuilder, NumberCellData, StrCellData, TypeOption, TypeOptionBuilder, TypeOptionCellData,
-    TypeOptionConfiguration,
+    TypeOptionConfiguration, TypeOptionTransform,
 };
 };
 use bytes::Bytes;
 use bytes::Bytes;
 use flowy_derive::ProtoBuf;
 use flowy_derive::ProtoBuf;
@@ -51,9 +51,6 @@ impl TypeOptionBuilder for NumberTypeOptionBuilder {
     fn serializer(&self) -> &dyn TypeOptionDataSerializer {
     fn serializer(&self) -> &dyn TypeOptionDataSerializer {
         &self.0
         &self.0
     }
     }
-    fn transform(&mut self, _field_type: &FieldType, _type_option_data: String) {
-        // Do nothing
-    }
 }
 }
 
 
 // Number
 // Number
@@ -79,7 +76,7 @@ impl_type_option!(NumberTypeOptionPB, FieldType::Number);
 impl TypeOption for NumberTypeOptionPB {
 impl TypeOption for NumberTypeOptionPB {
     type CellData = StrCellData;
     type CellData = StrCellData;
     type CellChangeset = NumberCellChangeset;
     type CellChangeset = NumberCellChangeset;
-    type CellPBType = StrCellData;
+    type CellProtobufType = StrCellData;
 }
 }
 
 
 impl TypeOptionConfiguration for NumberTypeOptionPB {
 impl TypeOptionConfiguration for NumberTypeOptionPB {
@@ -87,7 +84,7 @@ impl TypeOptionConfiguration for NumberTypeOptionPB {
 }
 }
 
 
 impl TypeOptionCellData for NumberTypeOptionPB {
 impl TypeOptionCellData for NumberTypeOptionPB {
-    fn convert_into_pb_type(&self, cell_data: <Self as TypeOption>::CellData) -> <Self as TypeOption>::CellPBType {
+    fn convert_to_protobuf(&self, cell_data: <Self as TypeOption>::CellData) -> <Self as TypeOption>::CellProtobufType {
         cell_data
         cell_data
     }
     }
 
 
@@ -128,6 +125,8 @@ pub(crate) fn strip_currency_symbol<T: ToString>(s: T) -> String {
     s
     s
 }
 }
 
 
+impl TypeOptionTransform for NumberTypeOptionPB {}
+
 impl CellDataDecoder for NumberTypeOptionPB {
 impl CellDataDecoder for NumberTypeOptionPB {
     fn try_decode_cell_data(
     fn try_decode_cell_data(
         &self,
         &self,

+ 3 - 7
frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/checklist_type_option.rs

@@ -1,7 +1,7 @@
 use crate::entities::{ChecklistFilterPB, FieldType};
 use crate::entities::{ChecklistFilterPB, FieldType};
 use crate::impl_type_option;
 use crate::impl_type_option;
 use crate::services::cell::{AnyCellChangeset, CellDataChangeset, FromCellString, TypeCellData};
 use crate::services::cell::{AnyCellChangeset, CellDataChangeset, FromCellString, TypeCellData};
-use crate::services::field::selection_type_option::type_option_transform::SelectOptionTypeOptionTransformer;
+
 use crate::services::field::{
 use crate::services::field::{
     BoxTypeOptionBuilder, SelectOptionCellChangeset, SelectOptionCellDataPB, SelectOptionIds, SelectOptionPB,
     BoxTypeOptionBuilder, SelectOptionCellChangeset, SelectOptionCellDataPB, SelectOptionIds, SelectOptionPB,
     SelectTypeOptionSharedAction, TypeOption, TypeOptionBuilder, TypeOptionCellData, TypeOptionConfiguration,
     SelectTypeOptionSharedAction, TypeOption, TypeOptionBuilder, TypeOptionCellData, TypeOptionConfiguration,
@@ -26,7 +26,7 @@ impl_type_option!(ChecklistTypeOptionPB, FieldType::Checklist);
 impl TypeOption for ChecklistTypeOptionPB {
 impl TypeOption for ChecklistTypeOptionPB {
     type CellData = SelectOptionIds;
     type CellData = SelectOptionIds;
     type CellChangeset = SelectOptionCellChangeset;
     type CellChangeset = SelectOptionCellChangeset;
-    type CellPBType = SelectOptionCellDataPB;
+    type CellProtobufType = SelectOptionCellDataPB;
 }
 }
 
 
 impl TypeOptionConfiguration for ChecklistTypeOptionPB {
 impl TypeOptionConfiguration for ChecklistTypeOptionPB {
@@ -34,7 +34,7 @@ impl TypeOptionConfiguration for ChecklistTypeOptionPB {
 }
 }
 
 
 impl TypeOptionCellData for ChecklistTypeOptionPB {
 impl TypeOptionCellData for ChecklistTypeOptionPB {
-    fn convert_into_pb_type(&self, cell_data: <Self as TypeOption>::CellData) -> <Self as TypeOption>::CellPBType {
+    fn convert_to_protobuf(&self, cell_data: <Self as TypeOption>::CellData) -> <Self as TypeOption>::CellProtobufType {
         self.get_selected_options(cell_data)
         self.get_selected_options(cell_data)
     }
     }
 
 
@@ -113,8 +113,4 @@ impl TypeOptionBuilder for ChecklistTypeOptionBuilder {
     fn serializer(&self) -> &dyn TypeOptionDataSerializer {
     fn serializer(&self) -> &dyn TypeOptionDataSerializer {
         &self.0
         &self.0
     }
     }
-
-    fn transform(&mut self, field_type: &FieldType, type_option_data: String) {
-        SelectOptionTypeOptionTransformer::transform_type_option(&mut self.0, field_type, type_option_data)
-    }
 }
 }

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

@@ -1,7 +1,7 @@
 use crate::entities::{FieldType, SelectOptionFilterPB};
 use crate::entities::{FieldType, SelectOptionFilterPB};
 use crate::impl_type_option;
 use crate::impl_type_option;
 use crate::services::cell::{AnyCellChangeset, CellDataChangeset, FromCellString, TypeCellData};
 use crate::services::cell::{AnyCellChangeset, CellDataChangeset, FromCellString, TypeCellData};
-use crate::services::field::selection_type_option::type_option_transform::SelectOptionTypeOptionTransformer;
+
 use crate::services::field::{
 use crate::services::field::{
     BoxTypeOptionBuilder, SelectOptionCellChangeset, SelectOptionCellDataPB, SelectOptionIds, SelectOptionPB,
     BoxTypeOptionBuilder, SelectOptionCellChangeset, SelectOptionCellDataPB, SelectOptionIds, SelectOptionPB,
     SelectTypeOptionSharedAction, TypeOption, TypeOptionBuilder, TypeOptionCellData, TypeOptionConfiguration,
     SelectTypeOptionSharedAction, TypeOption, TypeOptionBuilder, TypeOptionCellData, TypeOptionConfiguration,
@@ -26,7 +26,7 @@ impl_type_option!(MultiSelectTypeOptionPB, FieldType::MultiSelect);
 impl TypeOption for MultiSelectTypeOptionPB {
 impl TypeOption for MultiSelectTypeOptionPB {
     type CellData = SelectOptionIds;
     type CellData = SelectOptionIds;
     type CellChangeset = SelectOptionCellChangeset;
     type CellChangeset = SelectOptionCellChangeset;
-    type CellPBType = SelectOptionCellDataPB;
+    type CellProtobufType = SelectOptionCellDataPB;
 }
 }
 
 
 impl TypeOptionConfiguration for MultiSelectTypeOptionPB {
 impl TypeOptionConfiguration for MultiSelectTypeOptionPB {
@@ -34,7 +34,7 @@ impl TypeOptionConfiguration for MultiSelectTypeOptionPB {
 }
 }
 
 
 impl TypeOptionCellData for MultiSelectTypeOptionPB {
 impl TypeOptionCellData for MultiSelectTypeOptionPB {
-    fn convert_into_pb_type(&self, cell_data: <Self as TypeOption>::CellData) -> <Self as TypeOption>::CellPBType {
+    fn convert_to_protobuf(&self, cell_data: <Self as TypeOption>::CellData) -> <Self as TypeOption>::CellProtobufType {
         self.get_selected_options(cell_data)
         self.get_selected_options(cell_data)
     }
     }
 
 
@@ -119,17 +119,14 @@ impl TypeOptionBuilder for MultiSelectTypeOptionBuilder {
     fn serializer(&self) -> &dyn TypeOptionDataSerializer {
     fn serializer(&self) -> &dyn TypeOptionDataSerializer {
         &self.0
         &self.0
     }
     }
-
-    fn transform(&mut self, field_type: &FieldType, type_option_data: String) {
-        SelectOptionTypeOptionTransformer::transform_type_option(&mut self.0, field_type, type_option_data)
-    }
 }
 }
+
 #[cfg(test)]
 #[cfg(test)]
 mod tests {
 mod tests {
     use crate::entities::FieldType;
     use crate::entities::FieldType;
     use crate::services::cell::CellDataChangeset;
     use crate::services::cell::CellDataChangeset;
     use crate::services::field::type_options::selection_type_option::*;
     use crate::services::field::type_options::selection_type_option::*;
-    use crate::services::field::{CheckboxTypeOptionBuilder, FieldBuilder, TypeOptionBuilder};
+    use crate::services::field::{CheckboxTypeOptionBuilder, FieldBuilder, TypeOptionBuilder, TypeOptionTransform};
     use crate::services::field::{MultiSelectTypeOptionBuilder, MultiSelectTypeOptionPB};
     use crate::services::field::{MultiSelectTypeOptionBuilder, MultiSelectTypeOptionPB};
 
 
     #[test]
     #[test]
@@ -137,13 +134,13 @@ mod tests {
         let checkbox_type_option_builder = CheckboxTypeOptionBuilder::default();
         let checkbox_type_option_builder = CheckboxTypeOptionBuilder::default();
         let checkbox_type_option_data = checkbox_type_option_builder.serializer().json_str();
         let checkbox_type_option_data = checkbox_type_option_builder.serializer().json_str();
 
 
-        let mut multi_select = MultiSelectTypeOptionBuilder::default();
-        multi_select.transform(&FieldType::Checkbox, checkbox_type_option_data.clone());
-        debug_assert_eq!(multi_select.0.options.len(), 2);
+        let mut multi_select = MultiSelectTypeOptionBuilder::default().0;
+        multi_select.transform_type_option(FieldType::Checkbox, checkbox_type_option_data.clone());
+        debug_assert_eq!(multi_select.options.len(), 2);
 
 
         // Already contain the yes/no option. It doesn't need to insert new options
         // Already contain the yes/no option. It doesn't need to insert new options
-        multi_select.transform(&FieldType::Checkbox, checkbox_type_option_data);
-        debug_assert_eq!(multi_select.0.options.len(), 2);
+        multi_select.transform_type_option(FieldType::Checkbox, checkbox_type_option_data);
+        debug_assert_eq!(multi_select.options.len(), 2);
     }
     }
 
 
     #[test]
     #[test]
@@ -158,13 +155,13 @@ mod tests {
 
 
         let singleselect_type_option_data = singleselect_type_option_builder.serializer().json_str();
         let singleselect_type_option_data = singleselect_type_option_builder.serializer().json_str();
 
 
-        let mut multi_select = MultiSelectTypeOptionBuilder::default();
-        multi_select.transform(&FieldType::MultiSelect, singleselect_type_option_data.clone());
-        debug_assert_eq!(multi_select.0.options.len(), 2);
+        let mut multi_select = MultiSelectTypeOptionBuilder::default().0;
+        multi_select.transform_type_option(FieldType::MultiSelect, singleselect_type_option_data.clone());
+        debug_assert_eq!(multi_select.options.len(), 2);
 
 
         // Already contain the yes/no option. It doesn't need to insert new options
         // Already contain the yes/no option. It doesn't need to insert new options
-        multi_select.transform(&FieldType::MultiSelect, singleselect_type_option_data);
-        debug_assert_eq!(multi_select.0.options.len(), 2);
+        multi_select.transform_type_option(FieldType::MultiSelect, singleselect_type_option_data);
+        debug_assert_eq!(multi_select.options.len(), 2);
     }
     }
 
 
     // #[test]
     // #[test]

+ 30 - 10
frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/select_type_option.rs

@@ -4,9 +4,10 @@ use crate::services::cell::{
     CellDataDecoder, CellProtobufBlobParser, DecodedCellData, FromCellChangeset, FromCellString,
     CellDataDecoder, CellProtobufBlobParser, DecodedCellData, FromCellChangeset, FromCellString,
 };
 };
 
 
-use crate::services::field::selection_type_option::type_option_transform::SelectOptionTypeOptionTransformer;
+use crate::services::field::selection_type_option::type_option_transform::SelectOptionTypeOptionTransformHelper;
 use crate::services::field::{
 use crate::services::field::{
     ChecklistTypeOptionPB, MultiSelectTypeOptionPB, SingleSelectTypeOptionPB, TypeOption, TypeOptionCellData,
     ChecklistTypeOptionPB, MultiSelectTypeOptionPB, SingleSelectTypeOptionPB, TypeOption, TypeOptionCellData,
+    TypeOptionTransform,
 };
 };
 use bytes::Bytes;
 use bytes::Bytes;
 use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
 use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
@@ -128,6 +129,31 @@ pub trait SelectTypeOptionSharedAction: TypeOptionDataSerializer + Send + Sync {
     fn mut_options(&mut self) -> &mut Vec<SelectOptionPB>;
     fn mut_options(&mut self) -> &mut Vec<SelectOptionPB>;
 }
 }
 
 
+impl<T> TypeOptionTransform for T
+where
+    T: SelectTypeOptionSharedAction + TypeOption<CellData = SelectOptionIds> + TypeOptionDataSerializer,
+{
+    fn transformable(&self) -> bool {
+        true
+    }
+
+    fn transform_type_option(&mut self, old_type_option_field_type: FieldType, old_type_option_data: String) {
+        SelectOptionTypeOptionTransformHelper::transform_type_option(
+            self,
+            &old_type_option_field_type,
+            old_type_option_data,
+        );
+    }
+
+    fn transform_type_option_cell_data(
+        &self,
+        cell_data: <Self as TypeOption>::CellData,
+        decoded_field_type: &FieldType,
+    ) -> <Self as TypeOption>::CellData {
+        SelectOptionTypeOptionTransformHelper::transform_type_option_cell_data(self, cell_data, decoded_field_type)
+    }
+}
+
 impl<T> CellDataDecoder for T
 impl<T> CellDataDecoder for T
 where
 where
     T: SelectTypeOptionSharedAction + TypeOption<CellData = SelectOptionIds> + TypeOptionCellData,
     T: SelectTypeOptionSharedAction + TypeOption<CellData = SelectOptionIds> + TypeOptionCellData,
@@ -135,16 +161,10 @@ where
     fn try_decode_cell_data(
     fn try_decode_cell_data(
         &self,
         &self,
         cell_data: String,
         cell_data: String,
-        decoded_field_type: &FieldType,
-        field_rev: &FieldRevision,
+        _decoded_field_type: &FieldType,
+        _field_rev: &FieldRevision,
     ) -> FlowyResult<<Self as TypeOption>::CellData> {
     ) -> FlowyResult<<Self as TypeOption>::CellData> {
-        let cell_data = self.decode_type_option_cell_data(cell_data)?;
-        Ok(SelectOptionTypeOptionTransformer::transform_type_option_cell_data(
-            self,
-            cell_data,
-            decoded_field_type,
-            field_rev,
-        ))
+        self.decode_type_option_cell_data(cell_data)
     }
     }
 
 
     fn decode_cell_data_to_str(
     fn decode_cell_data_to_str(

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

@@ -1,7 +1,7 @@
 use crate::entities::{FieldType, SelectOptionFilterPB};
 use crate::entities::{FieldType, SelectOptionFilterPB};
 use crate::impl_type_option;
 use crate::impl_type_option;
 use crate::services::cell::{AnyCellChangeset, CellDataChangeset, FromCellString};
 use crate::services::cell::{AnyCellChangeset, CellDataChangeset, FromCellString};
-use crate::services::field::selection_type_option::type_option_transform::SelectOptionTypeOptionTransformer;
+
 use crate::services::field::{
 use crate::services::field::{
     BoxTypeOptionBuilder, SelectOptionCellDataPB, TypeOption, TypeOptionBuilder, TypeOptionCellData,
     BoxTypeOptionBuilder, SelectOptionCellDataPB, TypeOption, TypeOptionBuilder, TypeOptionCellData,
     TypeOptionConfiguration,
     TypeOptionConfiguration,
@@ -29,7 +29,7 @@ impl_type_option!(SingleSelectTypeOptionPB, FieldType::SingleSelect);
 impl TypeOption for SingleSelectTypeOptionPB {
 impl TypeOption for SingleSelectTypeOptionPB {
     type CellData = SelectOptionIds;
     type CellData = SelectOptionIds;
     type CellChangeset = SelectOptionCellChangeset;
     type CellChangeset = SelectOptionCellChangeset;
-    type CellPBType = SelectOptionCellDataPB;
+    type CellProtobufType = SelectOptionCellDataPB;
 }
 }
 
 
 impl TypeOptionConfiguration for SingleSelectTypeOptionPB {
 impl TypeOptionConfiguration for SingleSelectTypeOptionPB {
@@ -37,7 +37,7 @@ impl TypeOptionConfiguration for SingleSelectTypeOptionPB {
 }
 }
 
 
 impl TypeOptionCellData for SingleSelectTypeOptionPB {
 impl TypeOptionCellData for SingleSelectTypeOptionPB {
-    fn convert_into_pb_type(&self, cell_data: <Self as TypeOption>::CellData) -> <Self as TypeOption>::CellPBType {
+    fn convert_to_protobuf(&self, cell_data: <Self as TypeOption>::CellData) -> <Self as TypeOption>::CellProtobufType {
         self.get_selected_options(cell_data)
         self.get_selected_options(cell_data)
     }
     }
 
 
@@ -107,10 +107,6 @@ impl TypeOptionBuilder for SingleSelectTypeOptionBuilder {
     fn serializer(&self) -> &dyn TypeOptionDataSerializer {
     fn serializer(&self) -> &dyn TypeOptionDataSerializer {
         &self.0
         &self.0
     }
     }
-
-    fn transform(&mut self, field_type: &FieldType, type_option_data: String) {
-        SelectOptionTypeOptionTransformer::transform_type_option(&mut self.0, field_type, type_option_data)
-    }
 }
 }
 
 
 #[cfg(test)]
 #[cfg(test)]
@@ -125,13 +121,13 @@ mod tests {
         let checkbox_type_option_builder = CheckboxTypeOptionBuilder::default();
         let checkbox_type_option_builder = CheckboxTypeOptionBuilder::default();
         let checkbox_type_option_data = checkbox_type_option_builder.serializer().json_str();
         let checkbox_type_option_data = checkbox_type_option_builder.serializer().json_str();
 
 
-        let mut single_select = SingleSelectTypeOptionBuilder::default();
-        single_select.transform(&FieldType::Checkbox, checkbox_type_option_data.clone());
-        debug_assert_eq!(single_select.0.options.len(), 2);
+        let mut single_select = SingleSelectTypeOptionBuilder::default().0;
+        single_select.transform_type_option(FieldType::Checkbox, checkbox_type_option_data.clone());
+        debug_assert_eq!(single_select.options.len(), 2);
 
 
         // Already contain the yes/no option. It doesn't need to insert new options
         // Already contain the yes/no option. It doesn't need to insert new options
-        single_select.transform(&FieldType::Checkbox, checkbox_type_option_data);
-        debug_assert_eq!(single_select.0.options.len(), 2);
+        single_select.transform_type_option(FieldType::Checkbox, checkbox_type_option_data);
+        debug_assert_eq!(single_select.options.len(), 2);
     }
     }
 
 
     #[test]
     #[test]
@@ -146,13 +142,13 @@ mod tests {
 
 
         let multiselect_type_option_data = multiselect_type_option_builder.serializer().json_str();
         let multiselect_type_option_data = multiselect_type_option_builder.serializer().json_str();
 
 
-        let mut single_select = SingleSelectTypeOptionBuilder::default();
-        single_select.transform(&FieldType::MultiSelect, multiselect_type_option_data.clone());
-        debug_assert_eq!(single_select.0.options.len(), 2);
+        let mut single_select = SingleSelectTypeOptionBuilder::default().0;
+        single_select.transform_type_option(FieldType::MultiSelect, multiselect_type_option_data.clone());
+        debug_assert_eq!(single_select.options.len(), 2);
 
 
         // Already contain the yes/no option. It doesn't need to insert new options
         // Already contain the yes/no option. It doesn't need to insert new options
-        single_select.transform(&FieldType::MultiSelect, multiselect_type_option_data);
-        debug_assert_eq!(single_select.0.options.len(), 2);
+        single_select.transform_type_option(FieldType::MultiSelect, multiselect_type_option_data);
+        debug_assert_eq!(single_select.options.len(), 2);
     }
     }
 
 
     #[test]
     #[test]

+ 11 - 15
frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/type_option_transform.rs

@@ -5,24 +5,22 @@ use crate::services::field::{
     SingleSelectTypeOptionPB, TypeOption, CHECK, UNCHECK,
     SingleSelectTypeOptionPB, TypeOption, CHECK, UNCHECK,
 };
 };
 
 
-use grid_rev_model::FieldRevision;
-use serde_json;
+use grid_rev_model::TypeOptionDataDeserializer;
 
 
 /// Handles how to transform the cell data when switching between different field types
 /// Handles how to transform the cell data when switching between different field types
-pub struct SelectOptionTypeOptionTransformer();
-impl SelectOptionTypeOptionTransformer {
+pub(crate) struct SelectOptionTypeOptionTransformHelper();
+impl SelectOptionTypeOptionTransformHelper {
     /// Transform the TypeOptionData from 'field_type' to single select option type.
     /// Transform the TypeOptionData from 'field_type' to single select option type.
     ///
     ///
     /// # Arguments
     /// # Arguments
     ///
     ///
-    /// * `field_type`: the FieldType of the passed-in TypeOptionData
-    /// * `type_option_data`: the data that can be parsed into corresponding TypeOptionData.
+    /// * `old_field_type`: the FieldType of the passed-in TypeOptionData
     ///
     ///
-    pub fn transform_type_option<T>(shared: &mut T, field_type: &FieldType, _type_option_data: String)
+    pub fn transform_type_option<T>(shared: &mut T, old_field_type: &FieldType, old_type_option_data: String)
     where
     where
-        T: SelectTypeOptionSharedAction,
+        T: SelectTypeOptionSharedAction + TypeOption<CellData = SelectOptionIds>,
     {
     {
-        match field_type {
+        match old_field_type {
             FieldType::Checkbox => {
             FieldType::Checkbox => {
                 //add Yes and No options if it does not exist.
                 //add Yes and No options if it does not exist.
                 if !shared.options().iter().any(|option| option.name == CHECK) {
                 if !shared.options().iter().any(|option| option.name == CHECK) {
@@ -36,16 +34,16 @@ impl SelectOptionTypeOptionTransformer {
                 }
                 }
             }
             }
             FieldType::MultiSelect => {
             FieldType::MultiSelect => {
-                let option_pb: MultiSelectTypeOptionPB = serde_json::from_str(_type_option_data.as_str()).unwrap();
-                option_pb.options.iter().for_each(|new_option| {
+                let options = MultiSelectTypeOptionPB::from_json_str(&old_type_option_data).options;
+                options.iter().for_each(|new_option| {
                     if !shared.options().iter().any(|option| option.name == new_option.name) {
                     if !shared.options().iter().any(|option| option.name == new_option.name) {
                         shared.mut_options().push(new_option.clone());
                         shared.mut_options().push(new_option.clone());
                     }
                     }
                 })
                 })
             }
             }
             FieldType::SingleSelect => {
             FieldType::SingleSelect => {
-                let option_pb: SingleSelectTypeOptionPB = serde_json::from_str(_type_option_data.as_str()).unwrap();
-                option_pb.options.iter().for_each(|new_option| {
+                let options = SingleSelectTypeOptionPB::from_json_str(&old_type_option_data).options;
+                options.iter().for_each(|new_option| {
                     if !shared.options().iter().any(|option| option.name == new_option.name) {
                     if !shared.options().iter().any(|option| option.name == new_option.name) {
                         shared.mut_options().push(new_option.clone());
                         shared.mut_options().push(new_option.clone());
                     }
                     }
@@ -59,7 +57,6 @@ impl SelectOptionTypeOptionTransformer {
         shared: &T,
         shared: &T,
         cell_data: <T as TypeOption>::CellData,
         cell_data: <T as TypeOption>::CellData,
         decoded_field_type: &FieldType,
         decoded_field_type: &FieldType,
-        _field_rev: &FieldRevision,
     ) -> <T as TypeOption>::CellData
     ) -> <T as TypeOption>::CellData
     where
     where
         T: SelectTypeOptionSharedAction + TypeOption<CellData = SelectOptionIds>,
         T: SelectTypeOptionSharedAction + TypeOption<CellData = SelectOptionIds>,
@@ -75,7 +72,6 @@ impl SelectOptionTypeOptionTransformer {
                         transformed_ids.push(option.id.clone());
                         transformed_ids.push(option.id.clone());
                     }
                     }
                 });
                 });
-
                 SelectOptionIds::from(transformed_ids)
                 SelectOptionIds::from(transformed_ids)
             }
             }
             _ => SelectOptionIds::from(vec![]),
             _ => SelectOptionIds::from(vec![]),

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

@@ -6,6 +6,7 @@ use crate::services::cell::{
 };
 };
 use crate::services::field::{
 use crate::services::field::{
     BoxTypeOptionBuilder, TypeOption, TypeOptionBuilder, TypeOptionCellData, TypeOptionConfiguration,
     BoxTypeOptionBuilder, TypeOption, TypeOptionBuilder, TypeOptionCellData, TypeOptionConfiguration,
+    TypeOptionTransform,
 };
 };
 use bytes::Bytes;
 use bytes::Bytes;
 use flowy_derive::ProtoBuf;
 use flowy_derive::ProtoBuf;
@@ -28,9 +29,6 @@ impl TypeOptionBuilder for RichTextTypeOptionBuilder {
     fn serializer(&self) -> &dyn TypeOptionDataSerializer {
     fn serializer(&self) -> &dyn TypeOptionDataSerializer {
         &self.0
         &self.0
     }
     }
-    fn transform(&mut self, _field_type: &FieldType, _type_option_data: String) {
-        // Do nothing
-    }
 }
 }
 
 
 /// For the moment, the `RichTextTypeOptionPB` is empty. The `data` property is not
 /// For the moment, the `RichTextTypeOptionPB` is empty. The `data` property is not
@@ -46,15 +44,17 @@ impl_type_option!(RichTextTypeOptionPB, FieldType::RichText);
 impl TypeOption for RichTextTypeOptionPB {
 impl TypeOption for RichTextTypeOptionPB {
     type CellData = StrCellData;
     type CellData = StrCellData;
     type CellChangeset = String;
     type CellChangeset = String;
-    type CellPBType = StrCellData;
+    type CellProtobufType = StrCellData;
 }
 }
 
 
+impl TypeOptionTransform for RichTextTypeOptionPB {}
+
 impl TypeOptionConfiguration for RichTextTypeOptionPB {
 impl TypeOptionConfiguration for RichTextTypeOptionPB {
     type CellFilterConfiguration = TextFilterPB;
     type CellFilterConfiguration = TextFilterPB;
 }
 }
 
 
 impl TypeOptionCellData for RichTextTypeOptionPB {
 impl TypeOptionCellData for RichTextTypeOptionPB {
-    fn convert_into_pb_type(&self, cell_data: <Self as TypeOption>::CellData) -> <Self as TypeOption>::CellPBType {
+    fn convert_to_protobuf(&self, cell_data: <Self as TypeOption>::CellData) -> <Self as TypeOption>::CellProtobufType {
         cell_data
         cell_data
     }
     }
 
 

+ 145 - 20
frontend/rust-lib/flowy-grid/src/services/field/type_options/type_option.rs

@@ -6,20 +6,112 @@ use crate::services::field::{
 };
 };
 use bytes::Bytes;
 use bytes::Bytes;
 use flowy_error::FlowyResult;
 use flowy_error::FlowyResult;
-use grid_rev_model::FieldRevision;
+use grid_rev_model::{FieldRevision, TypeOptionDataDeserializer, TypeOptionDataSerializer};
 use protobuf::ProtobufError;
 use protobuf::ProtobufError;
 use std::fmt::Debug;
 use std::fmt::Debug;
 
 
 pub trait TypeOption {
 pub trait TypeOption {
+    /// `CellData` represents as the decoded model for current type option. Each of them impl the
+    /// `FromCellString` and `Default` trait. If the cell string can not be decoded into the specified
+    /// cell data type then the default value will be returned.
+    /// For example:
+    ///     FieldType::Checkbox => CheckboxCellData
+    ///     FieldType::Date => DateCellData
+    ///     FieldType::URL => URLCellData
+    ///
+    /// Uses `StrCellData` for any `TypeOption` if their cell data is pure `String`.
+    ///
     type CellData: FromCellString + Default;
     type CellData: FromCellString + Default;
+
+    ///
     type CellChangeset;
     type CellChangeset;
-    type CellPBType: TryInto<Bytes, Error = ProtobufError> + Debug;
+
+    ///  For the moment, the protobuf type only be used in the FFI of `Dart`. If the decoded cell
+    /// struct is just a `String`, then use the `StrCellData` as its `CellProtobufType`.
+    /// Otherwise, providing a custom protobuf type as its `CellProtobufType`.
+    /// For example:
+    ///     FieldType::Date => DateCellDataPB
+    ///     FieldType::URL => URLCellDataPB
+    ///
+    type CellProtobufType: TryInto<Bytes, Error = ProtobufError> + Debug;
+}
+
+pub trait TypeOptionCellData: TypeOption {
+    /// Convert the decoded cell data into corresponding `Protobuf struct`.
+    /// For example:
+    ///    FieldType::URL => URLCellDataPB
+    ///    FieldType::Date=> DateCellDataPB
+    fn convert_to_protobuf(&self, cell_data: <Self as TypeOption>::CellData) -> <Self as TypeOption>::CellProtobufType;
+
+    /// Decodes the opaque cell data to corresponding data struct.
+    // For example, the cell data is timestamp if its field type is `FieldType::Date`. This cell
+    // data can not directly show to user. So it needs to be encode as the date string with custom
+    // format setting. Encode `1647251762` to `"Mar 14,2022`
+    fn decode_type_option_cell_data(&self, cell_data: String) -> FlowyResult<<Self as TypeOption>::CellData>;
 }
 }
 
 
 pub trait TypeOptionConfiguration {
 pub trait TypeOptionConfiguration {
     type CellFilterConfiguration;
     type CellFilterConfiguration;
 }
 }
 
 
+pub trait TypeOptionTransform: TypeOption {
+    /// Returns true if the current `TypeOption` provides custom type option transformation
+    fn transformable(&self) -> bool {
+        false
+    }
+
+    /// Transform the TypeOption from one field type to another
+    /// For example, when switching from `checkbox` type-option to `single-select`
+    /// type-option, adding the `Yes` option if the `single-select` type-option doesn't contain it.
+    /// But the cell content is a string, `Yes`, it's need to do the cell content transform.
+    /// The `Yes` string will be transformed to the `Yes` option id.
+    ///
+    /// # Arguments
+    ///
+    /// * `old_type_option_field_type`: the FieldType of the passed-in TypeOption
+    /// * `old_type_option_data`: the data that can be parsed into corresponding `TypeOption`.
+    ///
+    ///
+    fn transform_type_option(&mut self, _old_type_option_field_type: FieldType, _old_type_option_data: String) {}
+
+    /// Transform the cell data from one field type to another
+    ///
+    /// # Arguments
+    ///
+    /// * `cell_data`: the cell data of the current field type
+    /// * `decoded_field_type`: the field type of the cell data that's going to be transformed into.
+    ///
+    fn transform_type_option_cell_data(
+        &self,
+        cell_data: <Self as TypeOption>::CellData,
+        _decoded_field_type: &FieldType,
+    ) -> <Self as TypeOption>::CellData {
+        // Do nothing, just return the passed-in cell data
+        cell_data
+    }
+}
+
+pub trait TypeOptionTransformHandler {
+    fn transform(&mut self, old_type_option_field_type: FieldType, old_type_option_data: String);
+
+    fn json_str(&self) -> String;
+}
+
+impl<T> TypeOptionTransformHandler for T
+where
+    T: TypeOptionTransform + TypeOptionDataSerializer,
+{
+    fn transform(&mut self, old_type_option_field_type: FieldType, old_type_option_data: String) {
+        if self.transformable() {
+            self.transform_type_option(old_type_option_field_type, old_type_option_data)
+        }
+    }
+
+    fn json_str(&self) -> String {
+        self.json_str()
+    }
+}
+
 pub trait TypeOptionCellDataHandler {
 pub trait TypeOptionCellDataHandler {
     fn handle_cell_data(
     fn handle_cell_data(
         &self,
         &self,
@@ -31,24 +123,9 @@ pub trait TypeOptionCellDataHandler {
     fn stringify_cell_data(&self, cell_data: String, field_type: &FieldType, field_rev: &FieldRevision) -> String;
     fn stringify_cell_data(&self, cell_data: String, field_type: &FieldType, field_rev: &FieldRevision) -> String;
 }
 }
 
 
-pub trait TypeOptionCellData: TypeOption {
-    ///
-    /// Convert the decoded cell data into corresponding `Protobuf struct`.
-    /// For example:
-    ///    FieldType::URL => URLCellDataPB
-    ///    FieldType::Date=> DateCellDataPB
-    fn convert_into_pb_type(&self, cell_data: <Self as TypeOption>::CellData) -> <Self as TypeOption>::CellPBType;
-
-    /// Decodes the opaque cell data to corresponding data struct.
-    // For example, the cell data is timestamp if its field type is `FieldType::Date`. This cell
-    // data can not directly show to user. So it needs to be encode as the date string with custom
-    // format setting. Encode `1647251762` to `"Mar 14,2022`
-    fn decode_type_option_cell_data(&self, cell_data: String) -> FlowyResult<<Self as TypeOption>::CellData>;
-}
-
 impl<T> TypeOptionCellDataHandler for T
 impl<T> TypeOptionCellDataHandler for T
 where
 where
-    T: TypeOption + CellDataDecoder + CellDataChangeset + TypeOptionCellData,
+    T: TypeOption + CellDataDecoder + CellDataChangeset + TypeOptionCellData + TypeOptionTransform,
 {
 {
     fn handle_cell_data(
     fn handle_cell_data(
         &self,
         &self,
@@ -56,8 +133,11 @@ where
         field_type: &FieldType,
         field_type: &FieldType,
         field_rev: &FieldRevision,
         field_rev: &FieldRevision,
     ) -> FlowyResult<CellProtobufBlob> {
     ) -> FlowyResult<CellProtobufBlob> {
-        let cell_data = self.try_decode_cell_data(cell_data, field_type, field_rev)?;
-        CellProtobufBlob::from(self.convert_into_pb_type(cell_data))
+        let mut cell_data = self.try_decode_cell_data(cell_data, field_type, field_rev)?;
+        if self.transformable() {
+            cell_data = self.transform_type_option_cell_data(cell_data, field_type);
+        }
+        CellProtobufBlob::from(self.convert_to_protobuf(cell_data))
     }
     }
 
 
     fn stringify_cell_data(
     fn stringify_cell_data(
@@ -117,3 +197,48 @@ impl<'a> FieldRevisionExt<'a> {
         }
         }
     }
     }
 }
 }
+
+pub fn transform_type_option(
+    type_option_data: &str,
+    new_field_type: &FieldType,
+    old_type_option_data: Option<String>,
+    old_field_type: FieldType,
+) -> String {
+    let mut transform_handler = get_type_option_transform_handler(type_option_data, new_field_type);
+    if let Some(old_type_option_data) = old_type_option_data {
+        transform_handler.transform(old_field_type, old_type_option_data);
+    }
+    transform_handler.json_str()
+}
+
+pub fn get_type_option_transform_handler(
+    type_option_data: &str,
+    field_type: &FieldType,
+) -> Box<dyn TypeOptionTransformHandler> {
+    match field_type {
+        FieldType::RichText => {
+            Box::new(RichTextTypeOptionPB::from_json_str(type_option_data)) as Box<dyn TypeOptionTransformHandler>
+        }
+        FieldType::Number => {
+            Box::new(NumberTypeOptionPB::from_json_str(type_option_data)) as Box<dyn TypeOptionTransformHandler>
+        }
+        FieldType::DateTime => {
+            Box::new(DateTypeOptionPB::from_json_str(type_option_data)) as Box<dyn TypeOptionTransformHandler>
+        }
+        FieldType::SingleSelect => {
+            Box::new(SingleSelectTypeOptionPB::from_json_str(type_option_data)) as Box<dyn TypeOptionTransformHandler>
+        }
+        FieldType::MultiSelect => {
+            Box::new(MultiSelectTypeOptionPB::from_json_str(type_option_data)) as Box<dyn TypeOptionTransformHandler>
+        }
+        FieldType::Checkbox => {
+            Box::new(CheckboxTypeOptionPB::from_json_str(type_option_data)) as Box<dyn TypeOptionTransformHandler>
+        }
+        FieldType::URL => {
+            Box::new(URLTypeOptionPB::from_json_str(type_option_data)) as Box<dyn TypeOptionTransformHandler>
+        }
+        FieldType::Checklist => {
+            Box::new(ChecklistTypeOptionPB::from_json_str(type_option_data)) as Box<dyn TypeOptionTransformHandler>
+        }
+    }
+}

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

@@ -2,8 +2,8 @@ use crate::entities::{FieldType, TextFilterPB};
 use crate::impl_type_option;
 use crate::impl_type_option;
 use crate::services::cell::{AnyCellChangeset, CellDataChangeset, CellDataDecoder, FromCellString};
 use crate::services::cell::{AnyCellChangeset, CellDataChangeset, CellDataDecoder, FromCellString};
 use crate::services::field::{
 use crate::services::field::{
-    BoxTypeOptionBuilder, TypeOption, TypeOptionBuilder, TypeOptionCellData, TypeOptionConfiguration, URLCellData,
-    URLCellDataPB,
+    BoxTypeOptionBuilder, TypeOption, TypeOptionBuilder, TypeOptionCellData, TypeOptionConfiguration,
+    TypeOptionTransform, URLCellData, URLCellDataPB,
 };
 };
 use bytes::Bytes;
 use bytes::Bytes;
 use fancy_regex::Regex;
 use fancy_regex::Regex;
@@ -26,10 +26,6 @@ impl TypeOptionBuilder for URLTypeOptionBuilder {
     fn serializer(&self) -> &dyn TypeOptionDataSerializer {
     fn serializer(&self) -> &dyn TypeOptionDataSerializer {
         &self.0
         &self.0
     }
     }
-
-    fn transform(&mut self, _field_type: &FieldType, _type_option_data: String) {
-        // Do nothing
-    }
 }
 }
 
 
 #[derive(Debug, Clone, Serialize, Deserialize, Default, ProtoBuf)]
 #[derive(Debug, Clone, Serialize, Deserialize, Default, ProtoBuf)]
@@ -42,15 +38,17 @@ impl_type_option!(URLTypeOptionPB, FieldType::URL);
 impl TypeOption for URLTypeOptionPB {
 impl TypeOption for URLTypeOptionPB {
     type CellData = URLCellData;
     type CellData = URLCellData;
     type CellChangeset = URLCellChangeset;
     type CellChangeset = URLCellChangeset;
-    type CellPBType = URLCellDataPB;
+    type CellProtobufType = URLCellDataPB;
 }
 }
 
 
+impl TypeOptionTransform for URLTypeOptionPB {}
+
 impl TypeOptionConfiguration for URLTypeOptionPB {
 impl TypeOptionConfiguration for URLTypeOptionPB {
     type CellFilterConfiguration = TextFilterPB;
     type CellFilterConfiguration = TextFilterPB;
 }
 }
 
 
 impl TypeOptionCellData for URLTypeOptionPB {
 impl TypeOptionCellData for URLTypeOptionPB {
-    fn convert_into_pb_type(&self, cell_data: <Self as TypeOption>::CellData) -> <Self as TypeOption>::CellPBType {
+    fn convert_to_protobuf(&self, cell_data: <Self as TypeOption>::CellData) -> <Self as TypeOption>::CellProtobufType {
         cell_data.into()
         cell_data.into()
     }
     }
 
 

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

@@ -5,8 +5,7 @@ use crate::manager::GridUser;
 use crate::services::block_manager::GridBlockManager;
 use crate::services::block_manager::GridBlockManager;
 use crate::services::cell::{apply_cell_data_changeset, decode_type_cell_data, CellProtobufBlob};
 use crate::services::cell::{apply_cell_data_changeset, decode_type_cell_data, CellProtobufBlob};
 use crate::services::field::{
 use crate::services::field::{
-    default_type_option_builder_from_type, type_option_builder_from_bytes, type_option_builder_from_json_str,
-    FieldBuilder,
+    default_type_option_builder_from_type, transform_type_option, type_option_builder_from_bytes, FieldBuilder,
 };
 };
 
 
 use crate::services::filter::FilterType;
 use crate::services::filter::FilterType;
@@ -280,11 +279,13 @@ impl GridRevisionEditor {
         let type_option_transform =
         let type_option_transform =
             |old_field_type: FieldTypeRevision, old_type_option: Option<String>, new_type_option: String| {
             |old_field_type: FieldTypeRevision, old_type_option: Option<String>, new_type_option: String| {
                 let old_field_type: FieldType = old_field_type.into();
                 let old_field_type: FieldType = old_field_type.into();
-                let mut type_option_builder = type_option_builder_from_json_str(&new_type_option, new_field_type);
-                if let Some(old_type_option) = old_type_option {
-                    type_option_builder.transform(&old_field_type, old_type_option)
-                }
-                type_option_builder.serializer().json_str()
+                // let mut type_option_builder = type_option_builder_from_json_str(&new_type_option, new_field_type);
+                // if let Some(old_type_option) = old_type_option {
+                //     type_option_builder.transform(&old_field_type, old_type_option)
+                // }
+                // type_option_builder.serializer().json_str()
+
+                transform_type_option(&new_type_option, new_field_type, old_type_option, old_field_type)
             };
             };
 
 
         let _ = self
         let _ = self

+ 1 - 0
shared-lib/grid-rev-model/src/grid_rev.rs

@@ -3,6 +3,7 @@ use bytes::Bytes;
 use indexmap::IndexMap;
 use indexmap::IndexMap;
 use nanoid::nanoid;
 use nanoid::nanoid;
 use serde::{Deserialize, Serialize};
 use serde::{Deserialize, Serialize};
+use std::str::FromStr;
 use std::sync::Arc;
 use std::sync::Arc;
 
 
 pub fn gen_grid_id() -> String {
 pub fn gen_grid_id() -> String {