Browse Source

chore: read group data from backend

appflowy 2 years ago
parent
commit
5de6a7447a
34 changed files with 366 additions and 301 deletions
  1. 0 7
      frontend/rust-lib/flowy-grid/src/entities/group_entities/checkbox_group.rs
  2. 56 0
      frontend/rust-lib/flowy-grid/src/entities/group_entities/configuration.rs
  3. 0 26
      frontend/rust-lib/flowy-grid/src/entities/group_entities/date_group.rs
  4. 2 12
      frontend/rust-lib/flowy-grid/src/entities/group_entities/mod.rs
  5. 0 7
      frontend/rust-lib/flowy-grid/src/entities/group_entities/number_group.rs
  6. 0 7
      frontend/rust-lib/flowy-grid/src/entities/group_entities/select_option_group.rs
  7. 0 7
      frontend/rust-lib/flowy-grid/src/entities/group_entities/text_group.rs
  8. 0 7
      frontend/rust-lib/flowy-grid/src/entities/group_entities/url_group.rs
  9. 14 2
      frontend/rust-lib/flowy-grid/src/services/cell/any_cell_data.rs
  10. 1 1
      frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option/checkbox_type_option_entities.rs
  11. 2 2
      frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/date_tests.rs
  12. 1 1
      frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/date_type_option_entities.rs
  13. 13 2
      frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option/number_type_option_entities.rs
  14. 1 1
      frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/multi_select_type_option.rs
  15. 2 2
      frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/select_option.rs
  16. 1 1
      frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/single_select_type_option.rs
  17. 4 4
      frontend/rust-lib/flowy-grid/src/services/field/type_options/text_type_option/text_type_option.rs
  18. 1 1
      frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option/url_tests.rs
  19. 1 1
      frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option/url_type_option_entities.rs
  20. 2 1
      frontend/rust-lib/flowy-grid/src/services/grid_editor.rs
  21. 0 70
      frontend/rust-lib/flowy-grid/src/services/group/group_configuration.rs
  22. 41 5
      frontend/rust-lib/flowy-grid/src/services/group/group_generator/checkbox_group.rs
  23. 0 5
      frontend/rust-lib/flowy-grid/src/services/group/group_generator/date_group.rs
  24. 73 38
      frontend/rust-lib/flowy-grid/src/services/group/group_generator/generator.rs
  25. 0 8
      frontend/rust-lib/flowy-grid/src/services/group/group_generator/mod.rs
  26. 0 5
      frontend/rust-lib/flowy-grid/src/services/group/group_generator/number_group.rs
  27. 67 32
      frontend/rust-lib/flowy-grid/src/services/group/group_generator/select_option_group.rs
  28. 0 5
      frontend/rust-lib/flowy-grid/src/services/group/group_generator/text_group.rs
  29. 0 5
      frontend/rust-lib/flowy-grid/src/services/group/group_generator/url_group.rs
  30. 75 25
      frontend/rust-lib/flowy-grid/src/services/group/group_service.rs
  31. 0 2
      frontend/rust-lib/flowy-grid/src/services/group/mod.rs
  32. 7 7
      frontend/rust-lib/flowy-grid/tests/grid/block_test/script.rs
  33. 1 1
      frontend/rust-lib/flowy-grid/tests/grid/script.rs
  34. 1 1
      shared-lib/flowy-sync/src/client_grid/grid_revision_pad.rs

+ 0 - 7
frontend/rust-lib/flowy-grid/src/entities/group_entities/checkbox_group.rs

@@ -1,7 +0,0 @@
-use flowy_derive::ProtoBuf;
-
-#[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)]
-pub struct CheckboxGroupConfigurationPB {
-    #[pb(index = 1)]
-    pub(crate) hide_empty: bool,
-}

+ 56 - 0
frontend/rust-lib/flowy-grid/src/entities/group_entities/configuration.rs

@@ -0,0 +1,56 @@
+use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
+
+#[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)]
+pub struct UrlGroupConfigurationPB {
+    #[pb(index = 1)]
+    hide_empty: bool,
+}
+
+#[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)]
+pub struct TextGroupConfigurationPB {
+    #[pb(index = 1)]
+    hide_empty: bool,
+}
+
+#[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)]
+pub struct SelectOptionGroupConfigurationPB {
+    #[pb(index = 1)]
+    hide_empty: bool,
+}
+
+#[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)]
+pub struct NumberGroupConfigurationPB {
+    #[pb(index = 1)]
+    hide_empty: bool,
+}
+
+#[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)]
+pub struct DateGroupConfigurationPB {
+    #[pb(index = 1)]
+    pub condition: DateCondition,
+
+    #[pb(index = 2)]
+    hide_empty: bool,
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, ProtoBuf_Enum)]
+#[repr(u8)]
+pub enum DateCondition {
+    Relative = 0,
+    Day = 1,
+    Week = 2,
+    Month = 3,
+    Year = 4,
+}
+
+impl std::default::Default for DateCondition {
+    fn default() -> Self {
+        DateCondition::Relative
+    }
+}
+
+#[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)]
+pub struct CheckboxGroupConfigurationPB {
+    #[pb(index = 1)]
+    pub(crate) hide_empty: bool,
+}

+ 0 - 26
frontend/rust-lib/flowy-grid/src/entities/group_entities/date_group.rs

@@ -1,26 +0,0 @@
-use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
-
-#[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)]
-pub struct DateGroupConfigurationPB {
-    #[pb(index = 1)]
-    pub condition: DateCondition,
-
-    #[pb(index = 2)]
-    hide_empty: bool,
-}
-
-#[derive(Debug, Clone, PartialEq, Eq, ProtoBuf_Enum)]
-#[repr(u8)]
-pub enum DateCondition {
-    Relative = 0,
-    Day = 1,
-    Week = 2,
-    Month = 3,
-    Year = 4,
-}
-
-impl std::default::Default for DateCondition {
-    fn default() -> Self {
-        DateCondition::Relative
-    }
-}

+ 2 - 12
frontend/rust-lib/flowy-grid/src/entities/group_entities/mod.rs

@@ -1,15 +1,5 @@
-mod checkbox_group;
-mod date_group;
+mod configuration;
 mod group;
-mod number_group;
-mod select_option_group;
-mod text_group;
-mod url_group;
 
-pub use checkbox_group::*;
-pub use date_group::*;
+pub use configuration::*;
 pub use group::*;
-pub use number_group::*;
-pub use select_option_group::*;
-pub use text_group::*;
-pub use url_group::*;

+ 0 - 7
frontend/rust-lib/flowy-grid/src/entities/group_entities/number_group.rs

@@ -1,7 +0,0 @@
-use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
-
-#[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)]
-pub struct NumberGroupConfigurationPB {
-    #[pb(index = 1)]
-    hide_empty: bool,
-}

+ 0 - 7
frontend/rust-lib/flowy-grid/src/entities/group_entities/select_option_group.rs

@@ -1,7 +0,0 @@
-use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
-
-#[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)]
-pub struct SelectOptionGroupConfigurationPB {
-    #[pb(index = 1)]
-    hide_empty: bool,
-}

+ 0 - 7
frontend/rust-lib/flowy-grid/src/entities/group_entities/text_group.rs

@@ -1,7 +0,0 @@
-use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
-
-#[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)]
-pub struct TextGroupConfigurationPB {
-    #[pb(index = 1)]
-    hide_empty: bool,
-}

+ 0 - 7
frontend/rust-lib/flowy-grid/src/entities/group_entities/url_group.rs

@@ -1,7 +0,0 @@
-use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
-
-#[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)]
-pub struct UrlGroupConfigurationPB {
-    #[pb(index = 1)]
-    hide_empty: bool,
-}

+ 14 - 2
frontend/rust-lib/flowy-grid/src/services/cell/any_cell_data.rs

@@ -114,6 +114,11 @@ impl AnyCellData {
 pub struct CellBytes(pub Bytes);
 
 pub trait CellBytesParser {
+    type Object;
+    fn parser(bytes: &Bytes) -> FlowyResult<Self::Object>;
+}
+
+pub trait CellBytesCustomParser {
     type Object;
     fn parse(&self, bytes: &Bytes) -> FlowyResult<Self::Object>;
 }
@@ -132,11 +137,18 @@ impl CellBytes {
         Ok(Self(bytes))
     }
 
-    pub fn with_parser<P>(&self) -> FlowyResult<P::Object>
+    pub fn parser<P>(&self) -> FlowyResult<P::Object>
     where
         P: CellBytesParser,
     {
-        P::parse(&self.0)
+        P::parser(&self.0)
+    }
+
+    pub fn custom_parser<P>(&self, parser: P) -> FlowyResult<P::Object>
+    where
+        P: CellBytesCustomParser,
+    {
+        parser.parse(&self.0)
     }
 
     // pub fn parse<'a, T: TryFrom<&'a [u8]>>(&'a self) -> FlowyResult<T>

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

@@ -60,7 +60,7 @@ impl ToString for CheckboxCellData {
 pub struct CheckboxCellDataParser();
 impl CellBytesParser for CheckboxCellDataParser {
     type Object = CheckboxCellData;
-    fn parse(&self, bytes: &Bytes) -> FlowyResult<Self::Object> {
+    fn parser(bytes: &Bytes) -> FlowyResult<Self::Object> {
         match String::from_utf8(bytes.to_vec()) {
             Ok(s) => CheckboxCellData::from_str(&s),
             Err(_) => Ok(CheckboxCellData("".to_string())),

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

@@ -3,7 +3,7 @@ mod tests {
     use crate::entities::FieldType;
     use crate::services::cell::CellDataOperation;
     use crate::services::field::*;
-    // use crate::services::field::{DateCellChangeset, DateCellData, DateFormat, DateTypeOption, TimeFormat};
+    // use crate::services::field::{DateCellChangeset, DateCellData, DateFormat, DateTypeOptionPB, TimeFormat};
     use flowy_grid_data_model::revision::FieldRevision;
     use strum::IntoEnumIterator;
 
@@ -137,7 +137,7 @@ mod tests {
         let decoded_data = type_option
             .decode_cell_data(encoded_data.into(), &FieldType::DateTime, field_rev)
             .unwrap()
-            .with_parser(DateCellDataParser())
+            .parser::<DateCellDataParser>()
             .unwrap();
 
         if type_option.include_time {

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

@@ -204,7 +204,7 @@ pub struct DateCellDataParser();
 impl CellBytesParser for DateCellDataParser {
     type Object = DateCellDataPB;
 
-    fn parse(&self, bytes: &Bytes) -> FlowyResult<Self::Object> {
+    fn parser(bytes: &Bytes) -> FlowyResult<Self::Object> {
         DateCellDataPB::try_from(bytes.as_ref()).map_err(internal_error)
     }
 }

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

@@ -1,4 +1,4 @@
-use crate::services::cell::CellBytesParser;
+use crate::services::cell::{CellBytesCustomParser, CellBytesParser};
 use crate::services::field::number_currency::Currency;
 use crate::services::field::{strip_currency_symbol, NumberFormat, STRIP_SYMBOL};
 use bytes::Bytes;
@@ -93,8 +93,19 @@ impl ToString for NumberCellData {
         }
     }
 }
-pub struct NumberCellDataParser(pub NumberFormat);
+pub struct NumberCellDataParser();
 impl CellBytesParser for NumberCellDataParser {
+    type Object = NumberCellData;
+    fn parser(bytes: &Bytes) -> FlowyResult<Self::Object> {
+        match String::from_utf8(bytes.to_vec()) {
+            Ok(s) => NumberCellData::from_format_str(&s, true, &NumberFormat::Num),
+            Err(_) => Ok(NumberCellData::default()),
+        }
+    }
+}
+
+pub struct NumberCellCustomDataParser(pub NumberFormat);
+impl CellBytesCustomParser for NumberCellCustomDataParser {
     type Object = NumberCellData;
     fn parse(&self, bytes: &Bytes) -> FlowyResult<Self::Object> {
         match String::from_utf8(bytes.to_vec()) {

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

@@ -180,7 +180,7 @@ mod tests {
             type_option
                 .decode_cell_data(cell_data.into(), &field_type, field_rev)
                 .unwrap()
-                .with_parser(SelectOptionCellDataParser())
+                .parser::<SelectOptionCellDataParser>()
                 .unwrap()
                 .select_options,
         );

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

@@ -206,7 +206,7 @@ impl std::ops::DerefMut for SelectOptionIds {
 pub struct SelectOptionIdsParser();
 impl CellBytesParser for SelectOptionIdsParser {
     type Object = SelectOptionIds;
-    fn parse(&self, bytes: &Bytes) -> FlowyResult<Self::Object> {
+    fn parser(bytes: &Bytes) -> FlowyResult<Self::Object> {
         match String::from_utf8(bytes.to_vec()) {
             Ok(s) => Ok(SelectOptionIds::from(s)),
             Err(_) => Ok(SelectOptionIds::from("".to_owned())),
@@ -218,7 +218,7 @@ pub struct SelectOptionCellDataParser();
 impl CellBytesParser for SelectOptionCellDataParser {
     type Object = SelectOptionCellDataPB;
 
-    fn parse(&self, bytes: &Bytes) -> FlowyResult<Self::Object> {
+    fn parser(bytes: &Bytes) -> FlowyResult<Self::Object> {
         SelectOptionCellDataPB::try_from(bytes.as_ref()).map_err(internal_error)
     }
 }

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

@@ -162,7 +162,7 @@ mod tests {
             type_option
                 .decode_cell_data(cell_data.into(), &field_type, field_rev)
                 .unwrap()
-                .with_parser(SelectOptionCellDataParser())
+                .parser::<SelectOptionCellDataParser>()
                 .unwrap()
                 .select_options,
         );

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

@@ -96,7 +96,7 @@ impl FromCellString for TextCellData {
 pub struct TextCellDataParser();
 impl CellBytesParser for TextCellDataParser {
     type Object = TextCellData;
-    fn parse(&self, bytes: &Bytes) -> FlowyResult<Self::Object> {
+    fn parser(bytes: &Bytes) -> FlowyResult<Self::Object> {
         match String::from_utf8(bytes.to_vec()) {
             Ok(s) => Ok(TextCellData(s)),
             Err(_) => Ok(TextCellData("".to_owned())),
@@ -124,7 +124,7 @@ mod tests {
             type_option
                 .decode_cell_data(1647251762.to_string().into(), &field_type, &date_time_field_rev)
                 .unwrap()
-                .with_parser(DateCellDataParser())
+                .parser::<DateCellDataParser>()
                 .unwrap()
                 .date,
             "Mar 14,2022".to_owned()
@@ -144,7 +144,7 @@ mod tests {
                     &single_select_field_rev
                 )
                 .unwrap()
-                .with_parser(SelectOptionCellDataParser())
+                .parser::<SelectOptionCellDataParser>()
                 .unwrap()
                 .select_options,
             vec![done_option],
@@ -167,7 +167,7 @@ mod tests {
             type_option
                 .decode_cell_data(cell_data.into(), &FieldType::MultiSelect, &multi_select_field_rev)
                 .unwrap()
-                .with_parser(SelectOptionCellDataParser())
+                .parser::<SelectOptionCellDataParser>()
                 .unwrap()
                 .select_options,
             vec![google_option, facebook_option]

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

@@ -184,7 +184,7 @@ mod tests {
         type_option
             .decode_cell_data(encoded_data.into(), field_type, field_rev)
             .unwrap()
-            .with_parser(URLCellDataParser())
+            .parser::<URLCellDataParser>()
             .unwrap()
     }
 }

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

@@ -30,7 +30,7 @@ pub struct URLCellDataParser();
 impl CellBytesParser for URLCellDataParser {
     type Object = URLCellDataPB;
 
-    fn parse(&self, bytes: &Bytes) -> FlowyResult<Self::Object> {
+    fn parser(bytes: &Bytes) -> FlowyResult<Self::Object> {
         URLCellDataPB::try_from(bytes.as_ref()).map_err(internal_error)
     }
 }

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

@@ -564,8 +564,9 @@ impl GridRevisionEditor {
         })
     }
 
+    #[tracing::instrument(level = "trace", skip_all, err)]
     pub async fn load_groups(&self) -> FlowyResult<RepeatedGridGroupPB> {
-        let groups = self.group_service.load_groups().await.unwrap_or(vec![]);
+        let groups = self.group_service.load_groups().await.unwrap_or_default();
         Ok(RepeatedGridGroupPB { items: groups })
     }
 

+ 0 - 70
frontend/rust-lib/flowy-grid/src/services/group/group_configuration.rs

@@ -1,70 +0,0 @@
-use crate::entities::{
-    CheckboxGroupConfigurationPB, DateGroupConfigurationPB, NumberGroupConfigurationPB,
-    SelectOptionGroupConfigurationPB, TextGroupConfigurationPB, UrlGroupConfigurationPB,
-};
-use crate::services::cell::CellBytes;
-use crate::services::field::{
-    CheckboxCellDataParser, DateCellDataParser, NumberCellDataParser, NumberFormat, SelectOptionCellDataParser,
-    TextCellDataParser, URLCellDataParser,
-};
-use crate::services::group::GroupAction;
-
-// impl GroupAction for TextGroupConfigurationPB {
-//     fn should_group(&self, content: &str, cell_bytes: CellBytes) -> bool {
-//         if let Ok(cell_data) = cell_bytes.with_parser(TextCellDataParser()) {
-//             cell_data.as_ref() == content
-//         } else {
-//             false
-//         }
-//     }
-// }
-//
-// impl GroupAction for NumberGroupConfigurationPB {
-//     fn should_group(&self, content: &str, cell_bytes: CellBytes) -> bool {
-//         if let Ok(cell_data) = cell_bytes.with_parser(NumberCellDataParser(NumberFormat::Num)) {
-//             false
-//         } else {
-//             false
-//         }
-//     }
-// }
-//
-// impl GroupAction for DateGroupConfigurationPB {
-//     fn should_group(&self, content: &str, cell_bytes: CellBytes) -> bool {
-//         if let Ok(cell_data) = cell_bytes.with_parser(DateCellDataParser()) {
-//             false
-//         } else {
-//             false
-//         }
-//     }
-// }
-//
-// impl GroupAction for SelectOptionGroupConfigurationPB {
-//     fn should_group(&self, content: &str, cell_bytes: CellBytes) -> bool {
-//         if let Ok(cell_data) = cell_bytes.with_parser(SelectOptionCellDataParser()) {
-//             false
-//         } else {
-//             false
-//         }
-//     }
-// }
-//
-// impl GroupAction for UrlGroupConfigurationPB {
-//     fn should_group(&self, content: &str, cell_bytes: CellBytes) -> bool {
-//         if let Ok(cell_data) = cell_bytes.with_parser(URLCellDataParser()) {
-//             false
-//         } else {
-//             false
-//         }
-//     }
-// }
-//
-// impl GroupAction for CheckboxGroupConfigurationPB {
-//     fn should_group(&self, content: &str, cell_bytes: CellBytes) -> bool {
-//         if let Ok(cell_data) = cell_bytes.with_parser(CheckboxCellDataParser()) {
-//             false
-//         } else {
-//             false
-//         }
-//     }
-// }

+ 41 - 5
frontend/rust-lib/flowy-grid/src/services/group/group_generator/checkbox_group.rs

@@ -1,7 +1,43 @@
 use crate::entities::CheckboxGroupConfigurationPB;
-use crate::services::cell::{AnyCellData, CellData, CellGroupOperation};
-use crate::services::field::{CheckboxCellData, CheckboxTypeOptionPB};
-use crate::services::group::GroupController;
-use flowy_error::FlowyResult;
 
-// pub type CheckboxGroupGenerator = GroupGenerator<CheckboxGroupConfigurationPB, CheckboxTypeOptionPB>;
+use crate::services::field::{CheckboxCellData, CheckboxCellDataParser, CheckboxTypeOptionPB, CHECK, UNCHECK};
+use crate::services::group::{Group, GroupAction, GroupCellContentProvider, GroupController, GroupGenerator};
+
+pub type CheckboxGroupController =
+    GroupController<CheckboxGroupConfigurationPB, CheckboxTypeOptionPB, CheckboxGroupGenerator, CheckboxCellDataParser>;
+
+pub struct CheckboxGroupGenerator();
+impl GroupGenerator for CheckboxGroupGenerator {
+    type ConfigurationType = CheckboxGroupConfigurationPB;
+    type TypeOptionType = CheckboxTypeOptionPB;
+
+    fn gen_groups(
+        _configuration: &Option<Self::ConfigurationType>,
+        _type_option: &Option<Self::TypeOptionType>,
+        _cell_content_provider: &dyn GroupCellContentProvider,
+    ) -> Vec<Group> {
+        let check_group = Group {
+            id: "true".to_string(),
+            desc: "".to_string(),
+            rows: vec![],
+            content: CHECK.to_string(),
+        };
+
+        let uncheck_group = Group {
+            id: "false".to_string(),
+            desc: "".to_string(),
+            rows: vec![],
+            content: UNCHECK.to_string(),
+        };
+
+        vec![check_group, uncheck_group]
+    }
+}
+
+impl GroupAction for CheckboxGroupController {
+    type CellDataType = CheckboxCellData;
+
+    fn should_group(&self, _content: &str, _cell_data: &Self::CellDataType) -> bool {
+        false
+    }
+}

+ 0 - 5
frontend/rust-lib/flowy-grid/src/services/group/group_generator/date_group.rs

@@ -1,5 +0,0 @@
-use crate::entities::CheckboxGroupConfigurationPB;
-use crate::services::field::DateTypeOptionPB;
-use crate::services::group::GroupController;
-
-// pub type CheckboxGroupGenerator = GroupGenerator<CheckboxGroupConfigurationPB, DateTypeOptionPB>;

+ 73 - 38
frontend/rust-lib/flowy-grid/src/services/group/group_generator/generator.rs

@@ -1,52 +1,70 @@
-use crate::services::cell::{decode_any_cell_data, CellBytes, CellBytesParser};
+use crate::entities::{GroupPB, RowPB};
+use crate::services::cell::{decode_any_cell_data, CellBytesParser};
 use bytes::Bytes;
 use flowy_error::FlowyResult;
 use flowy_grid_data_model::revision::{
-    CellRevision, FieldRevision, GroupConfigurationRevision, RowRevision, TypeOptionDataDeserializer,
+    FieldRevision, GroupConfigurationRevision, RowRevision, TypeOptionDataDeserializer,
 };
-use std::collections::HashMap;
+use indexmap::IndexMap;
 use std::marker::PhantomData;
 use std::sync::Arc;
 
-pub trait GroupAction<CD> {
-    fn should_group(&self, content: &str, cell_data: CD) -> bool;
+pub trait GroupAction {
+    type CellDataType;
+
+    fn should_group(&self, content: &str, cell_data: &Self::CellDataType) -> bool;
 }
 
 pub trait GroupCellContentProvider {
     /// We need to group the rows base on the deduplication cell content when the field type is
     /// RichText.
-    fn deduplication_cell_content(&self, field_id: &str) -> Vec<String> {
+    fn deduplication_cell_content(&self, _field_id: &str) -> Vec<String> {
         vec![]
     }
 }
 
-pub trait GroupGenerator<C, T> {
+pub trait GroupGenerator {
+    type ConfigurationType;
+    type TypeOptionType;
+
     fn gen_groups(
-        configuration: &Option<C>,
-        type_option: &Option<T>,
+        configuration: &Option<Self::ConfigurationType>,
+        type_option: &Option<Self::TypeOptionType>,
         cell_content_provider: &dyn GroupCellContentProvider,
-    ) -> HashMap<String, Group>;
+    ) -> Vec<Group>;
 }
 
 pub struct GroupController<C, T, G, CP> {
-    field_rev: Arc<FieldRevision>,
-    groups: HashMap<String, Group>,
-    type_option: Option<T>,
-    configuration: Option<C>,
+    pub field_rev: Arc<FieldRevision>,
+    pub groups: IndexMap<String, Group>,
+    pub type_option: Option<T>,
+    pub configuration: Option<C>,
     group_action_phantom: PhantomData<G>,
     cell_parser_phantom: PhantomData<CP>,
 }
 
 pub struct Group {
-    row_ids: Vec<String>,
-    content: String,
+    pub id: String,
+    pub desc: String,
+    pub rows: Vec<RowPB>,
+    pub content: String,
+}
+
+impl std::convert::From<Group> for GroupPB {
+    fn from(group: Group) -> Self {
+        Self {
+            group_id: group.id,
+            desc: group.desc,
+            rows: group.rows,
+        }
+    }
 }
 
 impl<C, T, G, CP> GroupController<C, T, G, CP>
 where
     C: TryFrom<Bytes, Error = protobuf::ProtobufError>,
     T: TypeOptionDataDeserializer,
-    G: GroupGenerator<C, T>,
+    G: GroupGenerator<ConfigurationType = C, TypeOptionType = T>,
 {
     pub fn new(
         field_rev: Arc<FieldRevision>,
@@ -57,46 +75,63 @@ where
             None => None,
             Some(content) => Some(C::try_from(Bytes::from(content))?),
         };
-        let field_type_rev = field_rev.field_type_rev.clone();
+        let field_type_rev = field_rev.field_type_rev;
         let type_option = field_rev.get_type_option_entry::<T>(field_type_rev);
+        let groups = G::gen_groups(&configuration, &type_option, cell_content_provider);
         Ok(Self {
             field_rev,
-            groups: G::gen_groups(&configuration, &type_option, cell_content_provider),
+            groups: groups.into_iter().map(|group| (group.id.clone(), group)).collect(),
             type_option,
             configuration,
             group_action_phantom: PhantomData,
             cell_parser_phantom: PhantomData,
         })
     }
+
+    pub fn take_groups(self) -> Vec<Group> {
+        self.groups.into_values().collect()
+    }
 }
 
 impl<C, T, G, CP> GroupController<C, T, G, CP>
 where
     CP: CellBytesParser,
-    Self: GroupAction<CP::Object>,
+    Self: GroupAction<CellDataType = CP::Object>,
 {
-    pub fn group_row(&mut self, row: &RowRevision) {
+    pub fn group_rows(&mut self, rows: &[Arc<RowRevision>]) -> FlowyResult<()> {
         if self.configuration.is_none() {
-            return;
+            return Ok(());
         }
-        if let Some(cell_rev) = row.cells.get(&self.field_rev.id) {
-            let mut group_row_id = None;
-            let cell_bytes = decode_any_cell_data(cell_rev.data.clone(), &self.field_rev);
-            // let cell_data = cell_bytes.with_parser(CP);
-            for group in self.groups.values() {
-                let cell_rev: CellRevision = cell_rev.clone();
-
-                // if self.should_group(&group.content, cell_bytes) {
-                //     group_row_id = Some(row.id.clone());
-                //     break;
-                // }
-            }
 
-            if let Some(group_row_id) = group_row_id {
-                self.groups.get_mut(&group_row_id).map(|group| {
-                    group.row_ids.push(group_row_id);
-                });
+        for row in rows {
+            if let Some(cell_rev) = row.cells.get(&self.field_rev.id) {
+                let mut records: Vec<GroupRecord> = vec![];
+
+                let cell_bytes = decode_any_cell_data(cell_rev.data.clone(), &self.field_rev);
+                let cell_data = cell_bytes.parser::<CP>()?;
+                for group in self.groups.values() {
+                    if self.should_group(&group.content, &cell_data) {
+                        records.push(GroupRecord {
+                            row: row.into(),
+                            group_id: group.id.clone(),
+                        });
+                        break;
+                    }
+                }
+
+                for record in records {
+                    if let Some(group) = self.groups.get_mut(&record.group_id) {
+                        group.rows.push(record.row);
+                    }
+                }
             }
         }
+
+        Ok(())
     }
 }
+
+struct GroupRecord {
+    row: RowPB,
+    group_id: String,
+}

+ 0 - 8
frontend/rust-lib/flowy-grid/src/services/group/group_generator/mod.rs

@@ -1,15 +1,7 @@
 mod checkbox_group;
-mod date_group;
 mod generator;
-mod number_group;
 mod select_option_group;
-mod text_group;
-mod url_group;
 
 pub use checkbox_group::*;
-pub use date_group::*;
 pub use generator::*;
-pub use number_group::*;
 pub use select_option_group::*;
-pub use text_group::*;
-pub use url_group::*;

+ 0 - 5
frontend/rust-lib/flowy-grid/src/services/group/group_generator/number_group.rs

@@ -1,5 +0,0 @@
-use crate::entities::NumberGroupConfigurationPB;
-use crate::services::field::NumberTypeOptionPB;
-use crate::services::group::GroupController;
-
-// pub type NumberGroupGenerator = GroupGenerator<NumberGroupConfigurationPB, NumberTypeOptionPB>;

+ 67 - 32
frontend/rust-lib/flowy-grid/src/services/group/group_generator/select_option_group.rs

@@ -1,12 +1,11 @@
 use crate::entities::SelectOptionGroupConfigurationPB;
-use crate::services::cell::CellBytes;
+
 use crate::services::field::{
-    MultiSelectTypeOptionPB, SelectOptionCellDataPB, SelectOptionCellDataParser, SelectedSelectOptions,
-    SingleSelectTypeOptionPB,
+    MultiSelectTypeOptionPB, SelectOptionCellDataPB, SelectOptionCellDataParser, SingleSelectTypeOptionPB,
 };
 use crate::services::group::{Group, GroupAction, GroupCellContentProvider, GroupController, GroupGenerator};
-use std::collections::HashMap;
 
+// SingleSelect
 pub type SingleSelectGroupController = GroupController<
     SelectOptionGroupConfigurationPB,
     SingleSelectTypeOptionPB,
@@ -15,38 +14,74 @@ pub type SingleSelectGroupController = GroupController<
 >;
 
 pub struct SingleSelectGroupGenerator();
-impl GroupGenerator<SelectOptionGroupConfigurationPB, SingleSelectTypeOptionPB> for SingleSelectGroupGenerator {
+impl GroupGenerator for SingleSelectGroupGenerator {
+    type ConfigurationType = SelectOptionGroupConfigurationPB;
+    type TypeOptionType = SingleSelectTypeOptionPB;
     fn gen_groups(
-        configuration: &Option<SelectOptionGroupConfigurationPB>,
-        type_option: &Option<SingleSelectTypeOptionPB>,
-        cell_content_provider: &dyn GroupCellContentProvider,
-    ) -> HashMap<String, Group> {
-        todo!()
+        _configuration: &Option<Self::ConfigurationType>,
+        type_option: &Option<Self::TypeOptionType>,
+        _cell_content_provider: &dyn GroupCellContentProvider,
+    ) -> Vec<Group> {
+        match type_option {
+            None => vec![],
+            Some(type_option) => type_option
+                .options
+                .iter()
+                .map(|option| Group {
+                    id: option.id.clone(),
+                    desc: option.name.clone(),
+                    rows: vec![],
+                    content: option.id.clone(),
+                })
+                .collect(),
+        }
     }
 }
 
-impl GroupAction<SelectOptionCellDataPB> for SingleSelectGroupController {
-    fn should_group(&self, content: &str, cell_data: SelectOptionCellDataPB) -> bool {
-        todo!()
+impl GroupAction for SingleSelectGroupController {
+    type CellDataType = SelectOptionCellDataPB;
+    fn should_group(&self, content: &str, cell_data: &SelectOptionCellDataPB) -> bool {
+        cell_data.select_options.iter().any(|option| option.id == content)
     }
 }
 
-// pub type MultiSelectGroupController =
-//     GroupController<SelectOptionGroupConfigurationPB, MultiSelectTypeOptionPB, MultiSelectGroupGenerator>;
-//
-// pub struct MultiSelectGroupGenerator();
-// impl GroupGenerator<SelectOptionGroupConfigurationPB, MultiSelectTypeOptionPB> for MultiSelectGroupGenerator {
-//     fn gen_groups(
-//         configuration: &Option<SelectOptionGroupConfigurationPB>,
-//         type_option: &Option<MultiSelectTypeOptionPB>,
-//         cell_content_provider: &dyn GroupCellContentProvider,
-//     ) -> HashMap<String, Group> {
-//         todo!()
-//     }
-// }
-//
-// impl GroupAction for MultiSelectGroupController {
-//     fn should_group(&self, content: &str, cell_bytes: CellBytes) -> bool {
-//         todo!()
-//     }
-// }
+// MultiSelect
+pub type MultiSelectGroupController = GroupController<
+    SelectOptionGroupConfigurationPB,
+    MultiSelectTypeOptionPB,
+    MultiSelectGroupGenerator,
+    SelectOptionCellDataParser,
+>;
+
+pub struct MultiSelectGroupGenerator();
+impl GroupGenerator for MultiSelectGroupGenerator {
+    type ConfigurationType = SelectOptionGroupConfigurationPB;
+    type TypeOptionType = MultiSelectTypeOptionPB;
+
+    fn gen_groups(
+        _configuration: &Option<Self::ConfigurationType>,
+        type_option: &Option<Self::TypeOptionType>,
+        _cell_content_provider: &dyn GroupCellContentProvider,
+    ) -> Vec<Group> {
+        match type_option {
+            None => vec![],
+            Some(type_option) => type_option
+                .options
+                .iter()
+                .map(|option| Group {
+                    id: option.id.clone(),
+                    desc: option.name.clone(),
+                    rows: vec![],
+                    content: option.id.clone(),
+                })
+                .collect(),
+        }
+    }
+}
+
+impl GroupAction for MultiSelectGroupController {
+    type CellDataType = SelectOptionCellDataPB;
+    fn should_group(&self, content: &str, cell_data: &SelectOptionCellDataPB) -> bool {
+        cell_data.select_options.iter().any(|option| option.id == content)
+    }
+}

+ 0 - 5
frontend/rust-lib/flowy-grid/src/services/group/group_generator/text_group.rs

@@ -1,5 +0,0 @@
-use crate::entities::TextGroupConfigurationPB;
-use crate::services::field::RichTextTypeOptionPB;
-use crate::services::group::GroupController;
-
-// pub type TextGroupGenerator = GroupGenerator<TextGroupConfigurationPB, RichTextTypeOptionPB>;

+ 0 - 5
frontend/rust-lib/flowy-grid/src/services/group/group_generator/url_group.rs

@@ -1,5 +0,0 @@
-use crate::entities::UrlGroupConfigurationPB;
-use crate::services::field::URLTypeOptionPB;
-use crate::services::group::GroupController;
-
-// pub type UrlGroupGenerator = GroupGenerator<UrlGroupConfigurationPB, URLTypeOptionPB>;

+ 75 - 25
frontend/rust-lib/flowy-grid/src/services/group/group_service.rs

@@ -1,15 +1,16 @@
+use crate::services::block_manager::GridBlockManager;
+use crate::services::grid_editor_task::GridServiceTaskScheduler;
+use crate::services::group::{
+    CheckboxGroupController, Group, GroupCellContentProvider, MultiSelectGroupController, SingleSelectGroupController,
+};
+
 use crate::entities::{
     CheckboxGroupConfigurationPB, DateGroupConfigurationPB, FieldType, GroupPB, NumberGroupConfigurationPB,
     SelectOptionGroupConfigurationPB, TextGroupConfigurationPB, UrlGroupConfigurationPB,
 };
-use crate::services::block_manager::GridBlockManager;
-use crate::services::cell::{decode_any_cell_data, CellBytes};
-use crate::services::field::TextCellDataParser;
-use crate::services::grid_editor_task::GridServiceTaskScheduler;
-use crate::services::group::{GroupAction, GroupCellContentProvider, SingleSelectGroupController};
 use bytes::Bytes;
 use flowy_error::FlowyResult;
-use flowy_grid_data_model::revision::{CellRevision, FieldRevision, GroupConfigurationRevision, RowRevision};
+use flowy_grid_data_model::revision::{gen_grid_group_id, FieldRevision, GroupConfigurationRevision, RowRevision};
 use flowy_sync::client_grid::GridRevisionPad;
 use std::sync::Arc;
 use tokio::sync::RwLock;
@@ -39,53 +40,102 @@ impl GridGroupService {
 
     pub(crate) async fn load_groups(&self) -> Option<Vec<GroupPB>> {
         let grid_pad = self.grid_pad.read().await;
-        let field_rev = find_group_field(grid_pad.fields())?;
-        let field_type: FieldType = field_rev.field_type_rev.clone().into();
-        let setting = grid_pad.get_setting_rev();
-        let mut configurations = setting.get_groups(&setting.layout, &field_rev.id, &field_rev.field_type_rev)?;
-
-        if configurations.is_empty() {
-            return None;
-        }
-        assert_eq!(configurations.len(), 1);
-        let configuration = (&*configurations.pop().unwrap()).clone();
+        let field_rev = find_group_field(grid_pad.fields()).unwrap();
+        let field_type: FieldType = field_rev.field_type_rev.into();
+        let configuration = self.get_group_configuration(field_rev).await;
 
         let blocks = self.block_manager.get_block_snapshots(None).await.unwrap();
-
         let row_revs = blocks
             .into_iter()
             .map(|block| block.row_revs)
             .flatten()
             .collect::<Vec<Arc<RowRevision>>>();
 
-        // let a = SingleSelectGroupController::new;
-        // let b = a(field_rev.clone(), configuration, &self.grid_pad);
+        match self.build_groups(&field_type, field_rev, row_revs, configuration) {
+            Ok(groups) => Some(groups),
+            Err(_) => None,
+        }
+    }
+
+    async fn get_group_configuration(&self, field_rev: &FieldRevision) -> GroupConfigurationRevision {
+        let grid_pad = self.grid_pad.read().await;
+        let setting = grid_pad.get_setting_rev();
+        let layout = &setting.layout;
+        let configurations = setting.get_groups(layout, &field_rev.id, &field_rev.field_type_rev);
+        match configurations {
+            None => self.default_group_configuration(field_rev),
+            Some(mut configurations) => {
+                assert_eq!(configurations.len(), 1);
+                (&*configurations.pop().unwrap()).clone()
+            }
+        }
+    }
 
-        let groups = match field_type {
+    fn default_group_configuration(&self, field_rev: &FieldRevision) -> GroupConfigurationRevision {
+        let field_type: FieldType = field_rev.field_type_rev.clone().into();
+        let bytes: Bytes = match field_type {
+            FieldType::RichText => TextGroupConfigurationPB::default().try_into().unwrap(),
+            FieldType::Number => NumberGroupConfigurationPB::default().try_into().unwrap(),
+            FieldType::DateTime => DateGroupConfigurationPB::default().try_into().unwrap(),
+            FieldType::SingleSelect => SelectOptionGroupConfigurationPB::default().try_into().unwrap(),
+            FieldType::MultiSelect => SelectOptionGroupConfigurationPB::default().try_into().unwrap(),
+            FieldType::Checkbox => CheckboxGroupConfigurationPB::default().try_into().unwrap(),
+            FieldType::URL => UrlGroupConfigurationPB::default().try_into().unwrap(),
+        };
+        GroupConfigurationRevision {
+            id: gen_grid_group_id(),
+            field_id: field_rev.id.clone(),
+            field_type_rev: field_rev.field_type_rev.clone(),
+            content: Some(bytes.to_vec()),
+        }
+    }
+
+    #[tracing::instrument(level = "trace", skip_all, err)]
+    fn build_groups(
+        &self,
+        field_type: &FieldType,
+        field_rev: &Arc<FieldRevision>,
+        row_revs: Vec<Arc<RowRevision>>,
+        configuration: GroupConfigurationRevision,
+    ) -> FlowyResult<Vec<GroupPB>> {
+        let groups: Vec<Group> = match field_type {
             FieldType::RichText => {
                 // let generator = GroupGenerator::<TextGroupConfigurationPB>::from_configuration(configuration);
+                vec![]
             }
             FieldType::Number => {
                 // let generator = GroupGenerator::<NumberGroupConfigurationPB>::from_configuration(configuration);
+                vec![]
             }
             FieldType::DateTime => {
                 // let generator = GroupGenerator::<DateGroupConfigurationPB>::from_configuration(configuration);
+                vec![]
             }
             FieldType::SingleSelect => {
-                let group_controller =
-                    SingleSelectGroupController::new(field_rev.clone(), configuration, &self.grid_pad);
+                let mut group_controller =
+                    SingleSelectGroupController::new(field_rev.clone(), configuration, &self.grid_pad)?;
+                let _ = group_controller.group_rows(&row_revs)?;
+                group_controller.take_groups()
             }
             FieldType::MultiSelect => {
-                // let group_generator = MultiSelectGroupControllern(configuration);
+                let mut group_controller =
+                    MultiSelectGroupController::new(field_rev.clone(), configuration, &self.grid_pad)?;
+                let _ = group_controller.group_rows(&row_revs)?;
+                group_controller.take_groups()
             }
             FieldType::Checkbox => {
-                // let generator = GroupGenerator::<CheckboxGroupConfigurationPB>::from_configuration(configuration);
+                let mut group_controller =
+                    CheckboxGroupController::new(field_rev.clone(), configuration, &self.grid_pad)?;
+                let _ = group_controller.group_rows(&row_revs)?;
+                group_controller.take_groups()
             }
             FieldType::URL => {
                 // let generator = GroupGenerator::<UrlGroupConfigurationPB>::from_configuration(configuration);
+                vec![]
             }
         };
-        None
+
+        Ok(groups.into_iter().map(GroupPB::from).collect())
     }
 }
 

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

@@ -1,7 +1,5 @@
-mod group_configuration;
 mod group_generator;
 mod group_service;
 
-pub(crate) use group_configuration::*;
 pub(crate) use group_generator::*;
 pub(crate) use group_service::*;

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

@@ -162,7 +162,7 @@ impl GridRowTest {
                     .get_cell_bytes(&cell_id)
                     .await
                     .unwrap()
-                    .with_parser(TextCellDataParser())
+                    .parser::<TextCellDataParser>()
                     .unwrap();
 
                 assert_eq!(cell_data.as_ref(), &expected);
@@ -177,7 +177,7 @@ impl GridRowTest {
                     .get_cell_bytes(&cell_id)
                     .await
                     .unwrap()
-                    .with_parser(NumberCellDataParser(number_type_option.format))
+                    .custom_parser(NumberCellCustomDataParser(number_type_option.format))
                     .unwrap();
                 assert_eq!(cell_data.to_string(), expected);
             }
@@ -187,7 +187,7 @@ impl GridRowTest {
                     .get_cell_bytes(&cell_id)
                     .await
                     .unwrap()
-                    .with_parser(DateCellDataParser())
+                    .parser::<DateCellDataParser>()
                     .unwrap();
 
                 assert_eq!(cell_data.date, expected);
@@ -198,7 +198,7 @@ impl GridRowTest {
                     .get_cell_bytes(&cell_id)
                     .await
                     .unwrap()
-                    .with_parser(SelectOptionCellDataParser())
+                    .parser::<SelectOptionCellDataParser>()
                     .unwrap();
                 let select_option = cell_data.select_options.first().unwrap();
                 assert_eq!(select_option.name, expected);
@@ -209,7 +209,7 @@ impl GridRowTest {
                     .get_cell_bytes(&cell_id)
                     .await
                     .unwrap()
-                    .with_parser(SelectOptionCellDataParser())
+                    .parser::<SelectOptionCellDataParser>()
                     .unwrap();
 
                 let s = cell_data
@@ -228,7 +228,7 @@ impl GridRowTest {
                     .get_cell_bytes(&cell_id)
                     .await
                     .unwrap()
-                    .with_parser(CheckboxCellDataParser())
+                    .parser::<CheckboxCellDataParser>()
                     .unwrap();
                 assert_eq!(cell_data.to_string(), expected);
             }
@@ -238,7 +238,7 @@ impl GridRowTest {
                     .get_cell_bytes(&cell_id)
                     .await
                     .unwrap()
-                    .with_parser(URLCellDataParser())
+                    .parser::<URLCellDataParser>()
                     .unwrap();
 
                 assert_eq!(cell_data.content, expected);

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

@@ -259,7 +259,7 @@ pub fn create_text_field(grid_id: &str) -> (InsertFieldParams, FieldMeta) {
     let cloned_field_meta = field_meta.clone();
 
     let type_option_data = field_meta
-        .get_type_option_entry::<RichTextTypeOption>(&field_meta.field_type)
+        .get_type_option_entry::<RichTextTypeOptionPB>(&field_meta.field_type)
         .unwrap()
         .protobuf_bytes()
         .to_vec();

+ 1 - 1
shared-lib/flowy-sync/src/client_grid/grid_revision_pad.rs

@@ -572,7 +572,7 @@ fn make_group_revision(params: &CreateGridGroupParams) -> GroupConfigurationRevi
     GroupConfigurationRevision {
         id: gen_grid_group_id(),
         field_id: params.field_id.clone(),
-        field_type_rev: params.field_type_rev.clone(),
+        field_type_rev: params.field_type_rev,
         content: params.content.clone(),
     }
 }