Browse Source

[rust]:delete app from trash

appflowy 3 năm trước cách đây
mục cha
commit
5d0ef5baf3

+ 2 - 2
app_flowy/lib/workspace/application/trash/trash_bloc.dart

@@ -31,7 +31,7 @@ class TrashBloc extends Bloc<TrashEvent, TrashState> {
         yield* _handleResult(result);
       },
       delete: (e) async* {
-        final result = await trasnManager.deleteViews([e.trashId]);
+        final result = await trasnManager.deleteViews([e.trash]);
         yield* _handleResult(result);
       },
       deleteAll: (e) async* {
@@ -75,7 +75,7 @@ class TrashEvent with _$TrashEvent {
   const factory TrashEvent.initial() = Initial;
   const factory TrashEvent.didReceiveTrash(List<Trash> trash) = ReceiveTrash;
   const factory TrashEvent.putback(String trashId) = Putback;
-  const factory TrashEvent.delete(String trashId) = Delete;
+  const factory TrashEvent.delete(Trash trash) = Delete;
   const factory TrashEvent.restoreAll() = RestoreAll;
   const factory TrashEvent.deleteAll() = DeleteAll;
 }

+ 32 - 32
app_flowy/lib/workspace/application/trash/trash_bloc.freezed.dart

@@ -32,9 +32,9 @@ class _$TrashEventTearOff {
     );
   }
 
-  Delete delete(String trashId) {
+  Delete delete(Trash trash) {
     return Delete(
-      trashId,
+      trash,
     );
   }
 
@@ -57,7 +57,7 @@ mixin _$TrashEvent {
     required TResult Function() initial,
     required TResult Function(List<Trash> trash) didReceiveTrash,
     required TResult Function(String trashId) putback,
-    required TResult Function(String trashId) delete,
+    required TResult Function(Trash trash) delete,
     required TResult Function() restoreAll,
     required TResult Function() deleteAll,
   }) =>
@@ -67,7 +67,7 @@ mixin _$TrashEvent {
     TResult Function()? initial,
     TResult Function(List<Trash> trash)? didReceiveTrash,
     TResult Function(String trashId)? putback,
-    TResult Function(String trashId)? delete,
+    TResult Function(Trash trash)? delete,
     TResult Function()? restoreAll,
     TResult Function()? deleteAll,
     required TResult orElse(),
@@ -152,7 +152,7 @@ class _$Initial implements Initial {
     required TResult Function() initial,
     required TResult Function(List<Trash> trash) didReceiveTrash,
     required TResult Function(String trashId) putback,
-    required TResult Function(String trashId) delete,
+    required TResult Function(Trash trash) delete,
     required TResult Function() restoreAll,
     required TResult Function() deleteAll,
   }) {
@@ -165,7 +165,7 @@ class _$Initial implements Initial {
     TResult Function()? initial,
     TResult Function(List<Trash> trash)? didReceiveTrash,
     TResult Function(String trashId)? putback,
-    TResult Function(String trashId)? delete,
+    TResult Function(Trash trash)? delete,
     TResult Function()? restoreAll,
     TResult Function()? deleteAll,
     required TResult orElse(),
@@ -278,7 +278,7 @@ class _$ReceiveTrash implements ReceiveTrash {
     required TResult Function() initial,
     required TResult Function(List<Trash> trash) didReceiveTrash,
     required TResult Function(String trashId) putback,
-    required TResult Function(String trashId) delete,
+    required TResult Function(Trash trash) delete,
     required TResult Function() restoreAll,
     required TResult Function() deleteAll,
   }) {
@@ -291,7 +291,7 @@ class _$ReceiveTrash implements ReceiveTrash {
     TResult Function()? initial,
     TResult Function(List<Trash> trash)? didReceiveTrash,
     TResult Function(String trashId)? putback,
-    TResult Function(String trashId)? delete,
+    TResult Function(Trash trash)? delete,
     TResult Function()? restoreAll,
     TResult Function()? deleteAll,
     required TResult orElse(),
@@ -407,7 +407,7 @@ class _$Putback implements Putback {
     required TResult Function() initial,
     required TResult Function(List<Trash> trash) didReceiveTrash,
     required TResult Function(String trashId) putback,
-    required TResult Function(String trashId) delete,
+    required TResult Function(Trash trash) delete,
     required TResult Function() restoreAll,
     required TResult Function() deleteAll,
   }) {
@@ -420,7 +420,7 @@ class _$Putback implements Putback {
     TResult Function()? initial,
     TResult Function(List<Trash> trash)? didReceiveTrash,
     TResult Function(String trashId)? putback,
-    TResult Function(String trashId)? delete,
+    TResult Function(Trash trash)? delete,
     TResult Function()? restoreAll,
     TResult Function()? deleteAll,
     required TResult orElse(),
@@ -474,7 +474,7 @@ abstract class Putback implements TrashEvent {
 abstract class $DeleteCopyWith<$Res> {
   factory $DeleteCopyWith(Delete value, $Res Function(Delete) then) =
       _$DeleteCopyWithImpl<$Res>;
-  $Res call({String trashId});
+  $Res call({Trash trash});
 }
 
 /// @nodoc
@@ -488,13 +488,13 @@ class _$DeleteCopyWithImpl<$Res> extends _$TrashEventCopyWithImpl<$Res>
 
   @override
   $Res call({
-    Object? trashId = freezed,
+    Object? trash = freezed,
   }) {
     return _then(Delete(
-      trashId == freezed
-          ? _value.trashId
-          : trashId // ignore: cast_nullable_to_non_nullable
-              as String,
+      trash == freezed
+          ? _value.trash
+          : trash // ignore: cast_nullable_to_non_nullable
+              as Trash,
     ));
   }
 }
@@ -502,27 +502,27 @@ class _$DeleteCopyWithImpl<$Res> extends _$TrashEventCopyWithImpl<$Res>
 /// @nodoc
 
 class _$Delete implements Delete {
-  const _$Delete(this.trashId);
+  const _$Delete(this.trash);
 
   @override
-  final String trashId;
+  final Trash trash;
 
   @override
   String toString() {
-    return 'TrashEvent.delete(trashId: $trashId)';
+    return 'TrashEvent.delete(trash: $trash)';
   }
 
   @override
   bool operator ==(dynamic other) {
     return identical(this, other) ||
         (other is Delete &&
-            (identical(other.trashId, trashId) ||
-                const DeepCollectionEquality().equals(other.trashId, trashId)));
+            (identical(other.trash, trash) ||
+                const DeepCollectionEquality().equals(other.trash, trash)));
   }
 
   @override
   int get hashCode =>
-      runtimeType.hashCode ^ const DeepCollectionEquality().hash(trashId);
+      runtimeType.hashCode ^ const DeepCollectionEquality().hash(trash);
 
   @JsonKey(ignore: true)
   @override
@@ -535,11 +535,11 @@ class _$Delete implements Delete {
     required TResult Function() initial,
     required TResult Function(List<Trash> trash) didReceiveTrash,
     required TResult Function(String trashId) putback,
-    required TResult Function(String trashId) delete,
+    required TResult Function(Trash trash) delete,
     required TResult Function() restoreAll,
     required TResult Function() deleteAll,
   }) {
-    return delete(trashId);
+    return delete(trash);
   }
 
   @override
@@ -548,13 +548,13 @@ class _$Delete implements Delete {
     TResult Function()? initial,
     TResult Function(List<Trash> trash)? didReceiveTrash,
     TResult Function(String trashId)? putback,
-    TResult Function(String trashId)? delete,
+    TResult Function(Trash trash)? delete,
     TResult Function()? restoreAll,
     TResult Function()? deleteAll,
     required TResult orElse(),
   }) {
     if (delete != null) {
-      return delete(trashId);
+      return delete(trash);
     }
     return orElse();
   }
@@ -591,9 +591,9 @@ class _$Delete implements Delete {
 }
 
 abstract class Delete implements TrashEvent {
-  const factory Delete(String trashId) = _$Delete;
+  const factory Delete(Trash trash) = _$Delete;
 
-  String get trashId => throw _privateConstructorUsedError;
+  Trash get trash => throw _privateConstructorUsedError;
   @JsonKey(ignore: true)
   $DeleteCopyWith<Delete> get copyWith => throw _privateConstructorUsedError;
 }
@@ -639,7 +639,7 @@ class _$RestoreAll implements RestoreAll {
     required TResult Function() initial,
     required TResult Function(List<Trash> trash) didReceiveTrash,
     required TResult Function(String trashId) putback,
-    required TResult Function(String trashId) delete,
+    required TResult Function(Trash trash) delete,
     required TResult Function() restoreAll,
     required TResult Function() deleteAll,
   }) {
@@ -652,7 +652,7 @@ class _$RestoreAll implements RestoreAll {
     TResult Function()? initial,
     TResult Function(List<Trash> trash)? didReceiveTrash,
     TResult Function(String trashId)? putback,
-    TResult Function(String trashId)? delete,
+    TResult Function(Trash trash)? delete,
     TResult Function()? restoreAll,
     TResult Function()? deleteAll,
     required TResult orElse(),
@@ -738,7 +738,7 @@ class _$DeleteAll implements DeleteAll {
     required TResult Function() initial,
     required TResult Function(List<Trash> trash) didReceiveTrash,
     required TResult Function(String trashId) putback,
-    required TResult Function(String trashId) delete,
+    required TResult Function(Trash trash) delete,
     required TResult Function() restoreAll,
     required TResult Function() deleteAll,
   }) {
@@ -751,7 +751,7 @@ class _$DeleteAll implements DeleteAll {
     TResult Function()? initial,
     TResult Function(List<Trash> trash)? didReceiveTrash,
     TResult Function(String trashId)? putback,
-    TResult Function(String trashId)? delete,
+    TResult Function(Trash trash)? delete,
     TResult Function()? restoreAll,
     TResult Function()? deleteAll,
     required TResult orElse(),

+ 1 - 1
app_flowy/lib/workspace/domain/i_trash.dart

@@ -8,7 +8,7 @@ abstract class ITrash {
 
   Future<Either<Unit, WorkspaceError>> putback(String trashId);
 
-  Future<Either<Unit, WorkspaceError>> deleteViews(List<String> trashIds);
+  Future<Either<Unit, WorkspaceError>> deleteViews(List<Trash> trashList);
 
   Future<Either<Unit, WorkspaceError>> restoreAll();
 

+ 2 - 2
app_flowy/lib/workspace/infrastructure/i_trash_impl.dart

@@ -25,8 +25,8 @@ class ITrashImpl implements ITrash {
   }
 
   @override
-  Future<Either<Unit, WorkspaceError>> deleteViews(List<String> trashIds) {
-    return repo.deleteViews(trashIds);
+  Future<Either<Unit, WorkspaceError>> deleteViews(List<Trash> trashList) {
+    return repo.deleteViews(trashList);
   }
 
   @override

+ 1 - 1
app_flowy/lib/workspace/infrastructure/i_workspace_impl.dart

@@ -36,7 +36,7 @@ class IWorkspaceListenerImpl extends IWorkspaceListener {
 
   @override
   void start({WorkspaceAppsChangedCallback? addAppCallback, WorkspaceUpdatedCallback? updatedCallback}) {
-    repo.startListening(createApp: addAppCallback, update: updatedCallback);
+    repo.startListening(appsChanged: addAppCallback, update: updatedCallback);
   }
 
   @override

+ 7 - 5
app_flowy/lib/workspace/infrastructure/repos/trash_repo.dart

@@ -21,12 +21,14 @@ class TrashRepo {
     return WorkspaceEventPutbackTrash(id).send();
   }
 
-  Future<Either<Unit, WorkspaceError>> deleteViews(List<String> viewIds) {
-    final trashIdentifiers = TrashIdentifiers(
-        items: viewIds.map((id) => TrashIdentifier.create()
-          ..id = id
-          ..ty = TrashType.View));
+  Future<Either<Unit, WorkspaceError>> deleteViews(List<Trash> trashList) {
+    final items = trashList.map((trash) {
+      return TrashIdentifier.create()
+        ..id = trash.id
+        ..ty = trash.ty;
+    });
 
+    final trashIdentifiers = TrashIdentifiers(items: items);
     return WorkspaceEventDeleteTrash(trashIdentifiers).send();
   }
 

+ 1 - 1
app_flowy/lib/workspace/presentation/stack_page/trash/trash_page.dart

@@ -160,7 +160,7 @@ class _TrashStackPageState extends State<TrashStackPage> {
               onRestore: () {
                 context.read<TrashBloc>().add(TrashEvent.putback(object.id));
               },
-              onDelete: () => context.read<TrashBloc>().add(TrashEvent.delete(object.id)),
+              onDelete: () => context.read<TrashBloc>().add(TrashEvent.delete(object)),
             ),
           );
         },

+ 1 - 0
backend/src/service/app/app.rs

@@ -101,6 +101,7 @@ pub(crate) async fn update_app(
     Ok(())
 }
 
+#[tracing::instrument(skip(transaction), err)]
 pub(crate) async fn delete_app(transaction: &mut DBTransaction<'_>, app_id: Uuid) -> Result<(), ServerError> {
     let (sql, args) = SqlBuilder::delete(APP_TABLE).and_where_eq("id", app_id).build()?;
     let _ = sqlx::query_with(&sql, args)

+ 1 - 1
backend/src/service/trash/router.rs

@@ -59,7 +59,7 @@ pub async fn delete_handler(
         let _ = delete_all_trash(&mut transaction, &logged_user).await?;
     } else {
         let records = make_records(params)?;
-        let _ = delete_trash(&mut transaction, records, &logged_user).await?;
+        let _ = delete_trash(&mut transaction, records).await?;
     }
 
     transaction

+ 4 - 1
backend/src/service/trash/trash.rs

@@ -13,6 +13,7 @@ use flowy_workspace::protobuf::{RepeatedTrash, Trash, TrashType};
 use sqlx::{postgres::PgArguments, Postgres, Row};
 use uuid::Uuid;
 
+#[tracing::instrument(skip(transaction, user), err)]
 pub(crate) async fn create_trash(
     transaction: &mut DBTransaction<'_>,
     records: Vec<(Uuid, i32)>,
@@ -66,10 +67,10 @@ pub(crate) async fn delete_all_trash(
     Ok(())
 }
 
+#[tracing::instrument(skip(transaction), err)]
 pub(crate) async fn delete_trash(
     transaction: &mut DBTransaction<'_>,
     records: Vec<(Uuid, i32)>,
-    _user: &LoggedUser,
 ) -> Result<(), ServerError> {
     for (trash_id, _) in records {
         // Read the trash_table and delete the original table according to the TrashType
@@ -99,6 +100,7 @@ pub(crate) async fn delete_trash(
     Ok(())
 }
 
+#[tracing::instrument(skip(transaction, targets), err)]
 async fn delete_trash_targets(
     transaction: &mut DBTransaction<'_>,
     targets: Vec<(Uuid, i32)>,
@@ -134,6 +136,7 @@ pub(crate) async fn read_trash_ids(
     Ok(ids)
 }
 
+#[tracing::instrument(skip(transaction, user), err)]
 pub(crate) async fn read_trash(
     transaction: &mut DBTransaction<'_>,
     user: &LoggedUser,

+ 1 - 0
backend/src/service/view/view.rs

@@ -44,6 +44,7 @@ pub(crate) async fn update_view(
     Ok(())
 }
 
+#[tracing::instrument(skip(transaction), err)]
 pub(crate) async fn delete_view(transaction: &mut DBTransaction<'_>, view_ids: Vec<Uuid>) -> Result<(), ServerError> {
     for view_id in view_ids {
         let (sql, args) = SqlBuilder::delete(VIEW_TABLE).and_where_eq("id", &view_id).build()?;

+ 3 - 1
backend/src/service/workspace/workspace.rs

@@ -66,6 +66,7 @@ pub(crate) async fn delete_workspace(
     Ok(())
 }
 
+#[tracing::instrument(skip(transaction, logged_user), err)]
 pub async fn read_workspaces(
     transaction: &mut DBTransaction<'_>,
     workspace_id: Option<String>,
@@ -109,7 +110,7 @@ pub async fn read_workspaces(
     Ok(repeated_workspace)
 }
 
-// transaction must be commit from caller
+#[tracing::instrument(skip(transaction, user), fields(app_count), err)]
 async fn read_workspace_apps<'c>(
     user: &LoggedUser,
     transaction: &mut DBTransaction<'_>,
@@ -126,6 +127,7 @@ async fn read_workspace_apps<'c>(
         .await
         .map_err(map_sqlx_error)?;
 
+    tracing::Span::current().record("app_count", &app_tables.len());
     let mut apps = vec![];
     for table in app_tables {
         let app = read_app(transaction, table.id, user).await?;

+ 6 - 9
rust-lib/flowy-workspace/src/services/app_controller.rs

@@ -47,7 +47,7 @@ impl AppController {
 
         conn.immediate_transaction::<_, WorkspaceError, _>(|| {
             let _ = self.save_app(app.clone(), &*conn)?;
-            let _ = notify_app_num_changed(&app.workspace_id, self.trash_can.clone(), conn)?;
+            let _ = notify_apps_changed(&app.workspace_id, self.trash_can.clone(), conn)?;
             Ok(())
         })?;
 
@@ -179,6 +179,7 @@ impl AppController {
     }
 }
 
+#[tracing::instrument(level = "debug", skip(database, trash_can))]
 async fn handle_trash_event(database: Arc<dyn WorkspaceDatabase>, trash_can: Arc<TrashCan>, event: TrashEvent) {
     let db_result = database.db_connection();
     match event {
@@ -188,7 +189,7 @@ async fn handle_trash_event(database: Arc<dyn WorkspaceDatabase>, trash_can: Arc
                 let _ = conn.immediate_transaction::<_, WorkspaceError, _>(|| {
                     for identifier in identifiers.items {
                         let app_table = AppTableSql::read_app(&identifier.id, conn)?;
-                        let _ = notify_app_num_changed(&app_table.workspace_id, trash_can.clone(), conn)?;
+                        let _ = notify_apps_changed(&app_table.workspace_id, trash_can.clone(), conn)?;
                     }
                     Ok(())
                 })?;
@@ -208,7 +209,7 @@ async fn handle_trash_event(database: Arc<dyn WorkspaceDatabase>, trash_can: Arc
                     }
 
                     for notify_id in notify_ids {
-                        let _ = notify_app_num_changed(&notify_id, trash_can.clone(), conn)?;
+                        let _ = notify_apps_changed(&notify_id, trash_can.clone(), conn)?;
                     }
                     Ok(())
                 })?;
@@ -220,11 +221,7 @@ async fn handle_trash_event(database: Arc<dyn WorkspaceDatabase>, trash_can: Arc
 }
 
 #[tracing::instrument(skip(workspace_id, trash_can, conn), err)]
-fn notify_app_num_changed(
-    workspace_id: &str,
-    trash_can: Arc<TrashCan>,
-    conn: &SqliteConnection,
-) -> WorkspaceResult<()> {
+fn notify_apps_changed(workspace_id: &str, trash_can: Arc<TrashCan>, conn: &SqliteConnection) -> WorkspaceResult<()> {
     let repeated_app = read_local_workspace_apps(workspace_id, trash_can, conn)?;
     send_dart_notification(workspace_id, WorkspaceNotification::WorkspaceAppsChanged)
         .payload(repeated_app)
@@ -232,7 +229,7 @@ fn notify_app_num_changed(
     Ok(())
 }
 
-fn read_local_workspace_apps(
+pub fn read_local_workspace_apps(
     workspace_id: &str,
     trash_can: Arc<TrashCan>,
     conn: &SqliteConnection,

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

@@ -9,7 +9,7 @@ use crate::{
 use crossbeam_utils::thread;
 use flowy_database::SqliteConnection;
 
-use std::sync::Arc;
+use std::{fmt::Formatter, sync::Arc};
 use tokio::sync::{broadcast, mpsc};
 
 pub struct TrashCan {
@@ -41,7 +41,7 @@ impl TrashCan {
             let conn = self.database.db_connection()?;
             conn.immediate_transaction::<_, WorkspaceError, _>(|| {
                 let _ = TrashTableSql::delete_trash(trash_id, &*conn)?;
-                notify_trash_num_changed(TrashTableSql::read_all(&conn)?);
+                notify_trash_changed(TrashTableSql::read_all(&conn)?);
                 Ok(())
             })?;
 
@@ -82,7 +82,7 @@ impl TrashCan {
         let _ = self.notify.send(TrashEvent::Putback(identifiers, tx));
         let _ = rx.recv().await;
 
-        notify_trash_num_changed(RepeatedTrash { items: vec![] });
+        notify_trash_changed(RepeatedTrash { items: vec![] });
         let _ = self.delete_all_trash_on_server().await?;
         Ok(())
     }
@@ -93,7 +93,7 @@ impl TrashCan {
         let trash_identifiers: TrashIdentifiers = repeated_trash.items.clone().into();
         let _ = self.delete_with_identifiers(trash_identifiers.clone()).await?;
 
-        notify_trash_num_changed(RepeatedTrash { items: vec![] });
+        notify_trash_changed(RepeatedTrash { items: vec![] });
         let _ = self.delete_all_trash_on_server().await?;
         Ok(())
     }
@@ -101,7 +101,7 @@ impl TrashCan {
     #[tracing::instrument(level = "debug", skip(self), err)]
     pub async fn delete(&self, trash_identifiers: TrashIdentifiers) -> WorkspaceResult<()> {
         let _ = self.delete_with_identifiers(trash_identifiers.clone()).await?;
-        notify_trash_num_changed(TrashTableSql::read_all(&*(self.database.db_connection()?))?);
+        notify_trash_changed(TrashTableSql::read_all(&*(self.database.db_connection()?))?);
         let _ = self.delete_trash_on_server(trash_identifiers)?;
 
         Ok(())
@@ -137,7 +137,7 @@ impl TrashCan {
     // DELETE operations. It’s not possible for us to use these commands to
     // CREATE and DROP tables operations because those are auto-commit in the
     // database.
-    #[tracing::instrument(level = "debug", skip(self, trash), err)]
+    #[tracing::instrument(level = "debug", skip(self, trash), fields(trash_count), err)]
     pub async fn add<T: Into<Trash>>(&self, trash: Vec<T>) -> Result<(), WorkspaceError> {
         let (tx, mut rx) = mpsc::channel::<WorkspaceResult<()>>(1);
         let repeated_trash = trash.into_iter().map(|t| t.into()).collect::<Vec<Trash>>();
@@ -145,13 +145,15 @@ impl TrashCan {
             .iter()
             .map(|t| t.into())
             .collect::<Vec<TrashIdentifier>>();
+
+        tracing::Span::current().record("trash_count", &identifiers.len());
         let _ = thread::scope(|_s| {
             let conn = self.database.db_connection()?;
             conn.immediate_transaction::<_, WorkspaceError, _>(|| {
                 let _ = TrashTableSql::create_trash(repeated_trash.clone(), &*conn)?;
                 let _ = self.create_trash_on_server(repeated_trash);
 
-                notify_trash_num_changed(TrashTableSql::read_all(&conn)?);
+                notify_trash_changed(TrashTableSql::read_all(&conn)?);
                 Ok(())
             })?;
             Ok::<(), WorkspaceError>(())
@@ -168,7 +170,6 @@ impl TrashCan {
 
     pub fn read_trash(&self, conn: &SqliteConnection) -> Result<RepeatedTrash, WorkspaceError> {
         let repeated_trash = TrashTableSql::read_all(&*conn)?;
-
         let _ = self.read_trash_on_server()?;
         Ok(repeated_trash)
     }
@@ -226,15 +227,15 @@ impl TrashCan {
                     match pool.get() {
                         Ok(conn) => {
                             let result = conn.immediate_transaction::<_, WorkspaceError, _>(|| {
-                                TrashTableSql::create_trash(repeated_trash.items.clone(), &*conn)
+                                let _ = TrashTableSql::create_trash(repeated_trash.items.clone(), &*conn)?;
+                                TrashTableSql::read_all(&conn)
                             });
 
                             match result {
-                                Ok(_) => {
+                                Ok(repeated_trash) => {
                                     // FIXME: User may modify the trash(add/putback) before the flying request comes
                                     // back that will cause the trash list to be outdated.
-                                    // TODO: impl with operation transform
-                                    notify_trash_num_changed(repeated_trash);
+                                    notify_trash_changed(repeated_trash);
                                 },
                                 Err(e) => log::error!("Save trash failed: {:?}", e),
                             }
@@ -257,7 +258,7 @@ impl TrashCan {
 }
 
 #[tracing::instrument(skip(repeated_trash), fields(trash_count))]
-fn notify_trash_num_changed(repeated_trash: RepeatedTrash) {
+fn notify_trash_changed(repeated_trash: RepeatedTrash) {
     tracing::Span::current().record("trash_count", &repeated_trash.len());
     send_anonymous_dart_notification(WorkspaceNotification::TrashUpdated)
         .payload(repeated_trash)
@@ -271,6 +272,16 @@ pub enum TrashEvent {
     Delete(TrashIdentifiers, mpsc::Sender<WorkspaceResult<()>>),
 }
 
+impl std::fmt::Debug for TrashEvent {
+    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
+        match self {
+            TrashEvent::NewTrash(identifiers, _) => f.write_str(&format!("{:?}", identifiers)),
+            TrashEvent::Putback(identifiers, _) => f.write_str(&format!("{:?}", identifiers)),
+            TrashEvent::Delete(identifiers, _) => f.write_str(&format!("{:?}", identifiers)),
+        }
+    }
+}
+
 impl TrashEvent {
     pub fn select(self, s: TrashType) -> Option<TrashEvent> {
         match self {

+ 6 - 9
rust-lib/flowy-workspace/src/services/view_controller.rs

@@ -64,7 +64,7 @@ impl ViewController {
 
         conn.immediate_transaction::<_, WorkspaceError, _>(|| {
             let _ = self.save_view(view.clone(), conn)?;
-            let _ = notify_view_num_changed(&view.belong_to_id, trash_can, &conn)?;
+            let _ = notify_views_changed(&view.belong_to_id, trash_can, &conn)?;
 
             Ok(())
         })?;
@@ -163,7 +163,7 @@ impl ViewController {
             .send();
 
         //
-        let _ = notify_view_num_changed(&updated_view.belong_to_id, self.trash_can.clone(), conn)?;
+        let _ = notify_views_changed(&updated_view.belong_to_id, self.trash_can.clone(), conn)?;
 
         let _ = self.update_view_on_server(params);
         Ok(updated_view)
@@ -253,6 +253,7 @@ impl ViewController {
     }
 }
 
+#[tracing::instrument(level = "debug", skip(database, document, trash_can))]
 async fn handle_trash_event(
     database: Arc<dyn WorkspaceDatabase>,
     document: Arc<FlowyDocument>,
@@ -268,7 +269,7 @@ async fn handle_trash_event(
                 let _ = conn.immediate_transaction::<_, WorkspaceError, _>(|| {
                     for identifier in identifiers.items {
                         let view_table = ViewTableSql::read_view(&identifier.id, conn)?;
-                        let _ = notify_view_num_changed(&view_table.belong_to_id, trash_can.clone(), conn)?;
+                        let _ = notify_views_changed(&view_table.belong_to_id, trash_can.clone(), conn)?;
                     }
                     Ok(())
                 })?;
@@ -289,7 +290,7 @@ async fn handle_trash_event(
                     }
 
                     for notify_id in notify_ids {
-                        let _ = notify_view_num_changed(&notify_id, trash_can.clone(), conn)?;
+                        let _ = notify_views_changed(&notify_id, trash_can.clone(), conn)?;
                     }
 
                     Ok(())
@@ -302,11 +303,7 @@ async fn handle_trash_event(
 }
 
 #[tracing::instrument(skip(belong_to_id, trash_can, conn), fields(view_count), err)]
-fn notify_view_num_changed(
-    belong_to_id: &str,
-    trash_can: Arc<TrashCan>,
-    conn: &SqliteConnection,
-) -> WorkspaceResult<()> {
+fn notify_views_changed(belong_to_id: &str, trash_can: Arc<TrashCan>, conn: &SqliteConnection) -> WorkspaceResult<()> {
     let repeated_view = read_local_belonging_view(belong_to_id, trash_can.clone(), conn)?;
     tracing::Span::current().record("view_count", &format!("{}", repeated_view.len()).as_str());
     send_dart_notification(&belong_to_id, WorkspaceNotification::AppViewsChanged)

+ 7 - 13
rust-lib/flowy-workspace/src/services/workspace_controller.rs

@@ -6,7 +6,7 @@ use crate::{
     errors::*,
     module::{WorkspaceDatabase, WorkspaceUser},
     notify::*,
-    services::{helper::spawn, server::Server, AppController, TrashCan, ViewController},
+    services::{helper::spawn, read_local_workspace_apps, server::Server, AppController, TrashCan, ViewController},
     sql_tables::workspace::{WorkspaceTable, WorkspaceTableChangeset, WorkspaceTableSql},
 };
 use flowy_database::SqliteConnection;
@@ -159,9 +159,9 @@ impl WorkspaceController {
     pub(crate) async fn read_workspace_apps(&self) -> Result<RepeatedApp, WorkspaceError> {
         let workspace_id = get_current_workspace()?;
         let conn = self.database.db_connection()?;
-        let apps = self.read_local_apps(&workspace_id, &*conn)?;
+        let repeated_app = self.read_local_apps(&workspace_id, &*conn)?;
         // TODO: read from server
-        Ok(RepeatedApp { items: apps })
+        Ok(repeated_app)
     }
 
     #[tracing::instrument(level = "debug", skip(self, conn), err)]
@@ -176,7 +176,7 @@ impl WorkspaceController {
 
         let mut workspaces = vec![];
         for table in workspace_tables {
-            let apps = self.read_local_apps(&table.id, conn)?;
+            let apps = self.read_local_apps(&table.id, conn)?.into_inner();
             let mut workspace: Workspace = table.into();
             workspace.apps.items = apps;
             workspaces.push(workspace);
@@ -202,15 +202,9 @@ impl WorkspaceController {
     }
 
     #[tracing::instrument(level = "debug", skip(self, conn), err)]
-    fn read_local_apps(&self, workspace_id: &str, conn: &SqliteConnection) -> Result<Vec<App>, WorkspaceError> {
-        let apps = self
-            .workspace_sql
-            .read_apps_belong_to_workspace(workspace_id, conn)?
-            .into_iter()
-            .map(|app_table| app_table.into())
-            .collect::<Vec<App>>();
-
-        Ok(apps)
+    fn read_local_apps(&self, workspace_id: &str, conn: &SqliteConnection) -> Result<RepeatedApp, WorkspaceError> {
+        let repeated_app = read_local_workspace_apps(workspace_id, self.trash_can.clone(), conn)?;
+        Ok(repeated_app)
     }
 }
 

+ 1 - 16
rust-lib/flowy-workspace/src/sql_tables/workspace/workspace_sql.rs

@@ -1,9 +1,6 @@
 use crate::{
     errors::WorkspaceError,
-    sql_tables::{
-        app::AppTable,
-        workspace::{WorkspaceTable, WorkspaceTableChangeset},
-    },
+    sql_tables::workspace::{WorkspaceTable, WorkspaceTableChangeset},
 };
 use diesel::SqliteConnection;
 use flowy_database::{
@@ -63,16 +60,4 @@ impl WorkspaceTableSql {
         diesel_delete_table!(workspace_table, workspace_id, conn);
         Ok(())
     }
-
-    pub(crate) fn read_apps_belong_to_workspace(
-        &self,
-        workspace_id: &str,
-        conn: &SqliteConnection,
-    ) -> Result<Vec<AppTable>, WorkspaceError> {
-        let workspace_table: WorkspaceTable = dsl::workspace_table
-            .filter(workspace_table::id.eq(workspace_id))
-            .first::<WorkspaceTable>(conn)?;
-        let apps = AppTable::belonging_to(&workspace_table).load::<AppTable>(conn)?;
-        Ok(apps)
-    }
 }