Browse Source

chore: listen backend notification from Tauri (#1743)

Nathan.fooo 2 years ago
parent
commit
7a750e5255
27 changed files with 237 additions and 58 deletions
  1. 10 0
      frontend/.vscode/launch.json
  2. 10 0
      frontend/.vscode/settings.json
  3. 10 1
      frontend/.vscode/tasks.json
  4. 4 3
      frontend/appflowy_tauri/src-tauri/src/main.rs
  5. 0 1
      frontend/appflowy_tauri/src-tauri/src/notification.rs
  6. 12 4
      frontend/appflowy_tauri/src/appflowy_app/App.tsx
  7. 1 0
      frontend/appflowy_tauri/src/appflowy_app/components/user/application/notifications/index.ts
  8. 27 0
      frontend/appflowy_tauri/src/appflowy_app/components/user/application/notifications/parser.ts
  9. 34 0
      frontend/appflowy_tauri/src/appflowy_app/components/user/application/notifications/user_listener.ts
  10. 2 0
      frontend/appflowy_tauri/src/services/backend/notifications/index.ts
  11. 29 0
      frontend/appflowy_tauri/src/services/backend/notifications/listener.ts
  12. 42 0
      frontend/appflowy_tauri/src/services/backend/notifications/parser.ts
  13. 2 2
      frontend/rust-lib/flowy-folder/src/manager.rs
  14. 2 2
      frontend/rust-lib/flowy-folder/src/notification.rs
  15. 3 3
      frontend/rust-lib/flowy-folder/src/services/app/controller.rs
  16. 2 2
      frontend/rust-lib/flowy-folder/src/services/trash/controller.rs
  17. 6 6
      frontend/rust-lib/flowy-folder/src/services/view/controller.rs
  18. 4 4
      frontend/rust-lib/flowy-folder/src/services/workspace/controller.rs
  19. 2 2
      frontend/rust-lib/flowy-folder/src/services/workspace/event_handler.rs
  20. 1 1
      frontend/rust-lib/flowy-grid/src/notification.rs
  21. 2 2
      frontend/rust-lib/flowy-grid/src/services/block_manager.rs
  22. 3 3
      frontend/rust-lib/flowy-grid/src/services/grid_editor.rs
  23. 4 4
      frontend/rust-lib/flowy-grid/src/services/view_editor/changed_notifier.rs
  24. 8 8
      frontend/rust-lib/flowy-grid/src/services/view_editor/editor.rs
  25. 6 1
      frontend/rust-lib/flowy-user/src/notification.rs
  26. 9 2
      frontend/rust-lib/flowy-user/src/services/user_session.rs
  27. 2 7
      frontend/scripts/makefile/tauri.toml

+ 10 - 0
frontend/.vscode/launch.json

@@ -106,6 +106,16 @@
             "preLaunchTask": "AF: Tauri UI Dev",
             "cwd": "${workspaceRoot}/appflowy_tauri/"
         },
+        // {
+        //     "type": "lldb",
+        //     "request": "launch",
+        //     "name": "AF-tauri: Production Debug",
+        //     "cargo": {
+        //         "args": ["build", "--release", "--manifest-path=./appflowy_tauri/src-tauri/Cargo.toml"]
+        //     },
+        //     "preLaunchTask": "AF: Tauri UI Build",
+        //     "cwd": "${workspaceRoot}/appflowy_tauri/"
+        // },
         {
             "name": "AF: Debug Rust",
             "request": "attach",

+ 10 - 0
frontend/.vscode/settings.json

@@ -9,6 +9,16 @@
         "editor.tabCompletion": "onlySnippets",
         "editor.wordBasedSuggestions": false,
     },
+    "[javascript]": {
+        "editor.formatOnSave": true,
+        "editor.rulers": [80],
+        "editor.defaultFormatter": "esbenp.prettier-vscode"
+    },
+    "[typescript]": {
+        "editor.formatOnSave": true,
+        "editor.rulers": [80],
+        "editor.defaultFormatter": "esbenp.prettier-vscode"
+    },
     "svgviewer.enableautopreview": true,
     "svgviewer.previewcolumn": "Active",
     "svgviewer.showzoominout": true,

+ 10 - 1
frontend/.vscode/tasks.json

@@ -190,7 +190,16 @@
 			"label": "AF: Tauri UI Dev",
 			"type": "shell",
 			"isBackground": true,
-			"command": "yarn dev",
+			"command": "npm run dev",
+			"problemMatcher": ["$tsc"],
+			"options": {
+				"cwd": "${workspaceFolder}/appflowy_tauri"
+			}
+		},
+		{
+			"label": "AF: Tauri UI Build",
+			"type": "shell",
+			"command": "npm run build",
 			"problemMatcher": ["$tsc"],
 			"options": {
 				"cwd": "${workspaceFolder}/appflowy_tauri"

+ 4 - 3
frontend/appflowy_tauri/src-tauri/src/main.rs

@@ -29,9 +29,10 @@ fn main() {
             });
         })
         .setup(|app| {
-            let window = app.get_window("main").unwrap();
-            #[cfg(debug_assertions)]
-            window.open_devtools();
+            if cfg!(debug_assertions) {
+                let window = app.get_window("main").unwrap();
+                window.open_devtools();
+            }
             Ok(())
         })
         .run(tauri::generate_context!())

+ 0 - 1
frontend/appflowy_tauri/src-tauri/src/notification.rs

@@ -5,7 +5,6 @@ use tauri::{AppHandle, Event, Manager, Wry};
 
 #[allow(dead_code)]
 pub const AF_EVENT: &str = "af-event";
-#[allow(dead_code)]
 pub const AF_NOTIFICATION: &str = "af-notification";
 
 #[tracing::instrument(level = "trace")]

+ 12 - 4
frontend/appflowy_tauri/src/appflowy_app/App.tsx

@@ -4,25 +4,33 @@ import {
   SignInPayloadPB,
 } from "../services/backend/events/flowy-user/index";
 import { nanoid } from "nanoid";
+import { UserNotificationListener } from "./components/user/application/notifications";
 
 
 function App() {
-  async function greet() {
+  async function sendSignInEvent() {
     let make_payload = () =>
       SignInPayloadPB.fromObject({
         email: nanoid(4) + "@gmail.com",
         password: "A!@123abc",
         name: "abc",
       });
+
+      let listener = await new UserNotificationListener("", (userProfile) => {
+        console.log(userProfile);
+        listener.stop();
+      });
+
+      listener.start();
+
     await UserEventSignIn(make_payload());
   }
 
   return (
     <div className="container">
       <h1>Welcome to AppFlowy!</h1>
-
-      <button type="button" onClick={() => greet()}>
-        Sign in
+      <button type="button" onClick={() => sendSignInEvent()}>
+       Test Sign In Event 
       </button>
     </div>
   );

+ 1 - 0
frontend/appflowy_tauri/src/appflowy_app/components/user/application/notifications/index.ts

@@ -0,0 +1 @@
+export * from "./user_listener";

+ 27 - 0
frontend/appflowy_tauri/src/appflowy_app/components/user/application/notifications/parser.ts

@@ -0,0 +1,27 @@
+import { Result } from "ts-results/result";
+import { UserNotification, FlowyError } from "../../../../../services/backend";
+import { NotificationParser, OnNotificationError } from "../../../../../services/backend/notifications/parser";
+
+declare type UserNotificationCallback = (ty: UserNotification, payload: Uint8Array) => void;
+
+export class UserNotificationParser extends NotificationParser<UserNotification> {
+  constructor(callback: UserNotificationCallback, id?: String, onError?: OnNotificationError) {
+    super(
+      callback,
+      (ty) => {
+        let notification = UserNotification[ty];
+        if (isUserNotification(notification)) {
+          return UserNotification[notification];
+        } else {
+          return UserNotification.Unknown;
+        }
+      },
+      id,
+      onError
+    );
+  }
+}
+
+const isUserNotification = (notification: string): notification is keyof typeof UserNotification => {
+  return Object.values(UserNotification).indexOf(notification) !== -1;
+};

+ 34 - 0
frontend/appflowy_tauri/src/appflowy_app/components/user/application/notifications/user_listener.ts

@@ -0,0 +1,34 @@
+import { FlowyError, UserNotification, UserProfilePB } from "../../../../../services/backend";
+import { AFNotificationListener, OnNotificationError } from "../../../../../services/backend/notifications";
+import { UserNotificationParser } from "./parser";
+
+declare type OnUserProfileUpdate = (userProfile: UserProfilePB) => void;
+
+export class UserNotificationListener extends AFNotificationListener<UserNotification> {
+  onProfileUpdate?: OnUserProfileUpdate;
+
+  constructor(userId?: String, onProfileUpdate?: OnUserProfileUpdate, onError?: OnNotificationError) {
+    let parser = new UserNotificationParser(
+      (notification, payload) => {
+        switch (notification) {
+          case UserNotification.UserAuthChanged:
+            break;
+          case UserNotification.UserProfileUpdated:
+            break;
+          case UserNotification.UserUnauthorized:
+            break;
+          case UserNotification.UserSignIn:
+            let userProfile = UserProfilePB.deserializeBinary(payload);
+            this.onProfileUpdate?.(userProfile);
+            break;
+          default:
+            break;
+        }
+      },
+      userId,
+      onError
+    );
+    super(parser);
+    this.onProfileUpdate = onProfileUpdate;
+  }
+}

+ 2 - 0
frontend/appflowy_tauri/src/services/backend/notifications/index.ts

@@ -0,0 +1,2 @@
+export * from "./listener";
+export * from "./parser";

+ 29 - 0
frontend/appflowy_tauri/src/services/backend/notifications/listener.ts

@@ -0,0 +1,29 @@
+import { listen, UnlistenFn } from "@tauri-apps/api/event";
+import { FlowyError } from "../classes/flowy-error";
+import { SubscribeObject } from "../classes/flowy-notification";
+import { NotificationParser } from "./parser";
+
+declare type OnError = (error: FlowyError) => void;
+
+export abstract class AFNotificationListener<T> {
+  parser?: NotificationParser<T> | null;
+  private _listener?: UnlistenFn;
+
+  protected constructor(parser?: NotificationParser<T>) {
+    this.parser = parser;
+  }
+
+  async start() {
+    this._listener = await listen("af-notification", (notification) => {
+      let object = SubscribeObject.fromObject(notification.payload as {});
+      this.parser?.parse(object);
+    });
+  }
+
+  async stop() {
+    if (this._listener != null) {
+      this._listener();
+    }
+    this.parser = null;
+  }
+}

+ 42 - 0
frontend/appflowy_tauri/src/services/backend/notifications/parser.ts

@@ -0,0 +1,42 @@
+import { Ok, Err, Result } from "ts-results/result";
+import { FlowyError } from "../classes/flowy-error";
+import { SubscribeObject } from "../classes/flowy-notification";
+
+export declare type OnNotificationPayload<T> = (ty: T, payload: Uint8Array) => void;
+export declare type OnNotificationError = (error: FlowyError) => void;
+export declare type NotificationTyParser<T> = (num: number) => T | null;
+export declare type ErrParser<E> = (data: Uint8Array) => E;
+
+export abstract class NotificationParser<T> {
+  id?: String;
+  onPayload: OnNotificationPayload<T>;
+  onError?: OnNotificationError;
+  tyParser: NotificationTyParser<T>;
+
+  constructor(onPayload: OnNotificationPayload<T>, tyParser: NotificationTyParser<T>, id?: String, onError?: OnNotificationError) {
+    this.id = id;
+    this.onPayload = onPayload;
+    this.onError = onError;
+    this.tyParser = tyParser;
+  }
+
+  parse(subject: SubscribeObject) {
+    if (typeof this.id !== "undefined" && this.id.length == 0) {
+      if (subject.id != this.id) {
+        return;
+      }
+    }
+
+    let ty = this.tyParser(subject.ty);
+    if (ty == null) {
+      return;
+    }
+
+    if (subject.has_error) {
+      let error = FlowyError.deserializeBinary(subject.error);
+      this.onError?.(error);
+    } else {
+      this.onPayload(ty, subject.payload);
+    }
+  }
+}

+ 2 - 2
frontend/rust-lib/flowy-folder/src/manager.rs

@@ -5,7 +5,7 @@ use crate::{
     entities::workspace::RepeatedWorkspacePB,
     errors::FlowyResult,
     event_map::{FolderCouldServiceV1, WorkspaceDatabase, WorkspaceUser},
-    notification::{send_dart_notification, FolderNotification},
+    notification::{send_notification, FolderNotification},
     services::{
         folder_editor::FolderEditor, persistence::FolderPersistence, set_current_workspace, AppController,
         TrashController, ViewController, WorkspaceController,
@@ -249,7 +249,7 @@ impl DefaultFolderBuilder {
         let repeated_workspace = RepeatedWorkspacePB {
             items: vec![workspace_rev.into()],
         };
-        send_dart_notification(token, FolderNotification::UserCreateWorkspace)
+        send_notification(token, FolderNotification::UserCreateWorkspace)
             .payload(repeated_workspace)
             .send();
         Ok(())

+ 2 - 2
frontend/rust-lib/flowy-folder/src/notification.rs

@@ -33,11 +33,11 @@ impl std::convert::From<FolderNotification> for i32 {
 }
 
 #[tracing::instrument(level = "trace")]
-pub(crate) fn send_dart_notification(id: &str, ty: FolderNotification) -> NotificationBuilder {
+pub(crate) fn send_notification(id: &str, ty: FolderNotification) -> NotificationBuilder {
     NotificationBuilder::new(id, ty, OBSERVABLE_CATEGORY)
 }
 
 #[tracing::instrument(level = "trace")]
-pub(crate) fn send_anonymous_dart_notification(ty: FolderNotification) -> NotificationBuilder {
+pub(crate) fn send_anonymous_notification(ty: FolderNotification) -> NotificationBuilder {
     NotificationBuilder::new("", ty, OBSERVABLE_CATEGORY)
 }

+ 3 - 3
frontend/rust-lib/flowy-folder/src/services/app/controller.rs

@@ -91,7 +91,7 @@ impl AppController {
             })
             .await?
             .into();
-        send_dart_notification(&app_id, FolderNotification::AppUpdated)
+        send_notification(&app_id, FolderNotification::AppUpdated)
             .payload(app)
             .send();
         self.update_app_on_server(params)?;
@@ -163,7 +163,7 @@ impl AppController {
                     {
                         Ok(_) => {
                             let app: AppPB = app_rev.into();
-                            send_dart_notification(&app.id, FolderNotification::AppUpdated)
+                            send_notification(&app.id, FolderNotification::AppUpdated)
                                 .payload(app)
                                 .send();
                         }
@@ -248,7 +248,7 @@ fn notify_apps_changed<'a>(
         .map(|app_rev| app_rev.into())
         .collect();
     let repeated_app = RepeatedAppPB { items };
-    send_dart_notification(workspace_id, FolderNotification::WorkspaceAppsChanged)
+    send_notification(workspace_id, FolderNotification::WorkspaceAppsChanged)
         .payload(repeated_app)
         .send();
     Ok(())

+ 2 - 2
frontend/rust-lib/flowy-folder/src/services/trash/controller.rs

@@ -2,7 +2,7 @@ use crate::{
     entities::trash::{RepeatedTrashIdPB, RepeatedTrashPB, TrashIdPB, TrashPB, TrashType},
     errors::{FlowyError, FlowyResult},
     event_map::{FolderCouldServiceV1, WorkspaceUser},
-    notification::{send_anonymous_dart_notification, FolderNotification},
+    notification::{send_anonymous_notification, FolderNotification},
     services::persistence::{FolderPersistence, FolderPersistenceTransaction},
 };
 
@@ -283,7 +283,7 @@ impl TrashController {
 fn notify_trash_changed<T: Into<RepeatedTrashPB>>(repeated_trash: T) {
     let repeated_trash = repeated_trash.into();
     tracing::Span::current().record("n_trash", repeated_trash.len());
-    send_anonymous_dart_notification(FolderNotification::TrashUpdated)
+    send_anonymous_notification(FolderNotification::TrashUpdated)
         .payload(repeated_trash)
         .send();
 }

+ 6 - 6
frontend/rust-lib/flowy-folder/src/services/view/controller.rs

@@ -8,7 +8,7 @@ use crate::{
     },
     errors::{FlowyError, FlowyResult},
     event_map::{FolderCouldServiceV1, WorkspaceUser},
-    notification::{send_dart_notification, FolderNotification},
+    notification::{send_notification, FolderNotification},
     services::{
         persistence::{FolderPersistence, FolderPersistenceTransaction, ViewChangeset},
         TrashController, TrashEvent,
@@ -225,7 +225,7 @@ impl ViewController {
             })
             .await?;
 
-        send_dart_notification(&view_id, FolderNotification::ViewMoveToTrash)
+        send_notification(&view_id, FolderNotification::ViewMoveToTrash)
             .payload(deleted_view)
             .send();
 
@@ -291,7 +291,7 @@ impl ViewController {
                 transaction.update_view(changeset)?;
                 let view_rev = transaction.read_view(&view_id)?;
                 let view: ViewPB = view_rev.clone().into();
-                send_dart_notification(&view_id, FolderNotification::ViewUpdated)
+                send_notification(&view_id, FolderNotification::ViewUpdated)
                     .payload(view)
                     .send();
                 notify_views_changed(&view_rev.app_id, self.trash_controller.clone(), &transaction)?;
@@ -356,7 +356,7 @@ impl ViewController {
                     {
                         Ok(_) => {
                             let view: ViewPB = view_rev.into();
-                            send_dart_notification(&view.id, FolderNotification::ViewUpdated)
+                            send_notification(&view.id, FolderNotification::ViewUpdated)
                                 .payload(view)
                                 .send();
                         }
@@ -518,7 +518,7 @@ fn read_local_views_with_transaction<'a>(
 }
 
 fn notify_dart(view: ViewPB, notification: FolderNotification) {
-    send_dart_notification(&view.id, notification).payload(view).send();
+    send_notification(&view.id, notification).payload(view).send();
 }
 
 #[tracing::instrument(
@@ -537,7 +537,7 @@ fn notify_views_changed<'a>(
     app_rev.belongings.retain(|view| !trash_ids.contains(&view.id));
     let app: AppPB = app_rev.into();
 
-    send_dart_notification(belong_to_id, FolderNotification::AppUpdated)
+    send_notification(belong_to_id, FolderNotification::AppUpdated)
         .payload(app)
         .send();
 

+ 4 - 4
frontend/rust-lib/flowy-folder/src/services/workspace/controller.rs

@@ -53,7 +53,7 @@ impl WorkspaceController {
             .map(|workspace_rev| workspace_rev.into())
             .collect();
         let repeated_workspace = RepeatedWorkspacePB { items: workspaces };
-        send_dart_notification(&token, FolderNotification::UserCreateWorkspace)
+        send_notification(&token, FolderNotification::UserCreateWorkspace)
             .payload(repeated_workspace)
             .send();
         set_current_workspace(&user_id, &workspace.id);
@@ -73,7 +73,7 @@ impl WorkspaceController {
             })
             .await?;
 
-        send_dart_notification(&workspace_id, FolderNotification::WorkspaceUpdated)
+        send_notification(&workspace_id, FolderNotification::WorkspaceUpdated)
             .payload(workspace)
             .send();
         self.update_workspace_on_server(params)?;
@@ -92,7 +92,7 @@ impl WorkspaceController {
                 self.read_local_workspaces(None, &user_id, &transaction)
             })
             .await?;
-        send_dart_notification(&token, FolderNotification::UserDeleteWorkspace)
+        send_notification(&token, FolderNotification::UserDeleteWorkspace)
             .payload(repeated_workspace)
             .send();
         self.delete_workspace_on_server(workspace_id)?;
@@ -236,7 +236,7 @@ pub async fn notify_workspace_setting_did_change(
         })
         .await?;
 
-    send_dart_notification(&token, FolderNotification::WorkspaceSetting)
+    send_notification(&token, FolderNotification::WorkspaceSetting)
         .payload(workspace_setting)
         .send();
     Ok(())

+ 2 - 2
frontend/rust-lib/flowy-folder/src/services/workspace/event_handler.rs

@@ -6,7 +6,7 @@ use crate::entities::{
 use crate::{
     errors::FlowyError,
     manager::FolderManager,
-    notification::{send_dart_notification, FolderNotification},
+    notification::{send_notification, FolderNotification},
     services::{get_current_workspace, read_local_workspace_apps, WorkspaceController},
 };
 use lib_dispatch::prelude::{data_result, AFPluginData, AFPluginState, DataResult};
@@ -151,7 +151,7 @@ fn read_workspaces_on_server(
                 .collect(),
         };
 
-        send_dart_notification(&token, FolderNotification::WorkspaceListUpdated)
+        send_notification(&token, FolderNotification::WorkspaceListUpdated)
             .payload(repeated_workspace)
             .send();
         Result::<(), FlowyError>::Ok(())

+ 1 - 1
frontend/rust-lib/flowy-grid/src/notification.rs

@@ -35,6 +35,6 @@ impl std::convert::From<GridDartNotification> for i32 {
 }
 
 #[tracing::instrument(level = "trace")]
-pub fn send_dart_notification(id: &str, ty: GridDartNotification) -> NotificationBuilder {
+pub fn send_notification(id: &str, ty: GridDartNotification) -> NotificationBuilder {
     NotificationBuilder::new(id, ty, OBSERVABLE_CATEGORY)
 }

+ 2 - 2
frontend/rust-lib/flowy-grid/src/services/block_manager.rs

@@ -1,6 +1,6 @@
 use crate::entities::{CellChangesetPB, InsertedRowPB, UpdatedRowPB};
 use crate::manager::GridUser;
-use crate::notification::{send_dart_notification, GridDartNotification};
+use crate::notification::{send_notification, GridDartNotification};
 use crate::services::block_editor::{GridBlockRevisionEditor, GridBlockRevisionMergeable};
 use crate::services::persistence::block_index::BlockIndexCache;
 use crate::services::persistence::rev_sqlite::{
@@ -262,7 +262,7 @@ impl GridBlockManager {
 
     async fn notify_did_update_cell(&self, changeset: CellChangesetPB) -> FlowyResult<()> {
         let id = format!("{}:{}", changeset.row_id, changeset.field_id);
-        send_dart_notification(&id, GridDartNotification::DidUpdateCell).send();
+        send_notification(&id, GridDartNotification::DidUpdateCell).send();
         Ok(())
     }
 }

+ 3 - 3
frontend/rust-lib/flowy-grid/src/services/grid_editor.rs

@@ -1,7 +1,7 @@
 use crate::entities::CellPathParams;
 use crate::entities::*;
 use crate::manager::GridUser;
-use crate::notification::{send_dart_notification, GridDartNotification};
+use crate::notification::{send_notification, GridDartNotification};
 use crate::services::block_manager::GridBlockManager;
 use crate::services::cell::{
     apply_cell_data_changeset, decode_type_cell_data, stringify_cell_data, AnyTypeCache, AtomicCellDataCache,
@@ -852,7 +852,7 @@ impl GridRevisionEditor {
             let notified_changeset = GridFieldChangesetPB::update(&self.grid_id, vec![updated_field.clone()]);
             self.notify_did_update_grid(notified_changeset).await?;
 
-            send_dart_notification(field_id, GridDartNotification::DidUpdateField)
+            send_notification(field_id, GridDartNotification::DidUpdateField)
                 .payload(updated_field)
                 .send();
         }
@@ -861,7 +861,7 @@ impl GridRevisionEditor {
     }
 
     async fn notify_did_update_grid(&self, changeset: GridFieldChangesetPB) -> FlowyResult<()> {
-        send_dart_notification(&self.grid_id, GridDartNotification::DidUpdateGridFields)
+        send_notification(&self.grid_id, GridDartNotification::DidUpdateGridFields)
             .payload(changeset)
             .send();
         Ok(())

+ 4 - 4
frontend/rust-lib/flowy-grid/src/services/view_editor/changed_notifier.rs

@@ -1,5 +1,5 @@
 use crate::entities::{GridRowsVisibilityChangesetPB, ReorderAllRowsPB, ReorderSingleRowPB};
-use crate::notification::{send_dart_notification, GridDartNotification};
+use crate::notification::{send_notification, GridDartNotification};
 use crate::services::filter::FilterResultNotification;
 use crate::services::sort::{ReorderAllRowsResult, ReorderSingleRowResult};
 use async_stream::stream;
@@ -37,7 +37,7 @@ impl GridViewChangedReceiverRunner {
                             invisible_rows: notification.invisible_rows,
                         };
 
-                        send_dart_notification(
+                        send_notification(
                             &changeset.view_id,
                             GridDartNotification::DidUpdateGridViewRowsVisibility,
                         )
@@ -48,7 +48,7 @@ impl GridViewChangedReceiverRunner {
                         let row_orders = ReorderAllRowsPB {
                             row_orders: notification.row_orders,
                         };
-                        send_dart_notification(&notification.view_id, GridDartNotification::DidReorderRows)
+                        send_notification(&notification.view_id, GridDartNotification::DidReorderRows)
                             .payload(row_orders)
                             .send()
                     }
@@ -58,7 +58,7 @@ impl GridViewChangedReceiverRunner {
                             old_index: notification.old_index as i32,
                             new_index: notification.new_index as i32,
                         };
-                        send_dart_notification(&notification.view_id, GridDartNotification::DidReorderSingleRow)
+                        send_notification(&notification.view_id, GridDartNotification::DidReorderSingleRow)
                             .payload(reorder_row)
                             .send()
                     }

+ 8 - 8
frontend/rust-lib/flowy-grid/src/services/view_editor/editor.rs

@@ -1,5 +1,5 @@
 use crate::entities::*;
-use crate::notification::{send_dart_notification, GridDartNotification};
+use crate::notification::{send_notification, GridDartNotification};
 use crate::services::block_manager::GridBlockEvent;
 use crate::services::cell::{AtomicCellDataCache, TypeCellData};
 use crate::services::field::{RowSingleCellData, TypeOptionCellDataHandler};
@@ -184,7 +184,7 @@ impl GridViewRevisionEditor {
             }
         };
 
-        send_dart_notification(&self.view_id, GridDartNotification::DidUpdateGridViewRows)
+        send_notification(&self.view_id, GridDartNotification::DidUpdateGridViewRows)
             .payload(changeset)
             .send();
     }
@@ -616,7 +616,7 @@ impl GridViewRevisionEditor {
 
             debug_assert!(!changeset.is_empty());
             if !changeset.is_empty() {
-                send_dart_notification(&changeset.view_id, GridDartNotification::DidGroupByNewField)
+                send_notification(&changeset.view_id, GridDartNotification::DidGroupByNewField)
                     .payload(changeset)
                     .send();
             }
@@ -630,33 +630,33 @@ impl GridViewRevisionEditor {
 
     async fn notify_did_update_setting(&self) {
         let setting = self.get_view_setting().await;
-        send_dart_notification(&self.view_id, GridDartNotification::DidUpdateGridSetting)
+        send_notification(&self.view_id, GridDartNotification::DidUpdateGridSetting)
             .payload(setting)
             .send();
     }
 
     pub async fn notify_did_update_group_rows(&self, payload: GroupRowsNotificationPB) {
-        send_dart_notification(&payload.group_id, GridDartNotification::DidUpdateGroup)
+        send_notification(&payload.group_id, GridDartNotification::DidUpdateGroup)
             .payload(payload)
             .send();
     }
 
     pub async fn notify_did_update_filter(&self, notification: FilterChangesetNotificationPB) {
-        send_dart_notification(&notification.view_id, GridDartNotification::DidUpdateFilter)
+        send_notification(&notification.view_id, GridDartNotification::DidUpdateFilter)
             .payload(notification)
             .send();
     }
 
     pub async fn notify_did_update_sort(&self, notification: SortChangesetNotificationPB) {
         if !notification.is_empty() {
-            send_dart_notification(&notification.view_id, GridDartNotification::DidUpdateSort)
+            send_notification(&notification.view_id, GridDartNotification::DidUpdateSort)
                 .payload(notification)
                 .send();
         }
     }
 
     async fn notify_did_update_view(&self, changeset: GroupViewChangesetPB) {
-        send_dart_notification(&self.view_id, GridDartNotification::DidUpdateGroupView)
+        send_notification(&self.view_id, GridDartNotification::DidUpdateGroupView)
             .payload(changeset)
             .send();
     }

+ 6 - 1
frontend/rust-lib/flowy-user/src/notification.rs

@@ -9,6 +9,7 @@ pub(crate) enum UserNotification {
     UserProfileUpdated = 2,
     UserUnauthorized = 3,
     UserWsConnectStateChanged = 4,
+    UserSignIn = 5,
 }
 
 impl std::default::Default for UserNotification {
@@ -23,6 +24,10 @@ impl std::convert::From<UserNotification> for i32 {
     }
 }
 
-pub(crate) fn dart_notify(id: &str, ty: UserNotification) -> NotificationBuilder {
+pub(crate) fn send_notification(id: &str, ty: UserNotification) -> NotificationBuilder {
     NotificationBuilder::new(id, ty, OBSERVABLE_CATEGORY)
 }
+
+pub(crate) fn send_sign_in_notification() -> NotificationBuilder {
+    NotificationBuilder::new("", UserNotification::UserSignIn, OBSERVABLE_CATEGORY)
+}

+ 9 - 2
frontend/rust-lib/flowy-user/src/services/user_session.rs

@@ -84,7 +84,13 @@ impl UserSession {
     #[tracing::instrument(level = "debug", skip(self))]
     pub async fn sign_in(&self, params: SignInParams) -> Result<UserProfilePB, FlowyError> {
         if self.is_user_login(&params.email) {
-            self.get_user_profile().await
+            match self.get_user_profile().await {
+                Ok(profile) => {
+                    send_sign_in_notification().payload(profile.clone()).send();
+                    Ok(profile)
+                }
+                Err(err) => Err(err),
+            }
         } else {
             let resp = self.cloud_service.sign_in(params).await?;
             let session: Session = resp.clone().into();
@@ -92,6 +98,7 @@ impl UserSession {
             let user_table = self.save_user(resp.into()).await?;
             let user_profile: UserProfilePB = user_table.into();
             self.notifier.notify_login(&user_profile.token, &user_profile.id);
+            send_sign_in_notification().payload(user_profile.clone()).send();
             Ok(user_profile)
         }
     }
@@ -134,7 +141,7 @@ impl UserSession {
         diesel_update_table!(user_table, changeset, &*self.db_connection()?);
 
         let user_profile = self.get_user_profile().await?;
-        dart_notify(&session.token, UserNotification::UserProfileUpdated)
+        send_notification(&session.token, UserNotification::UserProfileUpdated)
             .payload(user_profile)
             .send();
         self.update_user_on_server(&session.token, params).await?;

+ 2 - 7
frontend/scripts/makefile/tauri.toml

@@ -1,11 +1,5 @@
 [tasks.tauri_build]
-script = ["""
-    cd appflowy_tauri/src-tauri
-    npm run tauri build
-    """]
-script_runner = "@shell"
-
-[tasks.tauri_pb]
+description = "Build the Tauri backend & Run Code Generation"
 script = ["""
     cd appflowy_tauri/src-tauri
     cargo build
@@ -20,6 +14,7 @@ script = ["""
 script_runner = "@shell"
 
 [tasks.tauri_clean]
+description = "Remove all the building artifacts"
 run_task = { name = [
   "rust_lib_clean",
   "rm_macro_build_cache",