From 8fd9b68d9d3b5fc5d47ebffa0fe91298b0ec311b Mon Sep 17 00:00:00 2001 From: appflowy Date: Mon, 6 Jun 2022 20:06:08 +0800 Subject: [PATCH] fix: duplicate grid --- .../home/menu/app/header/add_button.dart | 2 +- frontend/rust-lib/Cargo.lock | 1 + frontend/rust-lib/flowy-folder/src/manager.rs | 4 +-- .../src/services/view/controller.rs | 6 ++-- frontend/rust-lib/flowy-grid/Cargo.toml | 1 + frontend/rust-lib/flowy-grid/src/manager.rs | 31 ++++++++++-------- .../src/services/block_meta_editor.rs | 6 +++- .../src/services/block_meta_manager.rs | 3 +- .../number_type_option/number_type_option.rs | 8 +++-- .../flowy-grid/src/services/grid_editor.rs | 29 +++++++++++++++++ .../flowy-sdk/src/deps_resolve/folder_deps.rs | 12 +++---- .../src/entities/meta.rs | 28 ++++++---------- .../src/client_grid/grid_block_meta_pad.rs | 21 +++++++++++- .../src/client_grid/grid_builder.rs | 32 +++++++++++++++---- .../src/client_grid/grid_meta_pad.rs | 26 +++++++++++++-- 15 files changed, 150 insertions(+), 60 deletions(-) diff --git a/frontend/app_flowy/lib/workspace/presentation/home/menu/app/header/add_button.dart b/frontend/app_flowy/lib/workspace/presentation/home/menu/app/header/add_button.dart index a015930a3e..39c13c1c12 100644 --- a/frontend/app_flowy/lib/workspace/presentation/home/menu/app/header/add_button.dart +++ b/frontend/app_flowy/lib/workspace/presentation/home/menu/app/header/add_button.dart @@ -46,8 +46,8 @@ class ActionList { return CreateItem( pluginBuilder: pluginBuilder, onSelected: (builder) { - FlowyOverlay.of(buildContext).remove(_identifier); onSelected(builder); + FlowyOverlay.of(buildContext).remove(_identifier); }, ); }, diff --git a/frontend/rust-lib/Cargo.lock b/frontend/rust-lib/Cargo.lock index 393a02ac73..57cfede8cb 100755 --- a/frontend/rust-lib/Cargo.lock +++ b/frontend/rust-lib/Cargo.lock @@ -937,6 +937,7 @@ dependencies = [ "flowy-revision", "flowy-sync", "flowy-test", + "futures", "indexmap", "lazy_static", "lib-dispatch", diff --git a/frontend/rust-lib/flowy-folder/src/manager.rs b/frontend/rust-lib/flowy-folder/src/manager.rs index fe9a160b39..3181c14625 100644 --- a/frontend/rust-lib/flowy-folder/src/manager.rs +++ b/frontend/rust-lib/flowy-folder/src/manager.rs @@ -241,11 +241,11 @@ pub trait ViewDataProcessor { fn close_container(&self, view_id: &str) -> FutureResult<(), FlowyError>; - fn delta_bytes(&self, view_id: &str) -> FutureResult; + fn view_delta_data(&self, view_id: &str) -> FutureResult; fn create_default_view(&self, user_id: &str, view_id: &str) -> FutureResult; - fn process_create_view_data(&self, user_id: &str, view_id: &str, data: Vec) -> FutureResult; + fn process_view_delta_data(&self, user_id: &str, view_id: &str, data: Vec) -> FutureResult; fn data_type(&self) -> ViewDataType; } diff --git a/frontend/rust-lib/flowy-folder/src/services/view/controller.rs b/frontend/rust-lib/flowy-folder/src/services/view/controller.rs index ae88073afc..4de3b306d8 100644 --- a/frontend/rust-lib/flowy-folder/src/services/view/controller.rs +++ b/frontend/rust-lib/flowy-folder/src/services/view/controller.rs @@ -60,7 +60,7 @@ impl ViewController { params.data = view_data.to_vec(); } else { let delta_data = processor - .process_create_view_data(&user_id, ¶ms.view_id, params.data.clone()) + .process_view_delta_data(&user_id, ¶ms.view_id, params.data.clone()) .await?; let _ = self .create_view(¶ms.view_id, params.data_type.clone(), delta_data) @@ -176,7 +176,7 @@ impl ViewController { .await?; let processor = self.get_data_processor(&view.data_type)?; - let delta_bytes = processor.delta_bytes(view_id).await?; + let delta_bytes = processor.view_delta_data(view_id).await?; let duplicate_params = CreateViewParams { belong_to_id: view.belong_to_id.clone(), name: format!("{} (copy)", &view.name), @@ -238,7 +238,7 @@ impl ViewController { } impl ViewController { - #[tracing::instrument(level = "debug", skip(self), err)] + #[tracing::instrument(level = "debug", skip(self, params), err)] async fn create_view_on_server(&self, params: CreateViewParams) -> Result { let token = self.user.token()?; let view = self.cloud_service.create_view(&token, params).await?; diff --git a/frontend/rust-lib/flowy-grid/Cargo.toml b/frontend/rust-lib/flowy-grid/Cargo.toml index 43b0cbf69f..1cf2ee0e53 100644 --- a/frontend/rust-lib/flowy-grid/Cargo.toml +++ b/frontend/rust-lib/flowy-grid/Cargo.toml @@ -37,6 +37,7 @@ serde_repr = "0.1" indexmap = {version = "1.8.1", features = ["serde"]} fancy-regex = "0.10.0" url = { version = "2"} +futures = "0.3.15" [dev-dependencies] flowy-test = { path = "../flowy-test" } diff --git a/frontend/rust-lib/flowy-grid/src/manager.rs b/frontend/rust-lib/flowy-grid/src/manager.rs index f8ea9e70ae..2965cb5bd9 100644 --- a/frontend/rust-lib/flowy-grid/src/manager.rs +++ b/frontend/rust-lib/flowy-grid/src/manager.rs @@ -154,11 +154,10 @@ pub async fn make_grid_view_data( grid_manager: Arc, build_context: BuildGridContext, ) -> FlowyResult { - let block_id = build_context.block_meta.block_id.clone(); let grid_meta = GridMeta { grid_id: view_id.to_string(), fields: build_context.field_metas, - blocks: vec![build_context.block_meta], + blocks: build_context.blocks, }; // Create grid @@ -168,19 +167,23 @@ pub async fn make_grid_view_data( Revision::initial_revision(user_id, view_id, grid_delta_data.clone()).into(); let _ = grid_manager.create_grid(view_id, repeated_revision).await?; - // Indexing the block's rows - build_context.block_meta_data.rows.iter().for_each(|row| { - let _ = grid_manager.block_index_cache.insert(&row.block_id, &row.id); - }); + for block_meta_data in build_context.blocks_meta_data { + let block_id = block_meta_data.block_id.clone(); - // Create grid's block - let grid_block_meta_delta = make_block_meta_delta(&build_context.block_meta_data); - let block_meta_delta_data = grid_block_meta_delta.to_delta_bytes(); - let repeated_revision: RepeatedRevision = - Revision::initial_revision(user_id, &block_id, block_meta_delta_data).into(); - let _ = grid_manager - .create_grid_block_meta(&block_id, repeated_revision) - .await?; + // Indexing the block's rows + block_meta_data.rows.iter().for_each(|row| { + let _ = grid_manager.block_index_cache.insert(&row.block_id, &row.id); + }); + + // Create grid's block + let grid_block_meta_delta = make_block_meta_delta(&block_meta_data); + let block_meta_delta_data = grid_block_meta_delta.to_delta_bytes(); + let repeated_revision: RepeatedRevision = + Revision::initial_revision(user_id, &block_id, block_meta_delta_data).into(); + let _ = grid_manager + .create_grid_block_meta(&block_id, repeated_revision) + .await?; + } Ok(grid_delta_data) } diff --git a/frontend/rust-lib/flowy-grid/src/services/block_meta_editor.rs b/frontend/rust-lib/flowy-grid/src/services/block_meta_editor.rs index d1cb847b37..d37c869156 100644 --- a/frontend/rust-lib/flowy-grid/src/services/block_meta_editor.rs +++ b/frontend/rust-lib/flowy-grid/src/services/block_meta_editor.rs @@ -1,6 +1,6 @@ use bytes::Bytes; use flowy_error::{FlowyError, FlowyResult}; -use flowy_grid_data_model::entities::{CellMeta, RowMeta, RowMetaChangeset, RowOrder}; +use flowy_grid_data_model::entities::{CellMeta, GridBlockMetaData, RowMeta, RowMetaChangeset, RowOrder}; use flowy_revision::{RevisionCloudService, RevisionCompactor, RevisionManager, RevisionObjectBuilder}; use flowy_sync::client_grid::{GridBlockMetaChange, GridBlockMetaPad}; use flowy_sync::entities::revision::Revision; @@ -41,6 +41,10 @@ impl GridBlockMetaEditor { }) } + pub async fn duplicate_block_meta_data(&self, duplicated_block_id: &str) -> GridBlockMetaData { + self.pad.read().await.duplicate_data(duplicated_block_id).await + } + /// return current number of rows and the inserted index. The inserted index will be None if the start_row_id is None pub(crate) async fn create_row( &self, diff --git a/frontend/rust-lib/flowy-grid/src/services/block_meta_manager.rs b/frontend/rust-lib/flowy-grid/src/services/block_meta_manager.rs index 6ce36488c2..ec7c47f069 100644 --- a/frontend/rust-lib/flowy-grid/src/services/block_meta_manager.rs +++ b/frontend/rust-lib/flowy-grid/src/services/block_meta_manager.rs @@ -47,7 +47,7 @@ impl GridBlockManager { debug_assert!(!block_id.is_empty()); match self.block_editor_map.get(block_id) { None => { - tracing::error!("The is a fatal error, block is not exist"); + tracing::error!("This is a fatal error, block with id:{} is not exist", block_id); let editor = Arc::new(make_block_meta_editor(&self.user, block_id).await?); self.block_editor_map.insert(block_id.to_owned(), editor.clone()); Ok(editor) @@ -267,6 +267,7 @@ async fn make_block_meta_editor_map( } async fn make_block_meta_editor(user: &Arc, block_id: &str) -> FlowyResult { + tracing::trace!("Open block:{} meta editor", block_id); let token = user.token()?; let user_id = user.user_id()?; let pool = user.db_pool()?; diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option/number_type_option.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option/number_type_option.rs index 82970ab25a..9c830797ed 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option/number_type_option.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option/number_type_option.rs @@ -77,7 +77,7 @@ impl NumberTypeOption { } fn cell_content_from_number_str(&self, s: &str) -> FlowyResult { - return match self.format { + match self.format { NumberFormat::Number => { if let Ok(v) = s.parse::() { return Ok(v.to_string()); @@ -94,7 +94,7 @@ impl NumberTypeOption { Ok(content) } _ => self.money_from_number_str(s), - }; + } } pub fn set_format(&mut self, format: NumberFormat) { @@ -173,7 +173,9 @@ impl CellDataOperation for NumberTypeOption { Ok(DecodedCellData::new(content)) } _ => { - let content = self.money_from_number_str(&cell_data).unwrap_or("".to_string()); + let content = self + .money_from_number_str(&cell_data) + .unwrap_or_else(|_| "".to_string()); Ok(DecodedCellData::new(content)) } } 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 e4cee15a6e..82db6aac1b 100644 --- a/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs +++ b/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs @@ -487,6 +487,35 @@ impl GridMetaEditor { self.grid_pad.read().await.delta_bytes() } + pub async fn duplicate_grid(&self) -> FlowyResult { + let grid_pad = self.grid_pad.read().await; + let original_blocks = grid_pad.get_block_metas(); + let (duplicated_fields, duplicated_blocks) = grid_pad.duplicate_grid_meta().await; + + let mut blocks_meta_data = vec![]; + if original_blocks.len() == duplicated_blocks.len() { + for (index, original_block_meta) in original_blocks.iter().enumerate() { + let grid_block_meta_editor = self.block_manager.get_editor(&original_block_meta.block_id).await?; + let duplicated_block_id = &duplicated_blocks[index].block_id; + + tracing::trace!("Duplicate block:{} meta data", duplicated_block_id); + let duplicated_block_meta_data = grid_block_meta_editor + .duplicate_block_meta_data(duplicated_block_id) + .await; + blocks_meta_data.push(duplicated_block_meta_data); + } + } else { + debug_assert_eq!(original_blocks.len(), duplicated_blocks.len()); + } + drop(grid_pad); + + Ok(BuildGridContext { + field_metas: duplicated_fields, + blocks: duplicated_blocks, + blocks_meta_data, + }) + } + async fn modify(&self, f: F) -> FlowyResult<()> where F: for<'a> FnOnce(&'a mut GridMetaPad) -> FlowyResult>, diff --git a/frontend/rust-lib/flowy-sdk/src/deps_resolve/folder_deps.rs b/frontend/rust-lib/flowy-sdk/src/deps_resolve/folder_deps.rs index 41835804af..846dddd55e 100644 --- a/frontend/rust-lib/flowy-sdk/src/deps_resolve/folder_deps.rs +++ b/frontend/rust-lib/flowy-sdk/src/deps_resolve/folder_deps.rs @@ -173,7 +173,7 @@ impl ViewDataProcessor for TextBlockViewDataProcessor { }) } - fn delta_bytes(&self, view_id: &str) -> FutureResult { + fn view_delta_data(&self, view_id: &str) -> FutureResult { let view_id = view_id.to_string(); let manager = self.0.clone(); FutureResult::new(async move { @@ -197,7 +197,7 @@ impl ViewDataProcessor for TextBlockViewDataProcessor { }) } - fn process_create_view_data( + fn process_view_delta_data( &self, _user_id: &str, _view_id: &str, @@ -245,13 +245,13 @@ impl ViewDataProcessor for GridViewDataProcessor { }) } - fn delta_bytes(&self, view_id: &str) -> FutureResult { + fn view_delta_data(&self, view_id: &str) -> FutureResult { let view_id = view_id.to_string(); let grid_manager = self.0.clone(); FutureResult::new(async move { let editor = grid_manager.open_grid(view_id).await?; - let delta_bytes = editor.delta_bytes().await; - Ok(delta_bytes) + let delta_bytes = editor.duplicate_grid().await?; + Ok(delta_bytes.into()) }) } @@ -264,7 +264,7 @@ impl ViewDataProcessor for GridViewDataProcessor { FutureResult::new(async move { make_grid_view_data(&user_id, &view_id, grid_manager, build_context).await }) } - fn process_create_view_data(&self, user_id: &str, view_id: &str, data: Vec) -> FutureResult { + fn process_view_delta_data(&self, user_id: &str, view_id: &str, data: Vec) -> FutureResult { let user_id = user_id.to_string(); let view_id = view_id.to_string(); let grid_manager = self.0.clone(); diff --git a/shared-lib/flowy-grid-data-model/src/entities/meta.rs b/shared-lib/flowy-grid-data-model/src/entities/meta.rs index 328b368fbc..d62965245b 100644 --- a/shared-lib/flowy-grid-data-model/src/entities/meta.rs +++ b/shared-lib/flowy-grid-data-model/src/entities/meta.rs @@ -203,11 +203,17 @@ impl CellMeta { } } -#[derive(Clone, Deserialize, Serialize)] +#[derive(Clone, Default, Deserialize, Serialize)] pub struct BuildGridContext { pub field_metas: Vec, - pub block_meta: GridBlockMeta, - pub block_meta_data: GridBlockMetaData, + pub blocks: Vec, + pub blocks_meta_data: Vec, +} + +impl BuildGridContext { + pub fn new() -> Self { + Self::default() + } } impl std::convert::From for Bytes { @@ -225,19 +231,3 @@ impl std::convert::TryFrom for BuildGridContext { Ok(ctx) } } - -impl std::default::Default for BuildGridContext { - fn default() -> Self { - let block_meta = GridBlockMeta::new(); - let block_meta_data = GridBlockMetaData { - block_id: block_meta.block_id.clone(), - rows: vec![], - }; - - Self { - field_metas: vec![], - block_meta, - block_meta_data, - } - } -} diff --git a/shared-lib/flowy-sync/src/client_grid/grid_block_meta_pad.rs b/shared-lib/flowy-sync/src/client_grid/grid_block_meta_pad.rs index 3370719e68..175890ad01 100644 --- a/shared-lib/flowy-sync/src/client_grid/grid_block_meta_pad.rs +++ b/shared-lib/flowy-sync/src/client_grid/grid_block_meta_pad.rs @@ -1,7 +1,9 @@ use crate::entities::revision::{md5, RepeatedRevision, Revision}; use crate::errors::{CollaborateError, CollaborateResult}; use crate::util::{cal_diff, make_delta_from_revisions}; -use flowy_grid_data_model::entities::{gen_block_id, CellMeta, GridBlockMetaData, RowMeta, RowMetaChangeset}; +use flowy_grid_data_model::entities::{ + gen_block_id, gen_row_id, CellMeta, GridBlockMetaData, RowMeta, RowMetaChangeset, +}; use lib_ot::core::{OperationTransformable, PlainTextAttributes, PlainTextDelta, PlainTextDeltaBuilder}; use serde::{Deserialize, Serialize}; use std::borrow::Cow; @@ -22,6 +24,23 @@ pub struct GridBlockMetaPad { } impl GridBlockMetaPad { + pub async fn duplicate_data(&self, duplicated_block_id: &str) -> GridBlockMetaData { + let duplicated_rows = self + .rows + .iter() + .map(|row| { + let mut duplicated_row = row.as_ref().clone(); + duplicated_row.id = gen_row_id(); + duplicated_row.block_id = duplicated_block_id.to_string(); + duplicated_row + }) + .collect::>(); + GridBlockMetaData { + block_id: duplicated_block_id.to_string(), + rows: duplicated_rows, + } + } + pub fn from_delta(delta: GridBlockMetaDelta) -> CollaborateResult { let s = delta.to_str()?; let meta_data: GridBlockMetaData = serde_json::from_str(&s).map_err(|e| { diff --git a/shared-lib/flowy-sync/src/client_grid/grid_builder.rs b/shared-lib/flowy-sync/src/client_grid/grid_builder.rs index fb800a9626..95e707a287 100644 --- a/shared-lib/flowy-sync/src/client_grid/grid_builder.rs +++ b/shared-lib/flowy-sync/src/client_grid/grid_builder.rs @@ -1,11 +1,27 @@ use crate::errors::{CollaborateError, CollaborateResult}; -use flowy_grid_data_model::entities::{BuildGridContext, FieldMeta, RowMeta}; +use flowy_grid_data_model::entities::{BuildGridContext, FieldMeta, GridBlockMeta, GridBlockMetaData, RowMeta}; -#[derive(Default)] pub struct GridBuilder { build_context: BuildGridContext, } +impl std::default::Default for GridBuilder { + fn default() -> Self { + let mut build_context = BuildGridContext::new(); + + let block_meta = GridBlockMeta::new(); + let block_meta_data = GridBlockMetaData { + block_id: block_meta.block_id.clone(), + rows: vec![], + }; + + build_context.blocks.push(block_meta); + build_context.blocks_meta_data.push(block_meta_data); + + GridBuilder { build_context } + } +} + impl GridBuilder { pub fn add_field(mut self, field: FieldMeta) -> Self { self.build_context.field_metas.push(field); @@ -13,9 +29,11 @@ impl GridBuilder { } pub fn add_empty_row(mut self) -> Self { - let row = RowMeta::new(&self.build_context.block_meta.block_id); - self.build_context.block_meta_data.rows.push(row); - self.build_context.block_meta.row_count += 1; + let row = RowMeta::new(&self.build_context.blocks.first().unwrap().block_id); + let block_meta = self.build_context.blocks.first_mut().unwrap(); + let block_meta_data = self.build_context.blocks_meta_data.first_mut().unwrap(); + block_meta_data.rows.push(row); + block_meta.row_count += 1; self } @@ -57,13 +75,13 @@ mod tests { let grid_meta = GridMeta { grid_id, fields: build_context.field_metas, - blocks: vec![build_context.block_meta], + blocks: build_context.blocks, }; let grid_meta_delta = make_grid_delta(&grid_meta); let _: GridMeta = serde_json::from_str(&grid_meta_delta.to_str().unwrap()).unwrap(); - let grid_block_meta_delta = make_block_meta_delta(&build_context.block_meta_data); + let grid_block_meta_delta = make_block_meta_delta(build_context.blocks_meta_data.first().unwrap()); let _: GridBlockMetaData = serde_json::from_str(&grid_block_meta_delta.to_str().unwrap()).unwrap(); } } diff --git a/shared-lib/flowy-sync/src/client_grid/grid_meta_pad.rs b/shared-lib/flowy-sync/src/client_grid/grid_meta_pad.rs index 791648cf14..0e255f0f12 100644 --- a/shared-lib/flowy-sync/src/client_grid/grid_meta_pad.rs +++ b/shared-lib/flowy-sync/src/client_grid/grid_meta_pad.rs @@ -3,8 +3,8 @@ use crate::errors::{internal_error, CollaborateError, CollaborateResult}; use crate::util::{cal_diff, make_delta_from_revisions}; use bytes::Bytes; use flowy_grid_data_model::entities::{ - gen_grid_id, FieldChangesetParams, FieldMeta, FieldOrder, FieldType, GridBlockMeta, GridBlockMetaChangeset, - GridMeta, + gen_block_id, gen_grid_id, FieldChangesetParams, FieldMeta, FieldOrder, FieldType, GridBlockMeta, + GridBlockMetaChangeset, GridMeta, }; use lib_infra::util::move_vec_element; use lib_ot::core::{OperationTransformable, PlainTextAttributes, PlainTextDelta, PlainTextDeltaBuilder}; @@ -24,6 +24,28 @@ pub trait JsonDeserializer { } impl GridMetaPad { + pub async fn duplicate_grid_meta(&self) -> (Vec, Vec) { + let fields = self + .grid_meta + .fields + .iter() + .map(|field| field.clone()) + .collect::>(); + + let blocks = self + .grid_meta + .blocks + .iter() + .map(|block| { + let mut duplicated_block = block.clone(); + duplicated_block.block_id = gen_block_id(); + duplicated_block + }) + .collect::>(); + + (fields, blocks) + } + pub fn from_delta(delta: GridMetaDelta) -> CollaborateResult { let s = delta.to_str()?; let grid: GridMeta = serde_json::from_str(&s)