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 271cbcf424..e3164c49f8 100644 --- a/frontend/rust-lib/flowy-grid/src/entities/field_entities.rs +++ b/frontend/rust-lib/flowy-grid/src/entities/field_entities.rs @@ -250,13 +250,6 @@ impl TryInto for FieldTypeOptionIdPB { } } -/// Certain field types have user-defined options such as color, date format, number format, -/// or a list of values for a multi-select list. These options are defined within a specialization -/// of the FieldTypeOption class. -/// -/// You could check [this](https://appflowy.gitbook.io/docs/essential-documentation/contribute-to-appflowy/architecture/frontend/grid#fieldtype) -/// for more information. -/// #[derive(Debug, Default, ProtoBuf)] pub struct FieldTypeOptionDataPB { #[pb(index = 1)] @@ -510,7 +503,15 @@ pub struct FieldChangesetParams { pub type_option_data: Option>, } - +/// Certain field types have user-defined options such as color, date format, number format, +/// or a list of values for a multi-select list. These options are defined within a specialization +/// of the FieldTypeOption class. +/// +/// You could check [this](https://appflowy.gitbook.io/docs/essential-documentation/contribute-to-appflowy/architecture/frontend/grid#fieldtype) +/// for more information. +/// +/// The order of the enum can't be changed. If you want to add a new type, +/// it would be better to append it to the end of the list. #[derive( Debug, Clone, @@ -525,8 +526,6 @@ pub struct FieldChangesetParams { Serialize_repr, Deserialize_repr, )] -/// The order of the enum can't be changed. If you want to add a new type, -/// it would be better to append it to the end of the list. #[repr(u8)] pub enum FieldType { RichText = 0, 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 bbcdb56e1b..8382dec4d8 100644 --- a/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs +++ b/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs @@ -193,7 +193,7 @@ impl GridRevisionEditor { .modify(|grid_pad| Ok(grid_pad.replace_field_rev(field_rev.clone())?)) .await?; - match self.view_manager.did_update_field(&field_rev.id, false).await { + match self.view_manager.did_update_view_field(&field_rev.id).await { Ok(_) => {} Err(e) => tracing::error!("View manager update field failed: {:?}", e), } @@ -214,27 +214,28 @@ impl GridRevisionEditor { Ok(()) } + /// Switch the field with id to a new field type. + /// + /// If the field type is not exist before, the default type option data will be created. + /// Each field type has its corresponding data, aka, the type option data. Check out [this](https://appflowy.gitbook.io/docs/essential-documentation/contribute-to-appflowy/architecture/frontend/grid#fieldtype) + /// for more information + /// + /// # Arguments + /// + /// * `field_id`: the id of the field + /// * `field_type`: the new field type of the field + /// pub async fn switch_to_field_type(&self, field_id: &str, field_type: &FieldType) -> FlowyResult<()> { - // let block_ids = self - // .get_block_metas() - // .await? - // .into_iter() - // .map(|block_meta| block_meta.block_id) - // .collect(); - // let cell_revs = self - // .block_meta_manager - // .get_cell_revs(block_ids, field_id, None) - // .await?; - - let type_option_json_builder = |field_type: &FieldTypeRevision| -> String { + let type_option_builder = |field_type: &FieldTypeRevision| -> String { let field_type: FieldType = field_type.into(); + return default_type_option_builder_from_type(&field_type) .data_format() .json_str(); }; let _ = self - .modify(|grid| Ok(grid.switch_to_field(field_id, field_type.clone(), type_option_json_builder)?)) + .modify(|grid| Ok(grid.switch_to_field(field_id, field_type.clone(), type_option_builder)?)) .await?; let _ = self.notify_did_update_grid_field(field_id).await?; @@ -276,6 +277,7 @@ impl GridRevisionEditor { Ok(field_revs) } + #[tracing::instrument(level = "debug", skip_all, err)] async fn update_field_rev(&self, params: FieldChangesetParams, field_type: FieldType) -> FlowyResult<()> { let mut is_type_option_changed = false; let _ = self @@ -333,14 +335,15 @@ impl GridRevisionEditor { }) .await?; - match self - .view_manager - .did_update_field(¶ms.field_id, is_type_option_changed) - .await - { - Ok(_) => {} - Err(e) => tracing::error!("View manager update field failed: {:?}", e), + if is_type_option_changed { + let _ = self + .view_manager + .did_update_view_field_type_option(¶ms.field_id) + .await?; + } else { + let _ = self.view_manager.did_update_view_field(¶ms.field_id).await?; } + Ok(()) } 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 d9f245c8b9..a7ce80f0f5 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 @@ -118,7 +118,9 @@ impl GridViewRevisionEditor { pub(crate) async fn did_delete_view_row(&self, row_rev: &RowRevision) { // Send the group notification if the current view has groups; let changesets = self - .mut_group_controller(|group_controller, field_rev| group_controller.did_delete_row(row_rev, &field_rev)) + .mut_group_controller(|group_controller, field_rev| { + group_controller.did_delete_delete_row(row_rev, &field_rev) + }) .await; if let Some(changesets) = changesets { @@ -131,7 +133,9 @@ impl GridViewRevisionEditor { pub(crate) async fn did_update_view_row(&self, row_rev: &RowRevision) { let changesets = self - .mut_group_controller(|group_controller, field_rev| group_controller.did_update_row(row_rev, &field_rev)) + .mut_group_controller(|group_controller, field_rev| { + group_controller.did_update_group_row(row_rev, &field_rev) + }) .await; if let Some(changesets) = changesets { @@ -239,7 +243,7 @@ impl GridViewRevisionEditor { .await?; } if self.group_controller.read().await.field_id() != params.field_id { - let _ = self.group_by_field(¶ms.field_id).await?; + let _ = self.group_by_view_field(¶ms.field_id).await?; self.notify_did_update_setting().await; } Ok(()) @@ -279,9 +283,9 @@ impl GridViewRevisionEditor { .await } #[tracing::instrument(level = "trace", skip_all, err)] - pub(crate) async fn did_update_field(&self, field_id: &str) -> FlowyResult<()> { + pub(crate) async fn did_update_view_field(&self, field_id: &str) -> FlowyResult<()> { if let Some(field_rev) = self.field_delegate.get_field_rev(field_id).await { - match self.group_controller.write().await.did_update_field(&field_rev)? { + match self.group_controller.write().await.did_update_group_field(&field_rev)? { None => {} Some(changeset) => { self.notify_did_update_view(changeset).await; @@ -291,8 +295,14 @@ impl GridViewRevisionEditor { Ok(()) } + /// + /// + /// # Arguments + /// + /// * `field_id`: + /// #[tracing::instrument(level = "debug", skip_all, err)] - pub(crate) async fn group_by_field(&self, field_id: &str) -> FlowyResult<()> { + pub(crate) async fn group_by_view_field(&self, field_id: &str) -> FlowyResult<()> { if let Some(field_rev) = self.field_delegate.get_field_rev(field_id).await { let new_group_controller = new_group_controller_with_field_rev( self.user_id.clone(), @@ -386,6 +396,7 @@ impl GridViewRevisionEditor { } } } + async fn new_group_controller( user_id: String, view_id: String, @@ -412,6 +423,17 @@ async fn new_group_controller( new_group_controller_with_field_rev(user_id, view_id, view_rev_pad, rev_manager, field_rev, row_delegate).await } +/// Returns a [GroupController] +/// +/// # Arguments +/// +/// * `user_id`: +/// * `view_id`: +/// * `view_rev_pad`: +/// * `rev_manager`: +/// * `field_rev`: +/// * `row_delegate`: +/// async fn new_group_controller_with_field_rev( user_id: String, view_id: String, 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 c57dbda2f2..4af30bd6dc 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 @@ -93,7 +93,7 @@ impl GridViewManager { pub(crate) async fn group_by_field(&self, field_id: &str) -> FlowyResult<()> { let view_editor = self.get_default_view_editor().await?; - let _ = view_editor.group_by_field(field_id).await?; + let _ = view_editor.group_by_view_field(field_id).await?; Ok(()) } @@ -177,18 +177,28 @@ impl GridViewManager { } #[tracing::instrument(level = "trace", skip(self), err)] - pub(crate) async fn did_update_field(&self, field_id: &str, is_type_option_changed: bool) -> FlowyResult<()> { + pub(crate) async fn did_update_view_field(&self, field_id: &str) -> FlowyResult<()> { let view_editor = self.get_default_view_editor().await?; // Only the field_id of the updated field is equal to the field_id of the group. // Update the group if view_editor.group_id().await != field_id { return Ok(()); } - if is_type_option_changed { - let _ = view_editor.group_by_field(field_id).await?; - } else { - let _ = view_editor.did_update_field(field_id).await?; - } + let _ = view_editor.did_update_view_field(field_id).await?; + Ok(()) + } + + /// Notifies the view's field type option data is changed + /// For the moment, only the groups will be generated after the type option data changed. A + /// [FieldRevision] has a property named type_options contains a list of type option data. + /// # Arguments + /// + /// * `field_id`: the id of the field in current view + /// + #[tracing::instrument(level = "trace", skip(self), err)] + pub(crate) async fn did_update_view_field_type_option(&self, field_id: &str) -> FlowyResult<()> { + let view_editor = self.get_default_view_editor().await?; + let _ = view_editor.group_by_view_field(field_id).await?; Ok(()) } diff --git a/frontend/rust-lib/flowy-grid/src/services/group/configuration.rs b/frontend/rust-lib/flowy-grid/src/services/group/configuration.rs index 595af8174a..62ca47482f 100644 --- a/frontend/rust-lib/flowy-grid/src/services/group/configuration.rs +++ b/frontend/rust-lib/flowy-grid/src/services/group/configuration.rs @@ -1,5 +1,5 @@ use crate::entities::{GroupPB, GroupViewChangesetPB}; -use crate::services::group::{default_group_configuration, make_default_group, GeneratedGroup, Group}; +use crate::services::group::{default_group_configuration, make_no_status_group, GeneratedGroupConfig, Group}; use flowy_error::{FlowyError, FlowyResult}; use flowy_grid_data_model::revision::{ FieldRevision, FieldTypeRevision, GroupConfigurationContentSerde, GroupConfigurationRevision, GroupRevision, @@ -34,14 +34,28 @@ impl std::fmt::Display for GroupContext { } } +/// A [GroupContext] represents as the groups memory cache +/// Each [GenericGroupController] has its own [GroupContext], the `context` has its own configuration +/// that is restored from the disk. +/// +/// The `context` contains a list of [Group]s and the grouping [FieldRevision] pub struct GroupContext { pub view_id: String, + /// The group configuration restored from the disk. + /// + /// Uses the [GroupConfigurationReader] to read the configuration data from disk configuration: Arc, - configuration_content: PhantomData, + configuration_phantom: PhantomData, + + /// The grouping field field_rev: Arc, + + /// Cache all the groups groups_map: IndexMap, - /// default_group is used to store the rows that don't belong to any groups. - // default_group: Group, + + /// A writer that implement the [GroupConfigurationWriter] trait is used to save the + /// configuration to disk + /// writer: Arc, } @@ -73,19 +87,21 @@ where groups_map: IndexMap::new(), writer, configuration, - configuration_content: PhantomData, + configuration_phantom: PhantomData, }) } - pub(crate) fn get_default_group(&self) -> Option<&Group> { + /// Returns the no `status` group + /// + /// We take the `id` of the `field` as the default group id + pub(crate) fn get_no_status_group(&self) -> Option<&Group> { self.groups_map.get(&self.field_rev.id) } - pub(crate) fn get_mut_default_group(&mut self) -> Option<&mut Group> { + pub(crate) fn get_mut_no_status_group(&mut self) -> Option<&mut Group> { self.groups_map.get_mut(&self.field_rev.id) } - /// Returns the groups without the default group pub(crate) fn groups(&self) -> Vec<&Group> { self.groups_map.values().collect() } @@ -142,23 +158,38 @@ where } } - #[tracing::instrument(level = "debug", skip(self, generated_groups), err)] + /// Reset the memory cache of the groups and update the group configuration + /// + /// # Arguments + /// + /// * `generated_group_configs`: the generated groups contains a list of [GeneratedGroupConfig]. + /// + /// Each [FieldType] can implement the [GroupGenerator] trait in order to generate different + /// groups. For example, the FieldType::Checkbox has the [CheckboxGroupGenerator] that implements + /// the [GroupGenerator] trait. + /// + /// Consider the passed-in generated_group_configs as new groups, the groups in the current + /// [GroupConfigurationRevision] as old groups. The old groups and the new groups will be merged + /// while keeping the order of the old groups. + /// + #[tracing::instrument(level = "debug", skip(self, generated_group_configs), err)] pub(crate) fn init_groups( &mut self, - generated_groups: Vec, + generated_group_configs: Vec, ) -> FlowyResult> { let mut new_groups = vec![]; let mut filter_content_map = HashMap::new(); - generated_groups.into_iter().for_each(|generate_group| { + generated_group_configs.into_iter().for_each(|generate_group| { filter_content_map.insert(generate_group.group_rev.id.clone(), generate_group.filter_content); new_groups.push(generate_group.group_rev); }); let mut old_groups = self.configuration.groups.clone(); if !old_groups.iter().any(|group| group.id == self.field_rev.id) { - old_groups.push(make_default_group(&self.field_rev)); + old_groups.push(make_no_status_group(&self.field_rev)); } + // The `all_group_revs` represents as the combination of the new groups and old groups let MergeGroupResult { mut all_group_revs, new_group_revs, @@ -171,6 +202,7 @@ where .map(|group_rev| group_rev.id) .collect::>(); + // Delete/Insert the group in the current configuration self.mut_configuration(|configuration| { let mut is_changed = false; if !deleted_group_ids.is_empty() { @@ -179,7 +211,6 @@ where .retain(|group| !deleted_group_ids.contains(&group.id)); is_changed = true; } - for group_rev in &mut all_group_revs { match configuration .groups @@ -187,14 +218,20 @@ where .position(|old_group_rev| old_group_rev.id == group_rev.id) { None => { + // Push the group to the end of the list if it doesn't exist in the group configuration.groups.push(group_rev.clone()); is_changed = true; } Some(pos) => { let mut old_group = configuration.groups.remove(pos); - group_rev.update_with_other(&old_group); - is_changed = is_group_changed(group_rev, &old_group); + // Take the old group setting + group_rev.update_with_other(&old_group); + if !is_changed { + is_changed = is_group_changed(group_rev, &old_group); + } + + // Consider the the name of the `group_rev` as the newest. old_group.name = group_rev.name.clone(); configuration.groups.insert(pos, old_group); } @@ -203,6 +240,7 @@ where is_changed })?; + // Update the memory cache of the groups all_group_revs.into_iter().for_each(|group_rev| { let filter_content = filter_content_map .get(&group_rev.id) @@ -257,24 +295,6 @@ where Ok(()) } - #[tracing::instrument(level = "trace", skip_all, err)] - pub fn save_configuration(&self) -> FlowyResult<()> { - let configuration = (&*self.configuration).clone(); - let writer = self.writer.clone(); - let field_id = self.field_rev.id.clone(); - let field_type = self.field_rev.ty; - tokio::spawn(async move { - match writer.save_configuration(&field_id, field_type, configuration).await { - Ok(_) => {} - Err(e) => { - tracing::error!("Save group configuration failed: {}", e); - } - } - }); - - Ok(()) - } - fn mut_configuration( &mut self, mut_configuration_fn: impl FnOnce(&mut GroupConfigurationRevision) -> bool, @@ -282,7 +302,18 @@ where let configuration = Arc::make_mut(&mut self.configuration); let is_changed = mut_configuration_fn(configuration); if is_changed { - let _ = self.save_configuration()?; + let configuration = (&*self.configuration).clone(); + let writer = self.writer.clone(); + let field_id = self.field_rev.id.clone(); + let field_type = self.field_rev.ty; + tokio::spawn(async move { + match writer.save_configuration(&field_id, field_type, configuration).await { + Ok(_) => {} + Err(e) => { + tracing::error!("Save group configuration failed: {}", e); + } + } + }); } Ok(()) } @@ -302,13 +333,6 @@ where fn merge_groups(old_groups: Vec, new_groups: Vec) -> MergeGroupResult { let mut merge_result = MergeGroupResult::new(); - // if old_groups.is_empty() { - // merge_result.all_group_revs.extend(new_groups.clone()); - // merge_result.all_group_revs.push(default_group); - // merge_result.new_group_revs = new_groups; - // return merge_result; - // } - // group_map is a helper map is used to filter out the new groups. let mut new_group_map: IndexMap = IndexMap::new(); new_groups.into_iter().for_each(|group_rev| { diff --git a/frontend/rust-lib/flowy-grid/src/services/group/controller.rs b/frontend/rust-lib/flowy-grid/src/services/group/controller.rs index 1a7bc8d218..1c0f724c0f 100644 --- a/frontend/rust-lib/flowy-grid/src/services/group/controller.rs +++ b/frontend/rust-lib/flowy-grid/src/services/group/controller.rs @@ -10,14 +10,20 @@ use flowy_grid_data_model::revision::{ use std::marker::PhantomData; use std::sync::Arc; -// 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: GroupControllerSharedOperation + Send + Sync { +/// The [GroupController] trait defines the group actions, including create/delete/move items +/// For example, the group will insert a item if the one of the new [RowRevision]'s [CellRevision]s +/// content match the group filter. +/// +/// Different [FieldType] has a different controller that implements the [GroupController] trait. +/// If the [FieldType] doesn't implement its group controller, then the [DefaultGroupController] will +/// be used. +/// +pub trait GroupController: GroupControllerActions + Send + Sync { fn will_create_row(&mut self, row_rev: &mut RowRevision, field_rev: &FieldRevision, group_id: &str); fn did_create_row(&mut self, row_pb: &RowPB, group_id: &str); } +/// The [GroupGenerator] trait is used to generate the groups for different [FieldType] pub trait GroupGenerator { type Context; type TypeOptionType; @@ -26,10 +32,10 @@ pub trait GroupGenerator { field_id: &str, group_ctx: &Self::Context, type_option: &Option, - ) -> Vec; + ) -> Vec; } -pub struct GeneratedGroup { +pub struct GeneratedGroupConfig { pub group_rev: GroupRevision, pub filter_content: String, } @@ -42,29 +48,42 @@ pub struct MoveGroupRowContext<'a> { pub to_row_id: Option, } -// Defines the shared actions each group controller can perform. -pub trait GroupControllerSharedOperation: Send + Sync { - // The field that is used for grouping the rows +/// Defines the shared actions each group controller can perform. +pub trait GroupControllerActions: Send + Sync { + /// The field that is used for grouping the rows fn field_id(&self) -> &str; + + /// Returns number of groups the current field has fn groups(&self) -> Vec; + + /// Returns the index and the group data with group_id fn get_group(&self, group_id: &str) -> Option<(usize, Group)>; + + /// Separates the rows into different groups fn fill_groups(&mut self, row_revs: &[Arc], field_rev: &FieldRevision) -> FlowyResult<()>; + + /// Remove the group with from_group_id and insert it to the index with to_group_id fn move_group(&mut self, from_group_id: &str, to_group_id: &str) -> FlowyResult<()>; - fn did_update_row( + + /// Insert the row to the group if the corresponding cell data is changed + fn did_update_group_row( &mut self, row_rev: &RowRevision, field_rev: &FieldRevision, ) -> FlowyResult>; - fn did_delete_row( + /// Remove the row from the group if the corresponding cell data is changed + fn did_delete_delete_row( &mut self, row_rev: &RowRevision, field_rev: &FieldRevision, ) -> FlowyResult>; + /// Move the row from one group to another group fn move_group_row(&mut self, context: MoveGroupRowContext) -> FlowyResult>; - fn did_update_field(&mut self, field_rev: &FieldRevision) -> FlowyResult>; + /// Update the group if the corresponding field is changed + fn did_update_group_field(&mut self, field_rev: &FieldRevision) -> FlowyResult>; } /// C: represents the group configuration that impl [GroupConfigurationSerde] @@ -106,7 +125,7 @@ where row_rev: &RowRevision, other_group_changesets: &[GroupChangesetPB], ) -> Option { - let default_group = self.group_ctx.get_mut_default_group()?; + let default_group = self.group_ctx.get_mut_no_status_group()?; // [other_group_inserted_row] contains all the inserted rows except the default group. let other_group_inserted_row = other_group_changesets @@ -167,7 +186,7 @@ where } } -impl GroupControllerSharedOperation for GenericGroupController +impl GroupControllerActions for GenericGroupController where P: CellBytesParser, C: GroupConfigurationContentSerde, @@ -228,7 +247,7 @@ where continue; } } - match self.group_ctx.get_mut_default_group() { + match self.group_ctx.get_mut_no_status_group() { None => {} Some(default_group) => default_group.add_row(row_rev.into()), } @@ -242,7 +261,7 @@ where self.group_ctx.move_group(from_group_id, to_group_id) } - fn did_update_row( + fn did_update_group_row( &mut self, row_rev: &RowRevision, field_rev: &FieldRevision, @@ -263,7 +282,7 @@ where } } - fn did_delete_row( + fn did_delete_delete_row( &mut self, row_rev: &RowRevision, field_rev: &FieldRevision, @@ -273,7 +292,7 @@ where let cell_bytes = decode_any_cell_data(cell_rev.data.clone(), field_rev).1; let cell_data = cell_bytes.parser::

()?; Ok(self.remove_row_if_match(row_rev, &cell_data)) - } else if let Some(group) = self.group_ctx.get_default_group() { + } else if let Some(group) = self.group_ctx.get_no_status_group() { Ok(vec![GroupChangesetPB::delete( group.id.clone(), vec![row_rev.id.clone()], @@ -300,7 +319,7 @@ where } } - fn did_update_field(&mut self, field_rev: &FieldRevision) -> FlowyResult> { + fn did_update_group_field(&mut self, field_rev: &FieldRevision) -> FlowyResult> { let type_option = field_rev.get_type_option::(field_rev.ty); let groups = G::generate_groups(&field_rev.id, &self.group_ctx, &type_option); let changeset = self.group_ctx.init_groups(groups)?; diff --git a/frontend/rust-lib/flowy-grid/src/services/group/controller_impls/checkbox_controller.rs b/frontend/rust-lib/flowy-grid/src/services/group/controller_impls/checkbox_controller.rs index a15b0cc62b..b26ff9bdbe 100644 --- a/frontend/rust-lib/flowy-grid/src/services/group/controller_impls/checkbox_controller.rs +++ b/frontend/rust-lib/flowy-grid/src/services/group/controller_impls/checkbox_controller.rs @@ -7,7 +7,7 @@ use crate::services::group::controller::{ }; use crate::services::cell::insert_checkbox_cell; -use crate::services::group::{move_group_row, GeneratedGroup}; +use crate::services::group::{move_group_row, GeneratedGroupConfig}; use flowy_grid_data_model::revision::{ CellRevision, CheckboxGroupConfigurationRevision, FieldRevision, GroupRevision, RowRevision, }; @@ -116,13 +116,13 @@ impl GroupGenerator for CheckboxGroupGenerator { _field_id: &str, _group_ctx: &Self::Context, _type_option: &Option, - ) -> Vec { - let check_group = GeneratedGroup { + ) -> Vec { + let check_group = GeneratedGroupConfig { group_rev: GroupRevision::new(CHECK.to_string(), "".to_string()), filter_content: CHECK.to_string(), }; - let uncheck_group = GeneratedGroup { + let uncheck_group = GeneratedGroupConfig { group_rev: GroupRevision::new(UNCHECK.to_string(), "".to_string()), filter_content: UNCHECK.to_string(), }; diff --git a/frontend/rust-lib/flowy-grid/src/services/group/controller_impls/default_controller.rs b/frontend/rust-lib/flowy-grid/src/services/group/controller_impls/default_controller.rs index ddcdd7f3e1..02bd1a6fb8 100644 --- a/frontend/rust-lib/flowy-grid/src/services/group/controller_impls/default_controller.rs +++ b/frontend/rust-lib/flowy-grid/src/services/group/controller_impls/default_controller.rs @@ -1,9 +1,13 @@ use crate::entities::{GroupChangesetPB, GroupViewChangesetPB, RowPB}; -use crate::services::group::{Group, GroupController, GroupControllerSharedOperation, MoveGroupRowContext}; +use crate::services::group::{Group, GroupController, GroupControllerActions, MoveGroupRowContext}; use flowy_error::FlowyResult; use flowy_grid_data_model::revision::{FieldRevision, RowRevision}; use std::sync::Arc; +/// A [DefaultGroupController] is used to handle the group actions for the [FieldType] that doesn't +/// implement its own group controller. The default group controller only contains one group, which +/// means all rows will be grouped in the same group. +/// pub struct DefaultGroupController { pub field_id: String, pub group: Group, @@ -26,7 +30,7 @@ impl DefaultGroupController { } } -impl GroupControllerSharedOperation for DefaultGroupController { +impl GroupControllerActions for DefaultGroupController { fn field_id(&self) -> &str { &self.field_id } @@ -50,7 +54,7 @@ impl GroupControllerSharedOperation for DefaultGroupController { Ok(()) } - fn did_update_row( + fn did_update_group_row( &mut self, _row_rev: &RowRevision, _field_rev: &FieldRevision, @@ -58,7 +62,7 @@ impl GroupControllerSharedOperation for DefaultGroupController { Ok(vec![]) } - fn did_delete_row( + fn did_delete_delete_row( &mut self, _row_rev: &RowRevision, _field_rev: &FieldRevision, @@ -70,7 +74,7 @@ impl GroupControllerSharedOperation for DefaultGroupController { todo!() } - fn did_update_field(&mut self, _field_rev: &FieldRevision) -> FlowyResult> { + fn did_update_group_field(&mut self, _field_rev: &FieldRevision) -> FlowyResult> { Ok(None) } } 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 index 4905c6eaa7..cf32043379 100644 --- 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 @@ -8,7 +8,7 @@ use crate::services::group::controller::{ }; use crate::services::group::controller_impls::select_option_controller::util::*; -use crate::services::group::GeneratedGroup; +use crate::services::group::GeneratedGroupConfig; use flowy_grid_data_model::revision::{FieldRevision, RowRevision, SelectOptionGroupConfigurationRevision}; // MultiSelect @@ -83,7 +83,7 @@ impl GroupGenerator for MultiSelectGroupGenerator { field_id: &str, group_ctx: &Self::Context, type_option: &Option, - ) -> Vec { + ) -> Vec { match type_option { None => vec![], Some(type_option) => generate_select_option_groups(field_id, group_ctx, &type_option.options), 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 index 0c86166520..3d39b20018 100644 --- 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 @@ -9,7 +9,7 @@ use crate::services::group::controller::{ use crate::services::group::controller_impls::select_option_controller::util::*; use crate::services::group::entities::Group; -use crate::services::group::GeneratedGroup; +use crate::services::group::GeneratedGroupConfig; use flowy_grid_data_model::revision::{FieldRevision, RowRevision, SelectOptionGroupConfigurationRevision}; // SingleSelect @@ -83,7 +83,7 @@ impl GroupGenerator for SingleSelectGroupGenerator { field_id: &str, group_ctx: &Self::Context, type_option: &Option, - ) -> Vec { + ) -> Vec { match type_option { None => vec![], Some(type_option) => generate_select_option_groups(field_id, group_ctx, &type_option.options), 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 index e5cbc8a8ec..e2e3455665 100644 --- 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 @@ -3,7 +3,7 @@ use crate::services::cell::{insert_checkbox_cell, insert_select_option_cell}; use crate::services::field::{SelectOptionCellDataPB, SelectOptionPB, CHECK}; use crate::services::group::configuration::GroupContext; use crate::services::group::controller::MoveGroupRowContext; -use crate::services::group::{GeneratedGroup, Group}; +use crate::services::group::{GeneratedGroupConfig, Group}; use flowy_grid_data_model::revision::{ CellRevision, FieldRevision, GroupRevision, RowRevision, SelectOptionGroupConfigurationRevision, }; @@ -155,10 +155,10 @@ pub fn generate_select_option_groups( _field_id: &str, _group_ctx: &SelectOptionGroupContext, options: &[SelectOptionPB], -) -> Vec { +) -> Vec { let groups = options .iter() - .map(|option| GeneratedGroup { + .map(|option| GeneratedGroupConfig { group_rev: GroupRevision::new(option.id.clone(), option.name.clone()), filter_content: option.id.clone(), }) diff --git a/frontend/rust-lib/flowy-grid/src/services/group/group_util.rs b/frontend/rust-lib/flowy-grid/src/services/group/group_util.rs index 8a901fd869..683bce705f 100644 --- a/frontend/rust-lib/flowy-grid/src/services/group/group_util.rs +++ b/frontend/rust-lib/flowy-grid/src/services/group/group_util.rs @@ -13,6 +13,17 @@ use flowy_grid_data_model::revision::{ }; use std::sync::Arc; +/// Returns a group controller. +/// +/// Each view can be grouped by one field, each field has its own group controller. +/// # Arguments +/// +/// * `view_id`: the id of the view +/// * `field_rev`: the grouping field +/// * `row_revs`: the rows will be separated into different groups +/// * `configuration_reader`: a reader used to read the group configuration from disk +/// * `configuration_writer`: as writer used to write the group configuration to disk +/// #[tracing::instrument(level = "trace", skip_all, err)] pub async fn make_group_controller( view_id: String, @@ -58,6 +69,7 @@ where } } + // Separates the rows into different groups let _ = group_controller.fill_groups(&row_revs, &field_rev)?; Ok(group_controller) } @@ -75,6 +87,12 @@ pub fn find_group_field(field_revs: &[Arc], layout: &LayoutRevisi } } +/// Returns a `default` group configuration for the [FieldRevision] +/// +/// # Arguments +/// +/// * `field_rev`: making the group configuration for the field +/// pub fn default_group_configuration(field_rev: &FieldRevision) -> GroupConfigurationRevision { let field_id = field_rev.id.clone(); let field_type_rev = field_rev.ty; @@ -115,17 +133,17 @@ pub fn default_group_configuration(field_rev: &FieldRevision) -> GroupConfigurat }; // Append the no `status` group - let default_group_rev = GroupRevision { + let no_status_group_rev = GroupRevision { id: field_rev.id.clone(), name: format!("No {}", field_rev.name), visible: true, }; - group_configuration_rev.groups.push(default_group_rev); + group_configuration_rev.groups.push(no_status_group_rev); group_configuration_rev } -pub fn make_default_group(field_rev: &FieldRevision) -> GroupRevision { +pub fn make_no_status_group(field_rev: &FieldRevision) -> GroupRevision { GroupRevision { id: field_rev.id.clone(), name: format!("No {}", field_rev.name), diff --git a/shared-lib/flowy-sync/src/client_grid/grid_revision_pad.rs b/shared-lib/flowy-sync/src/client_grid/grid_revision_pad.rs index df80521fae..bd80eb02c9 100644 --- a/shared-lib/flowy-sync/src/client_grid/grid_revision_pad.rs +++ b/shared-lib/flowy-sync/src/client_grid/grid_revision_pad.rs @@ -133,11 +133,20 @@ impl GridRevisionPad { ) } + /// Modifies the current field type of the [FieldTypeRevision] + /// + /// # Arguments + /// + /// * `field_id`: the id of the field + /// * `field_type`: the new field type of the field + /// * `type_option_builder`: builder for creating the field type's type option data + /// + /// pub fn switch_to_field( &mut self, field_id: &str, field_type: T, - type_option_json_builder: B, + type_option_builder: B, ) -> CollaborateResult> where B: FnOnce(&FieldTypeRevision) -> String, @@ -153,8 +162,9 @@ impl GridRevisionPad { } Some(field_rev) => { let mut_field_rev = Arc::make_mut(field_rev); + // If the type option data isn't exist before, creating the default type option data. if mut_field_rev.get_type_option_str(field_type).is_none() { - let type_option_json = type_option_json_builder(&field_type); + let type_option_json = type_option_builder(&field_type); mut_field_rev.insert_type_option_str(&field_type, type_option_json); }