Prechádzať zdrojové kódy

delete multiple view in one request

appflowy 3 rokov pred
rodič
commit
dfd6046214

+ 10 - 22
app_flowy/packages/flowy_sdk/lib/protobuf/flowy-workspace/view_delete.pb.dart

@@ -11,17 +11,17 @@ import 'package:protobuf/protobuf.dart' as $pb;
 
 class DeleteViewRequest extends $pb.GeneratedMessage {
   static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'DeleteViewRequest', createEmptyInstance: create)
-    ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'viewId')
+    ..pPS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'viewIds')
     ..hasRequiredFields = false
   ;
 
   DeleteViewRequest._() : super();
   factory DeleteViewRequest({
-    $core.String? viewId,
+    $core.Iterable<$core.String>? viewIds,
   }) {
     final _result = create();
-    if (viewId != null) {
-      _result.viewId = viewId;
+    if (viewIds != null) {
+      _result.viewIds.addAll(viewIds);
     }
     return _result;
   }
@@ -47,28 +47,22 @@ class DeleteViewRequest extends $pb.GeneratedMessage {
   static DeleteViewRequest? _defaultInstance;
 
   @$pb.TagNumber(1)
-  $core.String get viewId => $_getSZ(0);
-  @$pb.TagNumber(1)
-  set viewId($core.String v) { $_setString(0, v); }
-  @$pb.TagNumber(1)
-  $core.bool hasViewId() => $_has(0);
-  @$pb.TagNumber(1)
-  void clearViewId() => clearField(1);
+  $core.List<$core.String> get viewIds => $_getList(0);
 }
 
 class DeleteViewParams extends $pb.GeneratedMessage {
   static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'DeleteViewParams', createEmptyInstance: create)
-    ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'viewId')
+    ..pPS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'viewIds')
     ..hasRequiredFields = false
   ;
 
   DeleteViewParams._() : super();
   factory DeleteViewParams({
-    $core.String? viewId,
+    $core.Iterable<$core.String>? viewIds,
   }) {
     final _result = create();
-    if (viewId != null) {
-      _result.viewId = viewId;
+    if (viewIds != null) {
+      _result.viewIds.addAll(viewIds);
     }
     return _result;
   }
@@ -94,12 +88,6 @@ class DeleteViewParams extends $pb.GeneratedMessage {
   static DeleteViewParams? _defaultInstance;
 
   @$pb.TagNumber(1)
-  $core.String get viewId => $_getSZ(0);
-  @$pb.TagNumber(1)
-  set viewId($core.String v) { $_setString(0, v); }
-  @$pb.TagNumber(1)
-  $core.bool hasViewId() => $_has(0);
-  @$pb.TagNumber(1)
-  void clearViewId() => clearField(1);
+  $core.List<$core.String> get viewIds => $_getList(0);
 }
 

+ 4 - 4
app_flowy/packages/flowy_sdk/lib/protobuf/flowy-workspace/view_delete.pbjson.dart

@@ -12,19 +12,19 @@ import 'dart:typed_data' as $typed_data;
 const DeleteViewRequest$json = const {
   '1': 'DeleteViewRequest',
   '2': const [
-    const {'1': 'view_id', '3': 1, '4': 1, '5': 9, '10': 'viewId'},
+    const {'1': 'view_ids', '3': 1, '4': 3, '5': 9, '10': 'viewIds'},
   ],
 };
 
 /// Descriptor for `DeleteViewRequest`. Decode as a `google.protobuf.DescriptorProto`.
-final $typed_data.Uint8List deleteViewRequestDescriptor = $convert.base64Decode('ChFEZWxldGVWaWV3UmVxdWVzdBIXCgd2aWV3X2lkGAEgASgJUgZ2aWV3SWQ=');
+final $typed_data.Uint8List deleteViewRequestDescriptor = $convert.base64Decode('ChFEZWxldGVWaWV3UmVxdWVzdBIZCgh2aWV3X2lkcxgBIAMoCVIHdmlld0lkcw==');
 @$core.Deprecated('Use deleteViewParamsDescriptor instead')
 const DeleteViewParams$json = const {
   '1': 'DeleteViewParams',
   '2': const [
-    const {'1': 'view_id', '3': 1, '4': 1, '5': 9, '10': 'viewId'},
+    const {'1': 'view_ids', '3': 1, '4': 3, '5': 9, '10': 'viewIds'},
   ],
 };
 
 /// Descriptor for `DeleteViewParams`. Decode as a `google.protobuf.DescriptorProto`.
-final $typed_data.Uint8List deleteViewParamsDescriptor = $convert.base64Decode('ChBEZWxldGVWaWV3UGFyYW1zEhcKB3ZpZXdfaWQYASABKAlSBnZpZXdJZA==');
+final $typed_data.Uint8List deleteViewParamsDescriptor = $convert.base64Decode('ChBEZWxldGVWaWV3UGFyYW1zEhkKCHZpZXdfaWRzGAEgAygJUgd2aWV3SWRz');

+ 2 - 2
backend/src/service/view/router.rs

@@ -10,7 +10,7 @@ use flowy_workspace::protobuf::{CreateViewParams, DeleteViewParams, QueryViewPar
 use crate::service::{
     doc::doc::DocBiz,
     util::parse_from_payload,
-    view::{create_view, delete_view, read_view, update_view},
+    view::{create_view, delete_views, read_view, update_view},
 };
 use std::sync::Arc;
 
@@ -42,6 +42,6 @@ pub async fn update_handler(payload: Payload, pool: Data<PgPool>) -> Result<Http
 
 pub async fn delete_handler(payload: Payload, pool: Data<PgPool>) -> Result<HttpResponse, ServerError> {
     let params: DeleteViewParams = parse_from_payload(payload).await?;
-    let resp = delete_view(pool.get_ref(), &params.view_id).await?;
+    let resp = delete_views(pool.get_ref(), params.view_ids.into_vec()).await?;
     Ok(resp.into())
 }

+ 8 - 4
backend/src/service/view/sql_builder.rs

@@ -74,8 +74,12 @@ impl NewViewSqlBuilder {
     }
 }
 
-pub(crate) fn check_view_id(id: String) -> Result<Uuid, ServerError> {
-    let view_id = ViewId::parse(id).map_err(invalid_params)?;
-    let view_id = Uuid::parse_str(view_id.as_ref())?;
-    Ok(view_id)
+pub(crate) fn check_view_ids(ids: Vec<String>) -> Result<Vec<Uuid>, ServerError> {
+    let mut view_ids = vec![];
+    for id in ids {
+        let view_id = ViewId::parse(id).map_err(invalid_params)?;
+        let view_id = Uuid::parse_str(view_id.as_ref())?;
+        view_ids.push(view_id);
+    }
+    Ok(view_ids)
 }

+ 12 - 11
backend/src/service/view/view.rs

@@ -74,7 +74,7 @@ pub(crate) async fn read_view(
     params: QueryViewParams,
     _doc_biz: Data<Arc<DocBiz>>,
 ) -> Result<FlowyResponse, ServerError> {
-    let view_id = check_view_id(params.view_id)?;
+    let view_id = check_view_ids(vec![params.view_id])?.pop().unwrap();
     let mut transaction = pool
         .begin()
         .await
@@ -111,7 +111,7 @@ pub(crate) async fn read_view(
 }
 
 pub(crate) async fn update_view(pool: &PgPool, params: UpdateViewParams) -> Result<FlowyResponse, ServerError> {
-    let view_id = check_view_id(params.view_id.clone())?;
+    let view_id = check_view_ids(vec![params.view_id.clone()])?.pop().unwrap();
 
     let name = match params.has_name() {
         false => None,
@@ -159,21 +159,22 @@ pub(crate) async fn update_view(pool: &PgPool, params: UpdateViewParams) -> Resu
     Ok(FlowyResponse::success())
 }
 
-pub(crate) async fn delete_view(pool: &PgPool, view_id: &str) -> Result<FlowyResponse, ServerError> {
-    let view_id = check_view_id(view_id.to_owned())?;
+pub(crate) async fn delete_views(pool: &PgPool, view_ids: Vec<String>) -> Result<FlowyResponse, ServerError> {
+    let view_ids = check_view_ids(view_ids)?;
     let mut transaction = pool
         .begin()
         .await
         .context("Failed to acquire a Postgres connection to delete view")?;
 
-    let (sql, args) = SqlBuilder::delete(VIEW_TABLE).and_where_eq("id", &view_id).build()?;
+    for view_id in view_ids {
+        let (sql, args) = SqlBuilder::delete(VIEW_TABLE).and_where_eq("id", &view_id).build()?;
+        let _ = sqlx::query_with(&sql, args)
+            .execute(&mut transaction)
+            .await
+            .map_err(map_sqlx_error)?;
 
-    let _ = sqlx::query_with(&sql, args)
-        .execute(&mut transaction)
-        .await
-        .map_err(map_sqlx_error)?;
-
-    let _ = delete_doc(&mut transaction, view_id).await?;
+        let _ = delete_doc(&mut transaction, view_id).await?;
+    }
 
     transaction
         .commit()

+ 1 - 1
backend/tests/api/doc.rs

@@ -18,7 +18,7 @@ async fn doc_read() {
 async fn doc_delete() {
     let test = ViewTest::new().await;
     let delete_params = DeleteViewParams {
-        view_id: test.view.id.clone(),
+        view_ids: vec![test.view.id.clone()],
     };
     test.server.delete_view(delete_params).await;
 

+ 1 - 1
backend/tests/api/workspace.rs

@@ -157,7 +157,7 @@ async fn view_delete() {
     let test = ViewTest::new().await;
     // delete
     let delete_params = DeleteViewParams {
-        view_id: test.view.id.clone(),
+        view_ids: vec![test.view.id.clone()],
     };
     test.server.delete_view(delete_params).await;
 

+ 4 - 0
rust-lib/flowy-document/src/entities/doc/doc.rs

@@ -80,3 +80,7 @@ pub struct QueryDocParams {
     #[pb(index = 1)]
     pub doc_id: String,
 }
+
+impl std::convert::From<String> for QueryDocParams {
+    fn from(doc_id: String) -> Self { QueryDocParams { doc_id } }
+}

+ 1 - 1
rust-lib/flowy-workspace/src/entities/trash/trash_create.rs

@@ -1,4 +1,4 @@
-use crate::{errors::WorkspaceError, impl_def_and_def_mut};
+use crate::{impl_def_and_def_mut};
 use flowy_derive::ProtoBuf;
 use std::convert::TryInto;
 

+ 12 - 11
rust-lib/flowy-workspace/src/entities/view/view_delete.rs

@@ -1,32 +1,33 @@
 use crate::{entities::view::parser::ViewId, errors::WorkspaceError};
 use flowy_derive::ProtoBuf;
-use flowy_document::entities::doc::QueryDocParams;
+
 use std::convert::TryInto;
 
 #[derive(Default, ProtoBuf)]
 pub struct DeleteViewRequest {
     #[pb(index = 1)]
-    view_id: String,
+    view_ids: Vec<String>,
 }
 
 #[derive(Default, ProtoBuf)]
 pub struct DeleteViewParams {
     #[pb(index = 1)]
-    pub view_id: String,
+    pub view_ids: Vec<String>,
 }
 
 impl TryInto<DeleteViewParams> for DeleteViewRequest {
     type Error = WorkspaceError;
 
     fn try_into(self) -> Result<DeleteViewParams, Self::Error> {
-        let view_id = ViewId::parse(self.view_id)
-            .map_err(|e| WorkspaceError::view_id().context(e))?
-            .0;
+        let mut view_ids = vec![];
+        for view_id in self.view_ids {
+            let view_id = ViewId::parse(view_id)
+                .map_err(|e| WorkspaceError::view_id().context(e))?
+                .0;
 
-        Ok(DeleteViewParams { view_id })
-    }
-}
+            view_ids.push(view_id);
+        }
 
-impl std::convert::Into<QueryDocParams> for DeleteViewParams {
-    fn into(self) -> QueryDocParams { QueryDocParams { doc_id: self.view_id } }
+        Ok(DeleteViewParams { view_ids })
+    }
 }

+ 1 - 2
rust-lib/flowy-workspace/src/handlers/trash_handler.rs

@@ -1,13 +1,12 @@
 use crate::{
     entities::{
         trash::{RepeatedTrash, TrashIdentifier},
-        view::RepeatedView,
     },
     errors::WorkspaceError,
     services::TrashCan,
 };
 use flowy_dispatch::prelude::{data_result, Data, DataResult, Unit};
-use std::{convert::TryInto, sync::Arc};
+use std::{sync::Arc};
 
 #[tracing::instrument(skip(controller), err)]
 pub(crate) async fn read_trash_handler(controller: Unit<Arc<TrashCan>>) -> DataResult<RepeatedTrash, WorkspaceError> {

+ 61 - 62
rust-lib/flowy-workspace/src/protobuf/model/view_delete.rs

@@ -26,7 +26,7 @@
 #[derive(PartialEq,Clone,Default)]
 pub struct DeleteViewRequest {
     // message fields
-    pub view_id: ::std::string::String,
+    pub view_ids: ::protobuf::RepeatedField<::std::string::String>,
     // special fields
     pub unknown_fields: ::protobuf::UnknownFields,
     pub cached_size: ::protobuf::CachedSize,
@@ -43,30 +43,29 @@ impl DeleteViewRequest {
         ::std::default::Default::default()
     }
 
-    // string view_id = 1;
+    // repeated string view_ids = 1;
 
 
-    pub fn get_view_id(&self) -> &str {
-        &self.view_id
+    pub fn get_view_ids(&self) -> &[::std::string::String] {
+        &self.view_ids
     }
-    pub fn clear_view_id(&mut self) {
-        self.view_id.clear();
+    pub fn clear_view_ids(&mut self) {
+        self.view_ids.clear();
     }
 
     // Param is passed by value, moved
-    pub fn set_view_id(&mut self, v: ::std::string::String) {
-        self.view_id = v;
+    pub fn set_view_ids(&mut self, v: ::protobuf::RepeatedField<::std::string::String>) {
+        self.view_ids = v;
     }
 
     // Mutable pointer to the field.
-    // If field is not initialized, it is initialized with default value first.
-    pub fn mut_view_id(&mut self) -> &mut ::std::string::String {
-        &mut self.view_id
+    pub fn mut_view_ids(&mut self) -> &mut ::protobuf::RepeatedField<::std::string::String> {
+        &mut self.view_ids
     }
 
     // Take field
-    pub fn take_view_id(&mut self) -> ::std::string::String {
-        ::std::mem::replace(&mut self.view_id, ::std::string::String::new())
+    pub fn take_view_ids(&mut self) -> ::protobuf::RepeatedField<::std::string::String> {
+        ::std::mem::replace(&mut self.view_ids, ::protobuf::RepeatedField::new())
     }
 }
 
@@ -80,7 +79,7 @@ impl ::protobuf::Message for DeleteViewRequest {
             let (field_number, wire_type) = is.read_tag_unpack()?;
             match field_number {
                 1 => {
-                    ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.view_id)?;
+                    ::protobuf::rt::read_repeated_string_into(wire_type, is, &mut self.view_ids)?;
                 },
                 _ => {
                     ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?;
@@ -94,18 +93,18 @@ impl ::protobuf::Message for DeleteViewRequest {
     #[allow(unused_variables)]
     fn compute_size(&self) -> u32 {
         let mut my_size = 0;
-        if !self.view_id.is_empty() {
-            my_size += ::protobuf::rt::string_size(1, &self.view_id);
-        }
+        for value in &self.view_ids {
+            my_size += ::protobuf::rt::string_size(1, &value);
+        };
         my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields());
         self.cached_size.set(my_size);
         my_size
     }
 
     fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> {
-        if !self.view_id.is_empty() {
-            os.write_string(1, &self.view_id)?;
-        }
+        for v in &self.view_ids {
+            os.write_string(1, &v)?;
+        };
         os.write_unknown_fields(self.get_unknown_fields())?;
         ::std::result::Result::Ok(())
     }
@@ -144,10 +143,10 @@ impl ::protobuf::Message for DeleteViewRequest {
         static descriptor: ::protobuf::rt::LazyV2<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::LazyV2::INIT;
         descriptor.get(|| {
             let mut fields = ::std::vec::Vec::new();
-            fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>(
-                "view_id",
-                |m: &DeleteViewRequest| { &m.view_id },
-                |m: &mut DeleteViewRequest| { &mut m.view_id },
+            fields.push(::protobuf::reflect::accessor::make_repeated_field_accessor::<_, ::protobuf::types::ProtobufTypeString>(
+                "view_ids",
+                |m: &DeleteViewRequest| { &m.view_ids },
+                |m: &mut DeleteViewRequest| { &mut m.view_ids },
             ));
             ::protobuf::reflect::MessageDescriptor::new_pb_name::<DeleteViewRequest>(
                 "DeleteViewRequest",
@@ -165,7 +164,7 @@ impl ::protobuf::Message for DeleteViewRequest {
 
 impl ::protobuf::Clear for DeleteViewRequest {
     fn clear(&mut self) {
-        self.view_id.clear();
+        self.view_ids.clear();
         self.unknown_fields.clear();
     }
 }
@@ -185,7 +184,7 @@ impl ::protobuf::reflect::ProtobufValue for DeleteViewRequest {
 #[derive(PartialEq,Clone,Default)]
 pub struct DeleteViewParams {
     // message fields
-    pub view_id: ::std::string::String,
+    pub view_ids: ::protobuf::RepeatedField<::std::string::String>,
     // special fields
     pub unknown_fields: ::protobuf::UnknownFields,
     pub cached_size: ::protobuf::CachedSize,
@@ -202,30 +201,29 @@ impl DeleteViewParams {
         ::std::default::Default::default()
     }
 
-    // string view_id = 1;
+    // repeated string view_ids = 1;
 
 
-    pub fn get_view_id(&self) -> &str {
-        &self.view_id
+    pub fn get_view_ids(&self) -> &[::std::string::String] {
+        &self.view_ids
     }
-    pub fn clear_view_id(&mut self) {
-        self.view_id.clear();
+    pub fn clear_view_ids(&mut self) {
+        self.view_ids.clear();
     }
 
     // Param is passed by value, moved
-    pub fn set_view_id(&mut self, v: ::std::string::String) {
-        self.view_id = v;
+    pub fn set_view_ids(&mut self, v: ::protobuf::RepeatedField<::std::string::String>) {
+        self.view_ids = v;
     }
 
     // Mutable pointer to the field.
-    // If field is not initialized, it is initialized with default value first.
-    pub fn mut_view_id(&mut self) -> &mut ::std::string::String {
-        &mut self.view_id
+    pub fn mut_view_ids(&mut self) -> &mut ::protobuf::RepeatedField<::std::string::String> {
+        &mut self.view_ids
     }
 
     // Take field
-    pub fn take_view_id(&mut self) -> ::std::string::String {
-        ::std::mem::replace(&mut self.view_id, ::std::string::String::new())
+    pub fn take_view_ids(&mut self) -> ::protobuf::RepeatedField<::std::string::String> {
+        ::std::mem::replace(&mut self.view_ids, ::protobuf::RepeatedField::new())
     }
 }
 
@@ -239,7 +237,7 @@ impl ::protobuf::Message for DeleteViewParams {
             let (field_number, wire_type) = is.read_tag_unpack()?;
             match field_number {
                 1 => {
-                    ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.view_id)?;
+                    ::protobuf::rt::read_repeated_string_into(wire_type, is, &mut self.view_ids)?;
                 },
                 _ => {
                     ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?;
@@ -253,18 +251,18 @@ impl ::protobuf::Message for DeleteViewParams {
     #[allow(unused_variables)]
     fn compute_size(&self) -> u32 {
         let mut my_size = 0;
-        if !self.view_id.is_empty() {
-            my_size += ::protobuf::rt::string_size(1, &self.view_id);
-        }
+        for value in &self.view_ids {
+            my_size += ::protobuf::rt::string_size(1, &value);
+        };
         my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields());
         self.cached_size.set(my_size);
         my_size
     }
 
     fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> {
-        if !self.view_id.is_empty() {
-            os.write_string(1, &self.view_id)?;
-        }
+        for v in &self.view_ids {
+            os.write_string(1, &v)?;
+        };
         os.write_unknown_fields(self.get_unknown_fields())?;
         ::std::result::Result::Ok(())
     }
@@ -303,10 +301,10 @@ impl ::protobuf::Message for DeleteViewParams {
         static descriptor: ::protobuf::rt::LazyV2<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::LazyV2::INIT;
         descriptor.get(|| {
             let mut fields = ::std::vec::Vec::new();
-            fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>(
-                "view_id",
-                |m: &DeleteViewParams| { &m.view_id },
-                |m: &mut DeleteViewParams| { &mut m.view_id },
+            fields.push(::protobuf::reflect::accessor::make_repeated_field_accessor::<_, ::protobuf::types::ProtobufTypeString>(
+                "view_ids",
+                |m: &DeleteViewParams| { &m.view_ids },
+                |m: &mut DeleteViewParams| { &mut m.view_ids },
             ));
             ::protobuf::reflect::MessageDescriptor::new_pb_name::<DeleteViewParams>(
                 "DeleteViewParams",
@@ -324,7 +322,7 @@ impl ::protobuf::Message for DeleteViewParams {
 
 impl ::protobuf::Clear for DeleteViewParams {
     fn clear(&mut self) {
-        self.view_id.clear();
+        self.view_ids.clear();
         self.unknown_fields.clear();
     }
 }
@@ -342,18 +340,19 @@ impl ::protobuf::reflect::ProtobufValue for DeleteViewParams {
 }
 
 static file_descriptor_proto_data: &'static [u8] = b"\
-    \n\x11view_delete.proto\",\n\x11DeleteViewRequest\x12\x17\n\x07view_id\
-    \x18\x01\x20\x01(\tR\x06viewId\"+\n\x10DeleteViewParams\x12\x17\n\x07vie\
-    w_id\x18\x01\x20\x01(\tR\x06viewIdJ\xb0\x01\n\x06\x12\x04\0\0\x07\x01\n\
-    \x08\n\x01\x0c\x12\x03\0\0\x12\n\n\n\x02\x04\0\x12\x04\x02\0\x04\x01\n\n\
-    \n\x03\x04\0\x01\x12\x03\x02\x08\x19\n\x0b\n\x04\x04\0\x02\0\x12\x03\x03\
-    \x04\x17\n\x0c\n\x05\x04\0\x02\0\x05\x12\x03\x03\x04\n\n\x0c\n\x05\x04\0\
-    \x02\0\x01\x12\x03\x03\x0b\x12\n\x0c\n\x05\x04\0\x02\0\x03\x12\x03\x03\
-    \x15\x16\n\n\n\x02\x04\x01\x12\x04\x05\0\x07\x01\n\n\n\x03\x04\x01\x01\
-    \x12\x03\x05\x08\x18\n\x0b\n\x04\x04\x01\x02\0\x12\x03\x06\x04\x17\n\x0c\
-    \n\x05\x04\x01\x02\0\x05\x12\x03\x06\x04\n\n\x0c\n\x05\x04\x01\x02\0\x01\
-    \x12\x03\x06\x0b\x12\n\x0c\n\x05\x04\x01\x02\0\x03\x12\x03\x06\x15\x16b\
-    \x06proto3\
+    \n\x11view_delete.proto\".\n\x11DeleteViewRequest\x12\x19\n\x08view_ids\
+    \x18\x01\x20\x03(\tR\x07viewIds\"-\n\x10DeleteViewParams\x12\x19\n\x08vi\
+    ew_ids\x18\x01\x20\x03(\tR\x07viewIdsJ\xcc\x01\n\x06\x12\x04\0\0\x07\x01\
+    \n\x08\n\x01\x0c\x12\x03\0\0\x12\n\n\n\x02\x04\0\x12\x04\x02\0\x04\x01\n\
+    \n\n\x03\x04\0\x01\x12\x03\x02\x08\x19\n\x0b\n\x04\x04\0\x02\0\x12\x03\
+    \x03\x04!\n\x0c\n\x05\x04\0\x02\0\x04\x12\x03\x03\x04\x0c\n\x0c\n\x05\
+    \x04\0\x02\0\x05\x12\x03\x03\r\x13\n\x0c\n\x05\x04\0\x02\0\x01\x12\x03\
+    \x03\x14\x1c\n\x0c\n\x05\x04\0\x02\0\x03\x12\x03\x03\x1f\x20\n\n\n\x02\
+    \x04\x01\x12\x04\x05\0\x07\x01\n\n\n\x03\x04\x01\x01\x12\x03\x05\x08\x18\
+    \n\x0b\n\x04\x04\x01\x02\0\x12\x03\x06\x04!\n\x0c\n\x05\x04\x01\x02\0\
+    \x04\x12\x03\x06\x04\x0c\n\x0c\n\x05\x04\x01\x02\0\x05\x12\x03\x06\r\x13\
+    \n\x0c\n\x05\x04\x01\x02\0\x01\x12\x03\x06\x14\x1c\n\x0c\n\x05\x04\x01\
+    \x02\0\x03\x12\x03\x06\x1f\x20b\x06proto3\
 ";
 
 static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT;

+ 2 - 2
rust-lib/flowy-workspace/src/protobuf/proto/view_delete.proto

@@ -1,8 +1,8 @@
 syntax = "proto3";
 
 message DeleteViewRequest {
-    string view_id = 1;
+    repeated string view_ids = 1;
 }
 message DeleteViewParams {
-    string view_id = 1;
+    repeated string view_ids = 1;
 }

+ 2 - 2
rust-lib/flowy-workspace/src/services/trash_can.rs

@@ -6,8 +6,8 @@ use crate::{
     sql_tables::trash::{TrashSource, TrashTable, TrashTableSql},
 };
 use flowy_database::SqliteConnection;
-use parking_lot::RwLock;
-use std::{collections::HashSet, sync::Arc};
+
+use std::{sync::Arc};
 use tokio::sync::{broadcast, mpsc};
 
 #[derive(Clone)]

+ 13 - 14
rust-lib/flowy-workspace/src/services/view_controller.rs

@@ -9,7 +9,6 @@ use crate::{
 
 use crate::{
     entities::{
-        trash::Trash,
         view::{DeleteViewParams, QueryViewParams, RepeatedView},
     },
     errors::internal_error,
@@ -25,9 +24,9 @@ use flowy_document::{
 };
 
 use crate::errors::WorkspaceResult;
-use futures::{future, FutureExt, StreamExt, TryStreamExt};
+use futures::{FutureExt, StreamExt, TryStreamExt};
 use std::sync::Arc;
-use tokio::sync::broadcast::error::RecvError;
+
 
 pub(crate) struct ViewController {
     user: Arc<dyn WorkspaceUser>,
@@ -102,17 +101,19 @@ impl ViewController {
     #[tracing::instrument(level = "debug", skip(self, params), err)]
     pub(crate) async fn delete_view(&self, params: DeleteViewParams) -> Result<(), WorkspaceError> {
         let conn = &*self.database.db_connection()?;
-        let _ = self.delete_view_on_server(&params.view_id);
+        let _ = self.delete_view_on_server(params.view_ids.clone());
 
         conn.immediate_transaction::<_, WorkspaceError, _>(|| {
-            let view_table = ViewTableSql::delete_view(&params.view_id, conn)?;
-            let _ = self.document.delete(params.into())?;
+            for view_id in params.view_ids {
+                let view_table = ViewTableSql::delete_view(&view_id, conn)?;
+                let _ = self.document.delete(view_id.into())?;
 
-            let repeated_view = ViewTableSql::read_views(&view_table.belong_to_id, conn)?;
+                let repeated_view = ViewTableSql::read_views(&view_table.belong_to_id, conn)?;
 
-            send_dart_notification(&view_table.belong_to_id, WorkspaceNotification::AppViewsChanged)
-                .payload(repeated_view)
-                .send();
+                send_dart_notification(&view_table.belong_to_id, WorkspaceNotification::AppViewsChanged)
+                    .payload(repeated_view)
+                    .send();
+            }
             Ok(())
         })?;
 
@@ -189,12 +190,10 @@ impl ViewController {
     }
 
     #[tracing::instrument(skip(self), err)]
-    fn delete_view_on_server(&self, view_id: &str) -> Result<(), WorkspaceError> {
+    fn delete_view_on_server(&self, view_ids: Vec<String>) -> Result<(), WorkspaceError> {
         let token = self.user.token()?;
         let server = self.server.clone();
-        let params = DeleteViewParams {
-            view_id: view_id.to_string(),
-        };
+        let params = DeleteViewParams { view_ids };
         spawn(async move {
             match server.delete_view(&token, params).await {
                 Ok(_) => {},

+ 1 - 1
rust-lib/flowy-workspace/src/sql_tables/trash/trash_table.rs

@@ -1,5 +1,5 @@
 use crate::entities::trash::Trash;
-use diesel::sql_types::{Binary, Integer};
+use diesel::sql_types::{Integer};
 use flowy_database::schema::trash_table;
 
 #[derive(PartialEq, Clone, Debug, Queryable, Identifiable, Insertable, Associations)]

+ 3 - 3
rust-lib/flowy-workspace/src/sql_tables/view/view_sql.rs

@@ -5,7 +5,7 @@ use crate::{
 };
 use flowy_database::{
     prelude::*,
-    schema::{trash_table, trash_table::dsl::id as trash_id, view_table, view_table::dsl},
+    schema::{trash_table, view_table, view_table::dsl},
     SqliteConnection,
 };
 
@@ -36,7 +36,7 @@ impl ViewTableSql {
             .first::<ViewTable>(conn)?;
 
         let repeated_trash: Vec<String> = trash_table::dsl::trash_table
-            .select((trash_table::dsl::id))
+            .select(trash_table::dsl::id)
             .load(conn)?;
 
         if repeated_trash.contains(&view_table.id) {
@@ -54,7 +54,7 @@ impl ViewTableSql {
             .load::<ViewTable>(conn)?;
 
         let repeated_trash: Vec<String> = trash_table::dsl::trash_table
-            .select((trash_table::dsl::id))
+            .select(trash_table::dsl::id)
             .load(conn)?;
 
         view_tables = view_tables