diff --git a/frontend/rust-lib/flowy-grid/src/entities/block_entities.rs b/frontend/rust-lib/flowy-grid/src/entities/block_entities.rs index b712a701df..4d4fcc78c1 100644 --- a/frontend/rust-lib/flowy-grid/src/entities/block_entities.rs +++ b/frontend/rust-lib/flowy-grid/src/entities/block_entities.rs @@ -146,9 +146,9 @@ pub struct GridBlockChangesetPB { pub hide_rows: Vec, } impl GridBlockChangesetPB { - pub fn insert(block_id: &str, inserted_rows: Vec) -> Self { + pub fn insert(block_id: String, inserted_rows: Vec) -> Self { Self { - block_id: block_id.to_owned(), + block_id, inserted_rows, ..Default::default() } diff --git a/frontend/rust-lib/flowy-grid/src/entities/group_entities/board_card.rs b/frontend/rust-lib/flowy-grid/src/entities/group_entities/board_card.rs new file mode 100644 index 0000000000..d641c2d723 --- /dev/null +++ b/frontend/rust-lib/flowy-grid/src/entities/group_entities/board_card.rs @@ -0,0 +1,29 @@ +use flowy_derive::ProtoBuf; +use flowy_error::ErrorCode; +use flowy_grid_data_model::parser::NotEmptyStr; + +#[derive(ProtoBuf, Debug, Default, Clone)] +pub struct CreateBoardCardPayloadPB { + #[pb(index = 1)] + pub grid_id: String, + + #[pb(index = 2)] + pub group_id: String, +} +pub struct CreateBoardCardParams { + pub grid_id: String, + pub group_id: String, +} + +impl TryInto for CreateBoardCardPayloadPB { + type Error = ErrorCode; + + fn try_into(self) -> Result { + let grid_id = NotEmptyStr::parse(self.grid_id).map_err(|_| ErrorCode::GridIdIsEmpty)?; + let group_id = NotEmptyStr::parse(self.group_id).map_err(|_| ErrorCode::GroupIdIsEmpty)?; + Ok(CreateBoardCardParams { + grid_id: grid_id.0, + group_id: group_id.0, + }) + } +} diff --git a/frontend/rust-lib/flowy-grid/src/entities/group_entities/mod.rs b/frontend/rust-lib/flowy-grid/src/entities/group_entities/mod.rs index c1834c1009..7aa3a1a43e 100644 --- a/frontend/rust-lib/flowy-grid/src/entities/group_entities/mod.rs +++ b/frontend/rust-lib/flowy-grid/src/entities/group_entities/mod.rs @@ -1,5 +1,7 @@ +mod board_card; mod configuration; mod group; +pub use board_card::*; pub use configuration::*; pub use group::*; diff --git a/frontend/rust-lib/flowy-grid/src/event_handler.rs b/frontend/rust-lib/flowy-grid/src/event_handler.rs index e834c4652e..7f8ae72773 100644 --- a/frontend/rust-lib/flowy-grid/src/event_handler.rs +++ b/frontend/rust-lib/flowy-grid/src/event_handler.rs @@ -416,3 +416,14 @@ pub(crate) async fn get_groups_handler( let group = editor.load_groups().await?; data_result(group) } + +#[tracing::instrument(level = "debug", skip(data, manager), err)] +pub(crate) async fn create_board_card_handler( + data: Data, + manager: AppData>, +) -> DataResult { + let params: CreateBoardCardParams = data.into_inner().try_into()?; + let editor = manager.get_grid_editor(params.grid_id.as_ref())?; + let row = editor.create_board_card().await?; + data_result(row) +} diff --git a/frontend/rust-lib/flowy-grid/src/event_map.rs b/frontend/rust-lib/flowy-grid/src/event_map.rs index 9e0b2ef5dd..9a5303220c 100644 --- a/frontend/rust-lib/flowy-grid/src/event_map.rs +++ b/frontend/rust-lib/flowy-grid/src/event_map.rs @@ -39,6 +39,7 @@ pub fn create(grid_manager: Arc) -> Module { // Date .event(GridEvent::UpdateDateCell, update_date_cell_handler) // Group + .event(GridEvent::CreateBoardCard, create_row_handler) .event(GridEvent::GetGroup, get_groups_handler); module @@ -209,4 +210,7 @@ pub enum GridEvent { #[event(input = "GridIdPB", output = "RepeatedGridGroupPB")] GetGroup = 100, + + #[event(input = "CreateBoardCardPayloadPB", output = "RowPB")] + CreateBoardCard = 110, } diff --git a/frontend/rust-lib/flowy-grid/src/services/block_manager.rs b/frontend/rust-lib/flowy-grid/src/services/block_manager.rs index afeb58c5d4..8da912534f 100644 --- a/frontend/rust-lib/flowy-grid/src/services/block_manager.rs +++ b/frontend/rust-lib/flowy-grid/src/services/block_manager.rs @@ -62,22 +62,16 @@ impl GridBlockManager { Ok(self.get_editor(&block_id).await?) } - pub(crate) async fn create_row( - &self, - block_id: &str, - row_rev: RowRevision, - start_row_id: Option, - ) -> FlowyResult { + pub(crate) async fn create_row(&self, row_rev: RowRevision, start_row_id: Option) -> FlowyResult { + let block_id = row_rev.block_id.clone(); let _ = self.persistence.insert(&row_rev.block_id, &row_rev.id)?; let editor = self.get_editor(&row_rev.block_id).await?; let mut index_row_order = InsertedRowPB::from(&row_rev); let (row_count, row_index) = editor.create_row(row_rev, start_row_id).await?; index_row_order.index = row_index; - - let _ = self - .notify_did_update_block(block_id, GridBlockChangesetPB::insert(block_id, vec![index_row_order])) - .await?; + let changeset = GridBlockChangesetPB::insert(block_id.clone(), vec![index_row_order]); + let _ = self.notify_did_update_block(&block_id, changeset).await?; Ok(row_count) } @@ -98,10 +92,16 @@ impl GridBlockManager { row_order.index = index; inserted_row_orders.push(row_order); } - changesets.push(GridBlockMetaRevisionChangeset::from_row_count(&block_id, row_count)); + changesets.push(GridBlockMetaRevisionChangeset::from_row_count( + block_id.clone(), + row_count, + )); let _ = self - .notify_did_update_block(&block_id, GridBlockChangesetPB::insert(&block_id, inserted_row_orders)) + .notify_did_update_block( + &block_id, + GridBlockChangesetPB::insert(block_id.clone(), inserted_row_orders), + ) .await?; } @@ -154,7 +154,7 @@ impl GridBlockManager { .map(|row_info| Cow::Owned(row_info.row_id().to_owned())) .collect::>>(); let row_count = editor.delete_rows(row_ids).await?; - let changeset = GridBlockMetaRevisionChangeset::from_row_count(&grid_block.id, row_count); + let changeset = GridBlockMetaRevisionChangeset::from_row_count(grid_block.id.clone(), row_count); changesets.push(changeset); } 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 f2e28701df..82c4b23afb 100644 --- a/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs +++ b/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs @@ -37,7 +37,7 @@ pub struct GridRevisionEditor { pub(crate) filter_service: Arc, #[allow(dead_code)] - pub(crate) group_service: Arc, + pub(crate) group_service: Arc>, } impl Drop for GridRevisionEditor { @@ -62,17 +62,17 @@ impl GridRevisionEditor { let block_meta_revs = grid_pad.read().await.get_block_meta_revs(); let block_manager = Arc::new(GridBlockManager::new(grid_id, &user, block_meta_revs, persistence).await?); let filter_service = - Arc::new(GridFilterService::new(grid_pad.clone(), block_manager.clone(), task_scheduler.clone()).await); + GridFilterService::new(grid_pad.clone(), block_manager.clone(), task_scheduler.clone()).await; let group_service = - Arc::new(GridGroupService::new(grid_pad.clone(), block_manager.clone(), task_scheduler.clone()).await); + GridGroupService::new(grid_pad.clone(), block_manager.clone(), task_scheduler.clone()).await; let editor = Arc::new(Self { grid_id: grid_id.to_owned(), user, grid_pad, rev_manager, block_manager, - filter_service, - group_service, + filter_service: Arc::new(filter_service), + group_service: Arc::new(RwLock::new(group_service)), }); Ok(editor) @@ -275,20 +275,8 @@ impl GridRevisionEditor { } pub async fn create_row(&self, start_row_id: Option) -> FlowyResult { - let field_revs = self.grid_pad.read().await.get_field_revs(None)?; - let block_id = self.block_id().await?; - - // insert empty row below the row whose id is upper_row_id - let row_rev = RowRevisionBuilder::new(&block_id, &field_revs).build(); - let row_order = RowPB::from(&row_rev); - - // insert the row - let row_count = self.block_manager.create_row(&block_id, row_rev, start_row_id).await?; - - // update block row count - let changeset = GridBlockMetaRevisionChangeset::from_row_count(&block_id, row_count); - let _ = self.update_block(changeset).await?; - Ok(row_order) + let row_rev = self.create_row_rev().await?; + self.create_row_pb(row_rev, start_row_id).await } pub async fn insert_rows(&self, row_revs: Vec) -> FlowyResult> { @@ -564,12 +552,40 @@ impl GridRevisionEditor { }) } + pub async fn create_board_card(&self) -> FlowyResult { + let mut row_rev = self.create_row_rev().await?; + let _ = self.group_service.write().await.create_board_card(&mut row_rev).await; + self.create_row_pb(row_rev, None).await + } + #[tracing::instrument(level = "trace", skip_all, err)] pub async fn load_groups(&self) -> FlowyResult { - let groups = self.group_service.load_groups().await.unwrap_or_default(); + let groups = self.group_service.write().await.load_groups().await.unwrap_or_default(); Ok(RepeatedGridGroupPB { items: groups }) } + async fn create_row_rev(&self) -> FlowyResult { + let field_revs = self.grid_pad.read().await.get_field_revs(None)?; + let block_id = self.block_id().await?; + + // insert empty row below the row whose id is upper_row_id + let row_rev = RowRevisionBuilder::new(&block_id, &field_revs).build(); + Ok(row_rev) + } + + async fn create_row_pb(&self, row_rev: RowRevision, start_row_id: Option) -> FlowyResult { + let row_pb = RowPB::from(&row_rev); + let block_id = row_rev.block_id.clone(); + + // insert the row + let row_count = self.block_manager.create_row(row_rev, start_row_id).await?; + + // update block row count + let changeset = GridBlockMetaRevisionChangeset::from_row_count(block_id, row_count); + let _ = self.update_block(changeset).await?; + Ok(row_pb) + } + async fn modify(&self, f: F) -> FlowyResult<()> where F: for<'a> FnOnce(&'a mut GridRevisionPad) -> FlowyResult>, diff --git a/frontend/rust-lib/flowy-grid/src/services/group/group_generator/checkbox_group.rs b/frontend/rust-lib/flowy-grid/src/services/group/group_generator/checkbox_group.rs index 32b699d3a1..b976310bed 100644 --- a/frontend/rust-lib/flowy-grid/src/services/group/group_generator/checkbox_group.rs +++ b/frontend/rust-lib/flowy-grid/src/services/group/group_generator/checkbox_group.rs @@ -1,17 +1,43 @@ -use crate::entities::CheckboxGroupConfigurationPB; +use crate::entities::{CheckboxGroupConfigurationPB, RowPB}; +use flowy_error::FlowyResult; +use flowy_grid_data_model::revision::RowRevision; use crate::services::field::{CheckboxCellData, CheckboxCellDataParser, CheckboxTypeOptionPB, CHECK, UNCHECK}; -use crate::services::group::{Group, GroupAction, GroupCellContentProvider, GroupController, GroupGenerator}; +use crate::services::group::{ + Group, GroupActionHandler, GroupCellContentProvider, GroupController, GroupGenerator, Groupable, +}; pub type CheckboxGroupController = GroupController; +impl Groupable for CheckboxGroupController { + type CellDataType = CheckboxCellData; + + fn can_group(&self, _content: &str, _cell_data: &Self::CellDataType) -> bool { + false + } +} + +impl GroupActionHandler for CheckboxGroupController { + fn get_groups(&self) -> Vec { + self.groups() + } + + fn group_row(&mut self, row_rev: &RowRevision) -> FlowyResult<()> { + self.handle_row(row_rev) + } + + fn create_card(&self, row_rev: &mut RowRevision) { + todo!() + } +} + pub struct CheckboxGroupGenerator(); impl GroupGenerator for CheckboxGroupGenerator { type ConfigurationType = CheckboxGroupConfigurationPB; type TypeOptionType = CheckboxTypeOptionPB; - fn gen_groups( + fn generate_groups( _configuration: &Option, _type_option: &Option, _cell_content_provider: &dyn GroupCellContentProvider, @@ -33,11 +59,3 @@ impl GroupGenerator for CheckboxGroupGenerator { vec![check_group, uncheck_group] } } - -impl GroupAction for CheckboxGroupController { - type CellDataType = CheckboxCellData; - - fn should_group(&self, _content: &str, _cell_data: &Self::CellDataType) -> bool { - false - } -} diff --git a/frontend/rust-lib/flowy-grid/src/services/group/group_generator/generator.rs b/frontend/rust-lib/flowy-grid/src/services/group/group_generator/generator.rs index 1682bd9fbb..b841e745e4 100644 --- a/frontend/rust-lib/flowy-grid/src/services/group/group_generator/generator.rs +++ b/frontend/rust-lib/flowy-grid/src/services/group/group_generator/generator.rs @@ -9,12 +9,6 @@ use indexmap::IndexMap; use std::marker::PhantomData; use std::sync::Arc; -pub trait GroupAction { - type CellDataType; - - fn should_group(&self, content: &str, cell_data: &Self::CellDataType) -> bool; -} - pub trait GroupCellContentProvider { /// We need to group the rows base on the deduplication cell content when the field type is /// RichText. @@ -27,25 +21,47 @@ pub trait GroupGenerator { type ConfigurationType; type TypeOptionType; - fn gen_groups( + fn generate_groups( configuration: &Option, type_option: &Option, cell_content_provider: &dyn GroupCellContentProvider, ) -> Vec; } +pub trait Groupable { + type CellDataType; + fn can_group(&self, content: &str, cell_data: &Self::CellDataType) -> bool; +} + +pub trait GroupActionHandler: Send + Sync { + fn get_groups(&self) -> Vec; + fn group_row(&mut self, row_rev: &RowRevision) -> FlowyResult<()>; + fn group_rows(&mut self, row_revs: &[Arc]) -> FlowyResult<()> { + for row_rev in row_revs { + let _ = self.group_row(row_rev)?; + } + Ok(()) + } + fn create_card(&self, row_rev: &mut RowRevision); +} + const DEFAULT_GROUP_ID: &str = "default_group"; -pub struct GroupController { +/// C: represents the group configuration structure +/// T: the type option data deserializer that impl [TypeOptionDataDeserializer] +/// G: the group container generator +/// P: the parser that impl [CellBytesParser] for the CellBytes +pub struct GroupController { pub field_rev: Arc, - pub groups: IndexMap, - pub default_group: Group, + groups: IndexMap, + default_group: Group, pub type_option: Option, pub configuration: Option, group_action_phantom: PhantomData, - cell_parser_phantom: PhantomData, + cell_parser_phantom: PhantomData

, } +#[derive(Clone)] pub struct Group { pub id: String, pub desc: String, @@ -63,7 +79,7 @@ impl std::convert::From for GroupPB { } } -impl GroupController +impl GroupController where C: TryFrom, T: TypeOptionDataDeserializer, @@ -80,7 +96,7 @@ where }; let field_type_rev = field_rev.field_type_rev; let type_option = field_rev.get_type_option_entry::(field_type_rev); - let groups = G::gen_groups(&configuration, &type_option, cell_content_provider); + let groups = G::generate_groups(&configuration, &type_option, cell_content_provider); let default_group = Group { id: DEFAULT_GROUP_ID.to_owned(), @@ -100,9 +116,9 @@ where }) } - pub fn take_groups(self) -> Vec { - let default_group = self.default_group; - let mut groups: Vec = self.groups.into_values().collect(); + pub fn groups(&self) -> Vec { + let default_group = self.default_group.clone(); + let mut groups: Vec = self.groups.values().cloned().collect(); if !default_group.rows.is_empty() { groups.push(default_group); } @@ -110,48 +126,50 @@ where } } -impl GroupController +impl GroupController where - CP: CellBytesParser, - Self: GroupAction, + P: CellBytesParser, + Self: Groupable, { - pub fn group_rows(&mut self, rows: &[Arc]) -> FlowyResult<()> { + pub fn handle_row(&mut self, row: &RowRevision) -> FlowyResult<()> { if self.configuration.is_none() { return Ok(()); } - tracing::debug!("group {} rows", rows.len()); - - for row in rows { - if let Some(cell_rev) = row.cells.get(&self.field_rev.id) { - let mut records: Vec = vec![]; - - let cell_bytes = decode_any_cell_data(cell_rev.data.clone(), &self.field_rev); - let cell_data = cell_bytes.parser::()?; - for group in self.groups.values() { - if self.should_group(&group.content, &cell_data) { - records.push(GroupRecord { - row: row.into(), - group_id: group.id.clone(), - }); - } + if let Some(cell_rev) = row.cells.get(&self.field_rev.id) { + let mut records: Vec = vec![]; + let cell_bytes = decode_any_cell_data(cell_rev.data.clone(), &self.field_rev); + let cell_data = cell_bytes.parser::

()?; + for group in self.groups.values() { + if self.can_group(&group.content, &cell_data) { + records.push(GroupRecord { + row: row.into(), + group_id: group.id.clone(), + }); } - - if records.is_empty() { - self.default_group.rows.push(row.into()); - } else { - for record in records { - if let Some(group) = self.groups.get_mut(&record.group_id) { - group.rows.push(record.row); - } - } - } - } else { - self.default_group.rows.push(row.into()); } + + if records.is_empty() { + self.default_group.rows.push(row.into()); + } else { + for record in records { + if let Some(group) = self.groups.get_mut(&record.group_id) { + group.rows.push(record.row); + } + } + } + } else { + self.default_group.rows.push(row.into()); } Ok(()) } + + pub fn group_rows(&mut self, rows: &[Arc]) -> FlowyResult<()> { + for row in rows { + let _ = self.handle_row(row)?; + } + Ok(()) + } } struct GroupRecord { diff --git a/frontend/rust-lib/flowy-grid/src/services/group/group_generator/select_option_group.rs b/frontend/rust-lib/flowy-grid/src/services/group/group_generator/select_option_group.rs index bc4f1c4709..6666808ee5 100644 --- a/frontend/rust-lib/flowy-grid/src/services/group/group_generator/select_option_group.rs +++ b/frontend/rust-lib/flowy-grid/src/services/group/group_generator/select_option_group.rs @@ -1,9 +1,13 @@ -use crate::entities::SelectOptionGroupConfigurationPB; +use crate::entities::{RowPB, SelectOptionGroupConfigurationPB}; +use flowy_error::FlowyResult; +use flowy_grid_data_model::revision::RowRevision; use crate::services::field::{ MultiSelectTypeOptionPB, SelectOptionCellDataPB, SelectOptionCellDataParser, SingleSelectTypeOptionPB, }; -use crate::services::group::{Group, GroupAction, GroupCellContentProvider, GroupController, GroupGenerator}; +use crate::services::group::{ + Group, GroupActionHandler, GroupCellContentProvider, GroupController, GroupGenerator, Groupable, +}; // SingleSelect pub type SingleSelectGroupController = GroupController< @@ -13,11 +17,32 @@ pub type SingleSelectGroupController = GroupController< 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) + } +} + +impl GroupActionHandler for SingleSelectGroupController { + fn get_groups(&self) -> Vec { + self.groups() + } + + fn group_row(&mut self, row_rev: &RowRevision) -> FlowyResult<()> { + self.handle_row(row_rev) + } + + fn create_card(&self, row_rev: &mut RowRevision) { + todo!() + } +} + pub struct SingleSelectGroupGenerator(); impl GroupGenerator for SingleSelectGroupGenerator { type ConfigurationType = SelectOptionGroupConfigurationPB; type TypeOptionType = SingleSelectTypeOptionPB; - fn gen_groups( + fn generate_groups( _configuration: &Option, type_option: &Option, _cell_content_provider: &dyn GroupCellContentProvider, @@ -38,13 +63,6 @@ impl GroupGenerator for SingleSelectGroupGenerator { } } -impl GroupAction for SingleSelectGroupController { - type CellDataType = SelectOptionCellDataPB; - fn should_group(&self, content: &str, cell_data: &SelectOptionCellDataPB) -> bool { - cell_data.select_options.iter().any(|option| option.id == content) - } -} - // MultiSelect pub type MultiSelectGroupController = GroupController< SelectOptionGroupConfigurationPB, @@ -53,12 +71,33 @@ pub type MultiSelectGroupController = GroupController< 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) + } +} + +impl GroupActionHandler for MultiSelectGroupController { + fn get_groups(&self) -> Vec { + self.groups() + } + + fn group_row(&mut self, row_rev: &RowRevision) -> FlowyResult<()> { + self.handle_row(row_rev) + } + + fn create_card(&self, row_rev: &mut RowRevision) { + todo!() + } +} + pub struct MultiSelectGroupGenerator(); impl GroupGenerator for MultiSelectGroupGenerator { type ConfigurationType = SelectOptionGroupConfigurationPB; type TypeOptionType = MultiSelectTypeOptionPB; - fn gen_groups( + fn generate_groups( _configuration: &Option, type_option: &Option, _cell_content_provider: &dyn GroupCellContentProvider, @@ -78,10 +117,3 @@ impl GroupGenerator for MultiSelectGroupGenerator { } } } - -impl GroupAction for MultiSelectGroupController { - type CellDataType = SelectOptionCellDataPB; - fn should_group(&self, content: &str, cell_data: &SelectOptionCellDataPB) -> bool { - cell_data.select_options.iter().any(|option| option.id == content) - } -} 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 5be0141ca9..573ffcea75 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 @@ -1,12 +1,14 @@ use crate::services::block_manager::GridBlockManager; use crate::services::grid_editor_task::GridServiceTaskScheduler; use crate::services::group::{ - CheckboxGroupController, Group, GroupCellContentProvider, MultiSelectGroupController, SingleSelectGroupController, + CheckboxGroupController, Group, GroupActionHandler, GroupCellContentProvider, MultiSelectGroupController, + SingleSelectGroupController, }; use crate::entities::{ - CheckboxGroupConfigurationPB, DateGroupConfigurationPB, FieldType, GroupPB, NumberGroupConfigurationPB, - SelectOptionGroupConfigurationPB, TextGroupConfigurationPB, UrlGroupConfigurationPB, + CheckboxGroupConfigurationPB, CreateBoardCardParams, DateGroupConfigurationPB, FieldType, GroupPB, + NumberGroupConfigurationPB, RowPB, SelectOptionGroupConfigurationPB, TextGroupConfigurationPB, + UrlGroupConfigurationPB, }; use bytes::Bytes; use flowy_error::FlowyResult; @@ -18,10 +20,9 @@ use tokio::sync::RwLock; pub(crate) struct GridGroupService { #[allow(dead_code)] scheduler: Arc, - #[allow(dead_code)] grid_pad: Arc>, - #[allow(dead_code)] block_manager: Arc, + group_action_handler: Option>>, } impl GridGroupService { @@ -35,14 +36,14 @@ impl GridGroupService { scheduler, grid_pad, block_manager, + group_action_handler: None, } } - pub(crate) async fn load_groups(&self) -> Option> { - let grid_pad = self.grid_pad.read().await; - let field_rev = find_group_field(grid_pad.fields()).unwrap(); + pub(crate) async fn load_groups(&mut self) -> Option> { + let field_rev = find_group_field(self.grid_pad.read().await.fields()).unwrap(); let field_type: FieldType = field_rev.field_type_rev.into(); - let configuration = self.get_group_configuration(field_rev).await; + let configuration = self.get_group_configuration(&field_rev).await; let blocks = self.block_manager.get_block_snapshots(None).await.unwrap(); let row_revs = blocks @@ -51,19 +52,28 @@ impl GridGroupService { .flatten() .collect::>>(); - match self.build_groups(&field_type, field_rev, row_revs, configuration) { + match self + .build_groups(&field_type, &field_rev, row_revs, configuration) + .await + { Ok(groups) => Some(groups), Err(_) => None, } } - async fn get_group_configuration(&self, field_rev: &FieldRevision) -> GroupConfigurationRevision { + pub(crate) async fn create_board_card(&self, row_rev: &mut RowRevision) { + if let Some(group_action_handler) = self.group_action_handler.as_ref() { + group_action_handler.write().await.create_card(row_rev); + } + } + + pub(crate) async fn get_group_configuration(&self, field_rev: &FieldRevision) -> GroupConfigurationRevision { let grid_pad = self.grid_pad.read().await; let setting = grid_pad.get_setting_rev(); let layout = &setting.layout; let configurations = setting.get_groups(layout, &field_rev.id, &field_rev.field_type_rev); match configurations { - None => self.default_group_configuration(field_rev), + None => default_group_configuration(field_rev), Some(mut configurations) => { assert_eq!(configurations.len(), 1); (&*configurations.pop().unwrap()).clone() @@ -71,79 +81,81 @@ impl GridGroupService { } } - fn default_group_configuration(&self, field_rev: &FieldRevision) -> GroupConfigurationRevision { - let field_type: FieldType = field_rev.field_type_rev.clone().into(); - let bytes: Bytes = match field_type { - FieldType::RichText => TextGroupConfigurationPB::default().try_into().unwrap(), - FieldType::Number => NumberGroupConfigurationPB::default().try_into().unwrap(), - FieldType::DateTime => DateGroupConfigurationPB::default().try_into().unwrap(), - FieldType::SingleSelect => SelectOptionGroupConfigurationPB::default().try_into().unwrap(), - FieldType::MultiSelect => SelectOptionGroupConfigurationPB::default().try_into().unwrap(), - FieldType::Checkbox => CheckboxGroupConfigurationPB::default().try_into().unwrap(), - FieldType::URL => UrlGroupConfigurationPB::default().try_into().unwrap(), - }; - GroupConfigurationRevision { - id: gen_grid_group_id(), - field_id: field_rev.id.clone(), - field_type_rev: field_rev.field_type_rev.clone(), - content: Some(bytes.to_vec()), - } - } - #[tracing::instrument(level = "trace", skip_all, err)] - fn build_groups( - &self, + async fn build_groups( + &mut self, field_type: &FieldType, field_rev: &Arc, row_revs: Vec>, configuration: GroupConfigurationRevision, ) -> FlowyResult> { - let groups: Vec = match field_type { + match field_type { FieldType::RichText => { // let generator = GroupGenerator::::from_configuration(configuration); - vec![] } FieldType::Number => { // let generator = GroupGenerator::::from_configuration(configuration); - vec![] } FieldType::DateTime => { // let generator = GroupGenerator::::from_configuration(configuration); - vec![] } FieldType::SingleSelect => { - let mut group_controller = - SingleSelectGroupController::new(field_rev.clone(), configuration, &self.grid_pad)?; - let _ = group_controller.group_rows(&row_revs)?; - group_controller.take_groups() + let controller = SingleSelectGroupController::new(field_rev.clone(), configuration, &self.grid_pad)?; + self.group_action_handler = Some(Arc::new(RwLock::new(controller))); } FieldType::MultiSelect => { - let mut group_controller = - MultiSelectGroupController::new(field_rev.clone(), configuration, &self.grid_pad)?; - let _ = group_controller.group_rows(&row_revs)?; - group_controller.take_groups() + let controller = MultiSelectGroupController::new(field_rev.clone(), configuration, &self.grid_pad)?; + self.group_action_handler = Some(Arc::new(RwLock::new(controller))); } FieldType::Checkbox => { - let mut group_controller = - CheckboxGroupController::new(field_rev.clone(), configuration, &self.grid_pad)?; - let _ = group_controller.group_rows(&row_revs)?; - group_controller.take_groups() + let controller = CheckboxGroupController::new(field_rev.clone(), configuration, &self.grid_pad)?; + self.group_action_handler = Some(Arc::new(RwLock::new(controller))); } FieldType::URL => { // let generator = GroupGenerator::::from_configuration(configuration); - vec![] } }; + let mut groups = vec![]; + if let Some(group_action_handler) = self.group_action_handler.as_ref() { + let mut write_guard = group_action_handler.write().await; + let _ = write_guard.group_rows(&row_revs)?; + groups = write_guard.get_groups(); + drop(write_guard); + } + Ok(groups.into_iter().map(GroupPB::from).collect()) } } -fn find_group_field(field_revs: &[Arc]) -> Option<&Arc> { - field_revs.iter().find(|field_rev| { - let field_type: FieldType = field_rev.field_type_rev.into(); - field_type.can_be_group() - }) +fn find_group_field(field_revs: &[Arc]) -> Option> { + let field_rev = field_revs + .iter() + .find(|field_rev| { + let field_type: FieldType = field_rev.field_type_rev.into(); + field_type.can_be_group() + }) + .cloned(); + field_rev } impl GroupCellContentProvider for Arc> {} + +fn default_group_configuration(field_rev: &FieldRevision) -> GroupConfigurationRevision { + let field_type: FieldType = field_rev.field_type_rev.clone().into(); + let bytes: Bytes = match field_type { + FieldType::RichText => TextGroupConfigurationPB::default().try_into().unwrap(), + FieldType::Number => NumberGroupConfigurationPB::default().try_into().unwrap(), + FieldType::DateTime => DateGroupConfigurationPB::default().try_into().unwrap(), + FieldType::SingleSelect => SelectOptionGroupConfigurationPB::default().try_into().unwrap(), + FieldType::MultiSelect => SelectOptionGroupConfigurationPB::default().try_into().unwrap(), + FieldType::Checkbox => CheckboxGroupConfigurationPB::default().try_into().unwrap(), + FieldType::URL => UrlGroupConfigurationPB::default().try_into().unwrap(), + }; + GroupConfigurationRevision { + id: gen_grid_group_id(), + field_id: field_rev.id.clone(), + field_type_rev: field_rev.field_type_rev.clone(), + content: Some(bytes.to_vec()), + } +} diff --git a/shared-lib/flowy-error-code/src/code.rs b/shared-lib/flowy-error-code/src/code.rs index 352c4abbdb..5b676073da 100644 --- a/shared-lib/flowy-error-code/src/code.rs +++ b/shared-lib/flowy-error-code/src/code.rs @@ -111,6 +111,9 @@ pub enum ErrorCode { #[display(fmt = "Field's type option data should not be empty")] TypeOptionDataIsEmpty = 450, + #[display(fmt = "Group id is empty")] + GroupIdIsEmpty = 460, + #[display(fmt = "Invalid date time format")] InvalidDateTimeFormat = 500, diff --git a/shared-lib/flowy-grid-data-model/src/revision/grid_rev.rs b/shared-lib/flowy-grid-data-model/src/revision/grid_rev.rs index b60baff811..184f5266ed 100644 --- a/shared-lib/flowy-grid-data-model/src/revision/grid_rev.rs +++ b/shared-lib/flowy-grid-data-model/src/revision/grid_rev.rs @@ -88,9 +88,9 @@ pub struct GridBlockMetaRevisionChangeset { } impl GridBlockMetaRevisionChangeset { - pub fn from_row_count(block_id: &str, row_count: i32) -> Self { + pub fn from_row_count(block_id: String, row_count: i32) -> Self { Self { - block_id: block_id.to_string(), + block_id, start_row_index: None, row_count: Some(row_count), }