diff --git a/frontend/rust-lib/flowy-grid/src/services/block_revision_editor.rs b/frontend/rust-lib/flowy-grid/src/services/block_revision_editor.rs index 0d5f5d206e..a674098bfc 100644 --- a/frontend/rust-lib/flowy-grid/src/services/block_revision_editor.rs +++ b/frontend/rust-lib/flowy-grid/src/services/block_revision_editor.rs @@ -3,7 +3,7 @@ use bytes::Bytes; use flowy_error::{FlowyError, FlowyResult}; use flowy_grid_data_model::revision::{CellRevision, GridBlockRevision, RowMetaChangeset, RowRevision}; use flowy_revision::{RevisionCloudService, RevisionCompactor, RevisionManager, RevisionObjectBuilder}; -use flowy_sync::client_grid::{GridBlockMetaChange, GridBlockRevisionPad}; +use flowy_sync::client_grid::{GridBlockRevisionChangeset, GridBlockRevisionPad}; use flowy_sync::entities::revision::Revision; use flowy_sync::util::make_delta_from_revisions; use lib_infra::future::FutureResult; @@ -29,8 +29,8 @@ impl GridBlockRevisionEditor { let cloud = Arc::new(GridBlockRevisionCloudService { token: token.to_owned(), }); - let block_meta_pad = rev_manager.load::(Some(cloud)).await?; - let pad = Arc::new(RwLock::new(block_meta_pad)); + let block_revision_pad = rev_manager.load::(Some(cloud)).await?; + let pad = Arc::new(RwLock::new(block_revision_pad)); let rev_manager = Arc::new(rev_manager); let user_id = user_id.to_owned(); let block_id = block_id.to_owned(); @@ -145,7 +145,7 @@ impl GridBlockRevisionEditor { async fn modify(&self, f: F) -> FlowyResult<()> where - F: for<'a> FnOnce(&'a mut GridBlockRevisionPad) -> FlowyResult>, + F: for<'a> FnOnce(&'a mut GridBlockRevisionPad) -> FlowyResult>, { let mut write_guard = self.pad.write().await; match f(&mut *write_guard)? { @@ -157,8 +157,8 @@ impl GridBlockRevisionEditor { Ok(()) } - async fn apply_change(&self, change: GridBlockMetaChange) -> FlowyResult<()> { - let GridBlockMetaChange { delta, md5 } = change; + async fn apply_change(&self, change: GridBlockRevisionChangeset) -> FlowyResult<()> { + let GridBlockRevisionChangeset { delta, md5 } = change; let user_id = self.user_id.clone(); let (base_rev_id, rev_id) = self.rev_manager.next_rev_id_pair(); let delta_data = delta.json_bytes(); @@ -187,8 +187,8 @@ impl RevisionCloudService for GridBlockRevisionCloudService { } } -struct GridBlockMetaPadBuilder(); -impl RevisionObjectBuilder for GridBlockMetaPadBuilder { +struct GridBlockRevisionPadBuilder(); +impl RevisionObjectBuilder for GridBlockRevisionPadBuilder { type Output = GridBlockRevisionPad; fn build_object(object_id: &str, revisions: Vec) -> FlowyResult { 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 3b7a4e854f..3f9e11295a 100644 --- a/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs +++ b/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs @@ -16,7 +16,7 @@ use bytes::Bytes; use flowy_error::{ErrorCode, FlowyError, FlowyResult}; use flowy_grid_data_model::revision::*; use flowy_revision::{RevisionCloudService, RevisionCompactor, RevisionManager, RevisionObjectBuilder}; -use flowy_sync::client_grid::{GridChangeset, GridRevisionPad, JsonDeserializer}; +use flowy_sync::client_grid::{GridRevisionChangeset, GridRevisionPad, JsonDeserializer}; use flowy_sync::entities::grid::{FieldChangesetParams, GridSettingChangesetParams}; use flowy_sync::entities::revision::Revision; use flowy_sync::errors::CollaborateResult; @@ -608,7 +608,7 @@ impl GridRevisionEditor { async fn modify(&self, f: F) -> FlowyResult<()> where - F: for<'a> FnOnce(&'a mut GridRevisionPad) -> FlowyResult>, + F: for<'a> FnOnce(&'a mut GridRevisionPad) -> FlowyResult>, { let mut write_guard = self.grid_pad.write().await; if let Some(changeset) = f(&mut *write_guard)? { @@ -617,8 +617,8 @@ impl GridRevisionEditor { Ok(()) } - async fn apply_change(&self, change: GridChangeset) -> FlowyResult<()> { - let GridChangeset { delta, md5 } = change; + async fn apply_change(&self, change: GridRevisionChangeset) -> FlowyResult<()> { + let GridRevisionChangeset { delta, md5 } = change; let user_id = self.user.user_id()?; let (base_rev_id, rev_id) = self.rev_manager.next_rev_id_pair(); let delta_data = delta.json_bytes(); 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 new file mode 100644 index 0000000000..f287f7f89d --- /dev/null +++ b/frontend/rust-lib/flowy-grid/src/services/grid_view_editor.rs @@ -0,0 +1,48 @@ +use flowy_error::{FlowyError, FlowyResult}; +use flowy_grid_data_model::revision::GridViewRevision; +use flowy_revision::{RevisionCloudService, RevisionManager, RevisionObjectBuilder}; +use flowy_sync::client_grid::GridViewRevisionPad; +use flowy_sync::entities::revision::Revision; +use lib_infra::future::FutureResult; +use std::sync::Arc; +use tokio::sync::RwLock; + +pub struct GridViewRevisionEditor { + pad: Arc>, + rev_manager: Arc, +} + +impl GridViewRevisionEditor { + pub async fn new(token: &str, mut rev_manager: RevisionManager) -> FlowyResult { + let cloud = Arc::new(GridViewRevisionCloudService { + token: token.to_owned(), + }); + let view_revision_pad = rev_manager.load::(Some(cloud)).await?; + let pad = Arc::new(RwLock::new(view_revision_pad)); + let rev_manager = Arc::new(rev_manager); + + Ok(Self { pad, rev_manager }) + } +} + +struct GridViewRevisionCloudService { + #[allow(dead_code)] + token: String, +} + +impl RevisionCloudService for GridViewRevisionCloudService { + #[tracing::instrument(level = "trace", skip(self))] + fn fetch_object(&self, _user_id: &str, _object_id: &str) -> FutureResult, FlowyError> { + FutureResult::new(async move { Ok(vec![]) }) + } +} + +struct GridViewRevisionPadBuilder(); +impl RevisionObjectBuilder for GridViewRevisionPadBuilder { + type Output = GridViewRevisionPad; + + fn build_object(object_id: &str, revisions: Vec) -> FlowyResult { + let pad = GridViewRevisionPad::from_revisions(object_id, revisions)?; + Ok(pad) + } +} diff --git a/frontend/rust-lib/flowy-grid/src/services/mod.rs b/frontend/rust-lib/flowy-grid/src/services/mod.rs index dc45575ab3..2683d1f06a 100644 --- a/frontend/rust-lib/flowy-grid/src/services/mod.rs +++ b/frontend/rust-lib/flowy-grid/src/services/mod.rs @@ -7,6 +7,7 @@ pub mod field; mod filter; pub mod grid_editor; mod grid_editor_task; +pub mod grid_view_editor; pub mod group; pub mod persistence; pub mod row; diff --git a/shared-lib/flowy-grid-data-model/src/revision/grid_setting_rev.rs b/shared-lib/flowy-grid-data-model/src/revision/grid_setting_rev.rs index 817974436f..c9d3b034d8 100644 --- a/shared-lib/flowy-grid-data-model/src/revision/grid_setting_rev.rs +++ b/shared-lib/flowy-grid-data-model/src/revision/grid_setting_rev.rs @@ -25,7 +25,7 @@ pub type FilterConfigurationsByFieldId = HashMap; pub type GroupConfigurationsByFieldId = HashMap>>; // -pub type SortConfigurations = Configuration; +pub type SortConfiguration = Configuration; pub type SortConfigurationsByFieldId = HashMap>>; #[derive(Debug, Clone, Serialize, Deserialize, Default, Eq, PartialEq)] @@ -38,7 +38,7 @@ pub struct SettingRevision { pub groups: GroupConfiguration, #[serde(skip)] - pub sorts: SortConfigurations, + pub sorts: SortConfiguration, } #[derive(Debug, PartialEq, Eq, Hash, Clone, Serialize_repr, Deserialize_repr)] diff --git a/shared-lib/flowy-grid-data-model/src/revision/grid_view.rs b/shared-lib/flowy-grid-data-model/src/revision/grid_view.rs index 7cfbbb4e65..7331797541 100644 --- a/shared-lib/flowy-grid-data-model/src/revision/grid_view.rs +++ b/shared-lib/flowy-grid-data-model/src/revision/grid_view.rs @@ -1,6 +1,11 @@ use crate::revision::SettingRevision; +use nanoid::nanoid; use serde::{Deserialize, Serialize}; +pub fn gen_grid_view_id() -> String { + nanoid!(6) +} + #[derive(Debug, Clone, Default, Serialize, Deserialize)] pub struct GridViewRevision { pub view_id: String, @@ -8,13 +13,23 @@ pub struct GridViewRevision { pub grid_id: String, pub setting: SettingRevision, - // TODO: Save the rows' order. + // For the moment, we just use the order returned from the GridRevision - // #[serde(rename = "row")] - // pub row_orders: Vec, + #[allow(dead_code)] + #[serde(skip, rename = "row")] + pub row_orders: Vec, } -// #[derive(Debug, Clone, Default, Serialize, Deserialize)] -// pub struct RowOrderRevision { -// pub row_id: String, -// } +impl GridViewRevision { + pub fn new(grid_id: String) -> Self { + let mut view_rev = GridViewRevision::default(); + view_rev.grid_id = grid_id; + view_rev.view_id = gen_grid_view_id(); + view_rev + } +} + +#[derive(Debug, Clone, Default, Serialize, Deserialize)] +pub struct RowOrderRevision { + pub row_id: String, +} diff --git a/shared-lib/flowy-sync/src/client_grid/grid_block_revsion_pad.rs b/shared-lib/flowy-sync/src/client_grid/block_revision_pad.rs similarity index 83% rename from shared-lib/flowy-sync/src/client_grid/grid_block_revsion_pad.rs rename to shared-lib/flowy-sync/src/client_grid/block_revision_pad.rs index 51a331ecf7..e960ae42e0 100644 --- a/shared-lib/flowy-sync/src/client_grid/grid_block_revsion_pad.rs +++ b/shared-lib/flowy-sync/src/client_grid/block_revision_pad.rs @@ -1,6 +1,6 @@ use crate::entities::revision::{md5, RepeatedRevision, Revision}; use crate::errors::{CollaborateError, CollaborateResult}; -use crate::util::{cal_diff, make_delta_from_revisions}; +use crate::util::{cal_diff, make_delta_from_revisions, make_text_delta_from_revisions}; use flowy_grid_data_model::revision::{ gen_block_id, gen_row_id, CellRevision, GridBlockRevision, RowMetaChangeset, RowRevision, }; @@ -9,27 +9,24 @@ use std::borrow::Cow; use std::collections::HashMap; use std::sync::Arc; -pub type GridBlockRevisionDelta = TextDelta; -pub type GridBlockRevisionDeltaBuilder = TextDeltaBuilder; - #[derive(Debug, Clone)] pub struct GridBlockRevisionPad { - block_revision: GridBlockRevision, - pub(crate) delta: GridBlockRevisionDelta, + block: GridBlockRevision, + delta: TextDelta, } impl std::ops::Deref for GridBlockRevisionPad { type Target = GridBlockRevision; fn deref(&self) -> &Self::Target { - &self.block_revision + &self.block } } impl GridBlockRevisionPad { pub async fn duplicate_data(&self, duplicated_block_id: &str) -> GridBlockRevision { let duplicated_rows = self - .block_revision + .block .rows .iter() .map(|row| { @@ -45,18 +42,18 @@ impl GridBlockRevisionPad { } } - pub fn from_delta(delta: GridBlockRevisionDelta) -> CollaborateResult { + pub fn from_delta(delta: TextDelta) -> CollaborateResult { let s = delta.content()?; - let block_revision: GridBlockRevision = serde_json::from_str(&s).map_err(|e| { - let msg = format!("Deserialize delta to block meta failed: {}", e); + let revision: GridBlockRevision = serde_json::from_str(&s).map_err(|e| { + let msg = format!("Deserialize delta to GridBlockRevision failed: {}", e); tracing::error!("{}", s); CollaborateError::internal().context(msg) })?; - Ok(Self { block_revision, delta }) + Ok(Self { block: revision, delta }) } pub fn from_revisions(_grid_id: &str, revisions: Vec) -> CollaborateResult { - let block_delta: GridBlockRevisionDelta = make_delta_from_revisions::(revisions)?; + let block_delta: TextDelta = make_text_delta_from_revisions(revisions)?; Self::from_delta(block_delta) } @@ -65,7 +62,7 @@ impl GridBlockRevisionPad { &mut self, row: RowRevision, start_row_id: Option, - ) -> CollaborateResult> { + ) -> CollaborateResult> { self.modify(|rows| { if let Some(start_row_id) = start_row_id { if !start_row_id.is_empty() { @@ -81,7 +78,10 @@ impl GridBlockRevisionPad { }) } - pub fn delete_rows(&mut self, row_ids: Vec>) -> CollaborateResult> { + pub fn delete_rows( + &mut self, + row_ids: Vec>, + ) -> CollaborateResult> { self.modify(|rows| { rows.retain(|row| !row_ids.contains(&Cow::Borrowed(&row.id))); Ok(Some(())) @@ -93,10 +93,10 @@ impl GridBlockRevisionPad { T: AsRef + ToOwned + ?Sized, { match row_ids { - None => Ok(self.block_revision.rows.clone()), + None => Ok(self.block.rows.clone()), Some(row_ids) => { let row_map = self - .block_revision + .block .rows .iter() .map(|row| (row.id.as_str(), row.clone())) @@ -136,18 +136,18 @@ impl GridBlockRevisionPad { } pub fn number_of_rows(&self) -> i32 { - self.block_revision.rows.len() as i32 + self.block.rows.len() as i32 } pub fn index_of_row(&self, row_id: &str) -> Option { - self.block_revision + self.block .rows .iter() .position(|row| row.id == row_id) .map(|index| index as i32) } - pub fn update_row(&mut self, changeset: RowMetaChangeset) -> CollaborateResult> { + pub fn update_row(&mut self, changeset: RowMetaChangeset) -> CollaborateResult> { let row_id = changeset.row_id.clone(); self.modify_row(&row_id, |row| { let mut is_changed = None; @@ -172,7 +172,12 @@ impl GridBlockRevisionPad { }) } - pub fn move_row(&mut self, row_id: &str, from: usize, to: usize) -> CollaborateResult> { + pub fn move_row( + &mut self, + row_id: &str, + from: usize, + to: usize, + ) -> CollaborateResult> { self.modify(|row_revs| { if let Some(position) = row_revs.iter().position(|row_rev| row_rev.id == row_id) { debug_assert_eq!(from, position); @@ -185,33 +190,36 @@ impl GridBlockRevisionPad { }) } - pub fn modify(&mut self, f: F) -> CollaborateResult> + pub fn modify(&mut self, f: F) -> CollaborateResult> where F: for<'a> FnOnce(&'a mut Vec>) -> CollaborateResult>, { let cloned_self = self.clone(); - match f(&mut self.block_revision.rows)? { + match f(&mut self.block.rows)? { None => Ok(None), Some(_) => { - let old = cloned_self.to_json()?; - let new = self.to_json()?; + let old = cloned_self.revision_json()?; + let new = self.revision_json()?; match cal_diff::(old, new) { None => Ok(None), Some(delta) => { - tracing::trace!("[GridBlockMeta] Composing delta {}", delta.json_str()); + tracing::trace!("[GridBlockRevision] Composing delta {}", delta.json_str()); // tracing::debug!( // "[GridBlockMeta] current delta: {}", // self.delta.to_str().unwrap_or_else(|_| "".to_string()) // ); self.delta = self.delta.compose(&delta)?; - Ok(Some(GridBlockMetaChange { delta, md5: self.md5() })) + Ok(Some(GridBlockRevisionChangeset { + delta, + md5: md5(&self.delta.json_bytes()), + })) } } } } } - fn modify_row(&mut self, row_id: &str, f: F) -> CollaborateResult> + fn modify_row(&mut self, row_id: &str, f: F) -> CollaborateResult> where F: FnOnce(&mut RowRevision) -> CollaborateResult>, { @@ -225,27 +233,23 @@ impl GridBlockRevisionPad { }) } - pub fn to_json(&self) -> CollaborateResult { - serde_json::to_string(&self.block_revision) - .map_err(|e| CollaborateError::internal().context(format!("serial trash to json failed: {}", e))) + pub fn revision_json(&self) -> CollaborateResult { + serde_json::to_string(&self.block) + .map_err(|e| CollaborateError::internal().context(format!("serial block to json failed: {}", e))) } - pub fn md5(&self) -> String { - md5(&self.delta.json_bytes()) - } - - pub fn delta_str(&self) -> String { + pub fn json_str(&self) -> String { self.delta.json_str() } } -pub struct GridBlockMetaChange { - pub delta: GridBlockRevisionDelta, +pub struct GridBlockRevisionChangeset { + pub delta: TextDelta, /// md5: the md5 of the grid after applying the change. pub md5: String, } -pub fn make_grid_block_delta(block_rev: &GridBlockRevision) -> GridBlockRevisionDelta { +pub fn make_grid_block_delta(block_rev: &GridBlockRevision) -> TextDelta { let json = serde_json::to_string(&block_rev).unwrap(); TextDeltaBuilder::new().insert(&json).build() } @@ -265,14 +269,18 @@ impl std::default::Default for GridBlockRevisionPad { }; let delta = make_grid_block_delta(&block_revision); - GridBlockRevisionPad { block_revision, delta } + GridBlockRevisionPad { + block: block_revision, + delta, + } } } #[cfg(test)] mod tests { - use crate::client_grid::{GridBlockRevisionDelta, GridBlockRevisionPad}; + use crate::client_grid::GridBlockRevisionPad; use flowy_grid_data_model::revision::{RowMetaChangeset, RowRevision}; + use lib_ot::core::TextDelta; use std::borrow::Cow; #[test] @@ -369,7 +377,7 @@ mod tests { #[test] fn block_meta_delete_row() { let mut pad = test_pad(); - let pre_delta_str = pad.delta_str(); + let pre_delta_str = pad.json_str(); let row = RowRevision { id: "1".to_string(), block_id: pad.block_id.clone(), @@ -382,7 +390,7 @@ mod tests { let change = pad.delete_rows(vec![Cow::Borrowed(&row.id)]).unwrap().unwrap(); assert_eq!(change.delta.json_str(), r#"[{"retain":24},{"delete":66},{"retain":2}]"#); - assert_eq!(pad.delta_str(), pre_delta_str); + assert_eq!(pad.json_str(), pre_delta_str); } #[test] @@ -412,13 +420,13 @@ mod tests { ); assert_eq!( - pad.to_json().unwrap(), + pad.revision_json().unwrap(), r#"{"block_id":"1","rows":[{"id":"1","block_id":"1","cells":[],"height":100,"visibility":true}]}"# ); } fn test_pad() -> GridBlockRevisionPad { - let delta = GridBlockRevisionDelta::from_json(r#"[{"insert":"{\"block_id\":\"1\",\"rows\":[]}"}]"#).unwrap(); + let delta = TextDelta::from_json(r#"[{"insert":"{\"block_id\":\"1\",\"rows\":[]}"}]"#).unwrap(); GridBlockRevisionPad::from_delta(delta).unwrap() } } diff --git a/shared-lib/flowy-sync/src/client_grid/grid_revision_pad.rs b/shared-lib/flowy-sync/src/client_grid/grid_revision_pad.rs index 8e04871c09..25a7de66a8 100644 --- a/shared-lib/flowy-sync/src/client_grid/grid_revision_pad.rs +++ b/shared-lib/flowy-sync/src/client_grid/grid_revision_pad.rs @@ -77,7 +77,7 @@ impl GridRevisionPad { &mut self, new_field_rev: FieldRevision, start_field_id: Option, - ) -> CollaborateResult> { + ) -> CollaborateResult> { self.modify_grid(|grid_meta| { // Check if the field exists or not if grid_meta @@ -102,7 +102,7 @@ impl GridRevisionPad { }) } - pub fn delete_field_rev(&mut self, field_id: &str) -> CollaborateResult> { + pub fn delete_field_rev(&mut self, field_id: &str) -> CollaborateResult> { self.modify_grid( |grid_meta| match grid_meta.fields.iter().position(|field| field.id == field_id) { None => Ok(None), @@ -118,7 +118,7 @@ impl GridRevisionPad { &mut self, field_id: &str, duplicated_field_id: &str, - ) -> CollaborateResult> { + ) -> CollaborateResult> { self.modify_grid( |grid_meta| match grid_meta.fields.iter().position(|field| field.id == field_id) { None => Ok(None), @@ -138,7 +138,7 @@ impl GridRevisionPad { field_id: &str, field_type: T, type_option_json_builder: B, - ) -> CollaborateResult> + ) -> CollaborateResult> where B: FnOnce(&FieldTypeRevision) -> String, T: Into, @@ -169,7 +169,7 @@ impl GridRevisionPad { &mut self, changeset: FieldChangesetParams, deserializer: T, - ) -> CollaborateResult> { + ) -> CollaborateResult> { let field_id = changeset.field_id.clone(); self.modify_field(&field_id, |field| { let mut is_changed = None; @@ -228,7 +228,10 @@ impl GridRevisionPad { .find(|(_, field)| field.id == field_id) } - pub fn replace_field_rev(&mut self, field_rev: Arc) -> CollaborateResult> { + pub fn replace_field_rev( + &mut self, + field_rev: Arc, + ) -> CollaborateResult> { self.modify_grid( |grid_meta| match grid_meta.fields.iter().position(|field| field.id == field_rev.id) { None => Ok(None), @@ -246,7 +249,7 @@ impl GridRevisionPad { field_id: &str, from_index: usize, to_index: usize, - ) -> CollaborateResult> { + ) -> CollaborateResult> { self.modify_grid(|grid_meta| { match move_vec_element( &mut grid_meta.fields, @@ -292,7 +295,10 @@ impl GridRevisionPad { } } - pub fn create_block_meta_rev(&mut self, block: GridBlockMetaRevision) -> CollaborateResult> { + pub fn create_block_meta_rev( + &mut self, + block: GridBlockMetaRevision, + ) -> CollaborateResult> { self.modify_grid(|grid_meta| { if grid_meta.blocks.iter().any(|b| b.block_id == block.block_id) { tracing::warn!("Duplicate grid block"); @@ -322,7 +328,7 @@ impl GridRevisionPad { pub fn update_block_rev( &mut self, changeset: GridBlockMetaRevisionChangeset, - ) -> CollaborateResult> { + ) -> CollaborateResult> { let block_id = changeset.block_id.clone(); self.modify_block(&block_id, |block| { let mut is_changed = None; @@ -372,7 +378,7 @@ impl GridRevisionPad { pub fn update_grid_setting_rev( &mut self, changeset: GridSettingChangesetParams, - ) -> CollaborateResult> { + ) -> CollaborateResult> { self.modify_grid(|grid_rev| { let mut is_changed = None; if let Some(params) = changeset.insert_filter { @@ -446,7 +452,7 @@ impl GridRevisionPad { &self.grid_rev.fields } - fn modify_grid(&mut self, f: F) -> CollaborateResult> + fn modify_grid(&mut self, f: F) -> CollaborateResult> where F: FnOnce(&mut GridRevision) -> CollaborateResult>, { @@ -460,14 +466,14 @@ impl GridRevisionPad { None => Ok(None), Some(delta) => { self.delta = self.delta.compose(&delta)?; - Ok(Some(GridChangeset { delta, md5: self.md5() })) + Ok(Some(GridRevisionChangeset { delta, md5: self.md5() })) } } } } } - fn modify_block(&mut self, block_id: &str, f: F) -> CollaborateResult> + fn modify_block(&mut self, block_id: &str, f: F) -> CollaborateResult> where F: FnOnce(&mut GridBlockMetaRevision) -> CollaborateResult>, { @@ -485,7 +491,7 @@ impl GridRevisionPad { ) } - fn modify_field(&mut self, field_id: &str, f: F) -> CollaborateResult> + fn modify_field(&mut self, field_id: &str, f: F) -> CollaborateResult> where F: FnOnce(&mut FieldRevision) -> CollaborateResult>, { @@ -508,13 +514,13 @@ impl GridRevisionPad { } } -pub fn make_grid_rev_json_str(grid: &GridRevision) -> CollaborateResult { - let json = serde_json::to_string(grid) +pub fn make_grid_rev_json_str(grid_revision: &GridRevision) -> CollaborateResult { + let json = serde_json::to_string(grid_revision) .map_err(|err| internal_error(format!("Serialize grid to json str failed. {:?}", err)))?; Ok(json) } -pub struct GridChangeset { +pub struct GridRevisionChangeset { pub delta: GridRevisionDelta, /// md5: the md5 of the grid after applying the change. pub md5: String, diff --git a/shared-lib/flowy-sync/src/client_grid/mod.rs b/shared-lib/flowy-sync/src/client_grid/mod.rs index e76ae0cefe..4a9a0374f5 100644 --- a/shared-lib/flowy-sync/src/client_grid/mod.rs +++ b/shared-lib/flowy-sync/src/client_grid/mod.rs @@ -1,7 +1,9 @@ -mod grid_block_revsion_pad; +mod block_revision_pad; mod grid_builder; mod grid_revision_pad; +mod view_revision_pad; -pub use grid_block_revsion_pad::*; +pub use block_revision_pad::*; pub use grid_builder::*; pub use grid_revision_pad::*; +pub use view_revision_pad::*; diff --git a/shared-lib/flowy-sync/src/client_grid/view_revision_pad.rs b/shared-lib/flowy-sync/src/client_grid/view_revision_pad.rs new file mode 100644 index 0000000000..25b539faf6 --- /dev/null +++ b/shared-lib/flowy-sync/src/client_grid/view_revision_pad.rs @@ -0,0 +1,173 @@ +use crate::entities::revision::{md5, Revision}; +use crate::errors::{internal_error, CollaborateError, CollaborateResult}; +use crate::util::{cal_diff, make_delta_from_revisions, make_text_delta_from_revisions}; +use flowy_grid_data_model::revision::{ + FieldRevision, FieldTypeRevision, FilterConfigurationRevision, FilterConfigurationsByFieldId, GridViewRevision, + GroupConfigurationRevision, GroupConfigurationsByFieldId, SortConfigurationsByFieldId, +}; +use lib_ot::core::{OperationTransform, PhantomAttributes, TextDelta, TextDeltaBuilder}; +use std::sync::Arc; + +#[derive(Debug, Clone)] +pub struct GridViewRevisionPad { + view: Arc, + delta: TextDelta, +} + +impl std::ops::Deref for GridViewRevisionPad { + type Target = GridViewRevision; + + fn deref(&self) -> &Self::Target { + &self.view + } +} + +impl GridViewRevisionPad { + pub fn new(grid_id: String) -> Self { + let view = Arc::new(GridViewRevision::new(grid_id)); + let json = serde_json::to_string(&view).unwrap(); + let delta = TextDeltaBuilder::new().insert(&json).build(); + Self { view, delta } + } + + pub fn from_delta(delta: TextDelta) -> CollaborateResult { + let s = delta.content()?; + let view: GridViewRevision = serde_json::from_str(&s).map_err(|e| { + let msg = format!("Deserialize delta to GridViewRevision failed: {}", e); + tracing::error!("{}", s); + CollaborateError::internal().context(msg) + })?; + Ok(Self { + view: Arc::new(view), + delta, + }) + } + + pub fn from_revisions(_grid_id: &str, revisions: Vec) -> CollaborateResult { + let delta: TextDelta = make_text_delta_from_revisions(revisions)?; + Self::from_delta(delta) + } + + pub fn get_all_groups(&self, field_revs: &[Arc]) -> Option { + self.setting.groups.get_all_objects(field_revs) + } + + pub fn get_groups( + &self, + field_id: &str, + field_type_rev: &FieldTypeRevision, + ) -> Option>> { + self.setting.groups.get_objects(field_id, field_type_rev) + } + + pub fn insert_group( + &mut self, + field_id: &str, + field_type: &FieldTypeRevision, + group_rev: GroupConfigurationRevision, + ) -> CollaborateResult> { + self.modify(|view| { + // only one group can be set + view.setting.groups.remove_all(); + view.setting.groups.insert_object(field_id, field_type, group_rev); + Ok(Some(())) + }) + } + + pub fn delete_group( + &mut self, + field_id: &str, + field_type: &FieldTypeRevision, + group_id: &str, + ) -> CollaborateResult> { + self.modify(|view| { + if let Some(groups) = view.setting.groups.get_mut_objects(field_id, field_type) { + groups.retain(|group| group.id != group_id); + Ok(Some(())) + } else { + Ok(None) + } + }) + } + + pub fn get_all_filters(&self, field_revs: &[Arc]) -> Option { + self.setting.filters.get_all_objects(field_revs) + } + + pub fn get_filters( + &self, + field_id: &str, + field_type_rev: &FieldTypeRevision, + ) -> Option>> { + self.setting.filters.get_objects(field_id, field_type_rev) + } + + pub fn insert_filter( + &mut self, + field_id: &str, + field_type: &FieldTypeRevision, + filter_rev: FilterConfigurationRevision, + ) -> CollaborateResult> { + self.modify(|view| { + view.setting.filters.insert_object(field_id, field_type, filter_rev); + Ok(Some(())) + }) + } + + pub fn delete_filter( + &mut self, + field_id: &str, + field_type: &FieldTypeRevision, + filter_id: &str, + ) -> CollaborateResult> { + self.modify(|view| { + if let Some(filters) = view.setting.filters.get_mut_objects(field_id, field_type) { + filters.retain(|filter| filter.id != filter_id); + Ok(Some(())) + } else { + Ok(None) + } + }) + } + + pub fn get_all_sort(&self) -> Option { + None + } + + pub fn json_str(&self) -> CollaborateResult { + make_grid_view_rev_json_str(&self.view) + } + + fn modify(&mut self, f: F) -> CollaborateResult> + where + F: FnOnce(&mut GridViewRevision) -> CollaborateResult>, + { + let cloned_view = self.view.clone(); + match f(Arc::make_mut(&mut self.view))? { + None => Ok(None), + Some(_) => { + let old = make_grid_view_rev_json_str(&cloned_view)?; + let new = self.json_str()?; + match cal_diff::(old, new) { + None => Ok(None), + Some(delta) => { + self.delta = self.delta.compose(&delta)?; + let md5 = md5(&self.delta.json_bytes()); + Ok(Some(GridViewRevisionChangeset { delta, md5 })) + } + } + } + } + } +} + +pub struct GridViewRevisionChangeset { + pub delta: TextDelta, + pub md5: String, +} + +pub fn make_grid_view_rev_json_str(grid_revision: &GridViewRevision) -> CollaborateResult { + let json = serde_json::to_string(grid_revision) + .map_err(|err| internal_error(format!("Serialize grid view to json str failed. {:?}", err)))?; + Ok(json) +} diff --git a/shared-lib/flowy-sync/src/util.rs b/shared-lib/flowy-sync/src/util.rs index 7dd5c4af5c..d968d74796 100644 --- a/shared-lib/flowy-sync/src/util.rs +++ b/shared-lib/flowy-sync/src/util.rs @@ -7,7 +7,7 @@ use crate::{ errors::{CollaborateError, CollaborateResult}, }; use dissimilar::Chunk; -use lib_ot::core::{DeltaBuilder, OTString}; +use lib_ot::core::{DeltaBuilder, OTString, PhantomAttributes, TextDelta}; use lib_ot::{ core::{Attributes, Delta, OperationTransform, NEW_LINE, WHITESPACE}, rich_text::RichTextDelta, @@ -81,6 +81,10 @@ where Ok(delta) } +pub fn make_text_delta_from_revisions(revisions: Vec) -> CollaborateResult { + make_delta_from_revisions::(revisions) +} + pub fn make_delta_from_revision_pb(revisions: Vec) -> CollaborateResult> where T: Attributes + DeserializeOwned, diff --git a/shared-lib/lib-ot/src/core/delta/delta.rs b/shared-lib/lib-ot/src/core/delta/delta.rs index b422205a90..a95fd7c236 100644 --- a/shared-lib/lib-ot/src/core/delta/delta.rs +++ b/shared-lib/lib-ot/src/core/delta/delta.rs @@ -604,7 +604,7 @@ where serde_json::to_string(self).unwrap_or_else(|_| "".to_owned()) } - /// Get the content the [Delta] represents. + /// Get the content that the [Delta] represents. pub fn content(&self) -> Result { self.apply("") }