From 91b2917d603b9dc674bca8f282abe34f0e7a1b42 Mon Sep 17 00:00:00 2001 From: appflowy <annie@appflowy.io> Date: Sat, 20 Aug 2022 15:40:13 +0800 Subject: [PATCH] chore: reader and writter for group configuration --- .../flowy-grid/src/entities/field_entities.rs | 1 - .../rust-lib/flowy-grid/src/entities/mod.rs | 2 - .../src/entities/setting_entities.rs | 30 +- .../flowy-grid/src/entities/sort_entities.rs | 68 ----- .../rust-lib/flowy-grid/src/event_handler.rs | 1 - .../src/services/filter/filter_service.rs | 3 +- .../flowy-grid/src/services/grid_editor.rs | 92 +++--- .../src/services/grid_view_editor.rs | 143 ++++++--- .../src/services/grid_view_manager.rs | 5 +- .../flowy-grid/src/services/group/action.rs | 23 ++ .../src/services/group/configuration.rs | 76 +++++ .../checkbox_controller.rs | 44 ++- .../{controllers => controller_impls}/mod.rs | 2 - .../select_option_controller/mod.rs | 6 + .../multi_select_controller.rs | 110 +++++++ .../single_select_controller.rs | 111 +++++++ .../select_option_controller/util.rs | 108 +++++++ .../controllers/select_option_controller.rs | 286 ------------------ .../flowy-grid/src/services/group/entities.rs | 73 +++++ .../{controllers => }/group_controller.rs | 190 ++++-------- .../src/services/group/group_service.rs | 113 ++++--- .../flowy-grid/src/services/group/mod.rs | 10 +- .../src/services/setting/setting_builder.rs | 50 +-- .../src/revision/filter_rev.rs | 9 + .../src/revision/grid_setting_rev.rs | 147 +-------- .../src/revision/grid_view.rs | 104 ++++++- .../src/revision/group_rev.rs | 65 ++++ .../flowy-grid-data-model/src/revision/mod.rs | 2 + .../src/client_grid/view_revision_pad.rs | 36 +-- 29 files changed, 1015 insertions(+), 895 deletions(-) delete mode 100644 frontend/rust-lib/flowy-grid/src/entities/sort_entities.rs create mode 100644 frontend/rust-lib/flowy-grid/src/services/group/action.rs create mode 100644 frontend/rust-lib/flowy-grid/src/services/group/configuration.rs rename frontend/rust-lib/flowy-grid/src/services/group/{controllers => controller_impls}/checkbox_controller.rs (59%) rename frontend/rust-lib/flowy-grid/src/services/group/{controllers => controller_impls}/mod.rs (71%) create mode 100644 frontend/rust-lib/flowy-grid/src/services/group/controller_impls/select_option_controller/mod.rs create mode 100644 frontend/rust-lib/flowy-grid/src/services/group/controller_impls/select_option_controller/multi_select_controller.rs create mode 100644 frontend/rust-lib/flowy-grid/src/services/group/controller_impls/select_option_controller/single_select_controller.rs create mode 100644 frontend/rust-lib/flowy-grid/src/services/group/controller_impls/select_option_controller/util.rs delete mode 100644 frontend/rust-lib/flowy-grid/src/services/group/controllers/select_option_controller.rs create mode 100644 frontend/rust-lib/flowy-grid/src/services/group/entities.rs rename frontend/rust-lib/flowy-grid/src/services/group/{controllers => }/group_controller.rs (57%) create mode 100644 shared-lib/flowy-grid-data-model/src/revision/filter_rev.rs diff --git a/frontend/rust-lib/flowy-grid/src/entities/field_entities.rs b/frontend/rust-lib/flowy-grid/src/entities/field_entities.rs index 0993853b8e..271cbcf424 100644 --- a/frontend/rust-lib/flowy-grid/src/entities/field_entities.rs +++ b/frontend/rust-lib/flowy-grid/src/entities/field_entities.rs @@ -2,7 +2,6 @@ use flowy_derive::{ProtoBuf, ProtoBuf_Enum}; use flowy_error::ErrorCode; use flowy_grid_data_model::parser::NotEmptyStr; use flowy_grid_data_model::revision::{FieldRevision, FieldTypeRevision}; -use flowy_sync::entities::grid::FieldChangesetParams; use serde_repr::*; use std::sync::Arc; diff --git a/frontend/rust-lib/flowy-grid/src/entities/mod.rs b/frontend/rust-lib/flowy-grid/src/entities/mod.rs index 96c7a9ba60..eb11d982a4 100644 --- a/frontend/rust-lib/flowy-grid/src/entities/mod.rs +++ b/frontend/rust-lib/flowy-grid/src/entities/mod.rs @@ -6,7 +6,6 @@ mod grid_entities; mod group_entities; mod row_entities; mod setting_entities; -mod sort_entities; pub use block_entities::*; pub use cell_entities::*; @@ -16,4 +15,3 @@ pub use grid_entities::*; pub use group_entities::*; pub use row_entities::*; pub use setting_entities::*; -pub use sort_entities::*; diff --git a/frontend/rust-lib/flowy-grid/src/entities/setting_entities.rs b/frontend/rust-lib/flowy-grid/src/entities/setting_entities.rs index 67fcc884e9..9c02a2c692 100644 --- a/frontend/rust-lib/flowy-grid/src/entities/setting_entities.rs +++ b/frontend/rust-lib/flowy-grid/src/entities/setting_entities.rs @@ -1,13 +1,12 @@ use crate::entities::{ - CreatGroupParams, CreateFilterParams, CreateGridFilterPayloadPB, CreateGridGroupPayloadPB, CreateGridSortPayloadPB, - CreateSortParams, DeleteFilterParams, DeleteFilterPayloadPB, DeleteGroupParams, DeleteGroupPayloadPB, - RepeatedGridConfigurationFilterPB, RepeatedGridGroupConfigurationPB, RepeatedGridSortPB, + CreatGroupParams, CreateFilterParams, CreateGridFilterPayloadPB, CreateGridGroupPayloadPB, DeleteFilterParams, + DeleteFilterPayloadPB, DeleteGroupParams, DeleteGroupPayloadPB, RepeatedGridConfigurationFilterPB, + RepeatedGridGroupConfigurationPB, }; use flowy_derive::{ProtoBuf, ProtoBuf_Enum}; use flowy_error::ErrorCode; use flowy_grid_data_model::parser::NotEmptyStr; use flowy_grid_data_model::revision::LayoutRevision; -use flowy_sync::entities::grid::GridSettingChangesetParams; use std::collections::HashMap; use std::convert::TryInto; use strum::IntoEnumIterator; @@ -27,9 +26,6 @@ pub struct GridSettingPB { #[pb(index = 4)] pub group_configuration_by_field_id: HashMap<String, RepeatedGridGroupConfigurationPB>, - - #[pb(index = 5)] - pub sorts_by_field_id: HashMap<String, RepeatedGridSortPB>, } #[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)] @@ -99,12 +95,6 @@ pub struct GridSettingChangesetPayloadPB { #[pb(index = 6, one_of)] pub delete_group: Option<DeleteGroupPayloadPB>, - - #[pb(index = 7, one_of)] - pub insert_sort: Option<CreateGridSortPayloadPB>, - - #[pb(index = 8, one_of)] - pub delete_sort: Option<String>, } impl TryInto<GridSettingChangesetParams> for GridSettingChangesetPayloadPB { @@ -135,16 +125,6 @@ impl TryInto<GridSettingChangesetParams> for GridSettingChangesetPayloadPB { None => None, }; - let insert_sort = match self.insert_sort { - None => None, - Some(payload) => Some(payload.try_into()?), - }; - - let delete_sort = match self.delete_sort { - None => None, - Some(filter_id) => Some(NotEmptyStr::parse(filter_id).map_err(|_| ErrorCode::FieldIdIsEmpty)?.0), - }; - Ok(GridSettingChangesetParams { grid_id: view_id, layout_type: self.layout_type.into(), @@ -152,8 +132,6 @@ impl TryInto<GridSettingChangesetParams> for GridSettingChangesetPayloadPB { delete_filter, insert_group, delete_group, - insert_sort, - delete_sort, }) } } @@ -165,8 +143,6 @@ pub struct GridSettingChangesetParams { pub delete_filter: Option<DeleteFilterParams>, pub insert_group: Option<CreatGroupParams>, pub delete_group: Option<DeleteGroupParams>, - pub insert_sort: Option<CreateSortParams>, - pub delete_sort: Option<String>, } impl GridSettingChangesetParams { diff --git a/frontend/rust-lib/flowy-grid/src/entities/sort_entities.rs b/frontend/rust-lib/flowy-grid/src/entities/sort_entities.rs deleted file mode 100644 index 28486a1ee6..0000000000 --- a/frontend/rust-lib/flowy-grid/src/entities/sort_entities.rs +++ /dev/null @@ -1,68 +0,0 @@ -use flowy_derive::ProtoBuf; -use flowy_error::ErrorCode; -use flowy_grid_data_model::parser::NotEmptyStr; -use flowy_grid_data_model::revision::SortConfigurationRevision; -use std::convert::TryInto; -use std::sync::Arc; - -#[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)] -pub struct GridSort { - #[pb(index = 1)] - pub id: String, - - #[pb(index = 2, one_of)] - pub field_id: Option<String>, -} - -impl std::convert::From<&SortConfigurationRevision> for GridSort { - fn from(rev: &SortConfigurationRevision) -> Self { - GridSort { - id: rev.id.clone(), - - field_id: rev.field_id.clone(), - } - } -} - -#[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)] -pub struct RepeatedGridSortPB { - #[pb(index = 1)] - pub items: Vec<GridSort>, -} - -impl std::convert::From<Vec<Arc<SortConfigurationRevision>>> for RepeatedGridSortPB { - fn from(revs: Vec<Arc<SortConfigurationRevision>>) -> Self { - RepeatedGridSortPB { - items: revs.into_iter().map(|rev| rev.as_ref().into()).collect(), - } - } -} - -impl std::convert::From<Vec<GridSort>> for RepeatedGridSortPB { - fn from(items: Vec<GridSort>) -> Self { - Self { items } - } -} - -#[derive(ProtoBuf, Debug, Default, Clone)] -pub struct CreateGridSortPayloadPB { - #[pb(index = 1, one_of)] - pub field_id: Option<String>, -} - -impl TryInto<CreateSortParams> for CreateGridSortPayloadPB { - type Error = ErrorCode; - - fn try_into(self) -> Result<CreateSortParams, Self::Error> { - let field_id = match self.field_id { - None => None, - Some(field_id) => Some(NotEmptyStr::parse(field_id).map_err(|_| ErrorCode::FieldIdIsEmpty)?.0), - }; - - Ok(CreateSortParams { field_id }) - } -} - -pub struct CreateSortParams { - pub field_id: Option<String>, -} diff --git a/frontend/rust-lib/flowy-grid/src/event_handler.rs b/frontend/rust-lib/flowy-grid/src/event_handler.rs index f9f5e39399..47df88b976 100644 --- a/frontend/rust-lib/flowy-grid/src/event_handler.rs +++ b/frontend/rust-lib/flowy-grid/src/event_handler.rs @@ -10,7 +10,6 @@ use crate::services::field::{ use crate::services::row::make_row_from_row_rev; use flowy_error::{ErrorCode, FlowyError, FlowyResult}; use flowy_grid_data_model::revision::FieldRevision; -use flowy_sync::entities::grid::{FieldChangesetParams, GridSettingChangesetParams}; use lib_dispatch::prelude::{data_result, AppData, Data, DataResult}; use std::sync::Arc; diff --git a/frontend/rust-lib/flowy-grid/src/services/filter/filter_service.rs b/frontend/rust-lib/flowy-grid/src/services/filter/filter_service.rs index a2831c0ad9..8335a36fb2 100644 --- a/frontend/rust-lib/flowy-grid/src/services/filter/filter_service.rs +++ b/frontend/rust-lib/flowy-grid/src/services/filter/filter_service.rs @@ -4,7 +4,7 @@ #![allow(unused_imports)] #![allow(unused_results)] use crate::dart_notification::{send_dart_notification, GridNotification}; -use crate::entities::{FieldType, GridBlockChangesetPB}; +use crate::entities::{FieldType, GridBlockChangesetPB, GridSettingChangesetParams}; use crate::services::block_manager::GridBlockManager; use crate::services::cell::{AnyCellData, CellFilterOperation}; use crate::services::field::{ @@ -20,7 +20,6 @@ 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; diff --git a/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs b/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs index 055501e117..0559cfa364 100644 --- a/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs +++ b/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs @@ -15,7 +15,6 @@ use flowy_error::{ErrorCode, FlowyError, FlowyResult}; use flowy_grid_data_model::revision::*; use flowy_revision::{RevisionCloudService, RevisionCompactor, RevisionManager, RevisionObjectBuilder}; use flowy_sync::client_grid::{GridRevisionChangeset, GridRevisionPad, JsonDeserializer}; -use flowy_sync::entities::grid::{FieldChangesetParams, GridSettingChangesetParams}; use flowy_sync::entities::revision::Revision; use flowy_sync::errors::CollaborateResult; use flowy_sync::util::make_text_delta_from_revisions; @@ -101,14 +100,14 @@ impl GridRevisionEditor { grid_id, name: Some(field.name), desc: Some(field.desc), - field_type: Some(field.field_type.into()), + field_type: Some(field.field_type.clone().into()), frozen: Some(field.frozen), visibility: Some(field.visibility), width: Some(field.width), type_option_data: Some(type_option_data), }; - let _ = self.update_field_rev(changeset, field.field_type.clone()).await?; + let _ = self.update_field_rev(changeset, field.field_type).await?; let _ = self.notify_did_update_grid_field(&field_id).await?; } else { let _ = self @@ -262,60 +261,59 @@ impl GridRevisionEditor { } async fn update_field_rev(&self, params: FieldChangesetParams, field_type: FieldType) -> FlowyResult<()> { - let _ = self - .modify(|grid| { - let deserializer = TypeOptionJsonDeserializer(field_type); + self.modify(|grid| { + let deserializer = TypeOptionJsonDeserializer(field_type); - let changeset = grid.modify_field(¶ms.field_id, |field| { - let mut is_changed = None; - if let Some(name) = changeset.name { - field.name = name; - is_changed = Some(()) - } + let changeset = grid.modify_field(¶ms.field_id, |field| { + let mut is_changed = None; + if let Some(name) = params.name { + field.name = name; + is_changed = Some(()) + } - if let Some(desc) = changeset.desc { - field.desc = desc; - is_changed = Some(()) - } + if let Some(desc) = params.desc { + field.desc = desc; + is_changed = Some(()) + } - if let Some(field_type) = changeset.field_type { - field.ty = field_type; - is_changed = Some(()) - } + if let Some(field_type) = params.field_type { + field.ty = field_type; + is_changed = Some(()) + } - if let Some(frozen) = changeset.frozen { - field.frozen = frozen; - is_changed = Some(()) - } + if let Some(frozen) = params.frozen { + field.frozen = frozen; + is_changed = Some(()) + } - if let Some(visibility) = changeset.visibility { - field.visibility = visibility; - is_changed = Some(()) - } + if let Some(visibility) = params.visibility { + field.visibility = visibility; + is_changed = Some(()) + } - if let Some(width) = changeset.width { - field.width = width; - is_changed = Some(()) - } + if let Some(width) = params.width { + field.width = width; + is_changed = Some(()) + } - if let Some(type_option_data) = changeset.type_option_data { - match deserializer.deserialize(type_option_data) { - Ok(json_str) => { - let field_type = field.ty; - field.insert_type_option_str(&field_type, json_str); - is_changed = Some(()) - } - Err(err) => { - tracing::error!("Deserialize data to type option json failed: {}", err); - } + if let Some(type_option_data) = params.type_option_data { + match deserializer.deserialize(type_option_data) { + Ok(json_str) => { + let field_type = field.ty; + field.insert_type_option_str(&field_type, json_str); + is_changed = Some(()) + } + Err(err) => { + tracing::error!("Deserialize data to type option json failed: {}", err); } } + } - Ok(is_changed) - })?; - Ok(changeset) - }) - .await?; + Ok(is_changed) + })?; + Ok(changeset) + }) + .await } pub async fn create_block(&self, block_meta_rev: GridBlockMetaRevision) -> FlowyResult<()> { diff --git a/frontend/rust-lib/flowy-grid/src/services/grid_view_editor.rs b/frontend/rust-lib/flowy-grid/src/services/grid_view_editor.rs index ac1e905d8a..9a7173035a 100644 --- a/frontend/rust-lib/flowy-grid/src/services/grid_view_editor.rs +++ b/frontend/rust-lib/flowy-grid/src/services/grid_view_editor.rs @@ -1,18 +1,23 @@ use crate::dart_notification::{send_dart_notification, GridNotification}; use crate::entities::{ - CreateRowParams, GridFilterConfiguration, GridSettingPB, GroupPB, GroupRowsChangesetPB, InsertedRowPB, RowPB, + CreateRowParams, GridFilterConfiguration, GridLayout, GridLayoutPB, GridSettingChangesetParams, GridSettingPB, + GroupPB, GroupRowsChangesetPB, InsertedRowPB, RepeatedGridConfigurationFilterPB, RepeatedGridGroupConfigurationPB, + RowPB, }; use crate::services::grid_editor_task::GridServiceTaskScheduler; use crate::services::grid_view_manager::{GridViewFieldDelegate, GridViewRowDelegate}; -use crate::services::group::{default_group_configuration, GroupConfigurationDelegate, GroupService}; -use crate::services::setting::make_grid_setting; +use crate::services::group::{ + default_group_configuration, GroupConfigurationReader, GroupConfigurationWriter, GroupService, +}; use flowy_error::{FlowyError, FlowyResult}; -use flowy_grid_data_model::revision::{FieldRevision, GroupConfigurationRevision, RowChangeset, RowRevision}; +use flowy_grid_data_model::revision::{ + FieldRevision, FieldTypeRevision, GroupConfigurationRevision, RowChangeset, RowRevision, +}; use flowy_revision::{RevisionCloudService, RevisionManager, RevisionObjectBuilder}; use flowy_sync::client_grid::{GridViewRevisionChangeset, GridViewRevisionPad}; -use flowy_sync::entities::grid::GridSettingChangesetParams; use flowy_sync::entities::revision::Revision; use lib_infra::future::{wrap_future, AFFuture, FutureResult}; +use std::collections::HashMap; use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::Arc; use tokio::sync::RwLock; @@ -46,7 +51,14 @@ impl GridViewRevisionEditor { let view_revision_pad = rev_manager.load::<GridViewRevisionPadBuilder>(Some(cloud)).await?; let pad = Arc::new(RwLock::new(view_revision_pad)); let rev_manager = Arc::new(rev_manager); - let group_service = GroupService::new(Box::new(pad.clone())).await; + + let configuration_reader = GroupConfigurationReaderImpl(pad.clone()); + let configuration_writer = GroupConfigurationWriterImpl { + user_id: user_id.to_owned(), + rev_manager: rev_manager.clone(), + view_pad: pad.clone(), + }; + let group_service = GroupService::new(configuration_reader, configuration_writer).await; let user_id = user_id.to_owned(); let did_load_group = AtomicBool::new(false); Ok(Self { @@ -167,7 +179,7 @@ impl GridViewRevisionEditor { pub(crate) async fn get_setting(&self) -> GridSettingPB { let field_revs = self.field_delegate.get_field_revs().await; - let grid_setting = make_grid_setting(self.pad.read().await.get_setting_rev(), &field_revs); + let grid_setting = make_grid_setting(&*self.pad.read().await, &field_revs); grid_setting } @@ -177,13 +189,9 @@ impl GridViewRevisionEditor { todo!() } - // pub(crate) async fn insert_group(&self, params: CreateGroupParams) -> FlowyResult<()> { - // - // } - pub(crate) async fn get_filters(&self) -> Vec<GridFilterConfiguration> { let field_revs = self.field_delegate.get_field_revs().await; - match self.pad.read().await.get_setting_rev().get_all_filters(&field_revs) { + match self.pad.read().await.get_all_filters(&field_revs) { None => vec![], Some(filters) => filters .into_values() @@ -207,28 +215,24 @@ impl GridViewRevisionEditor { match f(&mut *write_guard)? { None => {} Some(change) => { - let _ = self.apply_change(change).await?; + let _ = apply_change(&self.user_id, self.rev_manager.clone(), change).await?; } } Ok(()) } +} - async fn apply_change(&self, change: GridViewRevisionChangeset) -> FlowyResult<()> { - let GridViewRevisionChangeset { delta, md5 } = change; - let user_id = self.user_id.clone(); - let (base_rev_id, rev_id) = self.rev_manager.next_rev_id_pair(); - let delta_data = delta.json_bytes(); - let revision = Revision::new( - &self.rev_manager.object_id, - base_rev_id, - rev_id, - delta_data, - &user_id, - md5, - ); - let _ = self.rev_manager.add_local_revision(&revision).await?; - Ok(()) - } +async fn apply_change( + user_id: &str, + rev_manager: Arc<RevisionManager>, + change: GridViewRevisionChangeset, +) -> FlowyResult<()> { + let GridViewRevisionChangeset { delta, md5 } = change; + let (base_rev_id, rev_id) = rev_manager.next_rev_id_pair(); + let delta_data = delta.json_bytes(); + let revision = Revision::new(&rev_manager.object_id, base_rev_id, rev_id, delta_data, &user_id, md5); + let _ = rev_manager.add_local_revision(&revision).await?; + Ok(()) } struct GridViewRevisionCloudService { @@ -253,19 +257,82 @@ impl RevisionObjectBuilder for GridViewRevisionPadBuilder { } } -impl GroupConfigurationDelegate for Arc<RwLock<GridViewRevisionPad>> { - fn get_group_configuration(&self, field_rev: Arc<FieldRevision>) -> AFFuture<GroupConfigurationRevision> { - let view_pad = self.clone(); +struct GroupConfigurationReaderImpl(Arc<RwLock<GridViewRevisionPad>>); + +impl GroupConfigurationReader for GroupConfigurationReaderImpl { + fn get_group_configuration(&self, field_rev: Arc<FieldRevision>) -> AFFuture<Arc<GroupConfigurationRevision>> { + let view_pad = self.0.clone(); wrap_future(async move { - let grid_pad = view_pad.read().await; - let configurations = grid_pad.get_groups(&field_rev.id, &field_rev.ty); + let view_pad = view_pad.read().await; + let configurations = view_pad.get_groups(&field_rev.id, &field_rev.ty); match configurations { - None => default_group_configuration(&field_rev), - Some(mut configurations) => { - assert_eq!(configurations.len(), 1); - (&*configurations.pop().unwrap()).clone() + None => { + let default_configuration = default_group_configuration(&field_rev); + Arc::new(default_configuration) } + Some(configuration) => configuration, } }) } } + +struct GroupConfigurationWriterImpl { + user_id: String, + rev_manager: Arc<RevisionManager>, + view_pad: Arc<RwLock<GridViewRevisionPad>>, +} + +impl GroupConfigurationWriter for GroupConfigurationWriterImpl { + fn save_group_configuration( + &self, + field_id: &str, + field_type: FieldTypeRevision, + configuration: Arc<GroupConfigurationRevision>, + ) -> AFFuture<FlowyResult<()>> { + let user_id = self.user_id.clone(); + let rev_manager = self.rev_manager.clone(); + let view_pad = self.view_pad.clone(); + let field_id = field_id.to_owned(); + + wrap_future(async move { + let configuration = (&*configuration).clone(); + match view_pad + .write() + .await + .insert_group_configuration(&field_id, &field_type, configuration)? + { + None => Ok(()), + Some(changeset) => apply_change(&user_id, rev_manager, changeset).await, + } + }) + } +} + +pub fn make_grid_setting(view_pad: &GridViewRevisionPad, field_revs: &[Arc<FieldRevision>]) -> GridSettingPB { + let current_layout_type: GridLayout = view_pad.layout.clone().into(); + let filters_by_field_id = view_pad + .get_all_filters(field_revs) + .map(|filters_by_field_id| { + filters_by_field_id + .into_iter() + .map(|(k, v)| (k, v.into())) + .collect::<HashMap<String, RepeatedGridConfigurationFilterPB>>() + }) + .unwrap_or_default(); + let groups_by_field_id = view_pad + .get_all_groups(field_revs) + .map(|groups_by_field_id| { + groups_by_field_id + .into_iter() + .map(|(k, v)| (k, v.into())) + .collect::<HashMap<String, RepeatedGridGroupConfigurationPB>>() + }) + .unwrap_or_default(); + + GridSettingPB { + layouts: GridLayoutPB::all(), + current_layout_type, + filter_configuration_by_field_id: filters_by_field_id, + group_configuration_by_field_id: groups_by_field_id, + } +} diff --git a/frontend/rust-lib/flowy-grid/src/services/grid_view_manager.rs b/frontend/rust-lib/flowy-grid/src/services/grid_view_manager.rs index 178befc10a..42c4ff1c65 100644 --- a/frontend/rust-lib/flowy-grid/src/services/grid_view_manager.rs +++ b/frontend/rust-lib/flowy-grid/src/services/grid_view_manager.rs @@ -1,4 +1,6 @@ -use crate::entities::{CreateRowParams, GridFilterConfiguration, GridSettingPB, RepeatedGridGroupPB, RowPB}; +use crate::entities::{ + CreateRowParams, GridFilterConfiguration, GridSettingChangesetParams, GridSettingPB, RepeatedGridGroupPB, RowPB, +}; use crate::manager::GridUser; use crate::services::grid_editor_task::GridServiceTaskScheduler; use crate::services::grid_view_editor::GridViewRevisionEditor; @@ -8,7 +10,6 @@ use flowy_error::FlowyResult; use flowy_grid_data_model::revision::{FieldRevision, RowChangeset, RowRevision}; use flowy_revision::disk::SQLiteGridViewRevisionPersistence; use flowy_revision::{RevisionCompactor, RevisionManager, RevisionPersistence, SQLiteRevisionSnapshotPersistence}; -use flowy_sync::entities::grid::GridSettingChangesetParams; use flowy_sync::entities::revision::Revision; use flowy_sync::util::make_text_delta_from_revisions; use lib_infra::future::AFFuture; diff --git a/frontend/rust-lib/flowy-grid/src/services/group/action.rs b/frontend/rust-lib/flowy-grid/src/services/group/action.rs new file mode 100644 index 0000000000..a495fe0a1f --- /dev/null +++ b/frontend/rust-lib/flowy-grid/src/services/group/action.rs @@ -0,0 +1,23 @@ +use crate::entities::GroupRowsChangesetPB; + +use flowy_grid_data_model::revision::{FieldRevision, RowChangeset, RowRevision}; + +pub trait GroupAction: Send + Sync { + type CellDataType; + fn can_group(&self, content: &str, cell_data: &Self::CellDataType) -> bool; + fn add_row_if_match(&mut self, row_rev: &RowRevision, cell_data: &Self::CellDataType) -> Vec<GroupRowsChangesetPB>; + fn remove_row_if_match( + &mut self, + row_rev: &RowRevision, + cell_data: &Self::CellDataType, + ) -> Vec<GroupRowsChangesetPB>; + + fn move_row_if_match( + &mut self, + field_rev: &FieldRevision, + row_rev: &RowRevision, + row_changeset: &mut RowChangeset, + cell_data: &Self::CellDataType, + to_row_id: &str, + ) -> Vec<GroupRowsChangesetPB>; +} diff --git a/frontend/rust-lib/flowy-grid/src/services/group/configuration.rs b/frontend/rust-lib/flowy-grid/src/services/group/configuration.rs new file mode 100644 index 0000000000..3d737c307f --- /dev/null +++ b/frontend/rust-lib/flowy-grid/src/services/group/configuration.rs @@ -0,0 +1,76 @@ +use flowy_error::FlowyResult; +use flowy_grid_data_model::revision::{ + FieldRevision, FieldTypeRevision, GroupConfigurationContentSerde, GroupConfigurationRevision, GroupRecordRevision, +}; +use lib_infra::future::AFFuture; +use std::sync::Arc; + +pub trait GroupConfigurationReader: Send + Sync + 'static { + fn get_group_configuration(&self, field_rev: Arc<FieldRevision>) -> AFFuture<Arc<GroupConfigurationRevision>>; +} + +pub trait GroupConfigurationWriter: Send + Sync + 'static { + fn save_group_configuration( + &self, + field_id: &str, + field_type: FieldTypeRevision, + configuration: Arc<GroupConfigurationRevision>, + ) -> AFFuture<FlowyResult<()>>; +} + +pub trait GroupConfigurationAction: Send + Sync { + fn group_records(&self) -> &[GroupRecordRevision]; + fn save_groups(&self) -> FlowyResult<()>; + fn hide_group(&self, group_id: &str) -> FlowyResult<()>; + fn show_group(&self, group_id: &str) -> FlowyResult<()>; +} + +pub struct GenericGroupConfiguration<C> { + field_rev: Arc<FieldRevision>, + reader: Arc<dyn GroupConfigurationReader>, + writer: Arc<dyn GroupConfigurationWriter>, + configuration: C, +} + +impl<C> GenericGroupConfiguration<C> +where + C: GroupConfigurationContentSerde, +{ + pub async fn new( + field_rev: Arc<FieldRevision>, + reader: Arc<dyn GroupConfigurationReader>, + writer: Arc<dyn GroupConfigurationWriter>, + ) -> FlowyResult<Self> { + let configuration = reader.get_group_configuration(field_rev.clone()).await; + let configuration = C::from_configuration(&configuration.content)?; + Ok(Self { + field_rev, + reader, + writer, + configuration, + }) + } +} + +impl<T> GroupConfigurationReader for Arc<T> +where + T: GroupConfigurationReader, +{ + fn get_group_configuration(&self, field_rev: Arc<FieldRevision>) -> AFFuture<Arc<GroupConfigurationRevision>> { + (**self).get_group_configuration(field_rev) + } +} + +impl<T> GroupConfigurationWriter for Arc<T> +where + T: GroupConfigurationWriter, +{ + fn save_group_configuration( + &self, + field_id: &str, + field_type: FieldTypeRevision, + configuration: Arc<GroupConfigurationRevision>, + ) -> AFFuture<FlowyResult<()>> { + (**self).save_group_configuration(field_id, field_type, configuration) + } +} diff --git a/frontend/rust-lib/flowy-grid/src/services/group/controllers/checkbox_controller.rs b/frontend/rust-lib/flowy-grid/src/services/group/controller_impls/checkbox_controller.rs similarity index 59% rename from frontend/rust-lib/flowy-grid/src/services/group/controllers/checkbox_controller.rs rename to frontend/rust-lib/flowy-grid/src/services/group/controller_impls/checkbox_controller.rs index c1284dd659..fca49513c8 100644 --- a/frontend/rust-lib/flowy-grid/src/services/group/controllers/checkbox_controller.rs +++ b/frontend/rust-lib/flowy-grid/src/services/group/controller_impls/checkbox_controller.rs @@ -1,20 +1,42 @@ -use crate::entities::{CheckboxGroupConfigurationPB, GroupRowsChangesetPB}; - -use flowy_grid_data_model::revision::{FieldRevision, RowChangeset, RowRevision}; - +use crate::entities::GroupRowsChangesetPB; use crate::services::field::{CheckboxCellData, CheckboxCellDataParser, CheckboxTypeOptionPB, CHECK, UNCHECK}; -use crate::services::group::{GenericGroupController, Group, GroupController, GroupGenerator, Groupable}; +use crate::services::group::action::GroupAction; +use crate::services::group::configuration::{GenericGroupConfiguration, GroupConfigurationAction}; +use crate::services::group::entities::Group; +use crate::services::group::group_controller::{GenericGroupController, GroupController, GroupGenerator}; +use flowy_error::FlowyResult; +use flowy_grid_data_model::revision::{ + CheckboxGroupConfigurationRevision, FieldRevision, GroupRecordRevision, RowChangeset, RowRevision, +}; pub type CheckboxGroupController = GenericGroupController< - CheckboxGroupConfigurationPB, + CheckboxGroupConfigurationRevision, CheckboxTypeOptionPB, CheckboxGroupGenerator, CheckboxCellDataParser, >; -impl Groupable for CheckboxGroupController { - type CellDataType = CheckboxCellData; +pub type CheckboxGroupConfiguration = GenericGroupConfiguration<CheckboxGroupConfigurationRevision>; +impl GroupConfigurationAction for CheckboxGroupConfiguration { + fn group_records(&self) -> &[GroupRecordRevision] { + todo!() + } + fn save_groups(&self) -> FlowyResult<()> { + todo!() + } + + fn hide_group(&self, group_id: &str) -> FlowyResult<()> { + todo!() + } + + fn show_group(&self, group_id: &str) -> FlowyResult<()> { + todo!() + } +} + +impl GroupAction for CheckboxGroupController { + type CellDataType = CheckboxCellData; fn can_group(&self, _content: &str, _cell_data: &Self::CellDataType) -> bool { false } @@ -55,13 +77,13 @@ impl GroupController for CheckboxGroupController { pub struct CheckboxGroupGenerator(); impl GroupGenerator for CheckboxGroupGenerator { - type ConfigurationType = CheckboxGroupConfigurationPB; + type ConfigurationType = CheckboxGroupConfiguration; type TypeOptionType = CheckboxTypeOptionPB; fn generate_groups( field_id: &str, - _configuration: &Option<Self::ConfigurationType>, - _type_option: &Option<Self::TypeOptionType>, + configuration: &Self::ConfigurationType, + type_option: &Option<Self::TypeOptionType>, ) -> Vec<Group> { let check_group = Group::new( "true".to_string(), diff --git a/frontend/rust-lib/flowy-grid/src/services/group/controllers/mod.rs b/frontend/rust-lib/flowy-grid/src/services/group/controller_impls/mod.rs similarity index 71% rename from frontend/rust-lib/flowy-grid/src/services/group/controllers/mod.rs rename to frontend/rust-lib/flowy-grid/src/services/group/controller_impls/mod.rs index 29ce5d091e..974f311a48 100644 --- a/frontend/rust-lib/flowy-grid/src/services/group/controllers/mod.rs +++ b/frontend/rust-lib/flowy-grid/src/services/group/controller_impls/mod.rs @@ -1,7 +1,5 @@ mod checkbox_controller; -mod group_controller; mod select_option_controller; pub use checkbox_controller::*; -pub use group_controller::*; pub use select_option_controller::*; diff --git a/frontend/rust-lib/flowy-grid/src/services/group/controller_impls/select_option_controller/mod.rs b/frontend/rust-lib/flowy-grid/src/services/group/controller_impls/select_option_controller/mod.rs new file mode 100644 index 0000000000..a2f393d093 --- /dev/null +++ b/frontend/rust-lib/flowy-grid/src/services/group/controller_impls/select_option_controller/mod.rs @@ -0,0 +1,6 @@ +mod multi_select_controller; +mod single_select_controller; +mod util; + +pub use multi_select_controller::*; +pub use single_select_controller::*; diff --git a/frontend/rust-lib/flowy-grid/src/services/group/controller_impls/select_option_controller/multi_select_controller.rs b/frontend/rust-lib/flowy-grid/src/services/group/controller_impls/select_option_controller/multi_select_controller.rs new file mode 100644 index 0000000000..33cd0613cd --- /dev/null +++ b/frontend/rust-lib/flowy-grid/src/services/group/controller_impls/select_option_controller/multi_select_controller.rs @@ -0,0 +1,110 @@ +use crate::entities::GroupRowsChangesetPB; +use crate::services::cell::insert_select_option_cell; +use crate::services::field::{MultiSelectTypeOptionPB, SelectOptionCellDataPB, SelectOptionCellDataParser}; +use crate::services::group::action::GroupAction; + +use crate::services::group::controller_impls::select_option_controller::util::*; +use crate::services::group::entities::Group; +use crate::services::group::group_controller::{GenericGroupController, GroupController, GroupGenerator}; +use flowy_grid_data_model::revision::{ + FieldRevision, RowChangeset, RowRevision, SelectOptionGroupConfigurationRevision, +}; + +// MultiSelect +pub type MultiSelectGroupController = GenericGroupController< + SelectOptionGroupConfigurationRevision, + MultiSelectTypeOptionPB, + MultiSelectGroupGenerator, + SelectOptionCellDataParser, +>; + +impl GroupAction for MultiSelectGroupController { + type CellDataType = SelectOptionCellDataPB; + + fn can_group(&self, content: &str, cell_data: &SelectOptionCellDataPB) -> bool { + cell_data.select_options.iter().any(|option| option.id == content) + } + + fn add_row_if_match(&mut self, row_rev: &RowRevision, cell_data: &Self::CellDataType) -> Vec<GroupRowsChangesetPB> { + let mut changesets = vec![]; + self.groups_map.iter_mut().for_each(|(_, group): (_, &mut Group)| { + add_row(group, &mut changesets, cell_data, row_rev); + }); + changesets + } + + fn remove_row_if_match( + &mut self, + row_rev: &RowRevision, + cell_data: &Self::CellDataType, + ) -> Vec<GroupRowsChangesetPB> { + let mut changesets = vec![]; + self.groups_map.iter_mut().for_each(|(_, group): (_, &mut Group)| { + remove_row(group, &mut changesets, cell_data, row_rev); + }); + changesets + } + + fn move_row_if_match( + &mut self, + field_rev: &FieldRevision, + row_rev: &RowRevision, + row_changeset: &mut RowChangeset, + cell_data: &Self::CellDataType, + to_row_id: &str, + ) -> Vec<GroupRowsChangesetPB> { + let mut group_changeset = vec![]; + self.groups_map.iter_mut().for_each(|(_, group): (_, &mut Group)| { + move_row( + group, + &mut group_changeset, + field_rev, + row_rev, + row_changeset, + cell_data, + to_row_id, + ); + }); + group_changeset + } +} + +impl GroupController for MultiSelectGroupController { + fn will_create_row(&mut self, row_rev: &mut RowRevision, field_rev: &FieldRevision, group_id: &str) { + let group: Option<&Group> = self.groups_map.get(group_id); + match group { + None => tracing::warn!("Can not find the group: {}", group_id), + Some(group) => { + let cell_rev = insert_select_option_cell(group.id.clone(), field_rev); + row_rev.cells.insert(field_rev.id.clone(), cell_rev); + } + } + } +} + +pub struct MultiSelectGroupGenerator(); +impl GroupGenerator for MultiSelectGroupGenerator { + type ConfigurationType = SelectOptionGroupConfiguration; + type TypeOptionType = MultiSelectTypeOptionPB; + fn generate_groups( + field_id: &str, + configuration: &Self::ConfigurationType, + type_option: &Option<Self::TypeOptionType>, + ) -> Vec<Group> { + match type_option { + None => vec![], + Some(type_option) => type_option + .options + .iter() + .map(|option| { + Group::new( + option.id.clone(), + field_id.to_owned(), + option.name.clone(), + option.id.clone(), + ) + }) + .collect(), + } + } +} diff --git a/frontend/rust-lib/flowy-grid/src/services/group/controller_impls/select_option_controller/single_select_controller.rs b/frontend/rust-lib/flowy-grid/src/services/group/controller_impls/select_option_controller/single_select_controller.rs new file mode 100644 index 0000000000..4c8360f427 --- /dev/null +++ b/frontend/rust-lib/flowy-grid/src/services/group/controller_impls/select_option_controller/single_select_controller.rs @@ -0,0 +1,111 @@ +use crate::entities::{GroupRowsChangesetPB, RowPB}; +use crate::services::cell::insert_select_option_cell; +use crate::services::field::{SelectOptionCellDataPB, SelectOptionCellDataParser, SingleSelectTypeOptionPB}; +use crate::services::group::action::GroupAction; + +use crate::services::group::controller_impls::select_option_controller::util::*; +use crate::services::group::entities::Group; +use crate::services::group::group_controller::{GenericGroupController, GroupController, GroupGenerator}; + +use flowy_grid_data_model::revision::{ + FieldRevision, RowChangeset, RowRevision, SelectOptionGroupConfigurationRevision, +}; + +// SingleSelect +pub type SingleSelectGroupController = GenericGroupController< + SelectOptionGroupConfigurationRevision, + SingleSelectTypeOptionPB, + SingleSelectGroupGenerator, + SelectOptionCellDataParser, +>; + +impl GroupAction for SingleSelectGroupController { + type CellDataType = SelectOptionCellDataPB; + fn can_group(&self, content: &str, cell_data: &SelectOptionCellDataPB) -> bool { + cell_data.select_options.iter().any(|option| option.id == content) + } + + fn add_row_if_match(&mut self, row_rev: &RowRevision, cell_data: &Self::CellDataType) -> Vec<GroupRowsChangesetPB> { + let mut changesets = vec![]; + self.groups_map.iter_mut().for_each(|(_, group): (_, &mut Group)| { + add_row(group, &mut changesets, cell_data, row_rev); + }); + changesets + } + + fn remove_row_if_match( + &mut self, + row_rev: &RowRevision, + cell_data: &Self::CellDataType, + ) -> Vec<GroupRowsChangesetPB> { + let mut changesets = vec![]; + self.groups_map.iter_mut().for_each(|(_, group): (_, &mut Group)| { + remove_row(group, &mut changesets, cell_data, row_rev); + }); + changesets + } + + fn move_row_if_match( + &mut self, + field_rev: &FieldRevision, + row_rev: &RowRevision, + row_changeset: &mut RowChangeset, + cell_data: &Self::CellDataType, + to_row_id: &str, + ) -> Vec<GroupRowsChangesetPB> { + let mut group_changeset = vec![]; + self.groups_map.iter_mut().for_each(|(_, group): (_, &mut Group)| { + move_row( + group, + &mut group_changeset, + field_rev, + row_rev, + row_changeset, + cell_data, + to_row_id, + ); + }); + group_changeset + } +} + +impl GroupController for SingleSelectGroupController { + fn will_create_row(&mut self, row_rev: &mut RowRevision, field_rev: &FieldRevision, group_id: &str) { + let group: Option<&mut Group> = self.groups_map.get_mut(group_id); + match group { + None => {} + Some(group) => { + let cell_rev = insert_select_option_cell(group.id.clone(), field_rev); + row_rev.cells.insert(field_rev.id.clone(), cell_rev); + group.add_row(RowPB::from(row_rev)); + } + } + } +} + +pub struct SingleSelectGroupGenerator(); +impl GroupGenerator for SingleSelectGroupGenerator { + type ConfigurationType = SelectOptionGroupConfiguration; + type TypeOptionType = SingleSelectTypeOptionPB; + fn generate_groups( + field_id: &str, + configuration: &Self::ConfigurationType, + type_option: &Option<Self::TypeOptionType>, + ) -> Vec<Group> { + match type_option { + None => vec![], + Some(type_option) => type_option + .options + .iter() + .map(|option| { + Group::new( + option.id.clone(), + field_id.to_owned(), + option.name.clone(), + option.id.clone(), + ) + }) + .collect(), + } + } +} diff --git a/frontend/rust-lib/flowy-grid/src/services/group/controller_impls/select_option_controller/util.rs b/frontend/rust-lib/flowy-grid/src/services/group/controller_impls/select_option_controller/util.rs new file mode 100644 index 0000000000..d95a39f60c --- /dev/null +++ b/frontend/rust-lib/flowy-grid/src/services/group/controller_impls/select_option_controller/util.rs @@ -0,0 +1,108 @@ +use crate::entities::{GroupRowsChangesetPB, InsertedRowPB, RowPB}; +use crate::services::cell::insert_select_option_cell; +use crate::services::field::SelectOptionCellDataPB; +use crate::services::group::configuration::{GenericGroupConfiguration, GroupConfigurationAction}; +use crate::services::group::Group; +use flowy_error::FlowyResult; +use flowy_grid_data_model::revision::{ + FieldRevision, GroupRecordRevision, RowChangeset, RowRevision, SelectOptionGroupConfigurationRevision, +}; + +pub type SelectOptionGroupConfiguration = GenericGroupConfiguration<SelectOptionGroupConfigurationRevision>; +impl GroupConfigurationAction for SelectOptionGroupConfiguration { + fn group_records(&self) -> &[GroupRecordRevision] { + todo!() + } + + fn save_groups(&self) -> FlowyResult<()> { + todo!() + } + + fn hide_group(&self, group_id: &str) -> FlowyResult<()> { + todo!() + } + + fn show_group(&self, group_id: &str) -> FlowyResult<()> { + todo!() + } +} + +pub fn add_row( + group: &mut Group, + changesets: &mut Vec<GroupRowsChangesetPB>, + cell_data: &SelectOptionCellDataPB, + row_rev: &RowRevision, +) { + cell_data.select_options.iter().for_each(|option| { + if option.id == group.id { + if !group.contains_row(&row_rev.id) { + let row_pb = RowPB::from(row_rev); + changesets.push(GroupRowsChangesetPB::insert( + group.id.clone(), + vec![InsertedRowPB::new(row_pb.clone())], + )); + group.add_row(row_pb); + } + } else if group.contains_row(&row_rev.id) { + changesets.push(GroupRowsChangesetPB::delete(group.id.clone(), vec![row_rev.id.clone()])); + group.remove_row(&row_rev.id); + } + }); +} + +pub fn remove_row( + group: &mut Group, + changesets: &mut Vec<GroupRowsChangesetPB>, + cell_data: &SelectOptionCellDataPB, + row_rev: &RowRevision, +) { + cell_data.select_options.iter().for_each(|option| { + if option.id == group.id && group.contains_row(&row_rev.id) { + changesets.push(GroupRowsChangesetPB::delete(group.id.clone(), vec![row_rev.id.clone()])); + group.remove_row(&row_rev.id); + } + }); +} + +pub fn move_row( + group: &mut Group, + group_changeset: &mut Vec<GroupRowsChangesetPB>, + field_rev: &FieldRevision, + row_rev: &RowRevision, + row_changeset: &mut RowChangeset, + cell_data: &SelectOptionCellDataPB, + to_row_id: &str, +) { + cell_data.select_options.iter().for_each(|option| { + // Remove the row in which group contains the row + let is_group_contains = group.contains_row(&row_rev.id); + let to_index = group.index_of_row(to_row_id); + + if option.id == group.id && is_group_contains { + group_changeset.push(GroupRowsChangesetPB::delete(group.id.clone(), vec![row_rev.id.clone()])); + group.remove_row(&row_rev.id); + } + + // Find the inserted group + if let Some(to_index) = to_index { + let row_pb = RowPB::from(row_rev); + let inserted_row = InsertedRowPB { + row: row_pb.clone(), + index: Some(to_index as i32), + }; + group_changeset.push(GroupRowsChangesetPB::insert(group.id.clone(), vec![inserted_row])); + if group.number_of_row() == to_index { + group.add_row(row_pb); + } else { + group.insert_row(to_index, row_pb); + } + } + + // If the inserted row comes from other group, it needs to update the corresponding cell content. + if to_index.is_some() && option.id != group.id { + // Update the corresponding row's cell content. + let cell_rev = insert_select_option_cell(group.id.clone(), field_rev); + row_changeset.cell_by_field_id.insert(field_rev.id.clone(), cell_rev); + } + }); +} diff --git a/frontend/rust-lib/flowy-grid/src/services/group/controllers/select_option_controller.rs b/frontend/rust-lib/flowy-grid/src/services/group/controllers/select_option_controller.rs deleted file mode 100644 index 29dc95891f..0000000000 --- a/frontend/rust-lib/flowy-grid/src/services/group/controllers/select_option_controller.rs +++ /dev/null @@ -1,286 +0,0 @@ -use crate::entities::{GroupRowsChangesetPB, InsertedRowPB, RowPB, SelectOptionGroupConfigurationPB}; -use crate::services::cell::insert_select_option_cell; -use crate::services::field::{ - MultiSelectTypeOptionPB, SelectOptionCellDataPB, SelectOptionCellDataParser, SingleSelectTypeOptionPB, -}; -use crate::services::group::{GenericGroupController, Group, GroupController, GroupGenerator, Groupable}; -use flowy_grid_data_model::revision::{FieldRevision, RowChangeset, RowRevision}; - -// SingleSelect -pub type SingleSelectGroupController = GenericGroupController< - SelectOptionGroupConfigurationPB, - SingleSelectTypeOptionPB, - SingleSelectGroupGenerator, - SelectOptionCellDataParser, ->; - -impl Groupable for SingleSelectGroupController { - type CellDataType = SelectOptionCellDataPB; - fn can_group(&self, content: &str, cell_data: &SelectOptionCellDataPB) -> bool { - cell_data.select_options.iter().any(|option| option.id == content) - } - - fn add_row_if_match(&mut self, row_rev: &RowRevision, cell_data: &Self::CellDataType) -> Vec<GroupRowsChangesetPB> { - let mut changesets = vec![]; - self.groups_map.iter_mut().for_each(|(_, group): (_, &mut Group)| { - add_row(group, &mut changesets, cell_data, row_rev); - }); - changesets - } - - fn remove_row_if_match( - &mut self, - row_rev: &RowRevision, - cell_data: &Self::CellDataType, - ) -> Vec<GroupRowsChangesetPB> { - let mut changesets = vec![]; - self.groups_map.iter_mut().for_each(|(_, group): (_, &mut Group)| { - remove_row(group, &mut changesets, cell_data, row_rev); - }); - changesets - } - - fn move_row_if_match( - &mut self, - field_rev: &FieldRevision, - row_rev: &RowRevision, - row_changeset: &mut RowChangeset, - cell_data: &Self::CellDataType, - to_row_id: &str, - ) -> Vec<GroupRowsChangesetPB> { - let mut group_changeset = vec![]; - self.groups_map.iter_mut().for_each(|(_, group): (_, &mut Group)| { - move_row( - group, - &mut group_changeset, - field_rev, - row_rev, - row_changeset, - cell_data, - to_row_id, - ); - }); - group_changeset - } -} - -impl GroupController for SingleSelectGroupController { - fn will_create_row(&mut self, row_rev: &mut RowRevision, field_rev: &FieldRevision, group_id: &str) { - let group: Option<&mut Group> = self.groups_map.get_mut(group_id); - match group { - None => {} - Some(group) => { - let cell_rev = insert_select_option_cell(group.id.clone(), field_rev); - row_rev.cells.insert(field_rev.id.clone(), cell_rev); - group.add_row(RowPB::from(row_rev)); - } - } - } -} - -pub struct SingleSelectGroupGenerator(); -impl GroupGenerator for SingleSelectGroupGenerator { - type ConfigurationType = SelectOptionGroupConfigurationPB; - type TypeOptionType = SingleSelectTypeOptionPB; - fn generate_groups( - field_id: &str, - _configuration: &Option<Self::ConfigurationType>, - type_option: &Option<Self::TypeOptionType>, - ) -> Vec<Group> { - match type_option { - None => vec![], - Some(type_option) => type_option - .options - .iter() - .map(|option| { - Group::new( - option.id.clone(), - field_id.to_owned(), - option.name.clone(), - option.id.clone(), - ) - }) - .collect(), - } - } -} - -// MultiSelect -pub type MultiSelectGroupController = GenericGroupController< - SelectOptionGroupConfigurationPB, - MultiSelectTypeOptionPB, - MultiSelectGroupGenerator, - SelectOptionCellDataParser, ->; - -impl Groupable for MultiSelectGroupController { - type CellDataType = SelectOptionCellDataPB; - - fn can_group(&self, content: &str, cell_data: &SelectOptionCellDataPB) -> bool { - cell_data.select_options.iter().any(|option| option.id == content) - } - - fn add_row_if_match(&mut self, row_rev: &RowRevision, cell_data: &Self::CellDataType) -> Vec<GroupRowsChangesetPB> { - let mut changesets = vec![]; - self.groups_map.iter_mut().for_each(|(_, group): (_, &mut Group)| { - add_row(group, &mut changesets, cell_data, row_rev); - }); - changesets - } - - fn remove_row_if_match( - &mut self, - row_rev: &RowRevision, - cell_data: &Self::CellDataType, - ) -> Vec<GroupRowsChangesetPB> { - let mut changesets = vec![]; - self.groups_map.iter_mut().for_each(|(_, group): (_, &mut Group)| { - remove_row(group, &mut changesets, cell_data, row_rev); - }); - changesets - } - - fn move_row_if_match( - &mut self, - field_rev: &FieldRevision, - row_rev: &RowRevision, - row_changeset: &mut RowChangeset, - cell_data: &Self::CellDataType, - to_row_id: &str, - ) -> Vec<GroupRowsChangesetPB> { - let mut group_changeset = vec![]; - self.groups_map.iter_mut().for_each(|(_, group): (_, &mut Group)| { - move_row( - group, - &mut group_changeset, - field_rev, - row_rev, - row_changeset, - cell_data, - to_row_id, - ); - }); - group_changeset - } -} - -impl GroupController for MultiSelectGroupController { - fn will_create_row(&mut self, row_rev: &mut RowRevision, field_rev: &FieldRevision, group_id: &str) { - let group: Option<&Group> = self.groups_map.get(group_id); - match group { - None => tracing::warn!("Can not find the group: {}", group_id), - Some(group) => { - let cell_rev = insert_select_option_cell(group.id.clone(), field_rev); - row_rev.cells.insert(field_rev.id.clone(), cell_rev); - } - } - } -} - -pub struct MultiSelectGroupGenerator(); -impl GroupGenerator for MultiSelectGroupGenerator { - type ConfigurationType = SelectOptionGroupConfigurationPB; - type TypeOptionType = MultiSelectTypeOptionPB; - - fn generate_groups( - field_id: &str, - _configuration: &Option<Self::ConfigurationType>, - type_option: &Option<Self::TypeOptionType>, - ) -> Vec<Group> { - match type_option { - None => vec![], - Some(type_option) => type_option - .options - .iter() - .map(|option| { - Group::new( - option.id.clone(), - field_id.to_owned(), - option.name.clone(), - option.id.clone(), - ) - }) - .collect(), - } - } -} - -fn add_row( - group: &mut Group, - changesets: &mut Vec<GroupRowsChangesetPB>, - cell_data: &SelectOptionCellDataPB, - row_rev: &RowRevision, -) { - cell_data.select_options.iter().for_each(|option| { - if option.id == group.id { - if !group.contains_row(&row_rev.id) { - let row_pb = RowPB::from(row_rev); - changesets.push(GroupRowsChangesetPB::insert( - group.id.clone(), - vec![InsertedRowPB::new(row_pb.clone())], - )); - group.add_row(row_pb); - } - } else if group.contains_row(&row_rev.id) { - changesets.push(GroupRowsChangesetPB::delete(group.id.clone(), vec![row_rev.id.clone()])); - group.remove_row(&row_rev.id); - } - }); -} - -fn remove_row( - group: &mut Group, - changesets: &mut Vec<GroupRowsChangesetPB>, - cell_data: &SelectOptionCellDataPB, - row_rev: &RowRevision, -) { - cell_data.select_options.iter().for_each(|option| { - if option.id == group.id && group.contains_row(&row_rev.id) { - changesets.push(GroupRowsChangesetPB::delete(group.id.clone(), vec![row_rev.id.clone()])); - group.remove_row(&row_rev.id); - } - }); -} - -fn move_row( - group: &mut Group, - group_changeset: &mut Vec<GroupRowsChangesetPB>, - field_rev: &FieldRevision, - row_rev: &RowRevision, - row_changeset: &mut RowChangeset, - cell_data: &SelectOptionCellDataPB, - to_row_id: &str, -) { - cell_data.select_options.iter().for_each(|option| { - // Remove the row in which group contains the row - let is_group_contains = group.contains_row(&row_rev.id); - let to_index = group.index_of_row(to_row_id); - - if option.id == group.id && is_group_contains { - group_changeset.push(GroupRowsChangesetPB::delete(group.id.clone(), vec![row_rev.id.clone()])); - group.remove_row(&row_rev.id); - } - - // Find the inserted group - if let Some(to_index) = to_index { - let row_pb = RowPB::from(row_rev); - let inserted_row = InsertedRowPB { - row: row_pb.clone(), - index: Some(to_index as i32), - }; - group_changeset.push(GroupRowsChangesetPB::insert(group.id.clone(), vec![inserted_row])); - if group.number_of_row() == to_index { - group.add_row(row_pb); - } else { - group.insert_row(to_index, row_pb); - } - } - - // If the inserted row comes from other group, it needs to update the corresponding cell content. - if to_index.is_some() && option.id != group.id { - // Update the corresponding row's cell content. - let cell_rev = insert_select_option_cell(group.id.clone(), field_rev); - row_changeset.cell_by_field_id.insert(field_rev.id.clone(), cell_rev); - } - }); -} diff --git a/frontend/rust-lib/flowy-grid/src/services/group/entities.rs b/frontend/rust-lib/flowy-grid/src/services/group/entities.rs new file mode 100644 index 0000000000..dd4171afb0 --- /dev/null +++ b/frontend/rust-lib/flowy-grid/src/services/group/entities.rs @@ -0,0 +1,73 @@ +use crate::entities::{GroupPB, RowPB}; + +#[derive(Clone)] +pub struct Group { + pub id: String, + pub field_id: String, + pub desc: String, + rows: Vec<RowPB>, + + /// [content] is used to determine which group the cell belongs to. + pub content: String, +} + +impl std::convert::From<Group> for GroupPB { + fn from(group: Group) -> Self { + Self { + field_id: group.field_id, + group_id: group.id, + desc: group.desc, + rows: group.rows, + } + } +} + +impl Group { + pub fn new(id: String, field_id: String, desc: String, content: String) -> Self { + Self { + id, + field_id, + desc, + rows: vec![], + content, + } + } + + pub fn contains_row(&self, row_id: &str) -> bool { + self.rows.iter().any(|row| row.id == row_id) + } + + pub fn remove_row(&mut self, row_id: &str) { + match self.rows.iter().position(|row| row.id == row_id) { + None => {} + Some(pos) => { + self.rows.remove(pos); + } + } + } + + pub fn add_row(&mut self, row_pb: RowPB) { + match self.rows.iter().find(|row| row.id == row_pb.id) { + None => { + self.rows.push(row_pb); + } + Some(_) => {} + } + } + + pub fn insert_row(&mut self, index: usize, row_pb: RowPB) { + if index < self.rows.len() { + self.rows.insert(index, row_pb); + } else { + tracing::error!("Insert row index:{} beyond the bounds:{},", index, self.rows.len()); + } + } + + pub fn index_of_row(&self, row_id: &str) -> Option<usize> { + self.rows.iter().position(|row| row.id == row_id) + } + + pub fn number_of_row(&self) -> usize { + self.rows.len() + } +} diff --git a/frontend/rust-lib/flowy-grid/src/services/group/controllers/group_controller.rs b/frontend/rust-lib/flowy-grid/src/services/group/group_controller.rs similarity index 57% rename from frontend/rust-lib/flowy-grid/src/services/group/controllers/group_controller.rs rename to frontend/rust-lib/flowy-grid/src/services/group/group_controller.rs index 07dcff3f77..fb2c0aaa6e 100644 --- a/frontend/rust-lib/flowy-grid/src/services/group/controllers/group_controller.rs +++ b/frontend/rust-lib/flowy-grid/src/services/group/group_controller.rs @@ -1,54 +1,43 @@ -use crate::entities::{GroupPB, GroupRowsChangesetPB, RowPB}; +use crate::entities::{GroupRowsChangesetPB, RowPB}; use crate::services::cell::{decode_any_cell_data, CellBytesParser}; -use bytes::Bytes; +use crate::services::group::action::GroupAction; +use crate::services::group::configuration::{GenericGroupConfiguration, GroupConfigurationReader}; +use crate::services::group::entities::Group; use flowy_error::FlowyResult; use flowy_grid_data_model::revision::{ - FieldRevision, GroupConfigurationRevision, RowChangeset, RowRevision, TypeOptionDataDeserializer, + FieldRevision, GroupConfigurationContentSerde, GroupConfigurationRevision, RowChangeset, RowRevision, + TypeOptionDataDeserializer, }; use indexmap::IndexMap; +use lib_infra::future::AFFuture; use std::marker::PhantomData; use std::sync::Arc; +const DEFAULT_GROUP_ID: &str = "default_group"; + +// Each kind of group must implement this trait to provide custom group +// operations. For example, insert cell data to the row_rev when creating +// a new row. +pub trait GroupController: GroupControllerSharedAction + Send + Sync { + fn will_create_row(&mut self, row_rev: &mut RowRevision, field_rev: &FieldRevision, group_id: &str); +} + pub trait GroupGenerator { type ConfigurationType; type TypeOptionType; fn generate_groups( field_id: &str, - configuration: &Option<Self::ConfigurationType>, + configuration: &Self::ConfigurationType, type_option: &Option<Self::TypeOptionType>, ) -> Vec<Group>; } -pub trait Groupable: Send + Sync { - type CellDataType; - fn can_group(&self, content: &str, cell_data: &Self::CellDataType) -> bool; - fn add_row_if_match(&mut self, row_rev: &RowRevision, cell_data: &Self::CellDataType) -> Vec<GroupRowsChangesetPB>; - fn remove_row_if_match( - &mut self, - row_rev: &RowRevision, - cell_data: &Self::CellDataType, - ) -> Vec<GroupRowsChangesetPB>; - - fn move_row_if_match( - &mut self, - field_rev: &FieldRevision, - row_rev: &RowRevision, - row_changeset: &mut RowChangeset, - cell_data: &Self::CellDataType, - to_row_id: &str, - ) -> Vec<GroupRowsChangesetPB>; -} - -pub trait GroupController: GroupControllerSharedAction + Send + Sync { - fn will_create_row(&mut self, row_rev: &mut RowRevision, field_rev: &FieldRevision, group_id: &str); -} - +// Defines the shared actions each group controller can perform. pub trait GroupControllerSharedAction: Send + Sync { // The field that is used for grouping the rows fn field_id(&self) -> &str; - fn groups(&self) -> Vec<Group>; - fn group_rows(&mut self, row_revs: &[Arc<RowRevision>], field_rev: &FieldRevision) -> FlowyResult<()>; + fn fill_groups(&mut self, row_revs: &[Arc<RowRevision>], field_rev: &FieldRevision) -> FlowyResult<Vec<Group>>; fn did_update_row( &mut self, row_rev: &RowRevision, @@ -70,105 +59,35 @@ pub trait GroupControllerSharedAction: Send + Sync { ) -> FlowyResult<Vec<GroupRowsChangesetPB>>; } -const DEFAULT_GROUP_ID: &str = "default_group"; - -/// C: represents the group configuration structure +/// C: represents the group configuration that impl [GroupConfigurationSerde] /// T: the type option data deserializer that impl [TypeOptionDataDeserializer] /// G: the group generator, [GroupGenerator] /// P: the parser that impl [CellBytesParser] for the CellBytes pub struct GenericGroupController<C, T, G, P> { pub field_id: String, pub groups_map: IndexMap<String, Group>, + + /// default_group is used to store the rows that don't belong to any groups. default_group: Group, pub type_option: Option<T>, - pub configuration: Option<C>, + pub configuration: GenericGroupConfiguration<C>, group_action_phantom: PhantomData<G>, cell_parser_phantom: PhantomData<P>, } -#[derive(Clone)] -pub struct Group { - pub id: String, - pub field_id: String, - pub desc: String, - rows: Vec<RowPB>, - pub content: String, -} - -impl std::convert::From<Group> for GroupPB { - fn from(group: Group) -> Self { - Self { - field_id: group.field_id, - group_id: group.id, - desc: group.desc, - rows: group.rows, - } - } -} - -impl Group { - pub fn new(id: String, field_id: String, desc: String, content: String) -> Self { - Self { - id, - field_id, - desc, - rows: vec![], - content, - } - } - - pub fn contains_row(&self, row_id: &str) -> bool { - self.rows.iter().any(|row| row.id == row_id) - } - - pub fn remove_row(&mut self, row_id: &str) { - match self.rows.iter().position(|row| row.id == row_id) { - None => {} - Some(pos) => { - self.rows.remove(pos); - } - } - } - - pub fn add_row(&mut self, row_pb: RowPB) { - match self.rows.iter().find(|row| row.id == row_pb.id) { - None => { - self.rows.push(row_pb); - } - Some(_) => {} - } - } - - pub fn insert_row(&mut self, index: usize, row_pb: RowPB) { - if index < self.rows.len() { - self.rows.insert(index, row_pb); - } else { - tracing::error!("Insert row index:{} beyond the bounds:{},", index, self.rows.len()); - } - } - - pub fn index_of_row(&self, row_id: &str) -> Option<usize> { - self.rows.iter().position(|row| row.id == row_id) - } - - pub fn number_of_row(&self) -> usize { - self.rows.len() - } -} - impl<C, T, G, P> GenericGroupController<C, T, G, P> where - C: TryFrom<Bytes, Error = protobuf::ProtobufError>, + C: GroupConfigurationContentSerde, T: TypeOptionDataDeserializer, - G: GroupGenerator<ConfigurationType = C, TypeOptionType = T>, + G: GroupGenerator<ConfigurationType = GenericGroupConfiguration<C>, TypeOptionType = T>, { - pub fn new(field_rev: &Arc<FieldRevision>, configuration: GroupConfigurationRevision) -> FlowyResult<Self> { - // let configuration = match configuration.content { - // None => None, - // Some(content) => Some(C::try_from(Bytes::from(content))?), - // }; - - let configuration = None; + pub async fn new( + field_rev: &Arc<FieldRevision>, + configuration_reader: Arc<dyn GroupConfigurationReader>, + configuration_writer: Arc<dyn GroupConfigurationReader>, + ) -> FlowyResult<Self> { + let configuration = + GenericGroupConfiguration::<C>::new(field_rev.clone(), configuration_reader, configuration_writer).await?; let field_type_rev = field_rev.ty; let type_option = field_rev.get_type_option_entry::<T>(field_type_rev); let groups = G::generate_groups(&field_rev.id, &configuration, &type_option); @@ -195,55 +114,52 @@ where impl<C, T, G, P> GroupControllerSharedAction for GenericGroupController<C, T, G, P> where P: CellBytesParser, - Self: Groupable<CellDataType = P::Object>, + Self: GroupAction<CellDataType = P::Object>, { fn field_id(&self) -> &str { &self.field_id } - fn groups(&self) -> Vec<Group> { - let default_group = self.default_group.clone(); - let mut groups: Vec<Group> = self.groups_map.values().cloned().collect(); - if !default_group.rows.is_empty() { - groups.push(default_group); - } - groups - } - - fn group_rows(&mut self, row_revs: &[Arc<RowRevision>], field_rev: &FieldRevision) -> FlowyResult<()> { - if self.configuration.is_none() { - return Ok(()); - } + fn fill_groups(&mut self, row_revs: &[Arc<RowRevision>], field_rev: &FieldRevision) -> FlowyResult<Vec<Group>> { + // if self.configuration.is_none() { + // return Ok(vec![]); + // } for row_rev in row_revs { if let Some(cell_rev) = row_rev.cells.get(&self.field_id) { - let mut records: Vec<GroupRecord> = vec![]; + let mut group_rows: Vec<GroupRow> = vec![]; let cell_bytes = decode_any_cell_data(cell_rev.data.clone(), field_rev); let cell_data = cell_bytes.parser::<P>()?; for group in self.groups_map.values() { if self.can_group(&group.content, &cell_data) { - records.push(GroupRecord { + group_rows.push(GroupRow { row: row_rev.into(), group_id: group.id.clone(), }); } } - if records.is_empty() { - self.default_group.rows.push(row_rev.into()); + if group_rows.is_empty() { + self.default_group.add_row(row_rev.into()); } else { - for record in records { - if let Some(group) = self.groups_map.get_mut(&record.group_id) { - group.rows.push(record.row); + for group_row in group_rows { + if let Some(group) = self.groups_map.get_mut(&group_row.group_id) { + group.add_row(group_row.row); } } } } else { - self.default_group.rows.push(row_rev.into()); + self.default_group.add_row(row_rev.into()); } } - Ok(()) + let default_group = self.default_group.clone(); + let mut groups: Vec<Group> = self.groups_map.values().cloned().collect(); + if !default_group.number_of_row() == 0 { + groups.push(default_group); + } + + Ok(groups) } fn did_update_row( @@ -292,7 +208,7 @@ where } } -struct GroupRecord { +struct GroupRow { row: RowPB, group_id: String, } diff --git a/frontend/rust-lib/flowy-grid/src/services/group/group_service.rs b/frontend/rust-lib/flowy-grid/src/services/group/group_service.rs index c07b3acec4..42e687445d 100644 --- a/frontend/rust-lib/flowy-grid/src/services/group/group_service.rs +++ b/frontend/rust-lib/flowy-grid/src/services/group/group_service.rs @@ -2,44 +2,48 @@ use crate::entities::{ CheckboxGroupConfigurationPB, DateGroupConfigurationPB, FieldType, GroupRowsChangesetPB, NumberGroupConfigurationPB, SelectOptionGroupConfigurationPB, TextGroupConfigurationPB, UrlGroupConfigurationPB, }; +use crate::services::group::configuration::GroupConfigurationReader; +use crate::services::group::group_controller::GroupController; use crate::services::group::{ - CheckboxGroupController, Group, GroupController, MultiSelectGroupController, SingleSelectGroupController, + CheckboxGroupController, Group, GroupConfigurationWriter, MultiSelectGroupController, SingleSelectGroupController, }; -use bytes::Bytes; use flowy_error::FlowyResult; use flowy_grid_data_model::revision::{ - gen_grid_group_id, CheckboxGroupConfigurationRevision, DateGroupConfigurationRevision, FieldRevision, - GroupConfigurationRevision, NumberGroupConfigurationRevision, RowChangeset, RowRevision, - SelectOptionGroupConfigurationRevision, TextGroupConfigurationRevision, UrlGroupConfigurationRevision, + CheckboxGroupConfigurationRevision, DateGroupConfigurationRevision, FieldRevision, GroupConfigurationRevision, + NumberGroupConfigurationRevision, RowChangeset, RowRevision, SelectOptionGroupConfigurationRevision, + TextGroupConfigurationRevision, UrlGroupConfigurationRevision, }; -use lib_infra::future::AFFuture; + use std::future::Future; use std::sync::Arc; use tokio::sync::RwLock; -pub trait GroupConfigurationDelegate: Send + Sync + 'static { - fn get_group_configuration(&self, field_rev: Arc<FieldRevision>) -> AFFuture<GroupConfigurationRevision>; -} - pub(crate) struct GroupService { - delegate: Box<dyn GroupConfigurationDelegate>, + configuration_reader: Arc<dyn GroupConfigurationReader>, + configuration_writer: Arc<dyn GroupConfigurationWriter>, group_controller: Option<Arc<RwLock<dyn GroupController>>>, } impl GroupService { - pub(crate) async fn new(delegate: Box<dyn GroupConfigurationDelegate>) -> Self { + pub(crate) async fn new<R, W>(configuration_reader: R, configuration_writer: W) -> Self + where + R: GroupConfigurationReader, + W: GroupConfigurationWriter, + { Self { - delegate, + configuration_reader: Arc::new(configuration_reader), + configuration_writer: Arc::new(configuration_writer), group_controller: None, } } pub(crate) async fn groups(&self) -> Vec<Group> { - if let Some(group_action_handler) = self.group_controller.as_ref() { - group_action_handler.read().await.groups() - } else { - vec![] - } + // if let Some(group_action_handler) = self.group_controller.as_ref() { + // group_action_handler.read().await.groups() + // } else { + // vec![] + // } + todo!() } pub(crate) async fn load_groups( @@ -49,13 +53,25 @@ impl GroupService { ) -> Option<Vec<Group>> { let field_rev = find_group_field(field_revs)?; let field_type: FieldType = field_rev.ty.into(); - let configuration = self.delegate.get_group_configuration(field_rev.clone()).await; - match self - .build_groups(&field_type, &field_rev, row_revs, configuration) - .await - { - Ok(groups) => Some(groups), - Err(_) => None, + match self.make_group_controller(&field_type, &field_rev).await { + Ok(group_controller) => { + self.group_controller = group_controller; + let mut groups = vec![]; + if let Some(group_action_handler) = self.group_controller.as_ref() { + let mut write_guard = group_action_handler.write().await; + groups = match write_guard.fill_groups(&row_revs, &field_rev) { + Ok(groups) => groups, + Err(e) => { + tracing::error!("Fill groups failed:{:?}", e); + vec![] + } + }; + + drop(write_guard); + } + Some(groups) + } + Err(_) => Some(vec![]), } } @@ -151,14 +167,13 @@ impl GroupService { } } - #[tracing::instrument(level = "trace", skip_all, err)] - async fn build_groups( + #[tracing::instrument(level = "trace", skip_all)] + async fn make_group_controller( &mut self, field_type: &FieldType, field_rev: &Arc<FieldRevision>, - row_revs: Vec<Arc<RowRevision>>, - configuration: GroupConfigurationRevision, - ) -> FlowyResult<Vec<Group>> { + ) -> FlowyResult<Option<Arc<RwLock<dyn GroupController>>>> { + let mut group_controller: Option<Arc<RwLock<dyn GroupController>>> = None; match field_type { FieldType::RichText => { // let generator = GroupGenerator::<TextGroupConfigurationPB>::from_configuration(configuration); @@ -170,31 +185,37 @@ impl GroupService { // let generator = GroupGenerator::<DateGroupConfigurationPB>::from_configuration(configuration); } FieldType::SingleSelect => { - let controller = SingleSelectGroupController::new(field_rev, configuration)?; - self.group_controller = Some(Arc::new(RwLock::new(controller))); + let controller = SingleSelectGroupController::new( + field_rev, + self.configuration_reader.clone(), + self.configuration_writer.clone(), + ) + .await?; + group_controller = Some(Arc::new(RwLock::new(controller))); } FieldType::MultiSelect => { - let controller = MultiSelectGroupController::new(field_rev, configuration)?; - self.group_controller = Some(Arc::new(RwLock::new(controller))); + let controller = MultiSelectGroupController::new( + field_rev, + self.configuration_reader.clone(), + self.configuration_writer.clone(), + ) + .await?; + group_controller = Some(Arc::new(RwLock::new(controller))); } FieldType::Checkbox => { - let controller = CheckboxGroupController::new(field_rev, configuration)?; - self.group_controller = Some(Arc::new(RwLock::new(controller))); + let controller = CheckboxGroupController::new( + field_rev, + self.configuration_reader.clone(), + self.configuration_writer.clone(), + ) + .await?; + group_controller = Some(Arc::new(RwLock::new(controller))) } FieldType::URL => { // let generator = GroupGenerator::<UrlGroupConfigurationPB>::from_configuration(configuration); } - }; - - let mut groups = vec![]; - if let Some(group_action_handler) = self.group_controller.as_ref() { - let mut write_guard = group_action_handler.write().await; - let _ = write_guard.group_rows(&row_revs, field_rev)?; - groups = write_guard.groups(); - drop(write_guard); } - - Ok(groups) + Ok(group_controller) } } diff --git a/frontend/rust-lib/flowy-grid/src/services/group/mod.rs b/frontend/rust-lib/flowy-grid/src/services/group/mod.rs index f8b96c8bab..19536b8c5b 100644 --- a/frontend/rust-lib/flowy-grid/src/services/group/mod.rs +++ b/frontend/rust-lib/flowy-grid/src/services/group/mod.rs @@ -1,5 +1,11 @@ -mod controllers; +mod action; +mod configuration; +mod controller_impls; +mod entities; +mod group_controller; mod group_service; -pub(crate) use controllers::*; +pub(crate) use configuration::*; +pub(crate) use controller_impls::*; +pub(crate) use entities::*; pub(crate) use group_service::*; diff --git a/frontend/rust-lib/flowy-grid/src/services/setting/setting_builder.rs b/frontend/rust-lib/flowy-grid/src/services/setting/setting_builder.rs index 1cc16f7da7..16ee630cc7 100644 --- a/frontend/rust-lib/flowy-grid/src/services/setting/setting_builder.rs +++ b/frontend/rust-lib/flowy-grid/src/services/setting/setting_builder.rs @@ -1,11 +1,4 @@ -use crate::entities::{ - GridLayout, GridLayoutPB, GridSettingPB, RepeatedGridConfigurationFilterPB, RepeatedGridGroupConfigurationPB, - RepeatedGridSortPB, -}; -use flowy_grid_data_model::revision::{FieldRevision, SettingRevision}; -use flowy_sync::entities::grid::{CreateFilterParams, DeleteFilterParams, GridSettingChangesetParams}; -use std::collections::HashMap; -use std::sync::Arc; +use crate::entities::{CreateFilterParams, DeleteFilterParams, GridLayout, GridSettingChangesetParams}; pub struct GridSettingChangesetBuilder { params: GridSettingChangesetParams, @@ -20,8 +13,6 @@ impl GridSettingChangesetBuilder { delete_filter: None, insert_group: None, delete_group: None, - insert_sort: None, - delete_sort: None, }; Self { params } } @@ -40,42 +31,3 @@ impl GridSettingChangesetBuilder { self.params } } - -pub fn make_grid_setting(grid_setting_rev: &SettingRevision, field_revs: &[Arc<FieldRevision>]) -> GridSettingPB { - let current_layout_type: GridLayout = grid_setting_rev.layout.clone().into(); - let filters_by_field_id = grid_setting_rev - .get_all_filters(field_revs) - .map(|filters_by_field_id| { - filters_by_field_id - .into_iter() - .map(|(k, v)| (k, v.into())) - .collect::<HashMap<String, RepeatedGridConfigurationFilterPB>>() - }) - .unwrap_or_default(); - let groups_by_field_id = grid_setting_rev - .get_all_groups(field_revs) - .map(|groups_by_field_id| { - groups_by_field_id - .into_iter() - .map(|(k, v)| (k, v.into())) - .collect::<HashMap<String, RepeatedGridGroupConfigurationPB>>() - }) - .unwrap_or_default(); - let sorts_by_field_id = grid_setting_rev - .get_all_sort() - .map(|sorts_by_field_id| { - sorts_by_field_id - .into_iter() - .map(|(k, v)| (k, v.into())) - .collect::<HashMap<String, RepeatedGridSortPB>>() - }) - .unwrap_or_default(); - - GridSettingPB { - layouts: GridLayoutPB::all(), - current_layout_type, - filter_configuration_by_field_id: filters_by_field_id, - group_configuration_by_field_id: groups_by_field_id, - sorts_by_field_id, - } -} diff --git a/shared-lib/flowy-grid-data-model/src/revision/filter_rev.rs b/shared-lib/flowy-grid-data-model/src/revision/filter_rev.rs new file mode 100644 index 0000000000..7079b52229 --- /dev/null +++ b/shared-lib/flowy-grid-data-model/src/revision/filter_rev.rs @@ -0,0 +1,9 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq, Hash)] +pub struct FilterConfigurationRevision { + pub id: String, + pub field_id: String, + pub condition: u8, + pub content: Option<String>, +} diff --git a/shared-lib/flowy-grid-data-model/src/revision/grid_setting_rev.rs b/shared-lib/flowy-grid-data-model/src/revision/grid_setting_rev.rs index ff15170932..01ca80a380 100644 --- a/shared-lib/flowy-grid-data-model/src/revision/grid_setting_rev.rs +++ b/shared-lib/flowy-grid-data-model/src/revision/grid_setting_rev.rs @@ -1,8 +1,7 @@ -use crate::revision::{FieldRevision, FieldTypeRevision}; +use crate::revision::{FieldRevision, FieldTypeRevision, FilterConfigurationRevision, GroupConfigurationRevision}; use indexmap::IndexMap; use nanoid::nanoid; use serde::{Deserialize, Serialize}; -use serde_repr::*; use std::collections::HashMap; use std::fmt::Debug; use std::sync::Arc; @@ -15,6 +14,7 @@ pub fn gen_grid_group_id() -> String { nanoid!(6) } +#[allow(dead_code)] pub fn gen_grid_sort_id() -> String { nanoid!(6) } @@ -24,114 +24,6 @@ pub type FilterConfigurationsByFieldId = HashMap<String, Vec<Arc<FilterConfigura // pub type GroupConfiguration = Configuration<GroupConfigurationRevision>; pub type GroupConfigurationsByFieldId = HashMap<String, Vec<Arc<GroupConfigurationRevision>>>; -// -pub type SortConfiguration = Configuration<SortConfigurationRevision>; -pub type SortConfigurationsByFieldId = HashMap<String, Vec<Arc<SortConfigurationRevision>>>; - -#[derive(Debug, Clone, Serialize, Deserialize, Default, Eq, PartialEq)] -pub struct SettingRevision { - pub layout: LayoutRevision, - - pub filters: FilterConfiguration, - - #[serde(default)] - pub groups: GroupConfiguration, - - #[serde(skip)] - pub sorts: SortConfiguration, -} - -#[derive(Debug, PartialEq, Eq, Hash, Clone, Serialize_repr, Deserialize_repr)] -#[repr(u8)] -pub enum LayoutRevision { - Table = 0, - Board = 1, -} - -impl ToString for LayoutRevision { - fn to_string(&self) -> String { - let layout_rev = self.clone() as u8; - layout_rev.to_string() - } -} - -impl std::default::Default for LayoutRevision { - fn default() -> Self { - LayoutRevision::Table - } -} - -impl SettingRevision { - pub fn get_all_groups(&self, field_revs: &[Arc<FieldRevision>]) -> Option<GroupConfigurationsByFieldId> { - self.groups.get_all_objects(field_revs) - } - - pub fn get_groups( - &self, - field_id: &str, - field_type_rev: &FieldTypeRevision, - ) -> Option<Vec<Arc<GroupConfigurationRevision>>> { - self.groups.get_objects(field_id, field_type_rev) - } - - pub fn get_mut_groups( - &mut self, - field_id: &str, - field_type: &FieldTypeRevision, - ) -> Option<&mut Vec<Arc<GroupConfigurationRevision>>> { - self.groups.get_mut_objects(field_id, field_type) - } - - pub fn insert_group( - &mut self, - field_id: &str, - field_type: &FieldTypeRevision, - group_rev: GroupConfigurationRevision, - ) { - // only one group can be set - self.groups.remove_all(); - self.groups.insert_object(field_id, field_type, group_rev); - } - - pub fn get_all_filters(&self, field_revs: &[Arc<FieldRevision>]) -> Option<FilterConfigurationsByFieldId> { - self.filters.get_all_objects(field_revs) - } - - pub fn get_filters( - &self, - field_id: &str, - field_type_rev: &FieldTypeRevision, - ) -> Option<Vec<Arc<FilterConfigurationRevision>>> { - self.filters.get_objects(field_id, field_type_rev) - } - - pub fn get_mut_filters( - &mut self, - field_id: &str, - field_type: &FieldTypeRevision, - ) -> Option<&mut Vec<Arc<FilterConfigurationRevision>>> { - self.filters.get_mut_objects(field_id, field_type) - } - - pub fn insert_filter( - &mut self, - field_id: &str, - field_type: &FieldTypeRevision, - filter_rev: FilterConfigurationRevision, - ) { - self.filters.insert_object(field_id, field_type, filter_rev); - } - - pub fn get_all_sort(&self) -> Option<SortConfigurationsByFieldId> { - None - } -} - -#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq)] -pub struct SortConfigurationRevision { - pub id: String, - pub field_id: Option<String>, -} #[derive(Debug, Clone, Serialize, Deserialize, Default, Eq, PartialEq)] #[serde(transparent)] @@ -239,38 +131,3 @@ where &mut self.object_by_field_type } } - -pub trait GroupConfigurationSerde { - fn from_configuration(s: &str) -> Result<Self, serde_json::Error>; -} - -#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq)] -pub struct GroupConfigurationRevision { - pub id: String, - pub field_id: String, - pub field_type_rev: FieldTypeRevision, - pub content: String, -} - -impl GroupConfigurationRevision { - pub fn new<T>(field_id: String, field_type: FieldTypeRevision, content: T) -> Result<Self, serde_json::Error> - where - T: serde::Serialize, - { - let content = serde_json::to_string(&content)?; - Ok(Self { - id: gen_grid_group_id(), - field_id, - field_type_rev: field_type, - content, - }) - } -} - -#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq, Hash)] -pub struct FilterConfigurationRevision { - pub id: String, - pub field_id: String, - pub condition: u8, - pub content: Option<String>, -} diff --git a/shared-lib/flowy-grid-data-model/src/revision/grid_view.rs b/shared-lib/flowy-grid-data-model/src/revision/grid_view.rs index 2fcc2fc4eb..9d4df3067e 100644 --- a/shared-lib/flowy-grid-data-model/src/revision/grid_view.rs +++ b/shared-lib/flowy-grid-data-model/src/revision/grid_view.rs @@ -1,19 +1,49 @@ -use crate::revision::SettingRevision; +use crate::revision::{ + FieldRevision, FieldTypeRevision, FilterConfiguration, FilterConfigurationRevision, FilterConfigurationsByFieldId, + GroupConfiguration, GroupConfigurationRevision, GroupConfigurationsByFieldId, +}; use nanoid::nanoid; use serde::{Deserialize, Serialize}; +use serde_repr::*; +use std::sync::Arc; #[allow(dead_code)] pub fn gen_grid_view_id() -> String { nanoid!(6) } +#[derive(Debug, PartialEq, Eq, Hash, Clone, Serialize_repr, Deserialize_repr)] +#[repr(u8)] +pub enum LayoutRevision { + Table = 0, + Board = 1, +} + +impl ToString for LayoutRevision { + fn to_string(&self) -> String { + let layout_rev = self.clone() as u8; + layout_rev.to_string() + } +} + +impl std::default::Default for LayoutRevision { + fn default() -> Self { + LayoutRevision::Table + } +} + #[derive(Debug, Clone, Default, Serialize, Deserialize)] pub struct GridViewRevision { pub view_id: String, pub grid_id: String, - pub setting: SettingRevision, + pub layout: LayoutRevision, + + pub filters: FilterConfiguration, + + #[serde(default)] + pub groups: GroupConfiguration, // For the moment, we just use the order returned from the GridRevision #[allow(dead_code)] @@ -26,10 +56,78 @@ impl GridViewRevision { GridViewRevision { view_id, grid_id, - setting: Default::default(), + layout: Default::default(), + filters: Default::default(), + groups: Default::default(), row_orders: vec![], } } + + pub fn get_all_groups(&self, field_revs: &[Arc<FieldRevision>]) -> Option<GroupConfigurationsByFieldId> { + self.groups.get_all_objects(field_revs) + } + + pub fn get_groups( + &self, + field_id: &str, + field_type_rev: &FieldTypeRevision, + ) -> Option<Arc<GroupConfigurationRevision>> { + let mut groups = self.groups.get_objects(field_id, field_type_rev)?; + if groups.is_empty() { + debug_assert_eq!(groups.len(), 1); + Some(groups.pop().unwrap()) + } else { + None + } + } + + pub fn get_mut_groups( + &mut self, + field_id: &str, + field_type: &FieldTypeRevision, + ) -> Option<&mut Vec<Arc<GroupConfigurationRevision>>> { + self.groups.get_mut_objects(field_id, field_type) + } + + pub fn insert_group( + &mut self, + field_id: &str, + field_type: &FieldTypeRevision, + group_rev: GroupConfigurationRevision, + ) { + // only one group can be set + self.groups.remove_all(); + self.groups.insert_object(field_id, field_type, group_rev); + } + + pub fn get_all_filters(&self, field_revs: &[Arc<FieldRevision>]) -> Option<FilterConfigurationsByFieldId> { + self.filters.get_all_objects(field_revs) + } + + pub fn get_filters( + &self, + field_id: &str, + field_type_rev: &FieldTypeRevision, + ) -> Option<Vec<Arc<FilterConfigurationRevision>>> { + self.filters.get_objects(field_id, field_type_rev) + } + + pub fn get_mut_filters( + &mut self, + field_id: &str, + field_type: &FieldTypeRevision, + ) -> Option<&mut Vec<Arc<FilterConfigurationRevision>>> { + self.filters.get_mut_objects(field_id, field_type) + } + + pub fn insert_filter( + &mut self, + field_id: &str, + field_type: &FieldTypeRevision, + filter_rev: FilterConfigurationRevision, + ) { + self.filters.insert_object(field_id, field_type, filter_rev); + } } #[derive(Debug, Clone, Default, Serialize, Deserialize)] diff --git a/shared-lib/flowy-grid-data-model/src/revision/group_rev.rs b/shared-lib/flowy-grid-data-model/src/revision/group_rev.rs index 932cc60033..83deeb2735 100644 --- a/shared-lib/flowy-grid-data-model/src/revision/group_rev.rs +++ b/shared-lib/flowy-grid-data-model/src/revision/group_rev.rs @@ -1,32 +1,91 @@ +use crate::revision::{gen_grid_group_id, FieldTypeRevision}; use serde::{Deserialize, Serialize}; +use serde_json::Error; use serde_repr::*; +pub trait GroupConfigurationContentSerde: Sized { + fn from_configuration(s: &str) -> Result<Self, serde_json::Error>; +} + +#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq)] +pub struct GroupConfigurationRevision { + pub id: String, + pub field_id: String, + pub field_type_rev: FieldTypeRevision, + pub content: String, +} + +impl GroupConfigurationRevision { + pub fn new<T>(field_id: String, field_type: FieldTypeRevision, content: T) -> Result<Self, serde_json::Error> + where + T: serde::Serialize, + { + let content = serde_json::to_string(&content)?; + Ok(Self { + id: gen_grid_group_id(), + field_id, + field_type_rev: field_type, + content, + }) + } +} + #[derive(Default, Serialize, Deserialize)] pub struct TextGroupConfigurationRevision { pub hide_empty: bool, } +impl GroupConfigurationContentSerde for TextGroupConfigurationRevision { + fn from_configuration(s: &str) -> Result<Self, Error> { + serde_json::from_str(s) + } +} + #[derive(Default, Serialize, Deserialize)] pub struct NumberGroupConfigurationRevision { pub hide_empty: bool, } +impl GroupConfigurationContentSerde for NumberGroupConfigurationRevision { + fn from_configuration(s: &str) -> Result<Self, Error> { + serde_json::from_str(s) + } +} + #[derive(Default, Serialize, Deserialize)] pub struct UrlGroupConfigurationRevision { pub hide_empty: bool, } +impl GroupConfigurationContentSerde for UrlGroupConfigurationRevision { + fn from_configuration(s: &str) -> Result<Self, Error> { + serde_json::from_str(s) + } +} + #[derive(Default, Serialize, Deserialize)] pub struct CheckboxGroupConfigurationRevision { pub hide_empty: bool, } +impl GroupConfigurationContentSerde for CheckboxGroupConfigurationRevision { + fn from_configuration(s: &str) -> Result<Self, Error> { + serde_json::from_str(s) + } +} + #[derive(Default, Serialize, Deserialize)] pub struct SelectOptionGroupConfigurationRevision { pub hide_empty: bool, pub groups: Vec<GroupRecordRevision>, } +impl GroupConfigurationContentSerde for SelectOptionGroupConfigurationRevision { + fn from_configuration(s: &str) -> Result<Self, Error> { + serde_json::from_str(s) + } +} + #[derive(Default, Serialize, Deserialize)] pub struct GroupRecordRevision { pub group_id: String, @@ -42,6 +101,12 @@ pub struct DateGroupConfigurationRevision { pub condition: DateCondition, } +impl GroupConfigurationContentSerde for DateGroupConfigurationRevision { + fn from_configuration(s: &str) -> Result<Self, Error> { + serde_json::from_str(s) + } +} + #[derive(Serialize_repr, Deserialize_repr)] #[repr(u8)] pub enum DateCondition { diff --git a/shared-lib/flowy-grid-data-model/src/revision/mod.rs b/shared-lib/flowy-grid-data-model/src/revision/mod.rs index d9df0910bd..460370b86b 100644 --- a/shared-lib/flowy-grid-data-model/src/revision/mod.rs +++ b/shared-lib/flowy-grid-data-model/src/revision/mod.rs @@ -1,9 +1,11 @@ +mod filter_rev; mod grid_block; mod grid_rev; mod grid_setting_rev; mod grid_view; mod group_rev; +pub use filter_rev::*; pub use grid_block::*; pub use grid_rev::*; pub use grid_setting_rev::*; diff --git a/shared-lib/flowy-sync/src/client_grid/view_revision_pad.rs b/shared-lib/flowy-sync/src/client_grid/view_revision_pad.rs index db52d0b38b..5ec4a87ef9 100644 --- a/shared-lib/flowy-sync/src/client_grid/view_revision_pad.rs +++ b/shared-lib/flowy-sync/src/client_grid/view_revision_pad.rs @@ -3,7 +3,7 @@ use crate::errors::{internal_error, CollaborateError, CollaborateResult}; use crate::util::{cal_diff, make_text_delta_from_revisions}; use flowy_grid_data_model::revision::{ FieldRevision, FieldTypeRevision, FilterConfigurationRevision, FilterConfigurationsByFieldId, GridViewRevision, - GroupConfigurationRevision, GroupConfigurationsByFieldId, SettingRevision, SortConfigurationsByFieldId, + GroupConfigurationRevision, GroupConfigurationsByFieldId, }; use lib_ot::core::{OperationTransform, PhantomAttributes, TextDelta, TextDeltaBuilder}; use std::sync::Arc; @@ -48,23 +48,11 @@ impl GridViewRevisionPad { Self::from_delta(delta) } - pub fn get_setting_rev(&self) -> &SettingRevision { - &self.view.setting - } - pub fn get_all_groups(&self, field_revs: &[Arc<FieldRevision>]) -> Option<GroupConfigurationsByFieldId> { - self.setting.groups.get_all_objects(field_revs) + self.groups.get_all_objects(field_revs) } - pub fn get_groups( - &self, - field_id: &str, - field_type_rev: &FieldTypeRevision, - ) -> Option<Vec<Arc<GroupConfigurationRevision>>> { - self.setting.groups.get_objects(field_id, field_type_rev) - } - - pub fn insert_group( + pub fn insert_group_configuration( &mut self, field_id: &str, field_type: &FieldTypeRevision, @@ -72,8 +60,8 @@ impl GridViewRevisionPad { ) -> CollaborateResult<Option<GridViewRevisionChangeset>> { self.modify(|view| { // only one group can be set - view.setting.groups.remove_all(); - view.setting.groups.insert_object(field_id, field_type, group_rev); + view.groups.remove_all(); + view.groups.insert_object(field_id, field_type, group_rev); Ok(Some(())) }) } @@ -85,7 +73,7 @@ impl GridViewRevisionPad { group_id: &str, ) -> CollaborateResult<Option<GridViewRevisionChangeset>> { self.modify(|view| { - if let Some(groups) = view.setting.groups.get_mut_objects(field_id, field_type) { + if let Some(groups) = view.groups.get_mut_objects(field_id, field_type) { groups.retain(|group| group.id != group_id); Ok(Some(())) } else { @@ -95,7 +83,7 @@ impl GridViewRevisionPad { } pub fn get_all_filters(&self, field_revs: &[Arc<FieldRevision>]) -> Option<FilterConfigurationsByFieldId> { - self.setting.filters.get_all_objects(field_revs) + self.filters.get_all_objects(field_revs) } pub fn get_filters( @@ -103,7 +91,7 @@ impl GridViewRevisionPad { field_id: &str, field_type_rev: &FieldTypeRevision, ) -> Option<Vec<Arc<FilterConfigurationRevision>>> { - self.setting.filters.get_objects(field_id, field_type_rev) + self.filters.get_objects(field_id, field_type_rev) } pub fn insert_filter( @@ -113,7 +101,7 @@ impl GridViewRevisionPad { filter_rev: FilterConfigurationRevision, ) -> CollaborateResult<Option<GridViewRevisionChangeset>> { self.modify(|view| { - view.setting.filters.insert_object(field_id, field_type, filter_rev); + view.filters.insert_object(field_id, field_type, filter_rev); Ok(Some(())) }) } @@ -125,7 +113,7 @@ impl GridViewRevisionPad { filter_id: &str, ) -> CollaborateResult<Option<GridViewRevisionChangeset>> { self.modify(|view| { - if let Some(filters) = view.setting.filters.get_mut_objects(field_id, field_type) { + if let Some(filters) = view.filters.get_mut_objects(field_id, field_type) { filters.retain(|filter| filter.id != filter_id); Ok(Some(())) } else { @@ -134,10 +122,6 @@ impl GridViewRevisionPad { }) } - pub fn get_all_sort(&self) -> Option<SortConfigurationsByFieldId> { - None - } - pub fn json_str(&self) -> CollaborateResult<String> { make_grid_view_rev_json_str(&self.view) }