feat: delete the view from the db when the view is deleted (#2703)

This commit is contained in:
Nathan.fooo 2023-06-05 09:42:11 +08:00 committed by GitHub
parent bec8122178
commit a50c940282
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 143 additions and 79 deletions

View File

@ -34,12 +34,12 @@ default = ["custom-protocol"]
custom-protocol = ["tauri/custom-protocol"]
[patch.crates-io]
collab = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "13b178" }
collab-folder = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "13b178" }
collab-persistence = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "13b178" }
collab-document = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "13b178" }
collab-database = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "13b178" }
appflowy-integrate = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "13b178" }
collab = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "cbc2e0" }
collab-folder = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "cbc2e0" }
collab-persistence = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "cbc2e0" }
collab-document = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "cbc2e0" }
collab-database = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "cbc2e0" }
appflowy-integrate = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "cbc2e0" }
#collab = { path = "../../AppFlowy-Collab/collab" }
#collab-folder = { path = "../../AppFlowy-Collab/collab-folder" }

View File

@ -85,7 +85,7 @@ checksum = "7de8ce5e0f9f8d88245311066a578d72b7af3e7088f32783804676302df237e4"
[[package]]
name = "appflowy-integrate"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=13b178#13b17802de31e75255b4303914042bdbb04361b2"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=cbc2e0#cbc2e0acb8420dc997921bb3f56b99f9975c2aab"
dependencies = [
"anyhow",
"collab",
@ -887,7 +887,7 @@ dependencies = [
[[package]]
name = "collab"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=13b178#13b17802de31e75255b4303914042bdbb04361b2"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=cbc2e0#cbc2e0acb8420dc997921bb3f56b99f9975c2aab"
dependencies = [
"anyhow",
"bytes",
@ -905,7 +905,7 @@ dependencies = [
[[package]]
name = "collab-client-ws"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=13b178#13b17802de31e75255b4303914042bdbb04361b2"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=cbc2e0#cbc2e0acb8420dc997921bb3f56b99f9975c2aab"
dependencies = [
"bytes",
"collab-sync",
@ -923,7 +923,7 @@ dependencies = [
[[package]]
name = "collab-database"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=13b178#13b17802de31e75255b4303914042bdbb04361b2"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=cbc2e0#cbc2e0acb8420dc997921bb3f56b99f9975c2aab"
dependencies = [
"anyhow",
"async-trait",
@ -949,7 +949,7 @@ dependencies = [
[[package]]
name = "collab-derive"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=13b178#13b17802de31e75255b4303914042bdbb04361b2"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=cbc2e0#cbc2e0acb8420dc997921bb3f56b99f9975c2aab"
dependencies = [
"proc-macro2",
"quote",
@ -961,7 +961,7 @@ dependencies = [
[[package]]
name = "collab-document"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=13b178#13b17802de31e75255b4303914042bdbb04361b2"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=cbc2e0#cbc2e0acb8420dc997921bb3f56b99f9975c2aab"
dependencies = [
"anyhow",
"collab",
@ -978,7 +978,7 @@ dependencies = [
[[package]]
name = "collab-folder"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=13b178#13b17802de31e75255b4303914042bdbb04361b2"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=cbc2e0#cbc2e0acb8420dc997921bb3f56b99f9975c2aab"
dependencies = [
"anyhow",
"collab",
@ -997,7 +997,7 @@ dependencies = [
[[package]]
name = "collab-persistence"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=13b178#13b17802de31e75255b4303914042bdbb04361b2"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=cbc2e0#cbc2e0acb8420dc997921bb3f56b99f9975c2aab"
dependencies = [
"bincode",
"chrono",
@ -1017,7 +1017,7 @@ dependencies = [
[[package]]
name = "collab-plugins"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=13b178#13b17802de31e75255b4303914042bdbb04361b2"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=cbc2e0#cbc2e0acb8420dc997921bb3f56b99f9975c2aab"
dependencies = [
"anyhow",
"async-trait",
@ -1047,7 +1047,7 @@ dependencies = [
[[package]]
name = "collab-sync"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=13b178#13b17802de31e75255b4303914042bdbb04361b2"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=cbc2e0#cbc2e0acb8420dc997921bb3f56b99f9975c2aab"
dependencies = [
"bytes",
"collab",

View File

@ -33,11 +33,11 @@ opt-level = 3
incremental = false
[patch.crates-io]
collab = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "13b178" }
collab-folder = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "13b178" }
collab-document = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "13b178" }
collab-database = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "13b178" }
appflowy-integrate = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "13b178" }
collab = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "cbc2e0" }
collab-folder = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "cbc2e0" }
collab-document = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "cbc2e0" }
collab-database = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "cbc2e0" }
appflowy-integrate = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "cbc2e0" }
#collab = { path = "../AppFlowy-Collab/collab" }
#collab-folder = { path = "../AppFlowy-Collab/collab-folder" }

View File

@ -5,6 +5,7 @@ use std::sync::Arc;
use appflowy_integrate::collab_builder::AppFlowyCollabBuilder;
use appflowy_integrate::RocksCollabDB;
use bytes::Bytes;
use tokio::sync::RwLock;
use flowy_database2::entities::DatabaseLayoutPB;
use flowy_database2::services::share::csv::CSVFormat;
@ -24,7 +25,6 @@ use flowy_folder2::ViewLayout;
use flowy_user::services::UserSession;
use lib_dispatch::prelude::ToBytes;
use lib_infra::future::FutureResult;
use tokio::sync::RwLock;
pub struct Folder2DepsResolver();
impl Folder2DepsResolver {
@ -121,7 +121,19 @@ impl FolderOperationHandler for DocumentFolderOperation {
let manager = self.0.clone();
let view_id = view_id.to_string();
FutureResult::new(async move {
manager.close_document(view_id)?;
manager.close_document(&view_id)?;
Ok(())
})
}
fn delete_view(&self, view_id: &str) -> FutureResult<(), FlowyError> {
let manager = self.0.clone();
let view_id = view_id.to_string();
FutureResult::new(async move {
match manager.delete_document(&view_id) {
Ok(_) => tracing::trace!("Delete document: {}", view_id),
Err(e) => tracing::error!("Failed to delete document: {}", e),
}
Ok(())
})
}
@ -210,6 +222,18 @@ impl FolderOperationHandler for DatabaseFolderOperation {
})
}
fn delete_view(&self, view_id: &str) -> FutureResult<(), FlowyError> {
let database_manager = self.0.clone();
let view_id = view_id.to_string();
FutureResult::new(async move {
match database_manager.delete_database_view(&view_id).await {
Ok(_) => tracing::trace!("Delete database view: {}", view_id),
Err(e) => tracing::error!("Failed to delete database: {}", e),
}
Ok(())
})
}
fn duplicate_view(&self, view_id: &str) -> FutureResult<Bytes, FlowyError> {
let database_manager = self.0.clone();
let view_id = view_id.to_owned();

View File

@ -132,6 +132,12 @@ impl DatabaseManager2 {
Ok(())
}
pub async fn delete_database_view(&self, view_id: &str) -> FlowyResult<()> {
let database = self.get_database_with_view_id(view_id).await?;
let _ = database.delete_database_view(view_id).await?;
Ok(())
}
pub async fn duplicate_database(&self, view_id: &str) -> FlowyResult<Vec<u8>> {
let database_data = self.with_user_database(Err(FlowyError::internal()), |database| {
let data = database.get_database_duplicated_data(view_id)?;

View File

@ -1,5 +1,6 @@
use flowy_derive::ProtoBuf_Enum;
use flowy_notification::NotificationBuilder;
const OBSERVABLE_CATEGORY: &str = "Grid";
#[derive(ProtoBuf_Enum, Debug)]
@ -37,6 +38,10 @@ pub enum DatabaseNotification {
DidSetNewLayoutField = 81,
// Trigger when the layout of the database is changed
DidUpdateDatabaseLayout = 82,
// Trigger when the database view is deleted
DidDeleteDatabaseView = 83,
// Trigger when the database view is moved to trash
DidMoveDatabaseViewToTrash = 84,
}
impl std::default::Default for DatabaseNotification {

View File

@ -312,7 +312,7 @@ impl<'a> CellBuilder<'a> {
.collect::<HashMap<String, &Field>>();
let mut cells = Cells::new();
for (field_id, cell_str) in cell_by_field_id.clone() {
for (field_id, cell_str) in cell_by_field_id {
if let Some(field) = field_maps.get(&field_id) {
let field_type = FieldType::from(field.field_type);
match field_type {

View File

@ -125,6 +125,14 @@ impl DatabaseEditor {
Ok(())
}
/// Returns the delete view ids.
/// If the view is inline view, all the reference views will be deleted. So the return value
/// will be the reference view ids and the inline view id. Otherwise, the return value will
/// be the view id.
pub async fn delete_database_view(&self, view_id: &str) -> FlowyResult<Vec<String>> {
Ok(self.database.lock().delete_view(view_id))
}
pub async fn update_group_setting(
&self,
view_id: &str,
@ -942,7 +950,7 @@ impl DatabaseEditor {
let view = database_view
.get_view()
.await
.ok_or_else(|| FlowyError::record_not_found())?;
.ok_or_else(FlowyError::record_not_found)?;
let rows = database_view.v_get_rows().await;
let (database_id, fields) = {
let database = self.database.lock();

View File

@ -108,7 +108,7 @@ pub(crate) async fn get_cell_for_row(
let cell_data = match &row_cell.cell {
None => None,
Some(cell) => handler.get_cell_data(&cell, &field_type, &field).ok(),
Some(cell) => handler.get_cell_data(cell, &field_type, &field).ok(),
};
Some(RowSingleCellData {
row_id: row_cell.row_id.clone(),
@ -133,7 +133,7 @@ pub(crate) async fn get_cells_for_field(
.map(|row_cell| {
let cell_data = match &row_cell.cell {
None => None,
Some(cell) => handler.get_cell_data(&cell, &field_type, &field).ok(),
Some(cell) => handler.get_cell_data(cell, &field_type, &field).ok(),
};
RowSingleCellData {
row_id: row_cell.row_id.clone(),

View File

@ -51,7 +51,7 @@ pub(crate) async fn close_document_handler(
manager: AFPluginState<Arc<DocumentManager>>,
) -> FlowyResult<()> {
let context = data.into_inner();
manager.close_document(context.document_id)?;
manager.close_document(&context.document_id)?;
Ok(())
}

View File

@ -3,6 +3,7 @@ use std::{collections::HashMap, sync::Arc};
use appflowy_integrate::collab_builder::AppFlowyCollabBuilder;
use appflowy_integrate::RocksCollabDB;
use collab_document::blocks::DocumentData;
use collab_document::YrsDocAction;
use parking_lot::RwLock;
use flowy_error::{FlowyError, FlowyResult};
@ -96,8 +97,19 @@ impl DocumentManager {
Ok(document)
}
pub fn close_document(&self, doc_id: String) -> FlowyResult<()> {
self.documents.write().remove(&doc_id);
pub fn close_document(&self, doc_id: &str) -> FlowyResult<()> {
self.documents.write().remove(doc_id);
Ok(())
}
pub fn delete_document(&self, doc_id: &str) -> FlowyResult<()> {
let uid = self.user.user_id()?;
let db = self.user.collab_db()?;
let _ = db.with_write_txn(|txn| {
txn.delete_doc(uid, &doc_id)?;
Ok(())
});
self.documents.write().remove(doc_id);
Ok(())
}
}

View File

@ -1,14 +1,15 @@
use std::{collections::HashMap, sync::Arc, vec};
use collab_document::blocks::{Block, BlockAction, BlockActionPayload, BlockActionType};
use flowy_document2::document_block_keys::PARAGRAPH_BLOCK_TYPE;
use nanoid::nanoid;
use serde_json::{json, to_value, Value};
use crate::document::util::default_collab_builder;
use flowy_document2::document_block_keys::PARAGRAPH_BLOCK_TYPE;
use flowy_document2::document_data::default_document_data;
use flowy_document2::manager::DocumentManager;
use crate::document::util::default_collab_builder;
use super::util::FakeUser;
#[test]
@ -33,7 +34,7 @@ fn restore_document() {
.get_document()
.unwrap();
// close a document
_ = manager.close_document(doc_id.clone());
_ = manager.close_document(&doc_id);
assert_eq!(data_b, data);
// restore
@ -46,7 +47,7 @@ fn restore_document() {
.get_document()
.unwrap();
// close a document
_ = manager.close_document(doc_id);
_ = manager.close_document(&doc_id);
assert_eq!(data_b, data);
}
@ -87,7 +88,7 @@ fn document_apply_insert_action() {
document.lock().apply_action(vec![insert_text_action]);
let data_a = document.lock().get_document().unwrap();
// close the original document
_ = manager.close_document(doc_id.clone());
_ = manager.close_document(&doc_id);
// re-open the document
let data_b = manager
@ -97,7 +98,7 @@ fn document_apply_insert_action() {
.get_document()
.unwrap();
// close a document
_ = manager.close_document(doc_id);
_ = manager.close_document(&doc_id);
assert_eq!(data_b, data_a);
}
@ -135,7 +136,7 @@ fn document_apply_update_page_action() {
tracing::trace!("{:?}", &actions);
document.lock().apply_action(actions);
let page_block_old = document.lock().get_block(&data.page_id).unwrap();
_ = manager.close_document(doc_id.clone());
_ = manager.close_document(&doc_id);
// re-open the document
let document = manager.open_document(doc_id).unwrap();
@ -203,12 +204,12 @@ fn document_apply_update_action() {
};
document.lock().apply_action(vec![update_text_action]);
// close the original document
_ = manager.close_document(doc_id.clone());
_ = manager.close_document(&doc_id);
// re-open the document
let document = manager.open_document(doc_id.clone()).unwrap();
let block = document.lock().get_block(&text_block_id).unwrap();
assert_eq!(block.data, updated_text_block_data);
// close a document
_ = manager.close_document(doc_id);
_ = manager.close_document(&doc_id);
}

View File

@ -1,3 +1,8 @@
use std::sync::Arc;
use flowy_error::FlowyError;
use lib_dispatch::prelude::{data_result_ok, AFPluginData, AFPluginState, DataResult};
use crate::entities::{
view_pb_without_child_views, CreateViewParams, CreateViewPayloadPB, CreateWorkspaceParams,
CreateWorkspacePayloadPB, ImportPB, MoveFolderItemPayloadPB, MoveViewParams, RepeatedTrashIdPB,
@ -6,11 +11,7 @@ use crate::entities::{
WorkspaceSettingPB,
};
use crate::manager::Folder2Manager;
use crate::share::ImportParams;
use flowy_error::FlowyError;
use lib_dispatch::prelude::{data_result_ok, AFPluginData, AFPluginState, DataResult};
use std::sync::Arc;
#[tracing::instrument(level = "debug", skip(data, folder), err)]
pub(crate) async fn create_workspace_handler(
@ -187,7 +188,7 @@ pub(crate) async fn delete_trash_handler(
) -> Result<(), FlowyError> {
let trash_ids = identifiers.into_inner().items;
for trash_id in trash_ids {
folder.delete_trash(&trash_id.id).await;
let _ = folder.delete_trash(&trash_id.id).await;
}
Ok(())
}

View File

@ -1,24 +1,22 @@
use std::collections::{HashMap, HashSet};
use std::ops::Deref;
use std::sync::{Arc, Weak};
use appflowy_integrate::collab_builder::AppFlowyCollabBuilder;
use collab::core::collab_state::CollabState;
use collab_folder::core::{
Folder, FolderContext, TrashChange, TrashChangeReceiver, TrashInfo, TrashRecord, View,
ViewChange, ViewChangeReceiver, ViewLayout, Workspace,
};
use parking_lot::Mutex;
use tracing::{event, Level};
use crate::deps::{FolderCloudService, FolderUser};
use flowy_error::{ErrorCode, FlowyError, FlowyResult};
use lib_infra::util::timestamp;
use tokio_stream::wrappers::WatchStream;
use tokio_stream::StreamExt;
use tracing::{event, Level};
use flowy_error::{ErrorCode, FlowyError, FlowyResult};
use lib_infra::util::timestamp;
use crate::deps::{FolderCloudService, FolderUser};
use crate::entities::{
view_pb_with_child_views, CreateViewParams, CreateWorkspaceParams, RepeatedTrashPB,
RepeatedViewPB, RepeatedWorkspacePB, UpdateViewParams, ViewPB,
@ -302,12 +300,6 @@ impl Folder2Manager {
}
}
#[tracing::instrument(level = "debug", skip(self, view_id), err)]
pub async fn delete_view(&self, view_id: &str) -> FlowyResult<()> {
self.with_folder((), |folder| folder.views.delete_views(vec![view_id]));
Ok(())
}
/// Move the view to trash. If the view is the current view, then set the current view to empty.
/// When the view is moved to trash, all the child views will be moved to trash as well.
#[tracing::instrument(level = "debug", skip(self), err)]
@ -453,27 +445,36 @@ impl Folder2Manager {
});
}
#[tracing::instrument(level = "trace", skip(self))]
pub(crate) async fn delete_trash(&self, trash_id: &str) {
self.with_folder((), |folder| {
folder.trash.delete_trash(vec![trash_id]);
folder.views.delete_views(vec![trash_id]);
})
}
/// Delete all the trash permanently.
#[tracing::instrument(level = "trace", skip(self))]
pub(crate) async fn delete_all_trash(&self) {
self.with_folder((), |folder| {
let trash = folder.trash.get_all_trash();
folder.trash.clear();
folder.views.delete_views(trash);
});
let deleted_trash = self.with_folder(vec![], |folder| folder.trash.get_all_trash());
for trash in deleted_trash {
let _ = self.delete_trash(&trash.id).await;
}
send_notification("trash", FolderNotification::DidUpdateTrash)
.payload(RepeatedTrashPB { items: vec![] })
.send();
}
/// Delete the trash permanently.
/// Delete the view will delete all the resources that the view holds. For example, if the view
/// is a database view. Then the database will be deleted as well.
#[tracing::instrument(level = "debug", skip(self, view_id), err)]
pub async fn delete_trash(&self, view_id: &str) -> FlowyResult<()> {
let view = self.with_folder(None, |folder| folder.views.get_view(view_id));
self.with_folder((), |folder| {
folder.trash.delete_trash(vec![view_id]);
folder.views.delete_views(vec![view_id]);
});
if let Some(view) = view {
if let Ok(handler) = self.get_handler(&view.layout) {
handler.delete_view(view_id).await?;
}
}
Ok(())
}
pub(crate) async fn import(&self, import_data: ImportParams) -> FlowyResult<View> {
if import_data.data.is_none() && import_data.file_path.is_none() {
return Err(FlowyError::new(

View File

@ -1,18 +1,20 @@
use crate::entities::{CreateViewParams, ViewLayoutPB};
use bytes::Bytes;
use collab_folder::core::{RepeatedView, ViewIdentifier, ViewLayout};
use flowy_error::FlowyError;
use lib_infra::future::FutureResult;
use lib_infra::util::timestamp;
use std::collections::HashMap;
use std::future::Future;
use std::sync::Arc;
pub type ViewData = Bytes;
use bytes::Bytes;
pub use collab_folder::core::View;
use collab_folder::core::{RepeatedView, ViewIdentifier, ViewLayout};
use tokio::sync::RwLock;
use flowy_error::FlowyError;
use lib_infra::future::FutureResult;
use lib_infra::util::timestamp;
use crate::entities::{CreateViewParams, ViewLayoutPB};
pub type ViewData = Bytes;
/// A builder for creating a view for a workspace.
/// The views created by this builder will be the first level views of the workspace.
pub struct WorkspaceViewBuilder {
@ -157,6 +159,10 @@ pub trait FolderOperationHandler {
/// the backend
fn close_view(&self, view_id: &str) -> FutureResult<(), FlowyError>;
/// Called when the view is deleted.
/// This will called after the view is deleted from the trash.
fn delete_view(&self, view_id: &str) -> FutureResult<(), FlowyError>;
/// Returns the [ViewData] that can be used to create the same view.
fn duplicate_view(&self, view_id: &str) -> FutureResult<ViewData, FlowyError>;