fix: duplicate grid

This commit is contained in:
appflowy 2022-06-06 20:06:08 +08:00
parent 7c03924e9c
commit 8fd9b68d9d
15 changed files with 150 additions and 60 deletions

View File

@ -46,8 +46,8 @@ class ActionList {
return CreateItem(
pluginBuilder: pluginBuilder,
onSelected: (builder) {
FlowyOverlay.of(buildContext).remove(_identifier);
onSelected(builder);
FlowyOverlay.of(buildContext).remove(_identifier);
},
);
},

View File

@ -937,6 +937,7 @@ dependencies = [
"flowy-revision",
"flowy-sync",
"flowy-test",
"futures",
"indexmap",
"lazy_static",
"lib-dispatch",

View File

@ -241,11 +241,11 @@ pub trait ViewDataProcessor {
fn close_container(&self, view_id: &str) -> FutureResult<(), FlowyError>;
fn delta_bytes(&self, view_id: &str) -> FutureResult<Bytes, FlowyError>;
fn view_delta_data(&self, view_id: &str) -> FutureResult<Bytes, FlowyError>;
fn create_default_view(&self, user_id: &str, view_id: &str) -> FutureResult<Bytes, FlowyError>;
fn process_create_view_data(&self, user_id: &str, view_id: &str, data: Vec<u8>) -> FutureResult<Bytes, FlowyError>;
fn process_view_delta_data(&self, user_id: &str, view_id: &str, data: Vec<u8>) -> FutureResult<Bytes, FlowyError>;
fn data_type(&self) -> ViewDataType;
}

View File

@ -60,7 +60,7 @@ impl ViewController {
params.data = view_data.to_vec();
} else {
let delta_data = processor
.process_create_view_data(&user_id, &params.view_id, params.data.clone())
.process_view_delta_data(&user_id, &params.view_id, params.data.clone())
.await?;
let _ = self
.create_view(&params.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<View, FlowyError> {
let token = self.user.token()?;
let view = self.cloud_service.create_view(&token, params).await?;

View File

@ -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" }

View File

@ -154,11 +154,10 @@ pub async fn make_grid_view_data(
grid_manager: Arc<GridManager>,
build_context: BuildGridContext,
) -> FlowyResult<Bytes> {
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)
}

View File

@ -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,

View File

@ -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<dyn GridUser>, block_id: &str) -> FlowyResult<GridBlockMetaEditor> {
tracing::trace!("Open block:{} meta editor", block_id);
let token = user.token()?;
let user_id = user.user_id()?;
let pool = user.db_pool()?;

View File

@ -77,7 +77,7 @@ impl NumberTypeOption {
}
fn cell_content_from_number_str(&self, s: &str) -> FlowyResult<String> {
return match self.format {
match self.format {
NumberFormat::Number => {
if let Ok(v) = s.parse::<f64>() {
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<String> 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))
}
}

View File

@ -487,6 +487,35 @@ impl GridMetaEditor {
self.grid_pad.read().await.delta_bytes()
}
pub async fn duplicate_grid(&self) -> FlowyResult<BuildGridContext> {
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<F>(&self, f: F) -> FlowyResult<()>
where
F: for<'a> FnOnce(&'a mut GridMetaPad) -> FlowyResult<Option<GridChangeset>>,

View File

@ -173,7 +173,7 @@ impl ViewDataProcessor for TextBlockViewDataProcessor {
})
}
fn delta_bytes(&self, view_id: &str) -> FutureResult<Bytes, FlowyError> {
fn view_delta_data(&self, view_id: &str) -> FutureResult<Bytes, FlowyError> {
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<Bytes, FlowyError> {
fn view_delta_data(&self, view_id: &str) -> FutureResult<Bytes, FlowyError> {
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<u8>) -> FutureResult<Bytes, FlowyError> {
fn process_view_delta_data(&self, user_id: &str, view_id: &str, data: Vec<u8>) -> FutureResult<Bytes, FlowyError> {
let user_id = user_id.to_string();
let view_id = view_id.to_string();
let grid_manager = self.0.clone();

View File

@ -203,11 +203,17 @@ impl CellMeta {
}
}
#[derive(Clone, Deserialize, Serialize)]
#[derive(Clone, Default, Deserialize, Serialize)]
pub struct BuildGridContext {
pub field_metas: Vec<FieldMeta>,
pub block_meta: GridBlockMeta,
pub block_meta_data: GridBlockMetaData,
pub blocks: Vec<GridBlockMeta>,
pub blocks_meta_data: Vec<GridBlockMetaData>,
}
impl BuildGridContext {
pub fn new() -> Self {
Self::default()
}
}
impl std::convert::From<BuildGridContext> for Bytes {
@ -225,19 +231,3 @@ impl std::convert::TryFrom<Bytes> 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,
}
}
}

View File

@ -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::<Vec<RowMeta>>();
GridBlockMetaData {
block_id: duplicated_block_id.to_string(),
rows: duplicated_rows,
}
}
pub fn from_delta(delta: GridBlockMetaDelta) -> CollaborateResult<Self> {
let s = delta.to_str()?;
let meta_data: GridBlockMetaData = serde_json::from_str(&s).map_err(|e| {

View File

@ -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();
}
}

View File

@ -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<FieldMeta>, Vec<GridBlockMeta>) {
let fields = self
.grid_meta
.fields
.iter()
.map(|field| field.clone())
.collect::<Vec<FieldMeta>>();
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::<Vec<GridBlockMeta>>();
(fields, blocks)
}
pub fn from_delta(delta: GridMetaDelta) -> CollaborateResult<Self> {
let s = delta.to_str()?;
let grid: GridMeta = serde_json::from_str(&s)