diff --git a/frontend/appflowy_flutter/lib/plugins/ai_chat/application/chat_bloc.dart b/frontend/appflowy_flutter/lib/plugins/ai_chat/application/chat_bloc.dart index 1822047d11..a34f6fa41a 100644 --- a/frontend/appflowy_flutter/lib/plugins/ai_chat/application/chat_bloc.dart +++ b/frontend/appflowy_flutter/lib/plugins/ai_chat/application/chat_bloc.dart @@ -6,6 +6,7 @@ import 'package:appflowy_backend/dispatch/dispatch.dart'; import 'package:appflowy_backend/log.dart'; import 'package:appflowy_backend/protobuf/flowy-ai/entities.pb.dart'; import 'package:appflowy_backend/protobuf/flowy-error/code.pb.dart'; +import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart'; import 'package:appflowy_result/appflowy_result.dart'; import 'package:collection/collection.dart'; import 'package:fixnum/fixnum.dart'; @@ -64,6 +65,9 @@ class ChatBloc extends Bloc { Future close() async { await answerStream?.dispose(); await listener.stop(); + final request = ViewIdPB(value: chatId); + unawaited(FolderEventCloseView(request).send()); + return super.close(); } diff --git a/frontend/appflowy_tauri/src-tauri/Cargo.lock b/frontend/appflowy_tauri/src-tauri/Cargo.lock index 1038047111..1f606efb14 100644 --- a/frontend/appflowy_tauri/src-tauri/Cargo.lock +++ b/frontend/appflowy_tauri/src-tauri/Cargo.lock @@ -172,7 +172,7 @@ checksum = "c1fd03a028ef38ba2276dce7e33fcd6369c158a1bca17946c4b1b701891c1ff7" [[package]] name = "app-error" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9f57fa63d5ee039f50b0d27b860679deb14fee2e#9f57fa63d5ee039f50b0d27b860679deb14fee2e" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=ea131f0baab67defe7591067357eced490072372#ea131f0baab67defe7591067357eced490072372" dependencies = [ "anyhow", "bincode", @@ -192,7 +192,7 @@ dependencies = [ [[package]] name = "appflowy-ai-client" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9f57fa63d5ee039f50b0d27b860679deb14fee2e#9f57fa63d5ee039f50b0d27b860679deb14fee2e" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=ea131f0baab67defe7591067357eced490072372#ea131f0baab67defe7591067357eced490072372" dependencies = [ "anyhow", "bytes", @@ -888,7 +888,7 @@ dependencies = [ [[package]] name = "client-api" version = "0.2.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9f57fa63d5ee039f50b0d27b860679deb14fee2e#9f57fa63d5ee039f50b0d27b860679deb14fee2e" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=ea131f0baab67defe7591067357eced490072372#ea131f0baab67defe7591067357eced490072372" dependencies = [ "again", "anyhow", @@ -944,7 +944,7 @@ dependencies = [ [[package]] name = "client-api-entity" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9f57fa63d5ee039f50b0d27b860679deb14fee2e#9f57fa63d5ee039f50b0d27b860679deb14fee2e" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=ea131f0baab67defe7591067357eced490072372#ea131f0baab67defe7591067357eced490072372" dependencies = [ "collab-entity", "collab-rt-entity", @@ -957,7 +957,7 @@ dependencies = [ [[package]] name = "client-websocket" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9f57fa63d5ee039f50b0d27b860679deb14fee2e#9f57fa63d5ee039f50b0d27b860679deb14fee2e" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=ea131f0baab67defe7591067357eced490072372#ea131f0baab67defe7591067357eced490072372" dependencies = [ "futures-channel", "futures-util", @@ -1257,7 +1257,7 @@ dependencies = [ [[package]] name = "collab-rt-entity" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9f57fa63d5ee039f50b0d27b860679deb14fee2e#9f57fa63d5ee039f50b0d27b860679deb14fee2e" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=ea131f0baab67defe7591067357eced490072372#ea131f0baab67defe7591067357eced490072372" dependencies = [ "anyhow", "bincode", @@ -1282,7 +1282,7 @@ dependencies = [ [[package]] name = "collab-rt-protocol" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9f57fa63d5ee039f50b0d27b860679deb14fee2e#9f57fa63d5ee039f50b0d27b860679deb14fee2e" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=ea131f0baab67defe7591067357eced490072372#ea131f0baab67defe7591067357eced490072372" dependencies = [ "anyhow", "async-trait", @@ -1554,7 +1554,7 @@ dependencies = [ "cssparser-macros", "dtoa-short", "itoa 1.0.6", - "phf 0.11.2", + "phf 0.8.0", "smallvec", ] @@ -1679,7 +1679,7 @@ checksum = "c2e66c9d817f1720209181c316d28635c050fa304f9c79e47a520882661b7308" [[package]] name = "database-entity" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9f57fa63d5ee039f50b0d27b860679deb14fee2e#9f57fa63d5ee039f50b0d27b860679deb14fee2e" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=ea131f0baab67defe7591067357eced490072372#ea131f0baab67defe7591067357eced490072372" dependencies = [ "anyhow", "app-error", @@ -3268,7 +3268,7 @@ dependencies = [ [[package]] name = "gotrue" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9f57fa63d5ee039f50b0d27b860679deb14fee2e#9f57fa63d5ee039f50b0d27b860679deb14fee2e" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=ea131f0baab67defe7591067357eced490072372#ea131f0baab67defe7591067357eced490072372" dependencies = [ "anyhow", "futures-util", @@ -3285,7 +3285,7 @@ dependencies = [ [[package]] name = "gotrue-entity" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9f57fa63d5ee039f50b0d27b860679deb14fee2e#9f57fa63d5ee039f50b0d27b860679deb14fee2e" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=ea131f0baab67defe7591067357eced490072372#ea131f0baab67defe7591067357eced490072372" dependencies = [ "anyhow", "app-error", @@ -3840,7 +3840,7 @@ dependencies = [ [[package]] name = "infra" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9f57fa63d5ee039f50b0d27b860679deb14fee2e#9f57fa63d5ee039f50b0d27b860679deb14fee2e" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=ea131f0baab67defe7591067357eced490072372#ea131f0baab67defe7591067357eced490072372" dependencies = [ "anyhow", "bytes", @@ -6576,7 +6576,7 @@ dependencies = [ [[package]] name = "shared-entity" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9f57fa63d5ee039f50b0d27b860679deb14fee2e#9f57fa63d5ee039f50b0d27b860679deb14fee2e" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=ea131f0baab67defe7591067357eced490072372#ea131f0baab67defe7591067357eced490072372" dependencies = [ "anyhow", "app-error", diff --git a/frontend/appflowy_tauri/src-tauri/Cargo.toml b/frontend/appflowy_tauri/src-tauri/Cargo.toml index ff1c679503..a6c36e1176 100644 --- a/frontend/appflowy_tauri/src-tauri/Cargo.toml +++ b/frontend/appflowy_tauri/src-tauri/Cargo.toml @@ -59,7 +59,7 @@ collab-importer = { version = "0.1" } # Run the script: # scripts/tool/update_client_api_rev.sh new_rev_id # ⚠️⚠️⚠️️ -client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "9f57fa63d5ee039f50b0d27b860679deb14fee2e" } +client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "ea131f0baab67defe7591067357eced490072372" } [dependencies] serde_json.workspace = true diff --git a/frontend/appflowy_web_app/src-tauri/Cargo.lock b/frontend/appflowy_web_app/src-tauri/Cargo.lock index 1a8ac21464..0e2e66d830 100644 --- a/frontend/appflowy_web_app/src-tauri/Cargo.lock +++ b/frontend/appflowy_web_app/src-tauri/Cargo.lock @@ -163,7 +163,7 @@ checksum = "c1fd03a028ef38ba2276dce7e33fcd6369c158a1bca17946c4b1b701891c1ff7" [[package]] name = "app-error" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9f57fa63d5ee039f50b0d27b860679deb14fee2e#9f57fa63d5ee039f50b0d27b860679deb14fee2e" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=ea131f0baab67defe7591067357eced490072372#ea131f0baab67defe7591067357eced490072372" dependencies = [ "anyhow", "bincode", @@ -183,7 +183,7 @@ dependencies = [ [[package]] name = "appflowy-ai-client" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9f57fa63d5ee039f50b0d27b860679deb14fee2e#9f57fa63d5ee039f50b0d27b860679deb14fee2e" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=ea131f0baab67defe7591067357eced490072372#ea131f0baab67defe7591067357eced490072372" dependencies = [ "anyhow", "bytes", @@ -877,7 +877,7 @@ dependencies = [ [[package]] name = "client-api" version = "0.2.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9f57fa63d5ee039f50b0d27b860679deb14fee2e#9f57fa63d5ee039f50b0d27b860679deb14fee2e" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=ea131f0baab67defe7591067357eced490072372#ea131f0baab67defe7591067357eced490072372" dependencies = [ "again", "anyhow", @@ -933,7 +933,7 @@ dependencies = [ [[package]] name = "client-api-entity" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9f57fa63d5ee039f50b0d27b860679deb14fee2e#9f57fa63d5ee039f50b0d27b860679deb14fee2e" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=ea131f0baab67defe7591067357eced490072372#ea131f0baab67defe7591067357eced490072372" dependencies = [ "collab-entity", "collab-rt-entity", @@ -946,7 +946,7 @@ dependencies = [ [[package]] name = "client-websocket" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9f57fa63d5ee039f50b0d27b860679deb14fee2e#9f57fa63d5ee039f50b0d27b860679deb14fee2e" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=ea131f0baab67defe7591067357eced490072372#ea131f0baab67defe7591067357eced490072372" dependencies = [ "futures-channel", "futures-util", @@ -1255,7 +1255,7 @@ dependencies = [ [[package]] name = "collab-rt-entity" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9f57fa63d5ee039f50b0d27b860679deb14fee2e#9f57fa63d5ee039f50b0d27b860679deb14fee2e" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=ea131f0baab67defe7591067357eced490072372#ea131f0baab67defe7591067357eced490072372" dependencies = [ "anyhow", "bincode", @@ -1280,7 +1280,7 @@ dependencies = [ [[package]] name = "collab-rt-protocol" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9f57fa63d5ee039f50b0d27b860679deb14fee2e#9f57fa63d5ee039f50b0d27b860679deb14fee2e" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=ea131f0baab67defe7591067357eced490072372#ea131f0baab67defe7591067357eced490072372" dependencies = [ "anyhow", "async-trait", @@ -1559,7 +1559,7 @@ dependencies = [ "cssparser-macros", "dtoa-short", "itoa 1.0.10", - "phf 0.11.2", + "phf 0.8.0", "smallvec", ] @@ -1684,7 +1684,7 @@ checksum = "7e962a19be5cfc3f3bf6dd8f61eb50107f356ad6270fbb3ed41476571db78be5" [[package]] name = "database-entity" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9f57fa63d5ee039f50b0d27b860679deb14fee2e#9f57fa63d5ee039f50b0d27b860679deb14fee2e" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=ea131f0baab67defe7591067357eced490072372#ea131f0baab67defe7591067357eced490072372" dependencies = [ "anyhow", "app-error", @@ -3350,7 +3350,7 @@ dependencies = [ [[package]] name = "gotrue" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9f57fa63d5ee039f50b0d27b860679deb14fee2e#9f57fa63d5ee039f50b0d27b860679deb14fee2e" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=ea131f0baab67defe7591067357eced490072372#ea131f0baab67defe7591067357eced490072372" dependencies = [ "anyhow", "futures-util", @@ -3367,7 +3367,7 @@ dependencies = [ [[package]] name = "gotrue-entity" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9f57fa63d5ee039f50b0d27b860679deb14fee2e#9f57fa63d5ee039f50b0d27b860679deb14fee2e" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=ea131f0baab67defe7591067357eced490072372#ea131f0baab67defe7591067357eced490072372" dependencies = [ "anyhow", "app-error", @@ -3927,7 +3927,7 @@ dependencies = [ [[package]] name = "infra" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9f57fa63d5ee039f50b0d27b860679deb14fee2e#9f57fa63d5ee039f50b0d27b860679deb14fee2e" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=ea131f0baab67defe7591067357eced490072372#ea131f0baab67defe7591067357eced490072372" dependencies = [ "anyhow", "bytes", @@ -6656,7 +6656,7 @@ dependencies = [ [[package]] name = "shared-entity" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9f57fa63d5ee039f50b0d27b860679deb14fee2e#9f57fa63d5ee039f50b0d27b860679deb14fee2e" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=ea131f0baab67defe7591067357eced490072372#ea131f0baab67defe7591067357eced490072372" dependencies = [ "anyhow", "app-error", diff --git a/frontend/appflowy_web_app/src-tauri/Cargo.toml b/frontend/appflowy_web_app/src-tauri/Cargo.toml index 6c5370c6dc..e15f726b57 100644 --- a/frontend/appflowy_web_app/src-tauri/Cargo.toml +++ b/frontend/appflowy_web_app/src-tauri/Cargo.toml @@ -58,7 +58,7 @@ collab-importer = { version = "0.1" } # Run the script: # scripts/tool/update_client_api_rev.sh new_rev_id # ⚠️⚠️⚠️️ -client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "9f57fa63d5ee039f50b0d27b860679deb14fee2e" } +client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "ea131f0baab67defe7591067357eced490072372" } [dependencies] serde_json.workspace = true diff --git a/frontend/rust-lib/Cargo.lock b/frontend/rust-lib/Cargo.lock index d777905546..46e172c6c4 100644 --- a/frontend/rust-lib/Cargo.lock +++ b/frontend/rust-lib/Cargo.lock @@ -163,7 +163,7 @@ checksum = "c1fd03a028ef38ba2276dce7e33fcd6369c158a1bca17946c4b1b701891c1ff7" [[package]] name = "app-error" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9f57fa63d5ee039f50b0d27b860679deb14fee2e#9f57fa63d5ee039f50b0d27b860679deb14fee2e" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=ea131f0baab67defe7591067357eced490072372#ea131f0baab67defe7591067357eced490072372" dependencies = [ "anyhow", "bincode", @@ -183,7 +183,7 @@ dependencies = [ [[package]] name = "appflowy-ai-client" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9f57fa63d5ee039f50b0d27b860679deb14fee2e#9f57fa63d5ee039f50b0d27b860679deb14fee2e" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=ea131f0baab67defe7591067357eced490072372#ea131f0baab67defe7591067357eced490072372" dependencies = [ "anyhow", "bytes", @@ -780,7 +780,7 @@ dependencies = [ [[package]] name = "client-api" version = "0.2.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9f57fa63d5ee039f50b0d27b860679deb14fee2e#9f57fa63d5ee039f50b0d27b860679deb14fee2e" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=ea131f0baab67defe7591067357eced490072372#ea131f0baab67defe7591067357eced490072372" dependencies = [ "again", "anyhow", @@ -836,7 +836,7 @@ dependencies = [ [[package]] name = "client-api-entity" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9f57fa63d5ee039f50b0d27b860679deb14fee2e#9f57fa63d5ee039f50b0d27b860679deb14fee2e" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=ea131f0baab67defe7591067357eced490072372#ea131f0baab67defe7591067357eced490072372" dependencies = [ "collab-entity", "collab-rt-entity", @@ -849,7 +849,7 @@ dependencies = [ [[package]] name = "client-websocket" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9f57fa63d5ee039f50b0d27b860679deb14fee2e#9f57fa63d5ee039f50b0d27b860679deb14fee2e" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=ea131f0baab67defe7591067357eced490072372#ea131f0baab67defe7591067357eced490072372" dependencies = [ "futures-channel", "futures-util", @@ -1118,7 +1118,7 @@ dependencies = [ [[package]] name = "collab-rt-entity" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9f57fa63d5ee039f50b0d27b860679deb14fee2e#9f57fa63d5ee039f50b0d27b860679deb14fee2e" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=ea131f0baab67defe7591067357eced490072372#ea131f0baab67defe7591067357eced490072372" dependencies = [ "anyhow", "bincode", @@ -1143,7 +1143,7 @@ dependencies = [ [[package]] name = "collab-rt-protocol" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9f57fa63d5ee039f50b0d27b860679deb14fee2e#9f57fa63d5ee039f50b0d27b860679deb14fee2e" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=ea131f0baab67defe7591067357eced490072372#ea131f0baab67defe7591067357eced490072372" dependencies = [ "anyhow", "async-trait", @@ -1538,7 +1538,7 @@ checksum = "c2e66c9d817f1720209181c316d28635c050fa304f9c79e47a520882661b7308" [[package]] name = "database-entity" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9f57fa63d5ee039f50b0d27b860679deb14fee2e#9f57fa63d5ee039f50b0d27b860679deb14fee2e" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=ea131f0baab67defe7591067357eced490072372#ea131f0baab67defe7591067357eced490072372" dependencies = [ "anyhow", "app-error", @@ -2982,7 +2982,7 @@ dependencies = [ [[package]] name = "gotrue" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9f57fa63d5ee039f50b0d27b860679deb14fee2e#9f57fa63d5ee039f50b0d27b860679deb14fee2e" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=ea131f0baab67defe7591067357eced490072372#ea131f0baab67defe7591067357eced490072372" dependencies = [ "anyhow", "futures-util", @@ -2999,7 +2999,7 @@ dependencies = [ [[package]] name = "gotrue-entity" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9f57fa63d5ee039f50b0d27b860679deb14fee2e#9f57fa63d5ee039f50b0d27b860679deb14fee2e" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=ea131f0baab67defe7591067357eced490072372#ea131f0baab67defe7591067357eced490072372" dependencies = [ "anyhow", "app-error", @@ -3484,7 +3484,7 @@ dependencies = [ [[package]] name = "infra" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9f57fa63d5ee039f50b0d27b860679deb14fee2e#9f57fa63d5ee039f50b0d27b860679deb14fee2e" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=ea131f0baab67defe7591067357eced490072372#ea131f0baab67defe7591067357eced490072372" dependencies = [ "anyhow", "bytes", @@ -5841,7 +5841,7 @@ dependencies = [ [[package]] name = "shared-entity" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=9f57fa63d5ee039f50b0d27b860679deb14fee2e#9f57fa63d5ee039f50b0d27b860679deb14fee2e" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=ea131f0baab67defe7591067357eced490072372#ea131f0baab67defe7591067357eced490072372" dependencies = [ "anyhow", "app-error", diff --git a/frontend/rust-lib/Cargo.toml b/frontend/rust-lib/Cargo.toml index be7c29c315..637636eaef 100644 --- a/frontend/rust-lib/Cargo.toml +++ b/frontend/rust-lib/Cargo.toml @@ -107,8 +107,8 @@ dashmap = "6.0.1" # Run the script.add_workspace_members: # scripts/tool/update_client_api_rev.sh new_rev_id # ⚠️⚠️⚠️️ -client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "9f57fa63d5ee039f50b0d27b860679deb14fee2e" } -client-api-entity = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "9f57fa63d5ee039f50b0d27b860679deb14fee2e" } +client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "ea131f0baab67defe7591067357eced490072372" } +client-api-entity = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "ea131f0baab67defe7591067357eced490072372" } [profile.dev] opt-level = 0 diff --git a/frontend/rust-lib/event-integration-test/src/folder_event.rs b/frontend/rust-lib/event-integration-test/src/folder_event.rs index c19ab85a8b..fae34e175c 100644 --- a/frontend/rust-lib/event-integration-test/src/folder_event.rs +++ b/frontend/rust-lib/event-integration-test/src/folder_event.rs @@ -1,4 +1,4 @@ -use flowy_folder::view_operation::{EncodedCollabType, ViewData}; +use flowy_folder::view_operation::{GatherEncodedCollab, ViewData}; use std::sync::Arc; use collab_folder::{FolderData, View}; @@ -190,14 +190,14 @@ impl EventIntegrationTest { payload.unwrap() } - pub async fn get_encoded_collab_v1_from_disk( + pub async fn gather_encode_collab_from_disk( &self, view_id: &str, layout: ViewLayout, - ) -> EncodedCollabType { + ) -> GatherEncodedCollab { self .folder_manager - .get_encode_collab_from_disk(view_id, &layout) + .gather_publish_encode_collab(view_id, &layout) .await .unwrap() } diff --git a/frontend/rust-lib/event-integration-test/tests/folder/local_test/publish_database_test.rs b/frontend/rust-lib/event-integration-test/tests/folder/local_test/publish_database_test.rs index 49935cbc86..6594fd83fc 100644 --- a/frontend/rust-lib/event-integration-test/tests/folder/local_test/publish_database_test.rs +++ b/frontend/rust-lib/event-integration-test/tests/folder/local_test/publish_database_test.rs @@ -5,7 +5,7 @@ use event_integration_test::EventIntegrationTest; use flowy_folder::entities::{ ImportItemPayloadPB, ImportPayloadPB, ImportTypePB, ViewLayoutPB, ViewPB, }; -use flowy_folder::view_operation::EncodedCollabType; +use flowy_folder::view_operation::GatherEncodedCollab; use crate::util::unzip; @@ -18,11 +18,11 @@ async fn publish_single_database_test() { let grid = import_csv("publish_grid_primary.csv", &test).await; let grid_encoded_collab = test - .get_encoded_collab_v1_from_disk(&grid.id, ViewLayout::Grid) + .gather_encode_collab_from_disk(&grid.id, ViewLayout::Grid) .await; match grid_encoded_collab { - EncodedCollabType::Database(encoded_collab) => { + GatherEncodedCollab::Database(encoded_collab) => { // the len of row collabs should be the same as the number of rows in the csv file let rows_len = encoded_collab.database_row_encoded_collabs.len(); assert_eq!(rows_len, 18); @@ -106,11 +106,11 @@ async fn test_publish_encode_collab_result( test.open_database(&id).await; let encoded_collab = test - .get_encoded_collab_v1_from_disk(&id, layout.into()) + .gather_encode_collab_from_disk(&id, layout.into()) .await; match encoded_collab { - EncodedCollabType::Database(encoded_collab) => { + GatherEncodedCollab::Database(encoded_collab) => { if let Some(rows_len) = expectations.get(&view.name.as_str()) { assert_eq!(encoded_collab.database_row_encoded_collabs.len(), *rows_len); } diff --git a/frontend/rust-lib/event-integration-test/tests/folder/local_test/publish_document_test.rs b/frontend/rust-lib/event-integration-test/tests/folder/local_test/publish_document_test.rs index c5cad05eb7..0d5b9bc08c 100644 --- a/frontend/rust-lib/event-integration-test/tests/folder/local_test/publish_document_test.rs +++ b/frontend/rust-lib/event-integration-test/tests/folder/local_test/publish_document_test.rs @@ -2,7 +2,7 @@ use collab_folder::ViewLayout; use event_integration_test::EventIntegrationTest; use flowy_folder::entities::{ViewLayoutPB, ViewPB}; use flowy_folder::publish_util::generate_publish_name; -use flowy_folder::view_operation::EncodedCollabType; +use flowy_folder::view_operation::GatherEncodedCollab; use flowy_folder_pub::entities::{ PublishDocumentPayload, PublishPayload, PublishViewInfo, PublishViewMeta, PublishViewMetaData, }; @@ -14,7 +14,7 @@ async fn mock_single_document_view_publish_payload( ) -> Vec { let view_id = &view.id; let layout: ViewLayout = view.layout.clone().into(); - let view_encoded_collab = test.get_encoded_collab_v1_from_disk(view_id, layout).await; + let view_encoded_collab = test.gather_encode_collab_from_disk(view_id, layout).await; let publish_view_info = PublishViewInfo { view_id: view_id.to_string(), name: view.name.to_string(), @@ -29,7 +29,7 @@ async fn mock_single_document_view_publish_payload( }; let data = match view_encoded_collab { - EncodedCollabType::Document(doc) => doc.document_encoded_collab.doc_state.to_vec(), + GatherEncodedCollab::Document(doc) => doc.doc_state.to_vec(), _ => panic!("Expected document collab"), }; @@ -54,7 +54,7 @@ async fn mock_nested_document_view_publish_payload( ) -> Vec { let view_id = &view.id; let layout: ViewLayout = view.layout.clone().into(); - let view_encoded_collab = test.get_encoded_collab_v1_from_disk(view_id, layout).await; + let view_encoded_collab = test.gather_encode_collab_from_disk(view_id, layout).await; let publish_view_info = PublishViewInfo { view_id: view_id.to_string(), name: view.name.to_string(), @@ -72,7 +72,7 @@ async fn mock_nested_document_view_publish_payload( let child_view = test.get_view(child_view_id).await; let child_layout: ViewLayout = child_view.layout.clone().into(); let child_view_encoded_collab = test - .get_encoded_collab_v1_from_disk(child_view_id, child_layout) + .gather_encode_collab_from_disk(child_view_id, child_layout) .await; let child_publish_view_info = PublishViewInfo { view_id: child_view_id.to_string(), @@ -89,12 +89,12 @@ async fn mock_nested_document_view_publish_payload( let child_publish_name = generate_publish_name(&child_view.id, &child_view.name); let data = match view_encoded_collab { - EncodedCollabType::Document(doc) => doc.document_encoded_collab.doc_state.to_vec(), + GatherEncodedCollab::Document(doc) => doc.doc_state.to_vec(), _ => panic!("Expected document collab"), }; let child_data = match child_view_encoded_collab { - EncodedCollabType::Document(doc) => doc.document_encoded_collab.doc_state.to_vec(), + GatherEncodedCollab::Document(doc) => doc.doc_state.to_vec(), _ => panic!("Expected document collab"), }; diff --git a/frontend/rust-lib/flowy-ai/src/ai_manager.rs b/frontend/rust-lib/flowy-ai/src/ai_manager.rs index 91e994763b..303aec2b40 100644 --- a/frontend/rust-lib/flowy-ai/src/ai_manager.rs +++ b/frontend/rust-lib/flowy-ai/src/ai_manager.rs @@ -1,6 +1,6 @@ use crate::chat::Chat; use crate::entities::{ - ChatInfoPB, ChatMessageListPB, ChatMessagePB, FilePB, RepeatedRelatedQuestionPB, + ChatInfoPB, ChatMessageListPB, ChatMessagePB, ChatSettingsPB, FilePB, RepeatedRelatedQuestionPB, }; use crate::local_ai::local_llm_chat::LocalAIController; use crate::middleware::chat_service_mw::AICloudServiceMiddleware; @@ -9,18 +9,19 @@ use crate::persistence::{insert_chat, read_chat_metadata, ChatTable}; use appflowy_plugin::manager::PluginManager; use dashmap::DashMap; use flowy_ai_pub::cloud::{ - ChatCloudService, ChatMessageMetadata, ChatMessageType, UpdateChatParams, + ChatCloudService, ChatMessageMetadata, ChatMessageType, ChatSettings, UpdateChatParams, }; use flowy_error::{FlowyError, FlowyResult}; use flowy_sqlite::kv::KVStorePreferences; use flowy_sqlite::DBConnection; +use crate::notification::{chat_notification_builder, ChatNotification}; use flowy_storage_pub::storage::StorageService; use lib_infra::async_trait::async_trait; use lib_infra::util::timestamp; use std::path::PathBuf; use std::sync::{Arc, Weak}; -use tracing::{info, trace}; +use tracing::{error, info, trace}; pub trait AIUserService: Send + Sync + 'static { fn user_id(&self) -> Result; @@ -31,22 +32,29 @@ pub trait AIUserService: Send + Sync + 'static { } #[async_trait] -pub trait AIQueryService: Send + Sync + 'static { +pub trait AIExternalService: Send + Sync + 'static { async fn query_chat_rag_ids( &self, parent_view_id: &str, chat_id: &str, ) -> Result, FlowyError>; - async fn sync_rag_documents(&self, rag_ids: Vec) -> Result<(), FlowyError>; + async fn sync_rag_documents( + &self, + workspace_id: &str, + rag_ids: Vec, + ) -> Result<(), FlowyError>; + + async fn notify_did_send_message(&self, chat_id: &str, message: &str) -> Result<(), FlowyError>; } pub struct AIManager { pub cloud_service_wm: Arc, pub user_service: Arc, - pub query_service: Arc, + pub external_service: Arc, chats: Arc>>, pub local_ai_controller: Arc, + store_preferences: Arc, } impl AIManager { @@ -55,7 +63,7 @@ impl AIManager { user_service: impl AIUserService, store_preferences: Arc, storage_service: Weak, - query_service: impl AIQueryService, + query_service: impl AIExternalService, ) -> AIManager { let user_service = Arc::new(user_service); let plugin_manager = Arc::new(PluginManager::new()); @@ -65,7 +73,7 @@ impl AIManager { user_service.clone(), chat_cloud_service.clone(), )); - let query_service = Arc::new(query_service); + let external_service = Arc::new(query_service); // setup local chat service let cloud_service_wm = Arc::new(AICloudServiceMiddleware::new( @@ -80,7 +88,8 @@ impl AIManager { user_service, chats: Arc::new(DashMap::new()), local_ai_controller, - query_service, + external_service, + store_preferences, } } @@ -99,12 +108,41 @@ impl AIManager { self.cloud_service_wm.clone(), )) }); - trace!("[AI Plugin] notify open chat: {}", chat_id); if self.local_ai_controller.is_running() { self.local_ai_controller.open_chat(chat_id); } + let user_service = self.user_service.clone(); + let cloud_service_wm = self.cloud_service_wm.clone(); + let store_preferences = self.store_preferences.clone(); + let external_service = self.external_service.clone(); + let chat_id = chat_id.to_string(); + tokio::spawn(async move { + match refresh_chat_setting( + &user_service, + &cloud_service_wm, + &store_preferences, + &chat_id, + ) + .await + { + Ok(settings) => { + if settings.rag_ids.is_empty() { + return; + } + if let Ok(workspace_id) = user_service.workspace_id() { + let _ = external_service + .sync_rag_documents(&workspace_id, settings.rag_ids) + .await; + } + }, + Err(err) => { + error!("failed to refresh chat settings: {}", err); + }, + } + }); + Ok(()) } @@ -152,7 +190,7 @@ impl AIManager { ) -> Result, FlowyError> { let workspace_id = self.user_service.workspace_id()?; let rag_ids = self - .query_service + .external_service .query_chat_rag_ids(parent_view_id, chat_id) .await .unwrap_or_default(); @@ -193,6 +231,10 @@ impl AIManager { metadata, ) .await?; + let _ = self + .external_service + .notify_did_send_message(chat_id, message) + .await; Ok(question) } @@ -302,31 +344,48 @@ impl AIManager { Ok(()) } - pub fn local_ai_purchased(&self) {} - pub async fn get_rag_ids(&self, chat_id: &str) -> FlowyResult> { - let workspace_id = self.user_service.workspace_id()?; - - let settings = self - .cloud_service_wm - .get_chat_settings(&workspace_id, chat_id) - .await?; + if let Some(settings) = self + .store_preferences + .get_object::(&setting_store_key(chat_id)) + { + return Ok(settings.rag_ids); + } + let settings = refresh_chat_setting( + &self.user_service, + &self.cloud_service_wm, + &self.store_preferences, + chat_id, + ) + .await?; Ok(settings.rag_ids) } pub async fn update_rag_ids(&self, chat_id: &str, rag_ids: Vec) -> FlowyResult<()> { + info!("[Chat] update chat:{} rag ids: {:?}", chat_id, rag_ids); + if !rag_ids.is_empty() { let workspace_id = self.user_service.workspace_id()?; let update_setting = UpdateChatParams { name: None, metadata: None, - rag_ids: Some(rag_ids), + rag_ids: Some(rag_ids.clone()), }; self .cloud_service_wm .update_chat_settings(&workspace_id, chat_id, update_setting) .await?; + + let user_service = self.user_service.clone(); + let external_service = self.external_service.clone(); + tokio::spawn(async move { + if let Ok(workspace_id) = user_service.workspace_id() { + let _ = external_service + .sync_rag_documents(&workspace_id, rag_ids) + .await; + } + }); } Ok(()) } @@ -346,3 +405,32 @@ fn save_chat(conn: DBConnection, chat_id: &str) -> FlowyResult<()> { insert_chat(conn, &row)?; Ok(()) } + +async fn refresh_chat_setting( + user_service: &Arc, + cloud_service: &Arc, + store_preferences: &Arc, + chat_id: &str, +) -> FlowyResult { + info!("[Chat] refresh chat:{} setting", chat_id); + let workspace_id = user_service.workspace_id()?; + let settings = cloud_service + .get_chat_settings(&workspace_id, chat_id) + .await?; + + if let Err(err) = store_preferences.set_object(&setting_store_key(chat_id), &settings) { + error!("failed to set chat settings: {}", err); + } + + chat_notification_builder(chat_id, ChatNotification::DidUpdateChatSettings) + .payload(ChatSettingsPB { + rag_ids: settings.rag_ids.clone(), + }) + .send(); + + Ok(settings) +} + +fn setting_store_key(chat_id: &str) -> String { + format!("chat_settings_{}", chat_id) +} diff --git a/frontend/rust-lib/flowy-ai/src/notification.rs b/frontend/rust-lib/flowy-ai/src/notification.rs index 24cd464cd1..c7857dbc8a 100644 --- a/frontend/rust-lib/flowy-ai/src/notification.rs +++ b/frontend/rust-lib/flowy-ai/src/notification.rs @@ -14,6 +14,7 @@ pub enum ChatNotification { FinishStreaming = 5, UpdateChatPluginState = 6, UpdateLocalChatAI = 7, + DidUpdateChatSettings = 8, } impl std::convert::From for i32 { diff --git a/frontend/rust-lib/flowy-core/src/deps_resolve/chat_deps.rs b/frontend/rust-lib/flowy-core/src/deps_resolve/chat_deps.rs index 7618caf737..5696987485 100644 --- a/frontend/rust-lib/flowy-core/src/deps_resolve/chat_deps.rs +++ b/frontend/rust-lib/flowy-core/src/deps_resolve/chat_deps.rs @@ -1,8 +1,10 @@ -use flowy_ai::ai_manager::{AIManager, AIQueryService, AIUserService}; +use collab_entity::CollabType; +use flowy_ai::ai_manager::{AIExternalService, AIManager, AIUserService}; use flowy_ai_pub::cloud::ChatCloudService; use flowy_error::FlowyError; use flowy_folder::ViewLayout; -use flowy_folder_pub::query::FolderQueryService; +use flowy_folder_pub::cloud::{FolderCloudService, FullSyncCollabParams}; +use flowy_folder_pub::query::FolderService; use flowy_sqlite::kv::KVStorePreferences; use flowy_sqlite::DBConnection; use flowy_storage_pub::storage::StorageService; @@ -10,6 +12,7 @@ use flowy_user::services::authenticate_user::AuthenticateUser; use lib_infra::async_trait::async_trait; use std::path::PathBuf; use std::sync::{Arc, Weak}; +use tracing::{error, info}; pub struct ChatDepsResolver; @@ -19,7 +22,8 @@ impl ChatDepsResolver { cloud_service: Arc, store_preferences: Arc, storage_service: Weak, - folder_query: impl FolderQueryService, + folder_cloud_service: Arc, + folder_service: impl FolderService, ) -> Arc { let user_service = ChatUserServiceImpl(authenticate_user); Arc::new(AIManager::new( @@ -28,25 +32,27 @@ impl ChatDepsResolver { store_preferences, storage_service, ChatQueryServiceImpl { - folder_query: Box::new(folder_query), + folder_service: Box::new(folder_service), + folder_cloud_service, }, )) } } struct ChatQueryServiceImpl { - folder_query: Box, + folder_service: Box, + folder_cloud_service: Arc, } #[async_trait] -impl AIQueryService for ChatQueryServiceImpl { +impl AIExternalService for ChatQueryServiceImpl { async fn query_chat_rag_ids( &self, parent_view_id: &str, chat_id: &str, ) -> Result, FlowyError> { let mut ids = self - .folder_query + .folder_service .get_sibling_ids_with_view_layout(parent_view_id, ViewLayout::Document) .await; @@ -57,14 +63,48 @@ impl AIQueryService for ChatQueryServiceImpl { Ok(ids) } - async fn sync_rag_documents(&self, rag_ids: Vec) -> Result<(), FlowyError> { + async fn sync_rag_documents( + &self, + workspace_id: &str, + rag_ids: Vec, + ) -> Result<(), FlowyError> { + info!("sync_rag_documents: {:?}", rag_ids); + for rag_id in rag_ids.iter() { - if let Some(_query_collab) = self.folder_query.get_collab(rag_id).await { - // TODO(nathan): sync + if let Some(query_collab) = self + .folder_service + .get_collab(rag_id, CollabType::Document) + .await + { + let params = FullSyncCollabParams { + object_id: rag_id.clone(), + collab_type: CollabType::Document, + encoded_collab: query_collab.encoded_collab, + }; + match self + .folder_cloud_service + .full_sync_collab_object(workspace_id, params) + .await + { + Ok(_) => info!("[Chat] full sync rag document: {}", rag_id), + Err(err) => error!("failed to sync rag document:{} error:{}", rag_id, err), + } } } Ok(()) } + + async fn notify_did_send_message(&self, chat_id: &str, message: &str) -> Result<(), FlowyError> { + info!( + "notify_did_send_message: chat_id: {}, message: {}", + chat_id, message + ); + self + .folder_service + .set_view_title_if_empty(chat_id, message) + .await?; + Ok(()) + } } struct ChatUserServiceImpl(Weak); diff --git a/frontend/rust-lib/flowy-core/src/deps_resolve/folder_deps.rs b/frontend/rust-lib/flowy-core/src/deps_resolve/folder_deps.rs index 27b02b8c77..b643631be9 100644 --- a/frontend/rust-lib/flowy-core/src/deps_resolve/folder_deps.rs +++ b/frontend/rust-lib/flowy-core/src/deps_resolve/folder_deps.rs @@ -12,13 +12,12 @@ use flowy_database2::DatabaseManager; use flowy_document::entities::DocumentDataPB; use flowy_document::manager::DocumentManager; use flowy_document::parser::json::parser::JsonToDocumentParser; -use flowy_error::{FlowyError, FlowyResult}; -use flowy_folder::entities::{CreateViewParams, ViewLayoutPB}; +use flowy_error::{internal_error, FlowyError, FlowyResult}; +use flowy_folder::entities::{CreateViewParams, UpdateViewParams, ViewLayoutPB}; use flowy_folder::manager::{FolderManager, FolderUser}; use flowy_folder::share::ImportType; use flowy_folder::view_operation::{ - DatabaseEncodedCollab, DocumentEncodedCollab, EncodedCollabType, FolderOperationHandler, - ImportedData, View, ViewData, + DatabaseEncodedCollab, FolderOperationHandler, GatherEncodedCollab, ImportedData, View, ViewData, }; use flowy_folder::ViewLayout; use flowy_search::folder::indexer::FolderIndexManagerImpl; @@ -34,7 +33,7 @@ use tokio::sync::RwLock; use crate::integrate::server::ServerProvider; use collab_plugins::local_storage::kv::KVTransactionDB; -use flowy_folder_pub::query::{FolderQueryService, QueryCollab}; +use flowy_folder_pub::query::{FolderQueryService, FolderService, FolderViewEdit, QueryCollab}; use lib_infra::async_trait::async_trait; pub struct FolderDepsResolver(); @@ -116,6 +115,10 @@ impl FolderUser for FolderUserImpl { struct DocumentFolderOperation(Arc); #[async_trait] impl FolderOperationHandler for DocumentFolderOperation { + fn name(&self) -> &str { + "DocumentFolderOperationHandler" + } + async fn create_workspace_view( &self, uid: i64, @@ -169,6 +172,16 @@ impl FolderOperationHandler for DocumentFolderOperation { Ok(data_bytes) } + async fn gather_publish_encode_collab( + &self, + user: &Arc, + view_id: &str, + ) -> Result { + let encoded_collab = + get_encoded_collab_v1_from_disk(user, view_id, CollabType::Document).await?; + Ok(GatherEncodedCollab::Document(encoded_collab)) + } + async fn create_view_with_view_data( &self, user_id: i64, @@ -209,47 +222,6 @@ impl FolderOperationHandler for DocumentFolderOperation { } } - async fn get_encoded_collab_v1_from_disk( - &self, - user: &Arc, - view_id: &str, - ) -> Result { - // get the collab_object_id for the document. - // the collab_object_id for the document is the view_id. - let workspace_id = user.workspace_id()?; - let uid = user - .user_id() - .map_err(|e| e.with_context("unable to get the uid: {}"))?; - - // get the collab db - let collab_db = user - .collab_db(uid) - .map_err(|e| e.with_context("unable to get the collab"))?; - let collab_db = collab_db.upgrade().ok_or_else(|| { - FlowyError::internal().with_context( - "The collab db has been dropped, indicating that the user has switched to a new account", - ) - })?; - let collab_read_txn = collab_db.read_txn(); - - // read the collab from the db - let collab = - load_collab_by_object_id(uid, &collab_read_txn, &workspace_id, view_id).map_err(|e| { - FlowyError::internal().with_context(format!("load document collab failed: {}", e)) - })?; - - let encoded_collab = collab - // encode the collab and check the integrity of the collab - .encode_collab_v1(|collab| CollabType::Document.validate_require_data(collab)) - .map_err(|e| { - FlowyError::internal().with_context(format!("encode document collab failed: {}", e)) - })?; - - Ok(EncodedCollabType::Document(DocumentEncodedCollab { - document_encoded_collab: encoded_collab, - })) - } - async fn import_from_bytes( &self, uid: i64, @@ -279,10 +251,6 @@ impl FolderOperationHandler for DocumentFolderOperation { // TODO(lucas): import file from local markdown file Ok(()) } - - fn name(&self) -> &str { - "DocumentFolderOperationHandler" - } } struct DatabaseFolderOperation(Arc); @@ -307,11 +275,11 @@ impl FolderOperationHandler for DatabaseFolderOperation { Ok(()) } - async fn get_encoded_collab_v1_from_disk( + async fn gather_publish_encode_collab( &self, user: &Arc, view_id: &str, - ) -> Result { + ) -> Result { let workspace_id = user.workspace_id()?; // get the collab_object_id for the database. // @@ -349,7 +317,6 @@ impl FolderOperationHandler for DatabaseFolderOperation { tokio::task::spawn_blocking(move || { let collab_read_txn = collab_db.read_txn(); - let database_collab = load_collab_by_object_id(uid, &collab_read_txn, &workspace_id, &oid) .map_err(|e| { FlowyError::internal().with_context(format!("load database collab failed: {}", e)) @@ -403,7 +370,7 @@ impl FolderOperationHandler for DatabaseFolderOperation { }) .collect::, FlowyError>>()?; - Ok(EncodedCollabType::Database(DatabaseEncodedCollab { + Ok(GatherEncodedCollab::Database(DatabaseEncodedCollab { database_encoded_collab, database_row_encoded_collabs, database_row_document_encoded_collabs, @@ -663,19 +630,62 @@ impl FolderOperationHandler for ChatFolderOperation { } } -#[derive(Clone, Debug)] -pub struct FolderQueryServiceImpl { +#[derive(Clone)] +pub struct FolderServiceImpl { folder_manager: Weak, + user: Arc, } +impl FolderService for FolderServiceImpl {} -impl FolderQueryServiceImpl { - pub fn new(folder_manager: Weak) -> Self { - Self { folder_manager } +impl FolderServiceImpl { + pub fn new( + folder_manager: Weak, + authenticate_user: Weak, + ) -> Self { + let user: Arc = Arc::new(FolderUserImpl { authenticate_user }); + Self { + folder_manager, + user, + } } } #[async_trait] -impl FolderQueryService for FolderQueryServiceImpl { +impl FolderViewEdit for FolderServiceImpl { + async fn set_view_title_if_empty(&self, view_id: &str, title: &str) -> FlowyResult<()> { + if title.is_empty() { + return Ok(()); + } + + if let Some(folder_manager) = self.folder_manager.upgrade() { + if let Ok(view) = folder_manager.get_view(view_id).await { + if view.name.is_empty() { + let title = if title.len() > 50 { + title.chars().take(50).collect() + } else { + title.to_string() + }; + + folder_manager + .update_view_with_params(UpdateViewParams { + view_id: view_id.to_string(), + name: Some(title), + desc: None, + thumbnail: None, + layout: None, + is_favorite: None, + extra: None, + }) + .await?; + } + } + } + Ok(()) + } +} + +#[async_trait] +impl FolderQueryService for FolderServiceImpl { async fn get_sibling_ids_with_view_layout( &self, parent_view_id: &str, @@ -708,8 +718,52 @@ impl FolderQueryService for FolderQueryServiceImpl { } } - async fn get_collab(&self, _object_id: &str) -> Option { - // TODO(nathan): return query collab - None + async fn get_collab(&self, object_id: &str, collab_type: CollabType) -> Option { + let encode_collab = get_encoded_collab_v1_from_disk(&self.user, object_id, collab_type.clone()) + .await + .ok(); + + encode_collab.map(|encoded_collab| QueryCollab { + collab_type, + encoded_collab, + }) } } + +#[inline] +async fn get_encoded_collab_v1_from_disk( + user: &Arc, + view_id: &str, + collab_type: CollabType, +) -> Result { + let workspace_id = user.workspace_id()?; + let uid = user + .user_id() + .map_err(|e| e.with_context("unable to get the uid: {}"))?; + + // get the collab db + let collab_db = user + .collab_db(uid) + .map_err(|e| e.with_context("unable to get the collab"))?; + let collab_db = collab_db.upgrade().ok_or_else(|| { + FlowyError::internal().with_context( + "The collab db has been dropped, indicating that the user has switched to a new account", + ) + })?; + let collab_read_txn = collab_db.read_txn(); + let collab = + load_collab_by_object_id(uid, &collab_read_txn, &workspace_id, view_id).map_err(|e| { + FlowyError::internal().with_context(format!("load document collab failed: {}", e)) + })?; + + tokio::task::spawn_blocking(move || { + let data = collab + .encode_collab_v1(|collab| collab_type.validate_require_data(collab)) + .map_err(|e| { + FlowyError::internal().with_context(format!("encode document collab failed: {}", e)) + })?; + Ok::<_, FlowyError>(data) + }) + .await + .map_err(internal_error)? +} diff --git a/frontend/rust-lib/flowy-core/src/integrate/trait_impls.rs b/frontend/rust-lib/flowy-core/src/integrate/trait_impls.rs index d5b2d07123..d3de12654b 100644 --- a/frontend/rust-lib/flowy-core/src/integrate/trait_impls.rs +++ b/frontend/rust-lib/flowy-core/src/integrate/trait_impls.rs @@ -33,7 +33,8 @@ use flowy_document::deps::DocumentData; use flowy_document_pub::cloud::{DocumentCloudService, DocumentSnapshot}; use flowy_error::{FlowyError, FlowyResult}; use flowy_folder_pub::cloud::{ - FolderCloudService, FolderCollabParams, FolderData, FolderSnapshot, Workspace, WorkspaceRecord, + FolderCloudService, FolderCollabParams, FolderData, FolderSnapshot, FullSyncCollabParams, + Workspace, WorkspaceRecord, }; use flowy_folder_pub::entities::PublishPayload; use flowy_server_pub::af_cloud_config::AFCloudConfiguration; @@ -417,6 +418,18 @@ impl FolderCloudService for ServerProvider { .import_zip(file_path) .await } + + async fn full_sync_collab_object( + &self, + workspace_id: &str, + params: FullSyncCollabParams, + ) -> Result<(), FlowyError> { + self + .get_server()? + .folder_service() + .full_sync_collab_object(workspace_id, params) + .await + } } #[async_trait] diff --git a/frontend/rust-lib/flowy-core/src/integrate/user.rs b/frontend/rust-lib/flowy-core/src/integrate/user.rs index 8a77916843..36f05d39ff 100644 --- a/frontend/rust-lib/flowy-core/src/integrate/user.rs +++ b/frontend/rust-lib/flowy-core/src/integrate/user.rs @@ -211,21 +211,15 @@ impl UserStatusCallback for UserStatusCallbackImpl { fn did_update_plans(&self, plans: Vec) { let mut storage_plan_changed = false; - let mut local_ai_enabled = false; for plan in &plans { match plan { SubscriptionPlan::Pro | SubscriptionPlan::Team => storage_plan_changed = true, - SubscriptionPlan::AiLocal => local_ai_enabled = true, _ => {}, } } if storage_plan_changed { self.storage_manager.enable_storage_write_access(); } - - if local_ai_enabled { - self.ai_manager.local_ai_purchased(); - } } fn did_update_storage_limitation(&self, can_write: bool) { diff --git a/frontend/rust-lib/flowy-core/src/lib.rs b/frontend/rust-lib/flowy-core/src/lib.rs index 95411d5cca..e55d638f2e 100644 --- a/frontend/rust-lib/flowy-core/src/lib.rs +++ b/frontend/rust-lib/flowy-core/src/lib.rs @@ -174,13 +174,17 @@ impl AppFlowyCore { ) .await; - let folder_query_service = FolderQueryServiceImpl::new(Arc::downgrade(&folder_manager)); + let folder_query_service = FolderServiceImpl::new( + Arc::downgrade(&folder_manager), + Arc::downgrade(&authenticate_user), + ); let ai_manager = ChatDepsResolver::resolve( Arc::downgrade(&authenticate_user), server_provider.clone(), store_preference.clone(), Arc::downgrade(&storage_manager.storage_service), + server_provider.clone(), folder_query_service.clone(), ); diff --git a/frontend/rust-lib/flowy-folder-pub/src/cloud.rs b/frontend/rust-lib/flowy-folder-pub/src/cloud.rs index 050397a1e3..3e7776d0bf 100644 --- a/frontend/rust-lib/flowy-folder-pub/src/cloud.rs +++ b/frontend/rust-lib/flowy-folder-pub/src/cloud.rs @@ -1,6 +1,7 @@ use crate::entities::PublishPayload; pub use anyhow::Error; use client_api::entity::{workspace_dto::PublishInfoView, PublishInfo}; +use collab::entity::EncodedCollab; use collab_entity::CollabType; pub use collab_folder::{Folder, FolderData, Workspace}; use flowy_error::FlowyError; @@ -40,6 +41,12 @@ pub trait FolderCloudService: Send + Sync + 'static { object_id: &str, ) -> Result, FlowyError>; + async fn full_sync_collab_object( + &self, + workspace_id: &str, + params: FullSyncCollabParams, + ) -> Result<(), FlowyError>; + async fn batch_create_folder_collab_objects( &self, workspace_id: &str, @@ -105,6 +112,13 @@ pub struct FolderCollabParams { pub collab_type: CollabType, } +#[derive(Debug)] +pub struct FullSyncCollabParams { + pub object_id: String, + pub encoded_collab: EncodedCollab, + pub collab_type: CollabType, +} + pub struct FolderSnapshot { pub snapshot_id: i64, pub database_id: String, diff --git a/frontend/rust-lib/flowy-folder-pub/src/query.rs b/frontend/rust-lib/flowy-folder-pub/src/query.rs index 52365a2803..ed4c62e696 100644 --- a/frontend/rust-lib/flowy-folder-pub/src/query.rs +++ b/frontend/rust-lib/flowy-folder-pub/src/query.rs @@ -1,14 +1,16 @@ use collab::entity::EncodedCollab; use collab_entity::CollabType; use collab_folder::ViewLayout; +use flowy_error::FlowyResult; use lib_infra::async_trait::async_trait; pub struct QueryCollab { - pub name: String, pub collab_type: CollabType, pub encoded_collab: EncodedCollab, } +pub trait FolderService: FolderQueryService + FolderViewEdit {} + #[async_trait] pub trait FolderQueryService: Send + Sync + 'static { async fn get_sibling_ids_with_view_layout( @@ -17,5 +19,10 @@ pub trait FolderQueryService: Send + Sync + 'static { view_layout: ViewLayout, ) -> Vec; - async fn get_collab(&self, object_id: &str) -> Option; + async fn get_collab(&self, object_id: &str, collab_type: CollabType) -> Option; +} + +#[async_trait] +pub trait FolderViewEdit: Send + Sync + 'static { + async fn set_view_title_if_empty(&self, view_id: &str, title: &str) -> FlowyResult<()>; } diff --git a/frontend/rust-lib/flowy-folder/src/manager.rs b/frontend/rust-lib/flowy-folder/src/manager.rs index 30fd60ddfe..1ac160c9ba 100644 --- a/frontend/rust-lib/flowy-folder/src/manager.rs +++ b/frontend/rust-lib/flowy-folder/src/manager.rs @@ -16,7 +16,7 @@ use crate::publish_util::{generate_publish_name, view_pb_to_publish_view}; use crate::share::{ImportData, ImportItem, ImportParams}; use crate::util::{folder_not_init_error, workspace_data_not_sync_error}; use crate::view_operation::{ - create_view, EncodedCollabType, FolderOperationHandler, FolderOperationHandlers, ViewData, + create_view, FolderOperationHandler, FolderOperationHandlers, GatherEncodedCollab, ViewData, }; use arc_swap::ArcSwapOption; use client_api::entity::workspace_dto::PublishInfoView; @@ -132,14 +132,14 @@ impl FolderManager { Ok(data) } - pub async fn get_encode_collab_from_disk( + pub async fn gather_publish_encode_collab( &self, view_id: &str, layout: &ViewLayout, - ) -> FlowyResult { + ) -> FlowyResult { let handler = self.get_handler(layout)?; let encoded_collab = handler - .get_encoded_collab_v1_from_disk(&self.user, view_id) + .gather_publish_encode_collab(&self.user, view_id) .await?; Ok(encoded_collab) } @@ -1524,8 +1524,8 @@ impl FolderManager { layout: ViewLayout, ) -> FlowyResult { let handler = self.get_handler(&layout)?; - let encoded_collab_wrapper: EncodedCollabType = handler - .get_encoded_collab_v1_from_disk(&self.user, view_id) + let encoded_collab_wrapper: GatherEncodedCollab = handler + .gather_publish_encode_collab(&self.user, view_id) .await?; let view = self.get_view_pb(view_id).await?; @@ -1556,7 +1556,7 @@ impl FolderManager { }; let payload = match encoded_collab_wrapper { - EncodedCollabType::Database(v) => { + GatherEncodedCollab::Database(v) => { let database_collab = v.database_encoded_collab.doc_state.to_vec(); let database_relations = v.database_relations; let database_row_collabs = v @@ -1579,11 +1579,11 @@ impl FolderManager { }; PublishPayload::Database(PublishDatabasePayload { meta, data }) }, - EncodedCollabType::Document(v) => { - let data = v.document_encoded_collab.doc_state.to_vec(); + GatherEncodedCollab::Document(v) => { + let data = v.doc_state.to_vec(); PublishPayload::Document(PublishDocumentPayload { meta, data }) }, - EncodedCollabType::Unknown => PublishPayload::Unknown, + GatherEncodedCollab::Unknown => PublishPayload::Unknown, }; Ok(payload) diff --git a/frontend/rust-lib/flowy-folder/src/view_operation.rs b/frontend/rust-lib/flowy-folder/src/view_operation.rs index 589d344256..a4f2792afc 100644 --- a/frontend/rust-lib/flowy-folder/src/view_operation.rs +++ b/frontend/rust-lib/flowy-folder/src/view_operation.rs @@ -19,17 +19,12 @@ use crate::manager::FolderUser; use crate::share::ImportType; #[derive(Debug, Clone)] -pub enum EncodedCollabType { - Document(DocumentEncodedCollab), +pub enum GatherEncodedCollab { + Document(EncodedCollab), Database(DatabaseEncodedCollab), Unknown, } -#[derive(Debug, Clone)] -pub struct DocumentEncodedCollab { - pub document_encoded_collab: EncodedCollab, -} - #[derive(Debug, Clone)] pub struct DatabaseEncodedCollab { pub database_encoded_collab: EncodedCollab, @@ -69,11 +64,11 @@ pub trait FolderOperationHandler: Send + Sync { async fn duplicate_view(&self, view_id: &str) -> Result; /// get the encoded collab data from the disk. - async fn get_encoded_collab_v1_from_disk( + async fn gather_publish_encode_collab( &self, _user: &Arc, _view_id: &str, - ) -> Result { + ) -> Result { Err(FlowyError::not_support()) } diff --git a/frontend/rust-lib/flowy-server/src/af_cloud/impls/folder.rs b/frontend/rust-lib/flowy-server/src/af_cloud/impls/folder.rs index ef41eb7380..a5e0b2e853 100644 --- a/frontend/rust-lib/flowy-server/src/af_cloud/impls/folder.rs +++ b/frontend/rust-lib/flowy-server/src/af_cloud/impls/folder.rs @@ -16,8 +16,8 @@ use uuid::Uuid; use flowy_error::{ErrorCode, FlowyError}; use flowy_folder_pub::cloud::{ - Folder, FolderCloudService, FolderCollabParams, FolderData, FolderSnapshot, Workspace, - WorkspaceRecord, + Folder, FolderCloudService, FolderCollabParams, FolderData, FolderSnapshot, FullSyncCollabParams, + Workspace, WorkspaceRecord, }; use flowy_folder_pub::entities::PublishPayload; use lib_infra::async_trait::async_trait; @@ -152,6 +152,25 @@ where Ok(doc_state) } + async fn full_sync_collab_object( + &self, + workspace_id: &str, + params: FullSyncCollabParams, + ) -> Result<(), FlowyError> { + let workspace_id = workspace_id.to_string(); + let try_get_client = self.inner.try_get_client(); + try_get_client? + .collab_full_sync( + &workspace_id, + ¶ms.object_id, + params.collab_type, + params.encoded_collab.doc_state.to_vec(), + params.encoded_collab.state_vector.to_vec(), + ) + .await?; + Ok(()) + } + async fn batch_create_folder_collab_objects( &self, workspace_id: &str, diff --git a/frontend/rust-lib/flowy-server/src/local_server/impls/folder.rs b/frontend/rust-lib/flowy-server/src/local_server/impls/folder.rs index 726bc9ae58..52d9a9e98c 100644 --- a/frontend/rust-lib/flowy-server/src/local_server/impls/folder.rs +++ b/frontend/rust-lib/flowy-server/src/local_server/impls/folder.rs @@ -7,8 +7,8 @@ use collab_entity::CollabType; use crate::local_server::LocalServerDB; use flowy_error::FlowyError; use flowy_folder_pub::cloud::{ - gen_workspace_id, FolderCloudService, FolderCollabParams, FolderData, FolderSnapshot, Workspace, - WorkspaceRecord, + gen_workspace_id, FolderCloudService, FolderCollabParams, FolderData, FolderSnapshot, + FullSyncCollabParams, Workspace, WorkspaceRecord, }; use flowy_folder_pub::entities::PublishPayload; use lib_infra::async_trait::async_trait; @@ -145,4 +145,12 @@ impl FolderCloudService for LocalServerFolderCloudServiceImpl { async fn import_zip(&self, _file_path: &str) -> Result<(), FlowyError> { Err(FlowyError::local_version_not_support()) } + + async fn full_sync_collab_object( + &self, + _workspace_id: &str, + _params: FullSyncCollabParams, + ) -> Result<(), FlowyError> { + Ok(()) + } }