Explorar o código

refactor: add folder entities's revision objects

appflowy %!s(int64=2) %!d(string=hai) anos
pai
achega
c2fad5021b

+ 8 - 5
frontend/rust-lib/flowy-folder/tests/workspace/folder_test.rs

@@ -1,7 +1,7 @@
 use crate::script::{invalid_workspace_name_test_case, FolderScript::*, FolderTest};
-
 use flowy_folder::entities::workspace::CreateWorkspacePayload;
 use flowy_folder_data_model::entities::view::ViewDataType;
+use flowy_folder_data_model::revision::{AppRevision, WorkspaceRevision};
 use flowy_revision::disk::RevisionState;
 use flowy_test::{event_builder::*, FlowySDKTest};
 
@@ -38,11 +38,12 @@ async fn workspace_create() {
 async fn workspace_read() {
     let mut test = FolderTest::new().await;
     let workspace = test.workspace.clone();
-    let json = serde_json::to_string(&workspace).unwrap();
+    let workspace_revision: WorkspaceRevision = workspace.clone().into();
+    let json = serde_json::to_string(&workspace_revision).unwrap();
 
     test.run_scripts(vec![
         ReadWorkspace(Some(workspace.id.clone())),
-        AssertWorkspaceJson(json),
+        AssertWorkspaceRevisionJson(json),
         AssertWorkspace(workspace),
     ])
     .await;
@@ -58,8 +59,10 @@ async fn workspace_create_with_apps() {
     .await;
 
     let app = test.app.clone();
-    let json = serde_json::to_string(&app).unwrap();
-    test.run_scripts(vec![ReadApp(app.id), AssertAppJson(json)]).await;
+    let app_revision: AppRevision = app.clone().into();
+    let json = serde_json::to_string(&app_revision).unwrap();
+    test.run_scripts(vec![ReadApp(app.id), AssertAppRevisionJson(json)])
+        .await;
 }
 
 #[tokio::test]

+ 9 - 6
frontend/rust-lib/flowy-folder/tests/workspace/script.rs

@@ -14,6 +14,7 @@ use flowy_folder_data_model::entities::{
     view::{CreateViewPayload, UpdateViewPayload},
     workspace::{CreateWorkspacePayload, RepeatedWorkspace},
 };
+use flowy_folder_data_model::revision::{AppRevision, WorkspaceRevision};
 use flowy_revision::disk::RevisionState;
 use flowy_revision::REVISION_WRITE_INTERVAL_IN_MILLIS;
 use flowy_sync::entities::text_block_info::TextBlockInfo;
@@ -28,7 +29,7 @@ pub enum FolderScript {
         name: String,
         desc: String,
     },
-    AssertWorkspaceJson(String),
+    AssertWorkspaceRevisionJson(String),
     AssertWorkspace(Workspace),
     ReadWorkspace(Option<String>),
 
@@ -37,7 +38,7 @@ pub enum FolderScript {
         name: String,
         desc: String,
     },
-    AssertAppJson(String),
+    AssertAppRevisionJson(String),
     AssertApp(App),
     ReadApp(String),
     UpdateApp {
@@ -138,12 +139,13 @@ impl FolderTest {
                 let workspace = create_workspace(sdk, &name, &desc).await;
                 self.workspace = workspace;
             }
-            FolderScript::AssertWorkspaceJson(expected_json) => {
+            FolderScript::AssertWorkspaceRevisionJson(expected_json) => {
                 let workspace = read_workspace(sdk, Some(self.workspace.id.clone()))
                     .await
                     .pop()
                     .unwrap();
-                let json = serde_json::to_string(&workspace).unwrap();
+                let workspace_revision: WorkspaceRevision = workspace.into();
+                let json = serde_json::to_string(&workspace_revision).unwrap();
                 assert_eq!(json, expected_json);
             }
             FolderScript::AssertWorkspace(workspace) => {
@@ -157,8 +159,9 @@ impl FolderTest {
                 let app = create_app(sdk, &self.workspace.id, &name, &desc).await;
                 self.app = app;
             }
-            FolderScript::AssertAppJson(expected_json) => {
-                let json = serde_json::to_string(&self.app).unwrap();
+            FolderScript::AssertAppRevisionJson(expected_json) => {
+                let app_revision: AppRevision = self.app.clone().into();
+                let json = serde_json::to_string(&app_revision).unwrap();
                 assert_eq!(json, expected_json);
             }
             FolderScript::AssertApp(app) => {

+ 1 - 43
shared-lib/flowy-folder-data-model/src/entities/app.rs

@@ -1,4 +1,3 @@
-use crate::entities::view::ViewSerde;
 use crate::{
     entities::view::RepeatedView,
     errors::ErrorCode,
@@ -10,7 +9,7 @@ use crate::{
 };
 use flowy_derive::ProtoBuf;
 use nanoid::nanoid;
-use serde::{Deserialize, Serialize};
+
 use std::convert::TryInto;
 
 pub fn gen_app_id() -> String {
@@ -43,40 +42,6 @@ pub struct App {
     pub create_time: i64,
 }
 
-#[derive(Serialize, Deserialize)]
-pub struct AppSerde {
-    pub id: String,
-
-    pub workspace_id: String,
-
-    pub name: String,
-
-    pub desc: String,
-
-    pub belongings: Vec<ViewSerde>,
-
-    pub version: i64,
-
-    pub modified_time: i64,
-
-    pub create_time: i64,
-}
-
-impl std::convert::From<AppSerde> for App {
-    fn from(app_serde: AppSerde) -> Self {
-        App {
-            id: app_serde.id,
-            workspace_id: app_serde.workspace_id,
-            name: app_serde.name,
-            desc: app_serde.desc,
-            belongings: app_serde.belongings.into(),
-            version: app_serde.version,
-            modified_time: app_serde.modified_time,
-            create_time: app_serde.create_time,
-        }
-    }
-}
-
 #[derive(Eq, PartialEq, Debug, Default, ProtoBuf, Clone)]
 pub struct RepeatedApp {
     #[pb(index = 1)]
@@ -85,13 +50,6 @@ pub struct RepeatedApp {
 
 impl_def_and_def_mut!(RepeatedApp, App);
 
-impl std::convert::From<Vec<AppSerde>> for RepeatedApp {
-    fn from(values: Vec<AppSerde>) -> Self {
-        let items = values.into_iter().map(|value| value.into()).collect::<Vec<App>>();
-        RepeatedApp { items }
-    }
-}
-
 #[derive(ProtoBuf, Default)]
 pub struct CreateAppPayload {
     #[pb(index = 1)]

+ 5 - 0
shared-lib/flowy-folder-data-model/src/entities/mod.rs

@@ -2,3 +2,8 @@ pub mod app;
 pub mod trash;
 pub mod view;
 pub mod workspace;
+
+pub use app::*;
+pub use trash::*;
+pub use view::*;
+pub use workspace::*;

+ 0 - 25
shared-lib/flowy-folder-data-model/src/entities/trash.rs

@@ -21,31 +21,6 @@ pub struct Trash {
     pub ty: TrashType,
 }
 
-#[derive(Serialize, Deserialize)]
-pub struct TrashSerde {
-    pub id: String,
-
-    pub name: String,
-
-    pub modified_time: i64,
-
-    pub create_time: i64,
-
-    pub ty: TrashType,
-}
-
-impl std::convert::From<TrashSerde> for Trash {
-    fn from(trash_serde: TrashSerde) -> Self {
-        Trash {
-            id: trash_serde.id,
-            name: trash_serde.name,
-            modified_time: trash_serde.modified_time,
-            create_time: trash_serde.create_time,
-            ty: trash_serde.ty,
-        }
-    }
-}
-
 #[derive(PartialEq, Debug, Default, ProtoBuf, Clone)]
 pub struct RepeatedTrash {
     #[pb(index = 1)]

+ 1 - 62
shared-lib/flowy-folder-data-model/src/entities/view.rs

@@ -9,7 +9,7 @@ use crate::{
 };
 use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
 use nanoid::nanoid;
-use serde::{Deserialize, Serialize};
+
 use serde_repr::*;
 use std::convert::TryInto;
 
@@ -56,60 +56,6 @@ pub struct View {
     pub plugin_type: i32,
 }
 
-#[derive(Serialize, Deserialize)]
-pub struct ViewSerde {
-    pub id: String,
-
-    pub belong_to_id: String,
-
-    pub name: String,
-
-    pub desc: String,
-
-    #[serde(default)]
-    pub data_type: ViewDataType,
-
-    pub version: i64,
-
-    pub belongings: Vec<ViewSerde>,
-
-    pub modified_time: i64,
-
-    pub create_time: i64,
-
-    #[serde(default)]
-    pub ext_data: String,
-
-    #[serde(default)]
-    pub thumbnail: String,
-
-    #[serde(default = "default_plugin_type")]
-    pub plugin_type: i32,
-}
-
-fn default_plugin_type() -> i32 {
-    0
-}
-
-impl std::convert::From<ViewSerde> for View {
-    fn from(view_serde: ViewSerde) -> Self {
-        View {
-            id: view_serde.id,
-            belong_to_id: view_serde.belong_to_id,
-            name: view_serde.name,
-            desc: view_serde.desc,
-            data_type: view_serde.data_type,
-            version: view_serde.version,
-            belongings: view_serde.belongings.into(),
-            modified_time: view_serde.modified_time,
-            create_time: view_serde.create_time,
-            ext_data: view_serde.ext_data,
-            thumbnail: view_serde.thumbnail,
-            plugin_type: view_serde.plugin_type,
-        }
-    }
-}
-
 #[derive(Eq, PartialEq, Debug, Default, ProtoBuf, Clone)]
 // #[serde(transparent)]
 pub struct RepeatedView {
@@ -119,13 +65,6 @@ pub struct RepeatedView {
 
 impl_def_and_def_mut!(RepeatedView, View);
 
-impl std::convert::From<Vec<ViewSerde>> for RepeatedView {
-    fn from(values: Vec<ViewSerde>) -> Self {
-        let items = values.into_iter().map(|value| value.into()).collect::<Vec<View>>();
-        RepeatedView { items }
-    }
-}
-
 impl std::convert::From<View> for Trash {
     fn from(view: View) -> Self {
         Trash {

+ 1 - 30
shared-lib/flowy-folder-data-model/src/entities/workspace.rs

@@ -1,4 +1,3 @@
-use crate::entities::app::AppSerde;
 use crate::{
     entities::{app::RepeatedApp, view::View},
     errors::*,
@@ -7,7 +6,7 @@ use crate::{
 };
 use flowy_derive::ProtoBuf;
 use nanoid::nanoid;
-use serde::{Deserialize, Serialize};
+
 use std::convert::TryInto;
 
 pub fn gen_workspace_id() -> String {
@@ -34,34 +33,6 @@ pub struct Workspace {
     pub create_time: i64,
 }
 
-#[derive(Serialize, Deserialize)]
-pub struct WorkspaceSerde {
-    pub id: String,
-
-    pub name: String,
-
-    pub desc: String,
-
-    pub apps: Vec<AppSerde>,
-
-    pub modified_time: i64,
-
-    pub create_time: i64,
-}
-
-impl std::convert::From<WorkspaceSerde> for Workspace {
-    fn from(workspace_serde: WorkspaceSerde) -> Self {
-        Workspace {
-            id: workspace_serde.id,
-            name: workspace_serde.name,
-            desc: workspace_serde.desc,
-            apps: workspace_serde.apps.into(),
-            modified_time: workspace_serde.modified_time,
-            create_time: workspace_serde.create_time,
-        }
-    }
-}
-
 #[derive(PartialEq, Debug, Default, ProtoBuf)]
 pub struct RepeatedWorkspace {
     #[pb(index = 1)]

+ 1 - 0
shared-lib/flowy-folder-data-model/src/lib.rs

@@ -6,6 +6,7 @@ mod macros;
 
 // #[cfg(feature = "backend")]
 pub mod protobuf;
+pub mod revision;
 pub mod user_default;
 
 pub mod errors {

+ 70 - 0
shared-lib/flowy-folder-data-model/src/revision/app.rs

@@ -0,0 +1,70 @@
+use crate::entities::app::App;
+use crate::entities::RepeatedApp;
+use crate::revision::ViewRevision;
+use serde::{Deserialize, Serialize};
+
+#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
+pub struct AppRevision {
+    pub id: String,
+
+    pub workspace_id: String,
+
+    pub name: String,
+
+    pub desc: String,
+
+    pub belongings: Vec<ViewRevision>,
+
+    pub version: i64,
+
+    pub modified_time: i64,
+
+    pub create_time: i64,
+}
+
+impl std::convert::From<AppRevision> for App {
+    fn from(app_serde: AppRevision) -> Self {
+        App {
+            id: app_serde.id,
+            workspace_id: app_serde.workspace_id,
+            name: app_serde.name,
+            desc: app_serde.desc,
+            belongings: app_serde.belongings.into(),
+            version: app_serde.version,
+            modified_time: app_serde.modified_time,
+            create_time: app_serde.create_time,
+        }
+    }
+}
+
+impl std::convert::From<App> for AppRevision {
+    fn from(app: App) -> Self {
+        AppRevision {
+            id: app.id,
+            workspace_id: app.workspace_id,
+            name: app.name,
+            desc: app.desc,
+            belongings: app.belongings.into(),
+            version: app.version,
+            modified_time: app.modified_time,
+            create_time: app.create_time,
+        }
+    }
+}
+
+impl std::convert::From<Vec<AppRevision>> for RepeatedApp {
+    fn from(values: Vec<AppRevision>) -> Self {
+        let items = values.into_iter().map(|value| value.into()).collect::<Vec<App>>();
+        RepeatedApp { items }
+    }
+}
+
+impl std::convert::From<RepeatedApp> for Vec<AppRevision> {
+    fn from(repeated_app: RepeatedApp) -> Self {
+        repeated_app
+            .items
+            .into_iter()
+            .map(|value| value.into())
+            .collect::<Vec<AppRevision>>()
+    }
+}

+ 9 - 0
shared-lib/flowy-folder-data-model/src/revision/mod.rs

@@ -0,0 +1,9 @@
+mod app;
+mod trash;
+mod view;
+mod workspace;
+
+pub use app::*;
+pub use trash::*;
+pub use view::*;
+pub use workspace::*;

+ 39 - 0
shared-lib/flowy-folder-data-model/src/revision/trash.rs

@@ -0,0 +1,39 @@
+use crate::entities::trash::{Trash, TrashType};
+use serde::{Deserialize, Serialize};
+
+#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
+pub struct TrashRevision {
+    pub id: String,
+
+    pub name: String,
+
+    pub modified_time: i64,
+
+    pub create_time: i64,
+
+    pub ty: TrashType,
+}
+
+impl std::convert::From<TrashRevision> for Trash {
+    fn from(trash_serde: TrashRevision) -> Self {
+        Trash {
+            id: trash_serde.id,
+            name: trash_serde.name,
+            modified_time: trash_serde.modified_time,
+            create_time: trash_serde.create_time,
+            ty: trash_serde.ty,
+        }
+    }
+}
+
+impl std::convert::From<Trash> for TrashRevision {
+    fn from(trash: Trash) -> Self {
+        TrashRevision {
+            id: trash.id,
+            name: trash.name,
+            modified_time: trash.modified_time,
+            create_time: trash.create_time,
+            ty: trash.ty,
+        }
+    }
+}

+ 93 - 0
shared-lib/flowy-folder-data-model/src/revision/view.rs

@@ -0,0 +1,93 @@
+use crate::entities::view::{View, ViewDataType};
+use crate::entities::RepeatedView;
+use serde::{Deserialize, Serialize};
+
+#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
+pub struct ViewRevision {
+    pub id: String,
+
+    pub belong_to_id: String,
+
+    pub name: String,
+
+    pub desc: String,
+
+    #[serde(default)]
+    pub data_type: ViewDataType,
+
+    pub version: i64,
+
+    pub belongings: Vec<ViewRevision>,
+
+    pub modified_time: i64,
+
+    pub create_time: i64,
+
+    #[serde(default)]
+    pub ext_data: String,
+
+    #[serde(default)]
+    pub thumbnail: String,
+
+    #[serde(default = "default_plugin_type")]
+    pub plugin_type: i32,
+}
+
+fn default_plugin_type() -> i32 {
+    0
+}
+
+impl std::convert::From<ViewRevision> for View {
+    fn from(view_serde: ViewRevision) -> Self {
+        View {
+            id: view_serde.id,
+            belong_to_id: view_serde.belong_to_id,
+            name: view_serde.name,
+            desc: view_serde.desc,
+            data_type: view_serde.data_type,
+            version: view_serde.version,
+            belongings: view_serde.belongings.into(),
+            modified_time: view_serde.modified_time,
+            create_time: view_serde.create_time,
+            ext_data: view_serde.ext_data,
+            thumbnail: view_serde.thumbnail,
+            plugin_type: view_serde.plugin_type,
+        }
+    }
+}
+
+impl std::convert::From<View> for ViewRevision {
+    fn from(view: View) -> Self {
+        ViewRevision {
+            id: view.id,
+            belong_to_id: view.belong_to_id,
+            name: view.name,
+            desc: view.desc,
+            data_type: view.data_type,
+            version: view.version,
+            belongings: view.belongings.into(),
+            modified_time: view.modified_time,
+            create_time: view.create_time,
+            ext_data: view.ext_data,
+            thumbnail: view.thumbnail,
+            plugin_type: view.plugin_type,
+        }
+    }
+}
+
+impl std::convert::From<Vec<ViewRevision>> for RepeatedView {
+    fn from(values: Vec<ViewRevision>) -> Self {
+        let items = values.into_iter().map(|value| value.into()).collect::<Vec<View>>();
+        RepeatedView { items }
+    }
+}
+
+impl std::convert::From<RepeatedView> for Vec<ViewRevision> {
+    fn from(repeated_view: RepeatedView) -> Self {
+        repeated_view
+            .items
+            .into_iter()
+            .map(|value| value.into())
+            .collect::<Vec<ViewRevision>>()
+    }
+}

+ 44 - 0
shared-lib/flowy-folder-data-model/src/revision/workspace.rs

@@ -0,0 +1,44 @@
+use crate::entities::workspace::Workspace;
+use crate::revision::AppRevision;
+use serde::{Deserialize, Serialize};
+
+#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
+pub struct WorkspaceRevision {
+    pub id: String,
+
+    pub name: String,
+
+    pub desc: String,
+
+    pub apps: Vec<AppRevision>,
+
+    pub modified_time: i64,
+
+    pub create_time: i64,
+}
+
+impl std::convert::From<WorkspaceRevision> for Workspace {
+    fn from(workspace_serde: WorkspaceRevision) -> Self {
+        Workspace {
+            id: workspace_serde.id,
+            name: workspace_serde.name,
+            desc: workspace_serde.desc,
+            apps: workspace_serde.apps.into(),
+            modified_time: workspace_serde.modified_time,
+            create_time: workspace_serde.create_time,
+        }
+    }
+}
+
+impl std::convert::From<Workspace> for WorkspaceRevision {
+    fn from(workspace: Workspace) -> Self {
+        WorkspaceRevision {
+            id: workspace.id,
+            name: workspace.name,
+            desc: workspace.desc,
+            apps: workspace.apps.into(),
+            modified_time: workspace.modified_time,
+            create_time: workspace.create_time,
+        }
+    }
+}

+ 10 - 5
shared-lib/flowy-sync/src/client_folder/builder.rs

@@ -5,15 +5,17 @@ use crate::{
     entities::revision::Revision,
     errors::{CollaborateError, CollaborateResult},
 };
-use flowy_folder_data_model::entities::{trash::Trash, workspace::Workspace};
+
+use flowy_folder_data_model::entities::{Trash, Workspace};
+use flowy_folder_data_model::revision::{TrashRevision, WorkspaceRevision};
 use lib_ot::core::{PlainTextAttributes, PlainTextDelta, PlainTextDeltaBuilder};
 use serde::{Deserialize, Serialize};
 use std::sync::Arc;
 
 #[derive(Serialize, Deserialize)]
 pub(crate) struct FolderPadBuilder {
-    workspaces: Vec<Arc<Workspace>>,
-    trash: Vec<Arc<Trash>>,
+    workspaces: Vec<Arc<WorkspaceRevision>>,
+    trash: Vec<Arc<TrashRevision>>,
 }
 
 impl FolderPadBuilder {
@@ -25,12 +27,15 @@ impl FolderPadBuilder {
     }
 
     pub(crate) fn with_workspace(mut self, workspaces: Vec<Workspace>) -> Self {
-        self.workspaces = workspaces.into_iter().map(Arc::new).collect::<Vec<_>>();
+        self.workspaces = workspaces
+            .into_iter()
+            .map(|workspace| Arc::new(workspace.into()))
+            .collect::<Vec<_>>();
         self
     }
 
     pub(crate) fn with_trash(mut self, trash: Vec<Trash>) -> Self {
-        self.trash = trash.into_iter().map(Arc::new).collect::<Vec<_>>();
+        self.trash = trash.into_iter().map(|t| Arc::new(t.into())).collect::<Vec<_>>();
         self
     }
 

+ 33 - 24
shared-lib/flowy-sync/src/client_folder/folder_pad.rs

@@ -1,3 +1,4 @@
+use crate::errors::internal_error;
 use crate::util::cal_diff;
 use crate::{
     client_folder::builder::FolderPadBuilder,
@@ -7,18 +8,17 @@ use crate::{
     },
     errors::{CollaborateError, CollaborateResult},
 };
-use flowy_folder_data_model::entities::{app::App, trash::Trash, view::View, workspace::Workspace};
-use lib_ot::core::*;
-
-use crate::errors::internal_error;
+use flowy_folder_data_model::entities::{App, Trash, View, Workspace};
+use flowy_folder_data_model::revision::{AppRevision, TrashRevision, ViewRevision, WorkspaceRevision};
 use lib_infra::util::move_vec_element;
+use lib_ot::core::*;
 use serde::{Deserialize, Serialize};
 use std::sync::Arc;
 
 #[derive(Debug, Deserialize, Serialize, Clone, Eq, PartialEq)]
 pub struct FolderPad {
-    pub(crate) workspaces: Vec<Arc<Workspace>>,
-    pub(crate) trash: Vec<Arc<Trash>>,
+    pub(crate) workspaces: Vec<Arc<WorkspaceRevision>>,
+    pub(crate) trash: Vec<Arc<TrashRevision>>,
     #[serde(skip)]
     pub(crate) delta: FolderDelta,
 }
@@ -63,7 +63,7 @@ impl FolderPad {
 
     #[tracing::instrument(level = "trace", skip(self, workspace), fields(workspace_name=%workspace.name), err)]
     pub fn create_workspace(&mut self, workspace: Workspace) -> CollaborateResult<Option<FolderChange>> {
-        let workspace = Arc::new(workspace);
+        let workspace = Arc::new(workspace.into());
         if self.workspaces.contains(&workspace) {
             tracing::warn!("[RootFolder]: Duplicate workspace");
             return Ok(None);
@@ -99,13 +99,13 @@ impl FolderPad {
                 let workspaces = self
                     .workspaces
                     .iter()
-                    .map(|workspace| workspace.as_ref().clone())
+                    .map(|workspace| workspace.as_ref().clone().into())
                     .collect::<Vec<Workspace>>();
                 Ok(workspaces)
             }
             Some(workspace_id) => {
                 if let Some(workspace) = self.workspaces.iter().find(|workspace| workspace.id == workspace_id) {
-                    Ok(vec![workspace.as_ref().clone()])
+                    Ok(vec![workspace.as_ref().clone().into()])
                 } else {
                     Err(CollaborateError::record_not_found()
                         .context(format!("Can't find workspace with id {}", workspace_id)))
@@ -125,12 +125,13 @@ impl FolderPad {
     #[tracing::instrument(level = "trace", skip(self), fields(app_name=%app.name), err)]
     pub fn create_app(&mut self, app: App) -> CollaborateResult<Option<FolderChange>> {
         let workspace_id = app.workspace_id.clone();
+        let app_serde: AppRevision = app.into();
         self.with_workspace(&workspace_id, move |workspace| {
-            if workspace.apps.contains(&app) {
+            if workspace.apps.contains(&app_serde) {
                 tracing::warn!("[RootFolder]: Duplicate app");
                 return Ok(None);
             }
-            workspace.apps.push(app);
+            workspace.apps.push(app_serde);
             Ok(Some(()))
         })
     }
@@ -138,7 +139,7 @@ impl FolderPad {
     pub fn read_app(&self, app_id: &str) -> CollaborateResult<App> {
         for workspace in &self.workspaces {
             if let Some(app) = workspace.apps.iter().find(|app| app.id == app_id) {
-                return Ok(app.clone());
+                return Ok(app.clone().into());
             }
         }
         Err(CollaborateError::record_not_found().context(format!("Can't find app with id {}", app_id)))
@@ -185,12 +186,13 @@ impl FolderPad {
     #[tracing::instrument(level = "trace", skip(self), fields(view_name=%view.name), err)]
     pub fn create_view(&mut self, view: View) -> CollaborateResult<Option<FolderChange>> {
         let app_id = view.belong_to_id.clone();
+        let view_serde: ViewRevision = view.into();
         self.with_app(&app_id, move |app| {
-            if app.belongings.contains(&view) {
+            if app.belongings.contains(&view_serde) {
                 tracing::warn!("[RootFolder]: Duplicate view");
                 return Ok(None);
             }
-            app.belongings.push(view);
+            app.belongings.push(view_serde);
             Ok(Some(()))
         })
     }
@@ -199,7 +201,7 @@ impl FolderPad {
         for workspace in &self.workspaces {
             for app in &(*workspace.apps) {
                 if let Some(view) = app.belongings.iter().find(|b| b.id == view_id) {
-                    return Ok(view.clone());
+                    return Ok(view.clone().into());
                 }
             }
         }
@@ -210,7 +212,7 @@ impl FolderPad {
         for workspace in &self.workspaces {
             for app in &(*workspace.apps) {
                 if app.id == belong_to_id {
-                    return Ok(app.belongings.clone().take_items());
+                    return Ok(app.belongings.iter().map(|view| view.clone().into()).collect());
                 }
             }
         }
@@ -261,7 +263,10 @@ impl FolderPad {
 
     pub fn create_trash(&mut self, trash: Vec<Trash>) -> CollaborateResult<Option<FolderChange>> {
         self.with_trash(|t| {
-            let mut new_trash = trash.into_iter().map(Arc::new).collect::<Vec<Arc<Trash>>>();
+            let mut new_trash = trash
+                .into_iter()
+                .map(|t| Arc::new(t.into()))
+                .collect::<Vec<Arc<TrashRevision>>>();
             t.append(&mut new_trash);
 
             Ok(Some(()))
@@ -270,9 +275,13 @@ impl FolderPad {
 
     pub fn read_trash(&self, trash_id: Option<String>) -> CollaborateResult<Vec<Trash>> {
         match trash_id {
-            None => Ok(self.trash.iter().map(|t| t.as_ref().clone()).collect::<Vec<Trash>>()),
+            None => Ok(self
+                .trash
+                .iter()
+                .map(|t| t.as_ref().clone().into())
+                .collect::<Vec<Trash>>()),
             Some(trash_id) => match self.trash.iter().find(|t| t.id == trash_id) {
-                Some(trash) => Ok(vec![trash.as_ref().clone()]),
+                Some(trash) => Ok(vec![trash.as_ref().clone().into()]),
                 None => Ok(vec![]),
             },
         }
@@ -304,7 +313,7 @@ impl FolderPad {
 impl FolderPad {
     fn modify_workspaces<F>(&mut self, f: F) -> CollaborateResult<Option<FolderChange>>
     where
-        F: FnOnce(&mut Vec<Arc<Workspace>>) -> CollaborateResult<Option<()>>,
+        F: FnOnce(&mut Vec<Arc<WorkspaceRevision>>) -> CollaborateResult<Option<()>>,
     {
         let cloned_self = self.clone();
         match f(&mut self.workspaces)? {
@@ -325,7 +334,7 @@ impl FolderPad {
 
     fn with_workspace<F>(&mut self, workspace_id: &str, f: F) -> CollaborateResult<Option<FolderChange>>
     where
-        F: FnOnce(&mut Workspace) -> CollaborateResult<Option<()>>,
+        F: FnOnce(&mut WorkspaceRevision) -> CollaborateResult<Option<()>>,
     {
         self.modify_workspaces(|workspaces| {
             if let Some(workspace) = workspaces.iter_mut().find(|workspace| workspace_id == workspace.id) {
@@ -339,7 +348,7 @@ impl FolderPad {
 
     fn with_trash<F>(&mut self, f: F) -> CollaborateResult<Option<FolderChange>>
     where
-        F: FnOnce(&mut Vec<Arc<Trash>>) -> CollaborateResult<Option<()>>,
+        F: FnOnce(&mut Vec<Arc<TrashRevision>>) -> CollaborateResult<Option<()>>,
     {
         let cloned_self = self.clone();
         match f(&mut self.trash)? {
@@ -360,7 +369,7 @@ impl FolderPad {
 
     fn with_app<F>(&mut self, app_id: &str, f: F) -> CollaborateResult<Option<FolderChange>>
     where
-        F: FnOnce(&mut App) -> CollaborateResult<Option<()>>,
+        F: FnOnce(&mut AppRevision) -> CollaborateResult<Option<()>>,
     {
         let workspace_id = match self
             .workspaces
@@ -382,7 +391,7 @@ impl FolderPad {
 
     fn with_view<F>(&mut self, belong_to_id: &str, view_id: &str, f: F) -> CollaborateResult<Option<FolderChange>>
     where
-        F: FnOnce(&mut View) -> CollaborateResult<Option<()>>,
+        F: FnOnce(&mut ViewRevision) -> CollaborateResult<Option<()>>,
     {
         self.with_app(belong_to_id, |app| {
             match app.belongings.iter_mut().find(|view| view_id == view.id) {

+ 1 - 6
shared-lib/flowy-sync/src/client_grid/grid_meta_pad.rs

@@ -25,12 +25,7 @@ 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 fields = self.grid_meta.fields.iter().cloned().collect::<Vec<FieldMeta>>();
 
         let blocks = self
             .grid_meta