Browse Source

Merge pull request #1150 from AppFlowy-IO/fix/1135_1

Fix/1135 issue 1
Nathan.fooo 2 years ago
parent
commit
6fa79b65f6

+ 1 - 1
frontend/rust-lib/flowy-folder/src/manager.rs

@@ -260,7 +260,7 @@ pub trait ViewDataProcessor {
 
     fn close_container(&self, view_id: &str) -> FutureResult<(), FlowyError>;
 
-    fn get_delta_data(&self, view_id: &str) -> FutureResult<Bytes, FlowyError>;
+    fn get_view_data(&self, view_id: &str) -> FutureResult<Bytes, FlowyError>;
 
     fn create_default_view(
         &self,

+ 4 - 2
frontend/rust-lib/flowy-folder/src/services/view/controller.rs

@@ -61,11 +61,13 @@ impl ViewController {
         let processor = self.get_data_processor(params.data_type.clone())?;
         let user_id = self.user.user_id()?;
         if params.view_content_data.is_empty() {
+            tracing::trace!("Create view with build-in data");
             let view_data = processor
                 .create_default_view(&user_id, &params.view_id, params.layout.clone())
                 .await?;
             params.view_content_data = view_data.to_vec();
         } else {
+            tracing::trace!("Create view with view data");
             let delta_data = processor
                 .create_view_from_delta_data(
                     &user_id,
@@ -231,7 +233,7 @@ impl ViewController {
             .await?;
 
         let processor = self.get_data_processor(view_rev.data_type.clone())?;
-        let delta_bytes = processor.get_delta_data(view_id).await?;
+        let view_data = processor.get_view_data(view_id).await?;
         let duplicate_params = CreateViewParams {
             belong_to_id: view_rev.app_id.clone(),
             name: format!("{} (copy)", &view_rev.name),
@@ -239,7 +241,7 @@ impl ViewController {
             thumbnail: view_rev.thumbnail,
             data_type: view_rev.data_type.into(),
             layout: view_rev.layout.into(),
-            view_content_data: delta_bytes.to_vec(),
+            view_content_data: view_data.to_vec(),
             view_id: gen_view_id(),
         };
 

+ 0 - 5
frontend/rust-lib/flowy-grid/src/dart_notification.rs

@@ -33,8 +33,3 @@ impl std::convert::From<GridNotification> for i32 {
 pub fn send_dart_notification(id: &str, ty: GridNotification) -> DartNotifyBuilder {
     DartNotifyBuilder::new(id, ty, OBSERVABLE_CATEGORY)
 }
-
-#[tracing::instrument(level = "trace")]
-pub fn send_anonymous_dart_notification(ty: GridNotification) -> DartNotifyBuilder {
-    DartNotifyBuilder::new("", ty, OBSERVABLE_CATEGORY)
-}

+ 14 - 3
frontend/rust-lib/flowy-grid/src/manager.rs

@@ -183,7 +183,14 @@ pub async fn make_grid_view_data(
     grid_manager: Arc<GridManager>,
     build_context: BuildGridContext,
 ) -> FlowyResult<Bytes> {
-    for block_meta_data in &build_context.blocks {
+    let BuildGridContext {
+        field_revs,
+        block_metas,
+        blocks,
+        grid_view_revision_data,
+    } = build_context;
+
+    for block_meta_data in &blocks {
         let block_id = &block_meta_data.block_id;
         // Indexing the block's rows
         block_meta_data.rows.iter().for_each(|row| {
@@ -200,7 +207,7 @@ pub async fn make_grid_view_data(
 
     // Will replace the grid_id with the value returned by the gen_grid_id()
     let grid_id = view_id.to_owned();
-    let grid_rev = GridRevision::from_build_context(&grid_id, build_context);
+    let grid_rev = GridRevision::from_build_context(&grid_id, field_revs, block_metas);
 
     // Create grid
     let grid_rev_delta = make_grid_delta(&grid_rev);
@@ -210,7 +217,11 @@ pub async fn make_grid_view_data(
     let _ = grid_manager.create_grid(&grid_id, repeated_revision).await?;
 
     // Create grid view
-    let grid_view = GridViewRevision::new(grid_id, view_id.to_owned(), layout.into());
+    let grid_view = if grid_view_revision_data.is_empty() {
+        GridViewRevision::new(grid_id, view_id.to_owned(), layout.into())
+    } else {
+        GridViewRevision::from_json(grid_view_revision_data)?
+    };
     let grid_view_delta = make_grid_view_delta(&grid_view);
     let grid_view_delta_bytes = grid_view_delta.json_bytes();
     let repeated_revision: RepeatedRevision =

+ 4 - 1
frontend/rust-lib/flowy-grid/src/services/cell/any_cell_data.rs

@@ -19,7 +19,10 @@ impl std::str::FromStr for AnyCellData {
     type Err = FlowyError;
 
     fn from_str(s: &str) -> Result<Self, Self::Err> {
-        let type_option_cell_data: AnyCellData = serde_json::from_str(s)?;
+        let type_option_cell_data: AnyCellData = serde_json::from_str(s).map_err(|err| {
+            let msg = format!("Deserialize {} to any cell data failed. Serde error: {}", s, err);
+            FlowyError::internal().context(msg)
+        })?;
         Ok(type_option_cell_data)
     }
 }

+ 23 - 12
frontend/rust-lib/flowy-grid/src/services/cell/cell_operation.rs

@@ -1,6 +1,7 @@
 use crate::entities::FieldType;
 use crate::services::cell::{AnyCellData, CellBytes};
 use crate::services::field::*;
+use std::fmt::Debug;
 
 use flowy_error::{ErrorCode, FlowyError, FlowyResult};
 use flowy_grid_data_model::revision::{CellRevision, FieldRevision, FieldTypeRevision};
@@ -73,20 +74,30 @@ pub fn apply_cell_data_changeset<C: ToString, T: AsRef<FieldRevision>>(
     Ok(AnyCellData::new(s, field_type).json())
 }
 
-pub fn decode_any_cell_data<T: TryInto<AnyCellData>>(data: T, field_rev: &FieldRevision) -> CellBytes {
-    if let Ok(any_cell_data) = data.try_into() {
-        let AnyCellData { data, field_type } = any_cell_data;
-        let to_field_type = field_rev.ty.into();
-        match try_decode_cell_data(data.into(), field_rev, &field_type, &to_field_type) {
-            Ok(cell_bytes) => cell_bytes,
-            Err(e) => {
-                tracing::error!("Decode cell data failed, {:?}", e);
-                CellBytes::default()
+pub fn decode_any_cell_data<T: TryInto<AnyCellData, Error = FlowyError> + Debug>(
+    data: T,
+    field_rev: &FieldRevision,
+) -> CellBytes {
+    match data.try_into() {
+        Ok(any_cell_data) => {
+            let AnyCellData { data, field_type } = any_cell_data;
+            let to_field_type = field_rev.ty.into();
+            match try_decode_cell_data(data.into(), field_rev, &field_type, &to_field_type) {
+                Ok(cell_bytes) => cell_bytes,
+                Err(e) => {
+                    tracing::error!("Decode cell data failed, {:?}", e);
+                    CellBytes::default()
+                }
             }
         }
-    } else {
-        tracing::error!("Decode type option data failed");
-        CellBytes::default()
+        Err(err) => {
+            tracing::error!(
+                "Decode type option data to type: {} failed: {:?}",
+                std::any::type_name::<T>(),
+                err,
+            );
+            CellBytes::default()
+        }
     }
 }
 

+ 2 - 0
frontend/rust-lib/flowy-grid/src/services/grid_editor.rs

@@ -673,6 +673,7 @@ impl GridRevisionEditor {
 
     pub async fn duplicate_grid(&self) -> FlowyResult<BuildGridContext> {
         let grid_pad = self.grid_pad.read().await;
+        let grid_view_revision_data = self.view_manager.duplicate_grid_view().await?;
         let original_blocks = grid_pad.get_block_meta_revs();
         let (duplicated_fields, duplicated_blocks) = grid_pad.duplicate_grid_block_meta().await;
 
@@ -698,6 +699,7 @@ impl GridRevisionEditor {
             field_revs: duplicated_fields.into_iter().map(Arc::new).collect(),
             block_metas: duplicated_blocks,
             blocks: blocks_meta_data,
+            grid_view_revision_data,
         })
     }
 

+ 5 - 0
frontend/rust-lib/flowy-grid/src/services/grid_view_editor.rs

@@ -74,6 +74,11 @@ impl GridViewRevisionEditor {
         })
     }
 
+    pub(crate) async fn duplicate_view_data(&self) -> FlowyResult<String> {
+        let json_str = self.pad.read().await.json_str()?;
+        Ok(json_str)
+    }
+
     pub(crate) async fn will_create_row(&self, row_rev: &mut RowRevision, params: &CreateRowParams) {
         if params.group_id.is_none() {
             return;

+ 6 - 0
frontend/rust-lib/flowy-grid/src/services/grid_view_manager.rs

@@ -56,6 +56,12 @@ impl GridViewManager {
         })
     }
 
+    pub(crate) async fn duplicate_grid_view(&self) -> FlowyResult<String> {
+        let editor = self.get_default_view_editor().await?;
+        let view_data = editor.duplicate_view_data().await?;
+        Ok(view_data)
+    }
+
     /// When the row was created, we may need to modify the [RowRevision] according to the [CreateRowParams].
     pub(crate) async fn will_create_row(&self, row_rev: &mut RowRevision, params: &CreateRowParams) {
         for view_editor in self.view_editors.iter() {

+ 1 - 0
frontend/rust-lib/flowy-grid/src/services/group/action.rs

@@ -14,5 +14,6 @@ pub trait GroupAction: Send + Sync {
     fn can_group(&self, content: &str, cell_data: &Self::CellDataType) -> bool;
     fn add_row_if_match(&mut self, row_rev: &RowRevision, cell_data: &Self::CellDataType) -> Vec<GroupChangesetPB>;
     fn remove_row_if_match(&mut self, row_rev: &RowRevision, cell_data: &Self::CellDataType) -> Vec<GroupChangesetPB>;
+    // Move row from one group to another
     fn move_row(&mut self, cell_data: &Self::CellDataType, context: MoveGroupRowContext) -> Vec<GroupChangesetPB>;
 }

+ 10 - 4
frontend/rust-lib/flowy-grid/src/services/group/controller.rs

@@ -86,8 +86,7 @@ where
     G: GroupGenerator<Context = GroupContext<C>, TypeOptionType = T>,
 {
     pub async fn new(field_rev: &Arc<FieldRevision>, mut configuration: GroupContext<C>) -> FlowyResult<Self> {
-        let field_type_rev = field_rev.ty;
-        let type_option = field_rev.get_type_option::<T>(field_type_rev);
+        let type_option = field_rev.get_type_option::<T>(field_rev.ty);
         let groups = G::generate_groups(&field_rev.id, &configuration, &type_option);
         let _ = configuration.init_groups(groups, true)?;
 
@@ -278,12 +277,19 @@ where
         }
     }
 
+    #[tracing::instrument(level = "trace", skip_all, err)]
     fn move_group_row(&mut self, context: MoveGroupRowContext) -> FlowyResult<Vec<GroupChangesetPB>> {
-        if let Some(cell_rev) = context.row_rev.cells.get(&self.field_id) {
-            let cell_bytes = decode_any_cell_data(cell_rev.data.clone(), context.field_rev);
+        let cell_rev = match context.row_rev.cells.get(&self.field_id) {
+            Some(cell_rev) => Some(cell_rev.clone()),
+            None => self.default_cell_rev(),
+        };
+
+        if let Some(cell_rev) = cell_rev {
+            let cell_bytes = decode_any_cell_data(cell_rev.data, context.field_rev);
             let cell_data = cell_bytes.parser::<P>()?;
             Ok(self.move_row(&cell_data, context))
         } else {
+            tracing::warn!("Unexpected moving group row, changes should not be empty");
             Ok(vec![])
         }
     }

+ 38 - 10
frontend/rust-lib/flowy-grid/src/services/group/controller_impls/select_option_controller/util.rs

@@ -1,11 +1,12 @@
-use crate::entities::{GroupChangesetPB, InsertedRowPB, RowPB};
-use crate::services::cell::insert_select_option_cell;
-use crate::services::field::{SelectOptionCellDataPB, SelectOptionPB};
+use crate::entities::{FieldType, GroupChangesetPB, InsertedRowPB, RowPB};
+use crate::services::cell::{insert_checkbox_cell, insert_select_option_cell};
+use crate::services::field::{SelectOptionCellDataPB, SelectOptionPB, CHECK};
 use crate::services::group::configuration::GroupContext;
-use crate::services::group::{GeneratedGroup, Group};
-
 use crate::services::group::controller::MoveGroupRowContext;
-use flowy_grid_data_model::revision::{GroupRevision, RowRevision, SelectOptionGroupConfigurationRevision};
+use crate::services::group::{GeneratedGroup, Group};
+use flowy_grid_data_model::revision::{
+    CellRevision, FieldRevision, GroupRevision, RowRevision, SelectOptionGroupConfigurationRevision,
+};
 
 pub type SelectOptionGroupContext = GroupContext<SelectOptionGroupConfigurationRevision>;
 
@@ -109,10 +110,16 @@ pub fn move_group_row(group: &mut Group, context: &mut MoveGroupRowContext) -> O
 
         // Update the corresponding row's cell content.
         if from_index.is_none() {
-            tracing::debug!("Mark row:{} belong to group:{}", row_rev.id, group.id);
-            let cell_rev = insert_select_option_cell(group.id.clone(), field_rev);
-            row_changeset.cell_by_field_id.insert(field_rev.id.clone(), cell_rev);
-            changeset.updated_rows.push(RowPB::from(*row_rev));
+            let cell_rev = make_inserted_cell_rev(&group.id, field_rev);
+            if let Some(cell_rev) = cell_rev {
+                tracing::debug!(
+                    "Update content of the cell in the row:{} to group:{}",
+                    row_rev.id,
+                    group.id
+                );
+                row_changeset.cell_by_field_id.insert(field_rev.id.clone(), cell_rev);
+                changeset.updated_rows.push(RowPB::from(*row_rev));
+            }
         }
     }
     if changeset.is_empty() {
@@ -122,6 +129,27 @@ pub fn move_group_row(group: &mut Group, context: &mut MoveGroupRowContext) -> O
     }
 }
 
+pub fn make_inserted_cell_rev(group_id: &str, field_rev: &FieldRevision) -> Option<CellRevision> {
+    let field_type: FieldType = field_rev.ty.into();
+    match field_type {
+        FieldType::SingleSelect => {
+            let cell_rev = insert_select_option_cell(group_id.to_owned(), field_rev);
+            Some(cell_rev)
+        }
+        FieldType::MultiSelect => {
+            let cell_rev = insert_select_option_cell(group_id.to_owned(), field_rev);
+            Some(cell_rev)
+        }
+        FieldType::Checkbox => {
+            let cell_rev = insert_checkbox_cell(group_id == CHECK, field_rev);
+            Some(cell_rev)
+        }
+        _ => {
+            tracing::warn!("Unknown field type: {:?}", field_type);
+            None
+        }
+    }
+}
 pub fn generate_select_option_groups(
     _field_id: &str,
     _group_ctx: &SelectOptionGroupContext,

+ 2 - 2
frontend/rust-lib/flowy-sdk/src/deps_resolve/folder_deps.rs

@@ -170,7 +170,7 @@ impl ViewDataProcessor for TextBlockViewDataProcessor {
         })
     }
 
-    fn get_delta_data(&self, view_id: &str) -> FutureResult<Bytes, FlowyError> {
+    fn get_view_data(&self, view_id: &str) -> FutureResult<Bytes, FlowyError> {
         let view_id = view_id.to_string();
         let manager = self.0.clone();
         FutureResult::new(async move {
@@ -247,7 +247,7 @@ impl ViewDataProcessor for GridViewDataProcessor {
         })
     }
 
-    fn get_delta_data(&self, view_id: &str) -> FutureResult<Bytes, FlowyError> {
+    fn get_view_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 {

+ 10 - 3
shared-lib/flowy-grid-data-model/src/revision/grid_rev.rs

@@ -34,11 +34,15 @@ impl GridRevision {
         }
     }
 
-    pub fn from_build_context(grid_id: &str, context: BuildGridContext) -> Self {
+    pub fn from_build_context(
+        grid_id: &str,
+        field_revs: Vec<Arc<FieldRevision>>,
+        block_metas: Vec<GridBlockMetaRevision>,
+    ) -> Self {
         Self {
             grid_id: grid_id.to_owned(),
-            fields: context.field_revs,
-            blocks: context.block_metas.into_iter().map(Arc::new).collect(),
+            fields: field_revs,
+            blocks: block_metas.into_iter().map(Arc::new).collect(),
         }
     }
 }
@@ -188,6 +192,9 @@ pub struct BuildGridContext {
     pub field_revs: Vec<Arc<FieldRevision>>,
     pub block_metas: Vec<GridBlockMetaRevision>,
     pub blocks: Vec<GridBlockRevision>,
+
+    // String in JSON format. It can be deserialized into [GridViewRevision]
+    pub grid_view_revision_data: String,
 }
 
 impl BuildGridContext {

+ 4 - 0
shared-lib/flowy-grid-data-model/src/revision/grid_view.rs

@@ -58,6 +58,10 @@ impl GridViewRevision {
             // row_orders: vec![],
         }
     }
+
+    pub fn from_json(json: String) -> Result<Self, serde_json::Error> {
+        serde_json::from_str(&json)
+    }
 }
 
 #[derive(Debug, Clone, Default, Serialize, Deserialize)]