Browse Source

chore: separate cell operation from row mod

appflowy 2 years ago
parent
commit
45774093e1
19 changed files with 214 additions and 206 deletions
  1. 1 1
      frontend/rust-lib/flowy-grid/src/event_handler.rs
  2. 151 0
      frontend/rust-lib/flowy-grid/src/services/cell/any_cell_data.rs
  3. 5 153
      frontend/rust-lib/flowy-grid/src/services/cell/cell_operation.rs
  4. 5 0
      frontend/rust-lib/flowy-grid/src/services/cell/mod.rs
  5. 1 1
      frontend/rust-lib/flowy-grid/src/services/field/select_option.rs
  6. 4 6
      frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option.rs
  7. 3 3
      frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option.rs
  8. 4 4
      frontend/rust-lib/flowy-grid/src/services/field/type_options/multi_select_type_option.rs
  9. 9 6
      frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option/number_type_option.rs
  10. 4 4
      frontend/rust-lib/flowy-grid/src/services/field/type_options/single_select_type_option.rs
  11. 3 3
      frontend/rust-lib/flowy-grid/src/services/field/type_options/text_type_option.rs
  12. 11 14
      frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option.rs
  13. 1 1
      frontend/rust-lib/flowy-grid/src/services/field/type_options/util/cell_data_util.rs
  14. 2 3
      frontend/rust-lib/flowy-grid/src/services/filter/filter_service.rs
  15. 6 3
      frontend/rust-lib/flowy-grid/src/services/grid_editor.rs
  16. 1 0
      frontend/rust-lib/flowy-grid/src/services/mod.rs
  17. 0 2
      frontend/rust-lib/flowy-grid/src/services/row/mod.rs
  18. 1 1
      frontend/rust-lib/flowy-grid/src/services/row/row_builder.rs
  19. 2 1
      frontend/rust-lib/flowy-grid/tests/grid/row_test.rs

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

@@ -1,10 +1,10 @@
 use crate::entities::*;
 use crate::manager::GridManager;
+use crate::services::cell::AnyCellData;
 use crate::services::field::select_option::*;
 use crate::services::field::{
     default_type_option_builder_from_type, type_option_builder_from_json_str, DateChangesetParams, DateChangesetPayload,
 };
-use crate::services::row::AnyCellData;
 use flowy_error::{ErrorCode, FlowyError, FlowyResult};
 use flowy_grid_data_model::revision::FieldRevision;
 use flowy_sync::entities::grid::{FieldChangesetParams, GridSettingChangesetParams};

+ 151 - 0
frontend/rust-lib/flowy-grid/src/services/cell/any_cell_data.rs

@@ -0,0 +1,151 @@
+use crate::entities::FieldType;
+use bytes::Bytes;
+use flowy_error::{internal_error, FlowyError, FlowyResult};
+use flowy_grid_data_model::revision::CellRevision;
+use serde::{Deserialize, Serialize};
+use std::str::FromStr;
+/// AnyCellData is a generic CellData, you can parse the cell_data according to the field_type.
+/// When the type of field is changed, it's different from the field_type of AnyCellData.
+/// So it will return an empty data. You could check the CellDataOperation trait for more information.
+#[derive(Debug, Serialize, Deserialize)]
+pub struct AnyCellData {
+    pub cell_data: String,
+    pub field_type: FieldType,
+}
+
+impl std::str::FromStr for AnyCellData {
+    type Err = FlowyError;
+
+    fn from_str(s: &str) -> Result<Self, Self::Err> {
+        let type_option_cell_data: AnyCellData = serde_json::from_str(s)?;
+        Ok(type_option_cell_data)
+    }
+}
+
+impl std::convert::TryInto<AnyCellData> for String {
+    type Error = FlowyError;
+
+    fn try_into(self) -> Result<AnyCellData, Self::Error> {
+        AnyCellData::from_str(&self)
+    }
+}
+
+impl std::convert::TryFrom<&CellRevision> for AnyCellData {
+    type Error = FlowyError;
+
+    fn try_from(value: &CellRevision) -> Result<Self, Self::Error> {
+        Self::from_str(&value.data)
+    }
+}
+
+impl std::convert::TryFrom<&Option<CellRevision>> for AnyCellData {
+    type Error = FlowyError;
+
+    fn try_from(value: &Option<CellRevision>) -> Result<Self, Self::Error> {
+        match value {
+            None => Err(FlowyError::invalid_data().context("Expected CellRevision, but receive None")),
+            Some(cell_rev) => AnyCellData::try_from(cell_rev),
+        }
+    }
+}
+
+impl std::convert::TryFrom<Option<CellRevision>> for AnyCellData {
+    type Error = FlowyError;
+
+    fn try_from(value: Option<CellRevision>) -> Result<Self, Self::Error> {
+        Self::try_from(&value)
+    }
+}
+
+impl AnyCellData {
+    pub fn new(content: String, field_type: FieldType) -> Self {
+        AnyCellData {
+            cell_data: content,
+            field_type,
+        }
+    }
+
+    pub fn json(&self) -> String {
+        serde_json::to_string(self).unwrap_or_else(|_| "".to_owned())
+    }
+
+    pub fn is_number(&self) -> bool {
+        self.field_type == FieldType::Number
+    }
+
+    pub fn is_text(&self) -> bool {
+        self.field_type == FieldType::RichText
+    }
+
+    pub fn is_checkbox(&self) -> bool {
+        self.field_type == FieldType::Checkbox
+    }
+
+    pub fn is_date(&self) -> bool {
+        self.field_type == FieldType::DateTime
+    }
+
+    pub fn is_single_select(&self) -> bool {
+        self.field_type == FieldType::SingleSelect
+    }
+
+    pub fn is_multi_select(&self) -> bool {
+        self.field_type == FieldType::MultiSelect
+    }
+
+    pub fn is_url(&self) -> bool {
+        self.field_type == FieldType::URL
+    }
+
+    pub fn is_select_option(&self) -> bool {
+        self.field_type == FieldType::MultiSelect || self.field_type == FieldType::SingleSelect
+    }
+}
+
+/// The data is encoded by protobuf or utf8. You should choose the corresponding decode struct to parse it.
+///
+/// For example:
+///
+/// * Use DateCellData to parse the data when the FieldType is Date.
+/// * Use URLCellData to parse the data when the FieldType is URL.
+/// * Use String to parse the data when the FieldType is RichText, Number, or Checkbox.
+/// * Check out the implementation of CellDataOperation trait for more information.
+#[derive(Default)]
+pub struct DecodedCellData {
+    pub data: Vec<u8>,
+}
+
+impl DecodedCellData {
+    pub fn new<T: AsRef<[u8]>>(data: T) -> Self {
+        Self {
+            data: data.as_ref().to_vec(),
+        }
+    }
+
+    pub fn try_from_bytes<T: TryInto<Bytes>>(bytes: T) -> FlowyResult<Self>
+    where
+        <T as TryInto<Bytes>>::Error: std::fmt::Debug,
+    {
+        let bytes = bytes.try_into().map_err(internal_error)?;
+        Ok(Self { data: bytes.to_vec() })
+    }
+
+    pub fn parse<'a, T: TryFrom<&'a [u8]>>(&'a self) -> FlowyResult<T>
+    where
+        <T as TryFrom<&'a [u8]>>::Error: std::fmt::Debug,
+    {
+        T::try_from(self.data.as_ref()).map_err(internal_error)
+    }
+}
+
+impl ToString for DecodedCellData {
+    fn to_string(&self) -> String {
+        match String::from_utf8(self.data.clone()) {
+            Ok(s) => s,
+            Err(e) => {
+                tracing::error!("DecodedCellData to string failed: {:?}", e);
+                "".to_string()
+            }
+        }
+    }
+}

+ 5 - 153
frontend/rust-lib/flowy-grid/src/services/row/cell_data_operation.rs → frontend/rust-lib/flowy-grid/src/services/cell/cell_operation.rs

@@ -1,13 +1,12 @@
-use crate::entities::FieldType;
-use crate::services::field::*;
-use bytes::Bytes;
-use flowy_error::{internal_error, ErrorCode, FlowyError, FlowyResult};
+use flowy_error::{ErrorCode, FlowyError, FlowyResult};
 use flowy_grid_data_model::revision::{CellRevision, FieldRevision, FieldTypeRevision};
-use serde::{Deserialize, Serialize};
 
-use std::str::FromStr;
+use crate::entities::FieldType;
+use crate::services::cell::{AnyCellData, DecodedCellData};
+use crate::services::field::*;
 
 pub trait CellFilterOperation<T> {
+    /// Return true if any_cell_data match the filter condition.
     fn apply_filter(&self, any_cell_data: AnyCellData, filter: &T) -> FlowyResult<bool>;
 }
 
@@ -27,105 +26,6 @@ pub trait CellDataOperation<D, C> {
     /// SelectOptionCellChangeset,DateCellChangeset. etc.  
     fn apply_changeset(&self, changeset: CellDataChangeset<C>, cell_rev: Option<CellRevision>) -> FlowyResult<String>;
 }
-
-/// AnyCellData is a generic CellData, you can parse the cell_data according to the field_type.
-/// When the type of field is changed, it's different from the field_type of AnyCellData.
-/// So it will return an empty data. You could check the CellDataOperation trait for more information.
-#[derive(Debug, Serialize, Deserialize)]
-pub struct AnyCellData {
-    pub cell_data: String,
-    pub field_type: FieldType,
-}
-
-impl std::str::FromStr for AnyCellData {
-    type Err = FlowyError;
-
-    fn from_str(s: &str) -> Result<Self, Self::Err> {
-        let type_option_cell_data: AnyCellData = serde_json::from_str(s)?;
-        Ok(type_option_cell_data)
-    }
-}
-
-impl std::convert::TryInto<AnyCellData> for String {
-    type Error = FlowyError;
-
-    fn try_into(self) -> Result<AnyCellData, Self::Error> {
-        AnyCellData::from_str(&self)
-    }
-}
-
-impl std::convert::TryFrom<&CellRevision> for AnyCellData {
-    type Error = FlowyError;
-
-    fn try_from(value: &CellRevision) -> Result<Self, Self::Error> {
-        Self::from_str(&value.data)
-    }
-}
-
-impl std::convert::TryFrom<&Option<CellRevision>> for AnyCellData {
-    type Error = FlowyError;
-
-    fn try_from(value: &Option<CellRevision>) -> Result<Self, Self::Error> {
-        match value {
-            None => Err(FlowyError::invalid_data().context("Expected CellRevision, but receive None")),
-            Some(cell_rev) => AnyCellData::try_from(cell_rev),
-        }
-    }
-}
-
-impl std::convert::TryFrom<Option<CellRevision>> for AnyCellData {
-    type Error = FlowyError;
-
-    fn try_from(value: Option<CellRevision>) -> Result<Self, Self::Error> {
-        Self::try_from(&value)
-    }
-}
-
-impl AnyCellData {
-    pub fn new(content: String, field_type: FieldType) -> Self {
-        AnyCellData {
-            cell_data: content,
-            field_type,
-        }
-    }
-
-    pub fn json(&self) -> String {
-        serde_json::to_string(self).unwrap_or_else(|_| "".to_owned())
-    }
-
-    pub fn is_number(&self) -> bool {
-        self.field_type == FieldType::Number
-    }
-
-    pub fn is_text(&self) -> bool {
-        self.field_type == FieldType::RichText
-    }
-
-    pub fn is_checkbox(&self) -> bool {
-        self.field_type == FieldType::Checkbox
-    }
-
-    pub fn is_date(&self) -> bool {
-        self.field_type == FieldType::DateTime
-    }
-
-    pub fn is_single_select(&self) -> bool {
-        self.field_type == FieldType::SingleSelect
-    }
-
-    pub fn is_multi_select(&self) -> bool {
-        self.field_type == FieldType::MultiSelect
-    }
-
-    pub fn is_url(&self) -> bool {
-        self.field_type == FieldType::URL
-    }
-
-    pub fn is_select_option(&self) -> bool {
-        self.field_type == FieldType::MultiSelect || self.field_type == FieldType::SingleSelect
-    }
-}
-
 /// The changeset will be deserialized into specific data base on the FieldType.
 /// For example, it's String on FieldType::RichText, and SelectOptionChangeset on FieldType::SingleSelect
 pub fn apply_cell_data_changeset<C: ToString, T: AsRef<FieldRevision>>(
@@ -292,51 +192,3 @@ impl std::convert::From<String> for CellDataChangeset<String> {
         CellDataChangeset(Some(s))
     }
 }
-
-/// The data is encoded by protobuf or utf8. You should choose the corresponding decode struct to parse it.
-///
-/// For example:
-///
-/// * Use DateCellData to parse the data when the FieldType is Date.
-/// * Use URLCellData to parse the data when the FieldType is URL.
-/// * Use String to parse the data when the FieldType is RichText, Number, or Checkbox.
-/// * Check out the implementation of CellDataOperation trait for more information.
-#[derive(Default)]
-pub struct DecodedCellData {
-    pub data: Vec<u8>,
-}
-
-impl DecodedCellData {
-    pub fn new<T: AsRef<[u8]>>(data: T) -> Self {
-        Self {
-            data: data.as_ref().to_vec(),
-        }
-    }
-
-    pub fn try_from_bytes<T: TryInto<Bytes>>(bytes: T) -> FlowyResult<Self>
-    where
-        <T as TryInto<Bytes>>::Error: std::fmt::Debug,
-    {
-        let bytes = bytes.try_into().map_err(internal_error)?;
-        Ok(Self { data: bytes.to_vec() })
-    }
-
-    pub fn parse<'a, T: TryFrom<&'a [u8]>>(&'a self) -> FlowyResult<T>
-    where
-        <T as TryFrom<&'a [u8]>>::Error: std::fmt::Debug,
-    {
-        T::try_from(self.data.as_ref()).map_err(internal_error)
-    }
-}
-
-impl ToString for DecodedCellData {
-    fn to_string(&self) -> String {
-        match String::from_utf8(self.data.clone()) {
-            Ok(s) => s,
-            Err(e) => {
-                tracing::error!("DecodedCellData to string failed: {:?}", e);
-                "".to_string()
-            }
-        }
-    }
-}

+ 5 - 0
frontend/rust-lib/flowy-grid/src/services/cell/mod.rs

@@ -0,0 +1,5 @@
+mod any_cell_data;
+mod cell_operation;
+
+pub use any_cell_data::*;
+pub use cell_operation::*;

+ 1 - 1
frontend/rust-lib/flowy-grid/src/services/field/select_option.rs

@@ -1,6 +1,6 @@
 use crate::entities::{CellChangeset, CellIdentifier, CellIdentifierPayload, FieldType};
+use crate::services::cell::{AnyCellData, FromCellChangeset, FromCellString};
 use crate::services::field::{MultiSelectTypeOption, SingleSelectTypeOption};
-use crate::services::row::{AnyCellData, FromCellChangeset, FromCellString};
 use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
 use flowy_error::{internal_error, ErrorCode, FlowyError, FlowyResult};
 use flowy_grid_data_model::parser::NotEmptyStr;

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

@@ -1,10 +1,9 @@
 use crate::entities::{FieldType, GridCheckboxFilter};
 use crate::impl_type_option;
-use crate::services::field::{BoxTypeOptionBuilder, TypeOptionBuilder};
-use crate::services::row::{
-    AnyCellData, CellData, CellDataChangeset, CellDataOperation, CellFilterOperation,
-    DecodedCellData,
+use crate::services::cell::{
+    AnyCellData, CellData, CellDataChangeset, CellDataOperation, CellFilterOperation, DecodedCellData,
 };
+use crate::services::field::{BoxTypeOptionBuilder, TypeOptionBuilder};
 use bytes::Bytes;
 use flowy_derive::ProtoBuf;
 use flowy_error::{FlowyError, FlowyResult};
@@ -116,10 +115,9 @@ impl std::convert::TryFrom<AnyCellData> for CheckboxCellData {
 
 #[cfg(test)]
 mod tests {
+    use crate::services::cell::{apply_cell_data_changeset, decode_any_cell_data};
     use crate::services::field::type_options::checkbox_type_option::{NO, YES};
-
     use crate::services::field::FieldBuilder;
-    use crate::services::row::{apply_cell_data_changeset, decode_any_cell_data};
 
     use crate::entities::FieldType;
 

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

@@ -1,11 +1,11 @@
 use crate::entities::{CellChangeset, FieldType, GridDateFilter};
 use crate::entities::{CellIdentifier, CellIdentifierPayload};
 use crate::impl_type_option;
-use crate::services::field::{BoxTypeOptionBuilder, TypeOptionBuilder};
-use crate::services::row::{
+use crate::services::cell::{
     AnyCellData, CellData, CellDataChangeset, CellDataOperation, CellFilterOperation, DecodedCellData,
     FromCellChangeset, FromCellString,
 };
+use crate::services::field::{BoxTypeOptionBuilder, TypeOptionBuilder};
 use bytes::Bytes;
 use chrono::format::strftime::StrftimeItems;
 use chrono::{NaiveDateTime, Timelike};
@@ -377,9 +377,9 @@ impl FromCellChangeset for DateCellChangeset {
 #[cfg(test)]
 mod tests {
     use crate::entities::FieldType;
+    use crate::services::cell::{CellDataChangeset, CellDataOperation};
     use crate::services::field::FieldBuilder;
     use crate::services::field::{DateCellChangeset, DateCellData, DateFormat, DateTypeOption, TimeFormat};
-    use crate::services::row::{CellDataChangeset, CellDataOperation};
     use flowy_grid_data_model::revision::FieldRevision;
     use strum::IntoEnumIterator;
 

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

@@ -1,15 +1,15 @@
 use crate::entities::{FieldType, GridSelectOptionFilter};
 
 use crate::impl_type_option;
+use crate::services::cell::{
+    AnyCellData, CellData, CellDataChangeset, CellDataOperation, CellFilterOperation, DecodedCellData,
+};
 use crate::services::field::select_option::{
     make_selected_select_options, SelectOption, SelectOptionCellChangeset, SelectOptionCellData, SelectOptionIds,
     SelectOptionOperation, SelectedSelectOptions, SELECTION_IDS_SEPARATOR,
 };
 use crate::services::field::type_options::util::get_cell_data;
 use crate::services::field::{BoxTypeOptionBuilder, TypeOptionBuilder};
-use crate::services::row::{
-    AnyCellData, CellData, CellDataChangeset, CellDataOperation, CellFilterOperation, DecodedCellData,
-};
 use bytes::Bytes;
 use flowy_derive::ProtoBuf;
 use flowy_error::{FlowyError, FlowyResult};
@@ -141,10 +141,10 @@ impl TypeOptionBuilder for MultiSelectTypeOptionBuilder {
 #[cfg(test)]
 mod tests {
     use crate::entities::FieldType;
+    use crate::services::cell::CellDataOperation;
     use crate::services::field::select_option::*;
     use crate::services::field::FieldBuilder;
     use crate::services::field::{MultiSelectTypeOption, MultiSelectTypeOptionBuilder};
-    use crate::services::row::CellDataOperation;
     use flowy_grid_data_model::revision::FieldRevision;
 
     #[test]

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

@@ -1,12 +1,12 @@
 use crate::impl_type_option;
 
 use crate::entities::{FieldType, GridNumberFilter};
+use crate::services::cell::{
+    AnyCellData, CellData, CellDataChangeset, CellDataOperation, CellFilterOperation, DecodedCellData,
+};
 use crate::services::field::number_currency::Currency;
 use crate::services::field::type_options::number_type_option::format::*;
 use crate::services::field::{BoxTypeOptionBuilder, TypeOptionBuilder};
-use crate::services::row::{
-    AnyCellData, CellData, CellDataChangeset, CellDataOperation, CellFilterOperation, DecodedCellData,
-};
 use bytes::Bytes;
 use flowy_derive::ProtoBuf;
 use flowy_error::{FlowyError, FlowyResult};
@@ -136,8 +136,11 @@ impl CellDataOperation<String, String> for NumberTypeOption {
         }
     }
 
-    fn apply_changeset(&self, changeset: CellDataChangeset<String>, _cell_rev: Option<CellRevision>) -> Result<String, FlowyError>
-    {
+    fn apply_changeset(
+        &self,
+        changeset: CellDataChangeset<String>,
+        _cell_rev: Option<CellRevision>,
+    ) -> Result<String, FlowyError> {
         let changeset = changeset.try_into_inner()?;
         let data = changeset.trim().to_string();
         let _ = self.format_cell_data(&data)?;
@@ -249,9 +252,9 @@ impl ToString for NumberCellData {
 #[cfg(test)]
 mod tests {
     use crate::entities::FieldType;
+    use crate::services::cell::CellDataOperation;
     use crate::services::field::FieldBuilder;
     use crate::services::field::{strip_currency_symbol, NumberFormat, NumberTypeOption};
-    use crate::services::row::CellDataOperation;
     use flowy_grid_data_model::revision::FieldRevision;
     use strum::IntoEnumIterator;
 

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

@@ -1,13 +1,13 @@
 use crate::entities::{FieldType, GridSelectOptionFilter};
 use crate::impl_type_option;
+use crate::services::cell::{
+    AnyCellData, CellData, CellDataChangeset, CellDataOperation, CellFilterOperation, DecodedCellData,
+};
 use crate::services::field::select_option::{
     make_selected_select_options, SelectOption, SelectOptionCellChangeset, SelectOptionCellData, SelectOptionIds,
     SelectOptionOperation,
 };
 use crate::services::field::{BoxTypeOptionBuilder, TypeOptionBuilder};
-use crate::services::row::{
-    AnyCellData, CellData, CellDataChangeset, CellDataOperation, CellFilterOperation, DecodedCellData,
-};
 use bytes::Bytes;
 use flowy_derive::ProtoBuf;
 use flowy_error::{FlowyError, FlowyResult};
@@ -122,10 +122,10 @@ impl TypeOptionBuilder for SingleSelectTypeOptionBuilder {
 #[cfg(test)]
 mod tests {
     use crate::entities::FieldType;
+    use crate::services::cell::CellDataOperation;
     use crate::services::field::select_option::*;
     use crate::services::field::type_options::*;
     use crate::services::field::FieldBuilder;
-    use crate::services::row::CellDataOperation;
     use flowy_grid_data_model::revision::FieldRevision;
 
     #[test]

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

@@ -1,10 +1,10 @@
 use crate::entities::{FieldType, GridTextFilter};
 use crate::impl_type_option;
-use crate::services::field::{BoxTypeOptionBuilder, TypeOptionBuilder};
-use crate::services::row::{
+use crate::services::cell::{
     try_decode_cell_data, AnyCellData, CellData, CellDataChangeset, CellDataOperation, CellFilterOperation,
     DecodedCellData,
 };
+use crate::services::field::{BoxTypeOptionBuilder, TypeOptionBuilder};
 use bytes::Bytes;
 use flowy_derive::ProtoBuf;
 use flowy_error::{FlowyError, FlowyResult};
@@ -95,10 +95,10 @@ impl std::convert::TryFrom<AnyCellData> for TextCellData {
 #[cfg(test)]
 mod tests {
     use crate::entities::FieldType;
+    use crate::services::cell::CellDataOperation;
     use crate::services::field::select_option::*;
     use crate::services::field::FieldBuilder;
     use crate::services::field::*;
-    use crate::services::row::CellDataOperation;
 
     #[test]
     fn text_description_test() {

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

@@ -1,9 +1,9 @@
 use crate::entities::{FieldType, GridTextFilter};
 use crate::impl_type_option;
-use crate::services::field::{BoxTypeOptionBuilder, TextCellData, TypeOptionBuilder};
-use crate::services::row::{
+use crate::services::cell::{
     AnyCellData, CellData, CellDataChangeset, CellDataOperation, CellFilterOperation, DecodedCellData, FromCellString,
 };
+use crate::services::field::{BoxTypeOptionBuilder, TextCellData, TypeOptionBuilder};
 use bytes::Bytes;
 use fancy_regex::Regex;
 use flowy_derive::ProtoBuf;
@@ -59,8 +59,11 @@ impl CellDataOperation<URLCellData, String> for URLTypeOption {
         DecodedCellData::try_from_bytes(cell_data)
     }
 
-    fn apply_changeset(&self, changeset: CellDataChangeset<String>, _cell_rev: Option<CellRevision>) -> Result<String, FlowyError>
-    {
+    fn apply_changeset(
+        &self,
+        changeset: CellDataChangeset<String>,
+        _cell_rev: Option<CellRevision>,
+    ) -> Result<String, FlowyError> {
         let changeset = changeset.try_into_inner()?;
         let mut url = "".to_string();
         if let Ok(Some(m)) = URL_REGEX.find(&changeset) {
@@ -118,17 +121,11 @@ impl FromCellString for URLCellData {
     }
 }
 
-// impl std::convert::From<AnyCellData> for URLCellData {
-//     fn from(any_cell_data: AnyCellData) -> Self {
-//         URLCellData::from_str(&any_cell_data.cell_data).unwrap_or_default()
-//     }
-// }
-
 impl std::convert::TryFrom<AnyCellData> for URLCellData {
-    type Error = ();
+    type Error = FlowyError;
 
-    fn try_from(_value: AnyCellData) -> Result<Self, Self::Error> {
-        todo!()
+    fn try_from(data: AnyCellData) -> Result<Self, Self::Error> {
+        serde_json::from_str::<URLCellData>(&data.cell_data).map_err(internal_error)
     }
 }
 
@@ -142,9 +139,9 @@ lazy_static! {
 #[cfg(test)]
 mod tests {
     use crate::entities::FieldType;
+    use crate::services::cell::{CellData, CellDataOperation};
     use crate::services::field::FieldBuilder;
     use crate::services::field::{URLCellData, URLTypeOption};
-    use crate::services::row::{CellData, CellDataOperation};
     use flowy_grid_data_model::revision::FieldRevision;
 
     #[test]

+ 1 - 1
frontend/rust-lib/flowy-grid/src/services/field/type_options/util/cell_data_util.rs

@@ -1,4 +1,4 @@
-use crate::services::row::AnyCellData;
+use crate::services::cell::AnyCellData;
 use flowy_grid_data_model::revision::CellRevision;
 use std::str::FromStr;
 

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

@@ -1,6 +1,7 @@
 use crate::dart_notification::{send_dart_notification, GridNotification};
 use crate::entities::{FieldType, GridBlockChangeset};
 use crate::services::block_manager::GridBlockManager;
+use crate::services::cell::{AnyCellData, CellFilterOperation};
 use crate::services::field::{
     CheckboxTypeOption, DateTypeOption, MultiSelectTypeOption, NumberTypeOption, RichTextTypeOption,
     SingleSelectTypeOption, URLTypeOption,
@@ -9,15 +10,13 @@ use crate::services::filter::filter_cache::{
     reload_filter_cache, FilterCache, FilterId, FilterResult, FilterResultCache,
 };
 use crate::services::grid_editor_task::GridServiceTaskScheduler;
-use crate::services::row::{AnyCellData, CellFilterOperation, GridBlockSnapshot};
+use crate::services::row::GridBlockSnapshot;
 use crate::services::tasks::{FilterTaskContext, Task, TaskContent};
-
 use flowy_error::FlowyResult;
 use flowy_grid_data_model::revision::{CellRevision, FieldId, FieldRevision, RowRevision};
 use flowy_sync::client_grid::GridRevisionPad;
 use flowy_sync::entities::grid::GridSettingChangesetParams;
 use rayon::prelude::*;
-
 use std::collections::HashMap;
 use std::sync::Arc;
 use tokio::sync::RwLock;

+ 6 - 3
frontend/rust-lib/flowy-grid/src/services/grid_editor.rs

@@ -1,13 +1,16 @@
 use crate::dart_notification::{send_dart_notification, GridNotification};
 use crate::entities::CellIdentifier;
+use crate::entities::*;
 use crate::manager::{GridTaskSchedulerRwLock, GridUser};
 use crate::services::block_manager::GridBlockManager;
+use crate::services::cell::{apply_cell_data_changeset, decode_any_cell_data};
 use crate::services::field::{default_type_option_builder_from_type, type_option_builder_from_bytes, FieldBuilder};
 use crate::services::filter::{GridFilterChangeset, GridFilterService};
 use crate::services::persistence::block_index::BlockIndexCache;
-use crate::services::row::*;
-
-use crate::entities::*;
+use crate::services::row::{
+    make_grid_blocks, make_row_from_row_rev, make_row_rev_from_context, make_rows_from_row_revs,
+    CreateRowRevisionBuilder, CreateRowRevisionPayload, GridBlockSnapshot,
+};
 use bytes::Bytes;
 use flowy_error::{ErrorCode, FlowyError, FlowyResult};
 use flowy_grid_data_model::revision::*;

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

@@ -2,6 +2,7 @@ mod util;
 
 mod block_manager;
 pub mod block_revision_editor;
+pub mod cell;
 pub mod field;
 mod filter;
 pub mod grid_editor;

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

@@ -1,7 +1,5 @@
-mod cell_data_operation;
 mod row_builder;
 mod row_loader;
 
-pub use cell_data_operation::*;
 pub use row_builder::*;
 pub(crate) use row_loader::*;

+ 1 - 1
frontend/rust-lib/flowy-grid/src/services/row/row_builder.rs

@@ -1,5 +1,5 @@
+use crate::services::cell::apply_cell_data_changeset;
 use crate::services::field::select_option::SelectOptionCellChangeset;
-use crate::services::row::apply_cell_data_changeset;
 use flowy_error::{FlowyError, FlowyResult};
 use flowy_grid_data_model::revision::{gen_row_id, CellRevision, FieldRevision, RowRevision, DEFAULT_ROW_HEIGHT};
 use indexmap::IndexMap;

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

@@ -4,9 +4,10 @@ use crate::grid::script::EditorScript::*;
 use crate::grid::script::*;
 use chrono::NaiveDateTime;
 use flowy_grid::entities::FieldType;
+use flowy_grid::services::cell::decode_any_cell_data;
 use flowy_grid::services::field::select_option::SELECTION_IDS_SEPARATOR;
 use flowy_grid::services::field::{DateCellData, MultiSelectTypeOption, SingleSelectTypeOption};
-use flowy_grid::services::row::{decode_any_cell_data, CreateRowRevisionBuilder};
+use flowy_grid::services::row::CreateRowRevisionBuilder;
 use flowy_grid_data_model::revision::RowMetaChangeset;
 
 #[tokio::test]