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 4d4fcc78c1..05750e7283 100644 --- a/frontend/rust-lib/flowy-grid/src/entities/block_entities.rs +++ b/frontend/rust-lib/flowy-grid/src/entities/block_entities.rs @@ -112,6 +112,12 @@ pub struct InsertedRowPB { pub index: Option, } +impl InsertedRowPB { + pub fn new(row: RowPB) -> Self { + Self { row, index: None } + } +} + impl std::convert::From for InsertedRowPB { fn from(row: RowPB) -> Self { Self { row, index: None } diff --git a/frontend/rust-lib/flowy-grid/src/entities/group_entities/group_changeset.rs b/frontend/rust-lib/flowy-grid/src/entities/group_entities/group_changeset.rs index 1feb0debe2..f4602b9a50 100644 --- a/frontend/rust-lib/flowy-grid/src/entities/group_entities/group_changeset.rs +++ b/frontend/rust-lib/flowy-grid/src/entities/group_entities/group_changeset.rs @@ -17,6 +17,9 @@ pub struct GroupRowsChangesetPB { } impl GroupRowsChangesetPB { + pub fn is_empty(&self) -> bool { + self.inserted_rows.is_empty() && self.deleted_rows.is_empty() && self.updated_rows.is_empty() + } pub fn insert(group_id: String, inserted_rows: Vec) -> Self { Self { group_id, diff --git a/frontend/rust-lib/flowy-grid/src/services/block_manager_trait_impl.rs b/frontend/rust-lib/flowy-grid/src/services/block_manager_trait_impl.rs new file mode 100644 index 0000000000..2696ef0b2c --- /dev/null +++ b/frontend/rust-lib/flowy-grid/src/services/block_manager_trait_impl.rs @@ -0,0 +1,45 @@ +use crate::services::block_manager::GridBlockManager; +use crate::services::grid_view_manager::{GridViewRowDelegate, GridViewRowOperation}; +use flowy_error::FlowyResult; +use flowy_grid_data_model::revision::RowRevision; +use lib_infra::future::{wrap_future, AFFuture}; +use std::sync::Arc; + +impl GridViewRowDelegate for Arc { + fn gv_index_of_row(&self, row_id: &str) -> AFFuture> { + let block_manager = self.clone(); + let row_id = row_id.to_owned(); + wrap_future(async move { block_manager.index_of_row(&row_id).await }) + } + + fn gv_get_row_rev(&self, row_id: &str) -> AFFuture>> { + let block_manager = self.clone(); + let row_id = row_id.to_owned(); + wrap_future(async move { + match block_manager.get_row_rev(&row_id).await { + Ok(row_rev) => row_rev, + Err(_) => None, + } + }) + } + + fn gv_row_revs(&self) -> AFFuture>> { + let block_manager = self.clone(); + + wrap_future(async move { + let blocks = block_manager.get_block_snapshots(None).await.unwrap(); + blocks + .into_iter() + .map(|block| block.row_revs) + .flatten() + .collect::>>() + }) + } +} + +impl GridViewRowOperation for Arc { + fn gv_move_row(&self, row_rev: Arc, from: usize, to: usize) -> AFFuture> { + let block_manager = self.clone(); + wrap_future(async move { block_manager.move_row(row_rev, from, to).await }) + } +} 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 215cd3c467..7c1d706e33 100644 --- a/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs +++ b/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs @@ -3,6 +3,7 @@ use crate::entities::GridCellIdParams; use crate::entities::*; use crate::manager::{GridTaskSchedulerRwLock, GridUser}; use crate::services::block_manager::GridBlockManager; + use crate::services::cell::{apply_cell_data_changeset, decode_any_cell_data, CellBytes}; use crate::services::field::{default_type_option_builder_from_type, type_option_builder_from_bytes, FieldBuilder}; use crate::services::filter::GridFilterService; @@ -11,7 +12,6 @@ use crate::services::persistence::block_index::BlockIndexCache; use crate::services::row::{ make_grid_blocks, make_row_from_row_rev, make_rows_from_row_revs, GridBlockSnapshot, RowRevisionBuilder, }; - use bytes::Bytes; use flowy_error::{ErrorCode, FlowyError, FlowyResult}; use flowy_grid_data_model::revision::*; @@ -68,9 +68,11 @@ impl GridRevisionEditor { // View manager let view_manager = Arc::new( GridViewManager::new( + grid_id.to_owned(), user.clone(), - grid_pad.clone(), - block_manager.clone(), + Arc::new(grid_pad.clone()), + Arc::new(block_manager.clone()), + Arc::new(block_manager.clone()), Arc::new(task_scheduler.clone()), ) .await?, @@ -403,7 +405,7 @@ impl GridRevisionEditor { content = Some(apply_cell_data_changeset(content.unwrap(), cell_rev, field_rev)?); let cell_changeset = CellChangesetPB { grid_id, - row_id, + row_id: row_id.clone(), field_id, content, }; @@ -411,6 +413,8 @@ impl GridRevisionEditor { .block_manager .update_cell(cell_changeset, make_row_from_row_rev) .await?; + + self.view_manager.did_update_row(&row_id).await; Ok(()) } } diff --git a/frontend/rust-lib/flowy-grid/src/services/grid_editor_trait_impl.rs b/frontend/rust-lib/flowy-grid/src/services/grid_editor_trait_impl.rs new file mode 100644 index 0000000000..43bc74bf12 --- /dev/null +++ b/frontend/rust-lib/flowy-grid/src/services/grid_editor_trait_impl.rs @@ -0,0 +1,32 @@ +use crate::services::grid_view_manager::GridViewFieldDelegate; +use flowy_grid_data_model::revision::FieldRevision; +use flowy_sync::client_grid::GridRevisionPad; +use lib_infra::future::{wrap_future, AFFuture}; +use std::sync::Arc; +use tokio::sync::RwLock; + +impl GridViewFieldDelegate for Arc> { + fn get_field_revs(&self) -> AFFuture>> { + let pad = self.clone(); + wrap_future(async move { + match pad.read().await.get_field_revs(None) { + Ok(field_revs) => field_revs, + Err(e) => { + tracing::error!("[GridViewRevisionDelegate] get field revisions failed: {}", e); + vec![] + } + } + }) + } + + fn get_field_rev(&self, field_id: &str) -> AFFuture>> { + let pad = self.clone(); + let field_id = field_id.to_owned(); + wrap_future(async move { + pad.read() + .await + .get_field_rev(&field_id) + .map(|(_, field_rev)| field_rev.clone()) + }) + } +} 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 6d1c231480..212febacf0 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,59 +1,44 @@ -use flowy_error::{FlowyError, FlowyResult}; - +use crate::dart_notification::{send_dart_notification, GridNotification}; use crate::entities::{ CreateRowParams, GridFilterConfiguration, GridLayout, GridSettingPB, GroupPB, GroupRowsChangesetPB, InsertedRowPB, RowPB, }; use crate::services::grid_editor_task::GridServiceTaskScheduler; -use crate::services::group::{default_group_configuration, Group, GroupConfigurationDelegate, GroupService}; +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 flowy_error::{FlowyError, FlowyResult}; use flowy_grid_data_model::revision::{FieldRevision, GroupConfigurationRevision, RowRevision}; use flowy_revision::{RevisionCloudService, RevisionManager, RevisionObjectBuilder}; use flowy_sync::client_grid::{GridViewRevisionChangeset, GridViewRevisionPad}; -use flowy_sync::entities::revision::Revision; - -use crate::dart_notification::{send_dart_notification, GridNotification}; -use crate::services::setting::make_grid_setting; use flowy_sync::entities::grid::GridSettingChangesetParams; +use flowy_sync::entities::revision::Revision; use lib_infra::future::{wrap_future, AFFuture, FutureResult}; use std::sync::Arc; use tokio::sync::RwLock; -pub trait GridViewRevisionDelegate: Send + Sync + 'static { - fn get_field_revs(&self) -> AFFuture>>; - fn get_field_rev(&self, field_id: &str) -> AFFuture>>; -} - -pub trait GridViewRevisionRowDataSource: Send + Sync + 'static { - fn row_revs(&self) -> AFFuture>>; -} - #[allow(dead_code)] pub struct GridViewRevisionEditor { user_id: String, view_id: String, pad: Arc>, rev_manager: Arc, - delegate: Arc, - data_source: Arc, + field_delegate: Arc, + row_delegate: Arc, group_service: Arc>, - groups: Arc>>, scheduler: Arc, } impl GridViewRevisionEditor { - pub(crate) async fn new( + pub(crate) async fn new( user_id: &str, token: &str, view_id: String, - delegate: Delegate, - data_source: DataSource, + field_delegate: Arc, + row_delegate: Arc, scheduler: Arc, mut rev_manager: RevisionManager, - ) -> FlowyResult - where - Delegate: GridViewRevisionDelegate, - DataSource: GridViewRevisionRowDataSource, - { + ) -> FlowyResult { let cloud = Arc::new(GridViewRevisionCloudService { token: token.to_owned(), }); @@ -62,16 +47,14 @@ impl GridViewRevisionEditor { let rev_manager = Arc::new(rev_manager); let group_service = GroupService::new(Box::new(pad.clone())).await; let user_id = user_id.to_owned(); - let groups = Arc::new(RwLock::new(vec![])); Ok(Self { pad, user_id, view_id, rev_manager, scheduler, - groups, - delegate: Arc::new(delegate), - data_source: Arc::new(data_source), + field_delegate, + row_delegate, group_service: Arc::new(RwLock::new(group_service)), }) } @@ -87,7 +70,9 @@ impl GridViewRevisionEditor { self.group_service .read() .await - .update_row(row_rev, group_id, |field_id| self.delegate.get_field_rev(&field_id)) + .fill_row(row_rev, group_id, |field_id| { + self.field_delegate.get_field_rev(&field_id) + }) .await; } }, @@ -120,34 +105,60 @@ impl GridViewRevisionEditor { } } + pub(crate) async fn did_update_row(&self, row_rev: &RowRevision) { + if let Some(changesets) = self + .group_service + .write() + .await + .did_update_row(row_rev, |field_id| self.field_delegate.get_field_rev(&field_id)) + .await + { + for changeset in changesets { + self.notify_did_update_group(changeset).await; + } + } + } + async fn group_id_of_row(&self, row_id: &str) -> Option { - let read_guard = self.groups.read().await; + let read_guard = &self.group_service.read().await.groups; for group in read_guard.iter() { - if group.rows.iter().any(|row| row.id == row_id) { + if group.contains_row(row_id) { return Some(group.id.clone()); } } - None } - pub(crate) async fn load_groups(&self) -> FlowyResult> { - let field_revs = self.delegate.get_field_revs().await; - let row_revs = self.data_source.row_revs().await; + // async fn get_mut_group(&self, group_id: &str, f: F) -> FlowyResult<()> + // where + // F: Fn(&mut Group) -> FlowyResult<()>, + // { + // for group in self.groups.write().await.iter_mut() { + // if group.id == group_id { + // let _ = f(group)?; + // } + // } + // Ok(()) + // } - // - let mut write_guard = self.group_service.write().await; - match write_guard.load_groups(&field_revs, row_revs).await { + pub(crate) async fn load_groups(&self) -> FlowyResult> { + let field_revs = self.field_delegate.get_field_revs().await; + let row_revs = self.row_delegate.gv_row_revs().await; + + match self + .group_service + .write() + .await + .load_groups(&field_revs, row_revs) + .await + { None => Ok(vec![]), - Some(groups) => { - *self.groups.write().await = groups.clone(); - Ok(groups.into_iter().map(GroupPB::from).collect()) - } + Some(groups) => Ok(groups.into_iter().map(GroupPB::from).collect()), } } pub(crate) async fn get_setting(&self) -> GridSettingPB { - let field_revs = self.delegate.get_field_revs().await; + 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); grid_setting } @@ -158,7 +169,7 @@ impl GridViewRevisionEditor { } pub(crate) async fn get_filters(&self) -> Vec { - let field_revs = self.delegate.get_field_revs().await; + let field_revs = self.field_delegate.get_field_revs().await; match self.pad.read().await.get_setting_rev().get_all_filters(&field_revs) { None => vec![], Some(filters) => filters 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 b5f8d41691..c2e13c1089 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 @@ -2,47 +2,66 @@ use crate::entities::{ CreateRowParams, GridFilterConfiguration, GridLayout, GridSettingPB, MoveRowParams, RepeatedGridGroupPB, RowPB, }; use crate::manager::GridUser; -use crate::services::block_manager::GridBlockManager; + use crate::services::grid_editor_task::GridServiceTaskScheduler; -use crate::services::grid_view_editor::{ - GridViewRevisionDelegate, GridViewRevisionEditor, GridViewRevisionRowDataSource, -}; +use crate::services::grid_view_editor::GridViewRevisionEditor; use bytes::Bytes; use dashmap::DashMap; use flowy_error::FlowyResult; use flowy_grid_data_model::revision::{FieldRevision, RowRevision}; use flowy_revision::disk::SQLiteGridViewRevisionPersistence; use flowy_revision::{RevisionCompactor, RevisionManager, RevisionPersistence, SQLiteRevisionSnapshotPersistence}; -use flowy_sync::client_grid::GridRevisionPad; + 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::{wrap_future, AFFuture}; +use lib_infra::future::AFFuture; use std::sync::Arc; -use tokio::sync::RwLock; type ViewId = String; +pub trait GridViewFieldDelegate: Send + Sync + 'static { + fn get_field_revs(&self) -> AFFuture>>; + fn get_field_rev(&self, field_id: &str) -> AFFuture>>; +} + +pub trait GridViewRowDelegate: Send + Sync + 'static { + fn gv_index_of_row(&self, row_id: &str) -> AFFuture>; + fn gv_get_row_rev(&self, row_id: &str) -> AFFuture>>; + fn gv_row_revs(&self) -> AFFuture>>; +} + +pub trait GridViewRowOperation: Send + Sync + 'static { + // Will be removed in the future. + fn gv_move_row(&self, row_rev: Arc, from: usize, to: usize) -> AFFuture>; +} + pub(crate) struct GridViewManager { + grid_id: String, user: Arc, - grid_pad: Arc>, - block_manager: Arc, + field_delegate: Arc, + row_delegate: Arc, + row_operation: Arc, view_editors: DashMap>, scheduler: Arc, } impl GridViewManager { pub(crate) async fn new( + grid_id: String, user: Arc, - grid_pad: Arc>, - block_manager: Arc, + field_delegate: Arc, + row_delegate: Arc, + row_operation: Arc, scheduler: Arc, ) -> FlowyResult { Ok(Self { + grid_id, user, - grid_pad, scheduler, - block_manager, + field_delegate, + row_delegate, + row_operation, view_editors: DashMap::default(), }) } @@ -54,7 +73,16 @@ impl GridViewManager { } pub(crate) async fn did_update_row(&self, row_id: &str) { - let row = self.block_manager.get_row_rev(row_id).await; + match self.row_delegate.gv_get_row_rev(row_id).await { + None => { + tracing::warn!("Can not find the row in grid view"); + } + Some(row_rev) => { + for view_editor in self.view_editors.iter() { + view_editor.did_update_row(&row_rev).await; + } + } + } } pub(crate) async fn did_create_row(&self, row_pb: &RowPB, params: &CreateRowParams) { @@ -103,19 +131,19 @@ impl GridViewManager { let from_index = from_index as usize; - match self.block_manager.get_row_rev(&row_id).await? { + match self.row_delegate.gv_get_row_rev(&row_id).await { None => tracing::warn!("Move row failed, can not find the row:{}", row_id), Some(row_rev) => match layout { GridLayout::Table => { tracing::trace!("Move row from {} to {}", from_index, to_index); let to_index = to_index as usize; - let _ = self.block_manager.move_row(row_rev, from_index, to_index).await?; + let _ = self.row_operation.gv_move_row(row_rev, from_index, to_index).await?; } GridLayout::Board => { if let Some(upper_row_id) = upper_row_id { - if let Some(to_index) = self.block_manager.index_of_row(&upper_row_id).await { + if let Some(to_index) = self.row_delegate.gv_index_of_row(&upper_row_id).await { tracing::trace!("Move row from {} to {}", from_index, to_index); - let _ = self.block_manager.move_row(row_rev, from_index, to_index).await?; + let _ = self.row_operation.gv_move_row(row_rev, from_index, to_index).await?; } } } @@ -132,8 +160,8 @@ impl GridViewManager { make_view_editor( &self.user, view_id, - self.grid_pad.clone(), - self.block_manager.clone(), + self.field_delegate.clone(), + self.row_delegate.clone(), self.scheduler.clone(), ) .await?, @@ -146,29 +174,33 @@ impl GridViewManager { } async fn get_default_view_editor(&self) -> FlowyResult> { - let grid_id = self.grid_pad.read().await.grid_id(); - self.get_view_editor(&grid_id).await + self.get_view_editor(&self.grid_id).await } } -async fn make_view_editor( +async fn make_view_editor( user: &Arc, view_id: &str, - delegate: Delegate, - data_source: DataSource, + field_delegate: Arc, + row_delegate: Arc, scheduler: Arc, -) -> FlowyResult -where - Delegate: GridViewRevisionDelegate, - DataSource: GridViewRevisionRowDataSource, -{ +) -> FlowyResult { tracing::trace!("Open view:{} editor", view_id); let rev_manager = make_grid_view_rev_manager(user, view_id).await?; let user_id = user.user_id()?; let token = user.token()?; let view_id = view_id.to_owned(); - GridViewRevisionEditor::new(&user_id, &token, view_id, delegate, data_source, scheduler, rev_manager).await + GridViewRevisionEditor::new( + &user_id, + &token, + view_id, + field_delegate, + row_delegate, + scheduler, + rev_manager, + ) + .await } pub async fn make_grid_view_rev_manager(user: &Arc, view_id: &str) -> FlowyResult { @@ -197,44 +229,3 @@ impl RevisionCompactor for GridViewRevisionCompactor { Ok(delta.json_bytes()) } } - -impl GridViewRevisionRowDataSource for Arc { - fn row_revs(&self) -> AFFuture>> { - let block_manager = self.clone(); - - wrap_future(async move { - let blocks = block_manager.get_block_snapshots(None).await.unwrap(); - blocks - .into_iter() - .map(|block| block.row_revs) - .flatten() - .collect::>>() - }) - } -} - -impl GridViewRevisionDelegate for Arc> { - fn get_field_revs(&self) -> AFFuture>> { - let pad = self.clone(); - wrap_future(async move { - match pad.read().await.get_field_revs(None) { - Ok(field_revs) => field_revs, - Err(e) => { - tracing::error!("[GridViewRevisionDelegate] get field revisions failed: {}", e); - vec![] - } - } - }) - } - - fn get_field_rev(&self, field_id: &str) -> AFFuture>> { - let pad = self.clone(); - let field_id = field_id.to_owned(); - wrap_future(async move { - pad.read() - .await - .get_field_rev(&field_id) - .map(|(_, field_rev)| field_rev.clone()) - }) - } -} 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 01c2e7a2d9..020a97e847 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,13 +1,16 @@ -use crate::entities::CheckboxGroupConfigurationPB; -use flowy_error::FlowyResult; +use crate::entities::{CheckboxGroupConfigurationPB, GroupRowsChangesetPB}; + use flowy_grid_data_model::revision::{FieldRevision, RowRevision}; -use std::sync::Arc; use crate::services::field::{CheckboxCellData, CheckboxCellDataParser, CheckboxTypeOptionPB, CHECK, UNCHECK}; -use crate::services::group::{Group, GroupActionHandler, GroupController, GroupGenerator, Groupable}; +use crate::services::group::{GenericGroupController, Group, GroupController, GroupGenerator, Groupable}; -pub type CheckboxGroupController = - GroupController; +pub type CheckboxGroupController = GenericGroupController< + CheckboxGroupConfigurationPB, + CheckboxTypeOptionPB, + CheckboxGroupGenerator, + CheckboxCellDataParser, +>; impl Groupable for CheckboxGroupController { type CellDataType = CheckboxCellData; @@ -15,22 +18,14 @@ impl Groupable for CheckboxGroupController { fn can_group(&self, _content: &str, _cell_data: &Self::CellDataType) -> bool { false } + + fn group_row(&mut self, _row_rev: &RowRevision, _cell_data: &Self::CellDataType) -> Vec { + todo!() + } } -impl GroupActionHandler for CheckboxGroupController { - fn field_id(&self) -> &str { - &self.field_id - } - - fn build_groups(&self) -> Vec { - self.make_groups() - } - - fn group_rows(&mut self, row_revs: &[Arc], field_rev: &FieldRevision) -> FlowyResult<()> { - self.handle_rows(row_revs, field_rev) - } - - fn update_card(&self, _row_rev: &mut RowRevision, _field_rev: &FieldRevision, _group_id: &str) { +impl GroupController for CheckboxGroupController { + fn fill_row(&self, _row_rev: &mut RowRevision, _field_rev: &FieldRevision, _group_id: &str) { todo!() } } @@ -44,20 +39,8 @@ impl GroupGenerator for CheckboxGroupGenerator { _configuration: &Option, _type_option: &Option, ) -> Vec { - let check_group = Group { - id: "true".to_string(), - desc: "".to_string(), - rows: vec![], - content: CHECK.to_string(), - }; - - let uncheck_group = Group { - id: "false".to_string(), - desc: "".to_string(), - rows: vec![], - content: UNCHECK.to_string(), - }; - + let check_group = Group::new("true".to_string(), "".to_string(), CHECK.to_string()); + let uncheck_group = Group::new("false".to_string(), "".to_string(), UNCHECK.to_string()); vec![check_group, uncheck_group] } } 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 11144184a8..becef0d784 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 @@ -1,13 +1,11 @@ -use crate::entities::{GroupPB, RowPB}; +use crate::entities::{GroupPB, GroupRowsChangesetPB, RowPB}; use crate::services::cell::{decode_any_cell_data, CellBytesParser}; use bytes::Bytes; use flowy_error::FlowyResult; use flowy_grid_data_model::revision::{ FieldRevision, GroupConfigurationRevision, RowRevision, TypeOptionDataDeserializer, }; - use indexmap::IndexMap; - use std::marker::PhantomData; use std::sync::Arc; @@ -21,29 +19,35 @@ pub trait GroupGenerator { ) -> Vec; } -pub trait Groupable { +pub trait Groupable: Send + Sync { type CellDataType; fn can_group(&self, content: &str, cell_data: &Self::CellDataType) -> bool; + fn group_row(&mut self, row_rev: &RowRevision, cell_data: &Self::CellDataType) -> Vec; } -pub trait GroupActionHandler: Send + Sync { +pub trait GroupController: GroupControllerSharedAction + Send + Sync { + fn fill_row(&self, row_rev: &mut RowRevision, field_rev: &FieldRevision, group_id: &str); +} + +pub trait GroupControllerSharedAction: Send + Sync { + // The field that is used for grouping the rows fn field_id(&self) -> &str; fn build_groups(&self) -> Vec; fn group_rows(&mut self, row_revs: &[Arc], field_rev: &FieldRevision) -> FlowyResult<()>; - fn update_card(&self, row_rev: &mut RowRevision, field_rev: &FieldRevision, group_id: &str); -} - -pub trait GroupActionHandler2: Send + Sync { - fn create_card(&self, row_rev: &mut RowRevision, field_rev: &FieldRevision, group_id: &str); + fn did_update_row( + &mut self, + row_rev: &RowRevision, + field_rev: &FieldRevision, + ) -> FlowyResult>; } const DEFAULT_GROUP_ID: &str = "default_group"; /// C: represents the group configuration structure /// T: the type option data deserializer that impl [TypeOptionDataDeserializer] -/// G: the group container generator +/// G: the group generator, [GroupGenerator] /// P: the parser that impl [CellBytesParser] for the CellBytes -pub struct GroupController { +pub struct GenericGroupController { pub field_id: String, pub groups_map: IndexMap, default_group: Group, @@ -57,7 +61,7 @@ pub struct GroupController { pub struct Group { pub id: String, pub desc: String, - pub rows: Vec, + rows: Vec, pub content: String, } @@ -71,7 +75,40 @@ impl std::convert::From for GroupPB { } } -impl GroupController +impl Group { + pub fn new(id: String, desc: String, content: String) -> Self { + Self { + 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(_) => {} + } + } +} + +impl GenericGroupController where C: TryFrom, T: TypeOptionDataDeserializer, @@ -86,12 +123,11 @@ where let type_option = field_rev.get_type_option_entry::(field_type_rev); let groups = G::generate_groups(&configuration, &type_option); - let default_group = Group { - id: DEFAULT_GROUP_ID.to_owned(), - desc: format!("No {}", field_rev.name), - rows: vec![], - content: "".to_string(), - }; + let default_group = Group::new( + DEFAULT_GROUP_ID.to_owned(), + format!("No {}", field_rev.name), + "".to_string(), + ); Ok(Self { field_id: field_rev.id.clone(), @@ -103,8 +139,18 @@ where cell_parser_phantom: PhantomData, }) } +} - pub fn make_groups(&self) -> Vec { +impl GroupControllerSharedAction for GenericGroupController +where + P: CellBytesParser, + Self: Groupable, +{ + fn field_id(&self) -> &str { + &self.field_id + } + + fn build_groups(&self) -> Vec { let default_group = self.default_group.clone(); let mut groups: Vec = self.groups_map.values().cloned().collect(); if !default_group.rows.is_empty() { @@ -112,35 +158,28 @@ where } groups } -} -impl GroupController -where - P: CellBytesParser, - Self: Groupable, -{ - pub fn handle_rows(&mut self, rows: &[Arc], field_rev: &FieldRevision) -> FlowyResult<()> { - // The field_rev might be None if corresponding field_rev is deleted. + fn group_rows(&mut self, row_revs: &[Arc], field_rev: &FieldRevision) -> FlowyResult<()> { if self.configuration.is_none() { return Ok(()); } - for row in rows { - if let Some(cell_rev) = row.cells.get(&self.field_id) { + for row_rev in row_revs { + if let Some(cell_rev) = row_rev.cells.get(&self.field_id) { let mut records: Vec = vec![]; let cell_bytes = decode_any_cell_data(cell_rev.data.clone(), field_rev); let cell_data = cell_bytes.parser::

()?; for group in self.groups_map.values() { if self.can_group(&group.content, &cell_data) { records.push(GroupRecord { - row: row.into(), + row: row_rev.into(), group_id: group.id.clone(), }); } } if records.is_empty() { - self.default_group.rows.push(row.into()); + self.default_group.rows.push(row_rev.into()); } else { for record in records { if let Some(group) = self.groups_map.get_mut(&record.group_id) { @@ -149,14 +188,71 @@ where } } } else { - self.default_group.rows.push(row.into()); + self.default_group.rows.push(row_rev.into()); } } Ok(()) } + + fn did_update_row( + &mut self, + row_rev: &RowRevision, + field_rev: &FieldRevision, + ) -> FlowyResult> { + if let Some(cell_rev) = row_rev.cells.get(&self.field_id) { + let cell_bytes = decode_any_cell_data(cell_rev.data.clone(), field_rev); + let cell_data = cell_bytes.parser::

()?; + Ok(self.group_row(row_rev, &cell_data)) + } else { + Ok(vec![]) + } + } } +// impl GroupController +// where +// P: CellBytesParser, +// Self: Groupable, +// { +// pub fn handle_rows(&mut self, rows: &[Arc], field_rev: &FieldRevision) -> FlowyResult<()> { +// // The field_rev might be None if corresponding field_rev is deleted. +// if self.configuration.is_none() { +// return Ok(()); +// } +// +// for row in rows { +// if let Some(cell_rev) = row.cells.get(&self.field_id) { +// let mut records: Vec = vec![]; +// let cell_bytes = decode_any_cell_data(cell_rev.data.clone(), field_rev); +// let cell_data = cell_bytes.parser::

()?; +// for group in self.groups_map.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_map.get_mut(&record.group_id) { +// group.rows.push(record.row); +// } +// } +// } +// } else { +// self.default_group.rows.push(row.into()); +// } +// } +// +// Ok(()) +// } +// } + struct GroupRecord { row: RowPB, group_id: String, 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 eb9ce69c9d..ce39e59955 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,17 +1,14 @@ -use crate::entities::SelectOptionGroupConfigurationPB; +use crate::entities::{GroupRowsChangesetPB, InsertedRowPB, RowPB, SelectOptionGroupConfigurationPB}; use crate::services::cell::insert_select_option_cell; -use flowy_error::FlowyResult; -use flowy_grid_data_model::revision::{FieldRevision, RowRevision}; - -use std::sync::Arc; - use crate::services::field::{ MultiSelectTypeOptionPB, SelectOptionCellDataPB, SelectOptionCellDataParser, SingleSelectTypeOptionPB, }; -use crate::services::group::{Group, GroupActionHandler, GroupController, GroupGenerator, Groupable}; +use crate::services::group::{GenericGroupController, Group, GroupController, GroupGenerator, Groupable}; + +use flowy_grid_data_model::revision::{FieldRevision, RowRevision}; // SingleSelect -pub type SingleSelectGroupController = GroupController< +pub type SingleSelectGroupController = GenericGroupController< SelectOptionGroupConfigurationPB, SingleSelectTypeOptionPB, SingleSelectGroupGenerator, @@ -23,22 +20,18 @@ impl Groupable for SingleSelectGroupController { fn can_group(&self, content: &str, cell_data: &SelectOptionCellDataPB) -> bool { cell_data.select_options.iter().any(|option| option.id == content) } + + fn group_row(&mut self, row_rev: &RowRevision, cell_data: &Self::CellDataType) -> Vec { + let mut changesets = vec![]; + self.groups_map.iter_mut().for_each(|(_, group): (_, &mut Group)| { + group_select_option_row(group, &mut changesets, cell_data, row_rev); + }); + changesets + } } -impl GroupActionHandler for SingleSelectGroupController { - fn field_id(&self) -> &str { - &self.field_id - } - - fn build_groups(&self) -> Vec { - self.make_groups() - } - - fn group_rows(&mut self, row_revs: &[Arc], field_rev: &FieldRevision) -> FlowyResult<()> { - self.handle_rows(row_revs, field_rev) - } - - fn update_card(&self, row_rev: &mut RowRevision, field_rev: &FieldRevision, group_id: &str) { +impl GroupController for SingleSelectGroupController { + fn fill_row(&self, row_rev: &mut RowRevision, field_rev: &FieldRevision, group_id: &str) { let group: Option<&Group> = self.groups_map.get(group_id); match group { None => {} @@ -63,19 +56,14 @@ impl GroupGenerator for SingleSelectGroupGenerator { Some(type_option) => type_option .options .iter() - .map(|option| Group { - id: option.id.clone(), - desc: option.name.clone(), - rows: vec![], - content: option.id.clone(), - }) + .map(|option| Group::new(option.id.clone(), option.name.clone(), option.id.clone())) .collect(), } } } // MultiSelect -pub type MultiSelectGroupController = GroupController< +pub type MultiSelectGroupController = GenericGroupController< SelectOptionGroupConfigurationPB, MultiSelectTypeOptionPB, MultiSelectGroupGenerator, @@ -84,25 +72,23 @@ pub type MultiSelectGroupController = GroupController< 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 group_row(&mut self, row_rev: &RowRevision, cell_data: &Self::CellDataType) -> Vec { + let mut changesets = vec![]; + + self.groups_map.iter_mut().for_each(|(_, group): (_, &mut Group)| { + group_select_option_row(group, &mut changesets, cell_data, row_rev); + }); + changesets + } } -impl GroupActionHandler for MultiSelectGroupController { - fn field_id(&self) -> &str { - &self.field_id - } - - fn build_groups(&self) -> Vec { - self.make_groups() - } - - fn group_rows(&mut self, row_revs: &[Arc], field_rev: &FieldRevision) -> FlowyResult<()> { - self.handle_rows(row_revs, field_rev) - } - - fn update_card(&self, row_rev: &mut RowRevision, field_rev: &FieldRevision, group_id: &str) { +impl GroupController for MultiSelectGroupController { + fn fill_row(&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), @@ -128,13 +114,31 @@ impl GroupGenerator for MultiSelectGroupGenerator { Some(type_option) => type_option .options .iter() - .map(|option| Group { - id: option.id.clone(), - desc: option.name.clone(), - rows: vec![], - content: option.id.clone(), - }) + .map(|option| Group::new(option.id.clone(), option.name.clone(), option.id.clone())) .collect(), } } } + +fn group_select_option_row( + group: &mut Group, + changesets: &mut Vec, + 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) { + group.remove_row(&row_rev.id); + changesets.push(GroupRowsChangesetPB::delete(group.id.clone(), vec![row_rev.id.clone()])); + } + }); +} 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 2fd4bed686..d2e713cf9d 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,9 +1,9 @@ use crate::entities::{ - CheckboxGroupConfigurationPB, DateGroupConfigurationPB, FieldType, NumberGroupConfigurationPB, - SelectOptionGroupConfigurationPB, TextGroupConfigurationPB, UrlGroupConfigurationPB, + CheckboxGroupConfigurationPB, DateGroupConfigurationPB, FieldType, GroupRowsChangesetPB, + NumberGroupConfigurationPB, SelectOptionGroupConfigurationPB, TextGroupConfigurationPB, UrlGroupConfigurationPB, }; use crate::services::group::{ - CheckboxGroupController, Group, GroupActionHandler, MultiSelectGroupController, SingleSelectGroupController, + CheckboxGroupController, Group, GroupController, MultiSelectGroupController, SingleSelectGroupController, }; use bytes::Bytes; use flowy_error::FlowyResult; @@ -18,15 +18,17 @@ pub trait GroupConfigurationDelegate: Send + Sync + 'static { } pub(crate) struct GroupService { + pub groups: Vec, delegate: Box, - action_handler: Option>>, + group_controller: Option>>, } impl GroupService { pub(crate) async fn new(delegate: Box) -> Self { Self { + groups: vec![], delegate, - action_handler: None, + group_controller: None, } } @@ -35,47 +37,58 @@ impl GroupService { field_revs: &[Arc], row_revs: Vec>, ) -> Option> { - let field_rev = find_group_field(field_revs).unwrap(); + let field_rev = find_group_field(field_revs)?; let field_type: FieldType = field_rev.field_type_rev.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), + Ok(groups) => { + self.groups = groups.clone(); + Some(groups) + } Err(_) => None, } } - pub(crate) async fn update_row(&self, row_rev: &mut RowRevision, group_id: &str, f: F) + pub(crate) async fn fill_row(&self, row_rev: &mut RowRevision, group_id: &str, get_field_fn: F) where F: FnOnce(String) -> O, O: Future>> + Send + Sync + 'static, { - if let Some(group_action_handler) = self.action_handler.as_ref() { - let field_id = group_action_handler.read().await.field_id().to_owned(); - match f(field_id).await { + if let Some(group_controller) = self.group_controller.as_ref() { + let field_id = group_controller.read().await.field_id().to_owned(); + match get_field_fn(field_id).await { None => {} Some(field_rev) => { - group_action_handler - .write() - .await - .update_card(row_rev, &field_rev, group_id); + group_controller.write().await.fill_row(row_rev, &field_rev, group_id); } } } } - #[allow(dead_code)] - pub async fn move_card(&self, _group_id: &str, _from: i32, _to: i32) { - // BoardCardChangesetPB { - // group_id: "".to_string(), - // inserted_cards: vec![], - // deleted_cards: vec![], - // updated_cards: vec![] - // } - // let row_pb = make_row_from_row_rev(row_rev); - todo!() + + #[tracing::instrument(level = "trace", skip_all)] + pub(crate) async fn did_update_row( + &self, + row_rev: &RowRevision, + get_field_fn: F, + ) -> Option> + where + F: FnOnce(String) -> O, + O: Future>> + Send + Sync + 'static, + { + let group_controller = self.group_controller.as_ref()?; + let field_id = group_controller.read().await.field_id().to_owned(); + let field_rev = get_field_fn(field_id).await?; + + match group_controller.write().await.did_update_row(row_rev, &field_rev) { + Ok(changeset) => Some(changeset), + Err(e) => { + tracing::error!("Update group data failed, {:?}", e); + None + } + } } #[tracing::instrument(level = "trace", skip_all, err)] @@ -98,15 +111,15 @@ impl GroupService { } FieldType::SingleSelect => { let controller = SingleSelectGroupController::new(field_rev, configuration)?; - self.action_handler = Some(Arc::new(RwLock::new(controller))); + self.group_controller = Some(Arc::new(RwLock::new(controller))); } FieldType::MultiSelect => { let controller = MultiSelectGroupController::new(field_rev, configuration)?; - self.action_handler = Some(Arc::new(RwLock::new(controller))); + self.group_controller = Some(Arc::new(RwLock::new(controller))); } FieldType::Checkbox => { let controller = CheckboxGroupController::new(field_rev, configuration)?; - self.action_handler = Some(Arc::new(RwLock::new(controller))); + self.group_controller = Some(Arc::new(RwLock::new(controller))); } FieldType::URL => { // let generator = GroupGenerator::::from_configuration(configuration); @@ -114,7 +127,7 @@ impl GroupService { }; let mut groups = vec![]; - if let Some(group_action_handler) = self.action_handler.as_ref() { + 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.build_groups(); diff --git a/frontend/rust-lib/flowy-grid/src/services/mod.rs b/frontend/rust-lib/flowy-grid/src/services/mod.rs index 2addb16686..ab864c544a 100644 --- a/frontend/rust-lib/flowy-grid/src/services/mod.rs +++ b/frontend/rust-lib/flowy-grid/src/services/mod.rs @@ -2,11 +2,13 @@ mod util; pub mod block_editor; mod block_manager; +mod block_manager_trait_impl; pub mod cell; pub mod field; mod filter; pub mod grid_editor; mod grid_editor_task; +mod grid_editor_trait_impl; pub mod grid_view_editor; pub mod grid_view_manager; pub mod group; diff --git a/frontend/rust-lib/flowy-revision/src/cache/reset.rs b/frontend/rust-lib/flowy-revision/src/cache/reset.rs index cc9228e9ff..bd1ef4ba58 100644 --- a/frontend/rust-lib/flowy-revision/src/cache/reset.rs +++ b/frontend/rust-lib/flowy-revision/src/cache/reset.rs @@ -38,7 +38,6 @@ where pub async fn run(&self) -> FlowyResult<()> { match KV::get_str(self.target.target_id()) { None => { - tracing::trace!("😁 reset object"); let _ = self.reset_object().await?; let _ = self.save_migrate_record()?; } diff --git a/frontend/rust-lib/flowy-sdk/src/lib.rs b/frontend/rust-lib/flowy-sdk/src/lib.rs index 602e1d2092..e0bd601987 100644 --- a/frontend/rust-lib/flowy-sdk/src/lib.rs +++ b/frontend/rust-lib/flowy-sdk/src/lib.rs @@ -75,7 +75,7 @@ fn crate_log_filter(level: String) -> String { filters.push(format!("lib_ws={}", level)); filters.push(format!("lib_infra={}", level)); filters.push(format!("flowy_sync={}", level)); - filters.push(format!("flowy_revision={}", level)); + // filters.push(format!("flowy_revision={}", level)); // filters.push(format!("lib_dispatch={}", level)); filters.push(format!("dart_ffi={}", "info"));