refactor: add folder entities's revision objects

This commit is contained in:
appflowy 2022-06-12 22:01:02 +08:00
parent 2b499ee62b
commit c2fad5021b
16 changed files with 325 additions and 206 deletions

View File

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

View File

@ -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) => {

View File

@ -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)]

View File

@ -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::*;

View File

@ -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)]

View File

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

View File

@ -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)]

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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) {

View File

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