mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2025-07-26 03:23:01 +00:00
chore: only sync when doucment was changed (#7081)
* chore: only sync when doucment was changed * chore: fmt
This commit is contained in:
20
frontend/appflowy_tauri/src-tauri/Cargo.lock
generated
20
frontend/appflowy_tauri/src-tauri/Cargo.lock
generated
@ -1031,7 +1031,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=dd8a1d13e97322338f027888a71340575cd9ad8f#dd8a1d13e97322338f027888a71340575cd9ad8f"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=67b31e4bcc64d81332c37efecb0a8618681f1db9#67b31e4bcc64d81332c37efecb0a8618681f1db9"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"arc-swap",
|
||||
@ -1056,7 +1056,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-database"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=dd8a1d13e97322338f027888a71340575cd9ad8f#dd8a1d13e97322338f027888a71340575cd9ad8f"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=67b31e4bcc64d81332c37efecb0a8618681f1db9#67b31e4bcc64d81332c37efecb0a8618681f1db9"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
@ -1096,7 +1096,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-document"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=dd8a1d13e97322338f027888a71340575cd9ad8f#dd8a1d13e97322338f027888a71340575cd9ad8f"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=67b31e4bcc64d81332c37efecb0a8618681f1db9#67b31e4bcc64d81332c37efecb0a8618681f1db9"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"arc-swap",
|
||||
@ -1117,7 +1117,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-entity"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=dd8a1d13e97322338f027888a71340575cd9ad8f#dd8a1d13e97322338f027888a71340575cd9ad8f"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=67b31e4bcc64d81332c37efecb0a8618681f1db9#67b31e4bcc64d81332c37efecb0a8618681f1db9"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bytes",
|
||||
@ -1137,7 +1137,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-folder"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=dd8a1d13e97322338f027888a71340575cd9ad8f#dd8a1d13e97322338f027888a71340575cd9ad8f"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=67b31e4bcc64d81332c37efecb0a8618681f1db9#67b31e4bcc64d81332c37efecb0a8618681f1db9"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"arc-swap",
|
||||
@ -1159,7 +1159,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-importer"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=dd8a1d13e97322338f027888a71340575cd9ad8f#dd8a1d13e97322338f027888a71340575cd9ad8f"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=67b31e4bcc64d81332c37efecb0a8618681f1db9#67b31e4bcc64d81332c37efecb0a8618681f1db9"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-recursion",
|
||||
@ -1209,6 +1209,9 @@ dependencies = [
|
||||
"collab-folder",
|
||||
"collab-plugins",
|
||||
"collab-user",
|
||||
"diesel",
|
||||
"flowy-error",
|
||||
"flowy-sqlite",
|
||||
"futures",
|
||||
"lib-infra",
|
||||
"serde",
|
||||
@ -1220,7 +1223,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-plugins"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=dd8a1d13e97322338f027888a71340575cd9ad8f#dd8a1d13e97322338f027888a71340575cd9ad8f"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=67b31e4bcc64d81332c37efecb0a8618681f1db9#67b31e4bcc64d81332c37efecb0a8618681f1db9"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-stream",
|
||||
@ -1300,7 +1303,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-user"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=dd8a1d13e97322338f027888a71340575cd9ad8f#dd8a1d13e97322338f027888a71340575cd9ad8f"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=67b31e4bcc64d81332c37efecb0a8618681f1db9#67b31e4bcc64d81332c37efecb0a8618681f1db9"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"collab",
|
||||
@ -2144,6 +2147,7 @@ dependencies = [
|
||||
"arc-swap",
|
||||
"base64 0.21.5",
|
||||
"bytes",
|
||||
"collab-integrate",
|
||||
"dashmap 6.0.1",
|
||||
"flowy-ai-pub",
|
||||
"flowy-codegen",
|
||||
|
@ -120,14 +120,14 @@ custom-protocol = ["tauri/custom-protocol"]
|
||||
# To switch to the local path, run:
|
||||
# scripts/tool/update_collab_source.sh
|
||||
# ⚠️⚠️⚠️️
|
||||
collab = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "dd8a1d13e97322338f027888a71340575cd9ad8f" }
|
||||
collab-entity = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "dd8a1d13e97322338f027888a71340575cd9ad8f" }
|
||||
collab-folder = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "dd8a1d13e97322338f027888a71340575cd9ad8f" }
|
||||
collab-document = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "dd8a1d13e97322338f027888a71340575cd9ad8f" }
|
||||
collab-database = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "dd8a1d13e97322338f027888a71340575cd9ad8f" }
|
||||
collab-plugins = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "dd8a1d13e97322338f027888a71340575cd9ad8f" }
|
||||
collab-user = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "dd8a1d13e97322338f027888a71340575cd9ad8f" }
|
||||
collab-importer = { version = "0.1", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "dd8a1d13e97322338f027888a71340575cd9ad8f" }
|
||||
collab = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "67b31e4bcc64d81332c37efecb0a8618681f1db9" }
|
||||
collab-entity = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "67b31e4bcc64d81332c37efecb0a8618681f1db9" }
|
||||
collab-folder = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "67b31e4bcc64d81332c37efecb0a8618681f1db9" }
|
||||
collab-document = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "67b31e4bcc64d81332c37efecb0a8618681f1db9" }
|
||||
collab-database = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "67b31e4bcc64d81332c37efecb0a8618681f1db9" }
|
||||
collab-plugins = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "67b31e4bcc64d81332c37efecb0a8618681f1db9" }
|
||||
collab-user = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "67b31e4bcc64d81332c37efecb0a8618681f1db9" }
|
||||
collab-importer = { version = "0.1", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "67b31e4bcc64d81332c37efecb0a8618681f1db9" }
|
||||
|
||||
# Working directory: frontend
|
||||
# To update the commit ID, run:
|
||||
|
20
frontend/appflowy_web_app/src-tauri/Cargo.lock
generated
20
frontend/appflowy_web_app/src-tauri/Cargo.lock
generated
@ -1029,7 +1029,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=dd8a1d13e97322338f027888a71340575cd9ad8f#dd8a1d13e97322338f027888a71340575cd9ad8f"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=67b31e4bcc64d81332c37efecb0a8618681f1db9#67b31e4bcc64d81332c37efecb0a8618681f1db9"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"arc-swap",
|
||||
@ -1054,7 +1054,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-database"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=dd8a1d13e97322338f027888a71340575cd9ad8f#dd8a1d13e97322338f027888a71340575cd9ad8f"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=67b31e4bcc64d81332c37efecb0a8618681f1db9#67b31e4bcc64d81332c37efecb0a8618681f1db9"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
@ -1094,7 +1094,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-document"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=dd8a1d13e97322338f027888a71340575cd9ad8f#dd8a1d13e97322338f027888a71340575cd9ad8f"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=67b31e4bcc64d81332c37efecb0a8618681f1db9#67b31e4bcc64d81332c37efecb0a8618681f1db9"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"arc-swap",
|
||||
@ -1115,7 +1115,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-entity"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=dd8a1d13e97322338f027888a71340575cd9ad8f#dd8a1d13e97322338f027888a71340575cd9ad8f"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=67b31e4bcc64d81332c37efecb0a8618681f1db9#67b31e4bcc64d81332c37efecb0a8618681f1db9"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bytes",
|
||||
@ -1135,7 +1135,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-folder"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=dd8a1d13e97322338f027888a71340575cd9ad8f#dd8a1d13e97322338f027888a71340575cd9ad8f"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=67b31e4bcc64d81332c37efecb0a8618681f1db9#67b31e4bcc64d81332c37efecb0a8618681f1db9"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"arc-swap",
|
||||
@ -1157,7 +1157,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-importer"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=dd8a1d13e97322338f027888a71340575cd9ad8f#dd8a1d13e97322338f027888a71340575cd9ad8f"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=67b31e4bcc64d81332c37efecb0a8618681f1db9#67b31e4bcc64d81332c37efecb0a8618681f1db9"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-recursion",
|
||||
@ -1207,6 +1207,9 @@ dependencies = [
|
||||
"collab-folder",
|
||||
"collab-plugins",
|
||||
"collab-user",
|
||||
"diesel",
|
||||
"flowy-error",
|
||||
"flowy-sqlite",
|
||||
"futures",
|
||||
"lib-infra",
|
||||
"serde",
|
||||
@ -1218,7 +1221,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-plugins"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=dd8a1d13e97322338f027888a71340575cd9ad8f#dd8a1d13e97322338f027888a71340575cd9ad8f"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=67b31e4bcc64d81332c37efecb0a8618681f1db9#67b31e4bcc64d81332c37efecb0a8618681f1db9"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-stream",
|
||||
@ -1298,7 +1301,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-user"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=dd8a1d13e97322338f027888a71340575cd9ad8f#dd8a1d13e97322338f027888a71340575cd9ad8f"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=67b31e4bcc64d81332c37efecb0a8618681f1db9#67b31e4bcc64d81332c37efecb0a8618681f1db9"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"collab",
|
||||
@ -2189,6 +2192,7 @@ dependencies = [
|
||||
"arc-swap",
|
||||
"base64 0.21.7",
|
||||
"bytes",
|
||||
"collab-integrate",
|
||||
"dashmap 6.0.1",
|
||||
"flowy-ai-pub",
|
||||
"flowy-codegen",
|
||||
|
@ -118,14 +118,14 @@ custom-protocol = ["tauri/custom-protocol"]
|
||||
# To switch to the local path, run:
|
||||
# scripts/tool/update_collab_source.sh
|
||||
# ⚠️⚠️⚠️️
|
||||
collab = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "dd8a1d13e97322338f027888a71340575cd9ad8f" }
|
||||
collab-entity = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "dd8a1d13e97322338f027888a71340575cd9ad8f" }
|
||||
collab-folder = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "dd8a1d13e97322338f027888a71340575cd9ad8f" }
|
||||
collab-document = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "dd8a1d13e97322338f027888a71340575cd9ad8f" }
|
||||
collab-database = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "dd8a1d13e97322338f027888a71340575cd9ad8f" }
|
||||
collab-plugins = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "dd8a1d13e97322338f027888a71340575cd9ad8f" }
|
||||
collab-user = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "dd8a1d13e97322338f027888a71340575cd9ad8f" }
|
||||
collab-importer = { version = "0.1", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "dd8a1d13e97322338f027888a71340575cd9ad8f" }
|
||||
collab = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "67b31e4bcc64d81332c37efecb0a8618681f1db9" }
|
||||
collab-entity = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "67b31e4bcc64d81332c37efecb0a8618681f1db9" }
|
||||
collab-folder = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "67b31e4bcc64d81332c37efecb0a8618681f1db9" }
|
||||
collab-document = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "67b31e4bcc64d81332c37efecb0a8618681f1db9" }
|
||||
collab-database = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "67b31e4bcc64d81332c37efecb0a8618681f1db9" }
|
||||
collab-plugins = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "67b31e4bcc64d81332c37efecb0a8618681f1db9" }
|
||||
collab-user = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "67b31e4bcc64d81332c37efecb0a8618681f1db9" }
|
||||
collab-importer = { version = "0.1", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "67b31e4bcc64d81332c37efecb0a8618681f1db9" }
|
||||
|
||||
|
||||
# Working directory: frontend
|
||||
|
20
frontend/rust-lib/Cargo.lock
generated
20
frontend/rust-lib/Cargo.lock
generated
@ -892,7 +892,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=dd8a1d13e97322338f027888a71340575cd9ad8f#dd8a1d13e97322338f027888a71340575cd9ad8f"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=67b31e4bcc64d81332c37efecb0a8618681f1db9#67b31e4bcc64d81332c37efecb0a8618681f1db9"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"arc-swap",
|
||||
@ -917,7 +917,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-database"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=dd8a1d13e97322338f027888a71340575cd9ad8f#dd8a1d13e97322338f027888a71340575cd9ad8f"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=67b31e4bcc64d81332c37efecb0a8618681f1db9#67b31e4bcc64d81332c37efecb0a8618681f1db9"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
@ -957,7 +957,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-document"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=dd8a1d13e97322338f027888a71340575cd9ad8f#dd8a1d13e97322338f027888a71340575cd9ad8f"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=67b31e4bcc64d81332c37efecb0a8618681f1db9#67b31e4bcc64d81332c37efecb0a8618681f1db9"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"arc-swap",
|
||||
@ -978,7 +978,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-entity"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=dd8a1d13e97322338f027888a71340575cd9ad8f#dd8a1d13e97322338f027888a71340575cd9ad8f"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=67b31e4bcc64d81332c37efecb0a8618681f1db9#67b31e4bcc64d81332c37efecb0a8618681f1db9"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bytes",
|
||||
@ -998,7 +998,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-folder"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=dd8a1d13e97322338f027888a71340575cd9ad8f#dd8a1d13e97322338f027888a71340575cd9ad8f"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=67b31e4bcc64d81332c37efecb0a8618681f1db9#67b31e4bcc64d81332c37efecb0a8618681f1db9"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"arc-swap",
|
||||
@ -1020,7 +1020,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-importer"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=dd8a1d13e97322338f027888a71340575cd9ad8f#dd8a1d13e97322338f027888a71340575cd9ad8f"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=67b31e4bcc64d81332c37efecb0a8618681f1db9#67b31e4bcc64d81332c37efecb0a8618681f1db9"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-recursion",
|
||||
@ -1070,6 +1070,9 @@ dependencies = [
|
||||
"collab-folder",
|
||||
"collab-plugins",
|
||||
"collab-user",
|
||||
"diesel",
|
||||
"flowy-error",
|
||||
"flowy-sqlite",
|
||||
"futures",
|
||||
"lib-infra",
|
||||
"serde",
|
||||
@ -1081,7 +1084,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-plugins"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=dd8a1d13e97322338f027888a71340575cd9ad8f#dd8a1d13e97322338f027888a71340575cd9ad8f"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=67b31e4bcc64d81332c37efecb0a8618681f1db9#67b31e4bcc64d81332c37efecb0a8618681f1db9"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-stream",
|
||||
@ -1161,7 +1164,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-user"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=dd8a1d13e97322338f027888a71340575cd9ad8f#dd8a1d13e97322338f027888a71340575cd9ad8f"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=67b31e4bcc64d81332c37efecb0a8618681f1db9#67b31e4bcc64d81332c37efecb0a8618681f1db9"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"collab",
|
||||
@ -2001,6 +2004,7 @@ dependencies = [
|
||||
"arc-swap",
|
||||
"base64 0.21.5",
|
||||
"bytes",
|
||||
"collab-integrate",
|
||||
"dashmap 6.0.1",
|
||||
"dotenv",
|
||||
"flowy-ai-pub",
|
||||
|
@ -143,14 +143,14 @@ rocksdb = { git = "https://github.com/rust-rocksdb/rust-rocksdb", rev = "1710120
|
||||
# To switch to the local path, run:
|
||||
# scripts/tool/update_collab_source.sh
|
||||
# ⚠️⚠️⚠️️
|
||||
collab = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "dd8a1d13e97322338f027888a71340575cd9ad8f" }
|
||||
collab-entity = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "dd8a1d13e97322338f027888a71340575cd9ad8f" }
|
||||
collab-folder = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "dd8a1d13e97322338f027888a71340575cd9ad8f" }
|
||||
collab-document = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "dd8a1d13e97322338f027888a71340575cd9ad8f" }
|
||||
collab-database = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "dd8a1d13e97322338f027888a71340575cd9ad8f" }
|
||||
collab-plugins = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "dd8a1d13e97322338f027888a71340575cd9ad8f" }
|
||||
collab-user = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "dd8a1d13e97322338f027888a71340575cd9ad8f" }
|
||||
collab-importer = { version = "0.1", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "dd8a1d13e97322338f027888a71340575cd9ad8f" }
|
||||
collab = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "67b31e4bcc64d81332c37efecb0a8618681f1db9" }
|
||||
collab-entity = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "67b31e4bcc64d81332c37efecb0a8618681f1db9" }
|
||||
collab-folder = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "67b31e4bcc64d81332c37efecb0a8618681f1db9" }
|
||||
collab-document = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "67b31e4bcc64d81332c37efecb0a8618681f1db9" }
|
||||
collab-database = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "67b31e4bcc64d81332c37efecb0a8618681f1db9" }
|
||||
collab-plugins = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "67b31e4bcc64d81332c37efecb0a8618681f1db9" }
|
||||
collab-user = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "67b31e4bcc64d81332c37efecb0a8618681f1db9" }
|
||||
collab-importer = { version = "0.1", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "67b31e4bcc64d81332c37efecb0a8618681f1db9" }
|
||||
|
||||
# Working directory: frontend
|
||||
# To update the commit ID, run:
|
||||
|
@ -24,6 +24,9 @@ tokio = { workspace = true, features = ["sync"] }
|
||||
lib-infra = { workspace = true }
|
||||
futures = "0.3"
|
||||
arc-swap = "1.7"
|
||||
flowy-sqlite = { workspace = true }
|
||||
diesel.workspace = true
|
||||
flowy-error.workspace = true
|
||||
|
||||
[features]
|
||||
default = []
|
||||
|
@ -1,24 +1,11 @@
|
||||
pub use collab::preclude::Snapshot;
|
||||
pub use collab_plugins::local_storage::CollabPersistenceConfig;
|
||||
pub use collab_plugins::CollabKVDB;
|
||||
use collab_plugins::{if_native, if_wasm};
|
||||
|
||||
pub mod collab_builder;
|
||||
pub mod config;
|
||||
|
||||
if_native! {
|
||||
mod native;
|
||||
mod plugin_provider {
|
||||
pub use crate::native::plugin_provider::*;
|
||||
}
|
||||
}
|
||||
|
||||
if_wasm! {
|
||||
mod wasm;
|
||||
mod plugin_provider {
|
||||
pub use crate::wasm::plugin_provider::*;
|
||||
}
|
||||
}
|
||||
pub mod persistence;
|
||||
mod plugin_provider;
|
||||
|
||||
pub use collab_plugins::local_storage::kv::doc::CollabKVAction;
|
||||
pub use collab_plugins::local_storage::kv::error::PersistenceError;
|
||||
|
@ -1 +0,0 @@
|
||||
pub mod plugin_provider;
|
@ -1,57 +0,0 @@
|
||||
use collab::preclude::CollabPlugin;
|
||||
|
||||
use crate::collab_builder::{CollabPluginProviderContext, CollabPluginProviderType};
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
pub trait CollabCloudPluginProvider: 'static {
|
||||
fn provider_type(&self) -> CollabPluginProviderType;
|
||||
|
||||
fn get_plugins(&self, context: CollabPluginProviderContext) -> Vec<Box<dyn CollabPlugin>>;
|
||||
|
||||
fn is_sync_enabled(&self) -> bool;
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
impl<U> CollabCloudPluginProvider for std::rc::Rc<U>
|
||||
where
|
||||
U: CollabCloudPluginProvider,
|
||||
{
|
||||
fn provider_type(&self) -> CollabPluginProviderType {
|
||||
(**self).provider_type()
|
||||
}
|
||||
|
||||
fn get_plugins(&self, context: CollabPluginProviderContext) -> Vec<Box<dyn CollabPlugin>> {
|
||||
(**self).get_plugins(context)
|
||||
}
|
||||
|
||||
fn is_sync_enabled(&self) -> bool {
|
||||
(**self).is_sync_enabled()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
pub trait CollabCloudPluginProvider: Send + Sync + 'static {
|
||||
fn provider_type(&self) -> CollabPluginProviderType;
|
||||
|
||||
fn get_plugins(&self, context: CollabPluginProviderContext) -> Vec<Box<dyn CollabPlugin>>;
|
||||
|
||||
fn is_sync_enabled(&self) -> bool;
|
||||
}
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
impl<U> CollabCloudPluginProvider for std::sync::Arc<U>
|
||||
where
|
||||
U: CollabCloudPluginProvider,
|
||||
{
|
||||
fn provider_type(&self) -> CollabPluginProviderType {
|
||||
(**self).provider_type()
|
||||
}
|
||||
|
||||
fn get_plugins(&self, context: CollabPluginProviderContext) -> Vec<Box<dyn CollabPlugin>> {
|
||||
(**self).get_plugins(context)
|
||||
}
|
||||
|
||||
fn is_sync_enabled(&self) -> bool {
|
||||
(**self).is_sync_enabled()
|
||||
}
|
||||
}
|
@ -0,0 +1,55 @@
|
||||
use diesel::upsert::excluded;
|
||||
use flowy_error::{FlowyError, FlowyResult};
|
||||
use flowy_sqlite::{
|
||||
diesel, insert_into,
|
||||
query_dsl::*,
|
||||
schema::{af_collab_metadata, af_collab_metadata::dsl},
|
||||
DBConnection, ExpressionMethods, Identifiable, Insertable, Queryable,
|
||||
};
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[derive(Queryable, Insertable, Identifiable)]
|
||||
#[diesel(table_name = af_collab_metadata)]
|
||||
#[diesel(primary_key(object_id))]
|
||||
pub struct AFCollabMetadata {
|
||||
pub object_id: String,
|
||||
pub updated_at: i64,
|
||||
pub prev_sync_state_vector: Vec<u8>,
|
||||
pub collab_type: i32,
|
||||
}
|
||||
|
||||
pub fn batch_insert_collab_metadata(
|
||||
mut conn: DBConnection,
|
||||
new_metadata: &[AFCollabMetadata],
|
||||
) -> FlowyResult<()> {
|
||||
conn.immediate_transaction(|conn| {
|
||||
for metadata in new_metadata {
|
||||
let _ = insert_into(af_collab_metadata::table)
|
||||
.values(metadata)
|
||||
.on_conflict(af_collab_metadata::object_id)
|
||||
.do_update()
|
||||
.set((
|
||||
af_collab_metadata::updated_at.eq(excluded(af_collab_metadata::updated_at)),
|
||||
af_collab_metadata::prev_sync_state_vector
|
||||
.eq(excluded(af_collab_metadata::prev_sync_state_vector)),
|
||||
))
|
||||
.execute(conn)?;
|
||||
}
|
||||
Ok::<(), FlowyError>(())
|
||||
})?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn batch_select_collab_metadata(
|
||||
mut conn: DBConnection,
|
||||
object_ids: &[String],
|
||||
) -> FlowyResult<HashMap<String, AFCollabMetadata>> {
|
||||
let metadata = dsl::af_collab_metadata
|
||||
.filter(af_collab_metadata::object_id.eq_any(object_ids))
|
||||
.load::<AFCollabMetadata>(&mut conn)?
|
||||
.into_iter()
|
||||
.map(|m| (m.object_id.clone(), m))
|
||||
.collect();
|
||||
Ok(metadata)
|
||||
}
|
@ -0,0 +1 @@
|
||||
pub mod collab_metadata_sql;
|
@ -1,9 +1,8 @@
|
||||
use crate::collab_builder::{CollabPluginProviderContext, CollabPluginProviderType};
|
||||
use collab::preclude::CollabPlugin;
|
||||
use lib_infra::future::Fut;
|
||||
use std::rc::Rc;
|
||||
|
||||
pub trait CollabCloudPluginProvider: 'static {
|
||||
use crate::collab_builder::{CollabPluginProviderContext, CollabPluginProviderType};
|
||||
|
||||
pub trait CollabCloudPluginProvider: Send + Sync + 'static {
|
||||
fn provider_type(&self) -> CollabPluginProviderType;
|
||||
|
||||
fn get_plugins(&self, context: CollabPluginProviderContext) -> Vec<Box<dyn CollabPlugin>>;
|
||||
@ -11,9 +10,9 @@ pub trait CollabCloudPluginProvider: 'static {
|
||||
fn is_sync_enabled(&self) -> bool;
|
||||
}
|
||||
|
||||
impl<T> CollabCloudPluginProvider for Rc<T>
|
||||
impl<U> CollabCloudPluginProvider for std::sync::Arc<U>
|
||||
where
|
||||
T: CollabCloudPluginProvider,
|
||||
U: CollabCloudPluginProvider,
|
||||
{
|
||||
fn provider_type(&self) -> CollabPluginProviderType {
|
||||
(**self).provider_type()
|
@ -1 +0,0 @@
|
||||
pub mod plugin_provider;
|
@ -45,6 +45,7 @@ zip = { workspace = true, features = ["deflate"] }
|
||||
zip-extensions = "0.8.0"
|
||||
pin-project = "1.1.5"
|
||||
flowy-storage-pub = { workspace = true }
|
||||
collab-integrate.workspace = true
|
||||
|
||||
[target.'cfg(any(target_os = "macos", target_os = "linux", target_os = "windows"))'.dependencies]
|
||||
notify = "6.1.1"
|
||||
|
@ -5,6 +5,7 @@ use crate::entities::{
|
||||
use crate::local_ai::local_llm_chat::LocalAIController;
|
||||
use crate::middleware::chat_service_mw::AICloudServiceMiddleware;
|
||||
use crate::persistence::{insert_chat, read_chat_metadata, ChatTable};
|
||||
use std::collections::HashMap;
|
||||
|
||||
use appflowy_plugin::manager::PluginManager;
|
||||
use dashmap::DashMap;
|
||||
@ -16,6 +17,9 @@ use flowy_sqlite::kv::KVStorePreferences;
|
||||
use flowy_sqlite::DBConnection;
|
||||
|
||||
use crate::notification::{chat_notification_builder, ChatNotification};
|
||||
use collab_integrate::persistence::collab_metadata_sql::{
|
||||
batch_insert_collab_metadata, batch_select_collab_metadata, AFCollabMetadata,
|
||||
};
|
||||
use flowy_storage_pub::storage::StorageService;
|
||||
use lib_infra::async_trait::async_trait;
|
||||
use lib_infra::util::timestamp;
|
||||
@ -31,7 +35,6 @@ pub trait AIUserService: Send + Sync + 'static {
|
||||
fn application_root_dir(&self) -> Result<PathBuf, FlowyError>;
|
||||
}
|
||||
|
||||
|
||||
/// AIExternalService is an interface for external services that AI plugin can interact with.
|
||||
#[async_trait]
|
||||
pub trait AIExternalService: Send + Sync + 'static {
|
||||
@ -45,7 +48,8 @@ pub trait AIExternalService: Send + Sync + 'static {
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
rag_ids: Vec<String>,
|
||||
) -> Result<(), FlowyError>;
|
||||
rag_metadata_map: HashMap<String, AFCollabMetadata>,
|
||||
) -> Result<Vec<AFCollabMetadata>, FlowyError>;
|
||||
|
||||
async fn notify_did_send_message(&self, chat_id: &str, message: &str) -> Result<(), FlowyError>;
|
||||
}
|
||||
@ -130,14 +134,7 @@ impl AIManager {
|
||||
.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;
|
||||
}
|
||||
let _ = sync_chat_documents(user_service, external_service, settings.rag_ids).await;
|
||||
},
|
||||
Err(err) => {
|
||||
error!("failed to refresh chat settings: {}", err);
|
||||
@ -167,7 +164,8 @@ impl AIManager {
|
||||
}
|
||||
|
||||
pub async fn get_chat_info(&self, chat_id: &str) -> FlowyResult<ChatInfoPB> {
|
||||
let mut conn = self.user_service.sqlite_connection(0)?;
|
||||
let uid = self.user_service.user_id()?;
|
||||
let mut conn = self.user_service.sqlite_connection(uid)?;
|
||||
let metadata = read_chat_metadata(&mut conn, chat_id)?;
|
||||
let files = metadata
|
||||
.files
|
||||
@ -397,17 +395,44 @@ impl AIManager {
|
||||
|
||||
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;
|
||||
}
|
||||
});
|
||||
sync_chat_documents(user_service, external_service, rag_ids).await?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
async fn sync_chat_documents(
|
||||
user_service: Arc<dyn AIUserService>,
|
||||
external_service: Arc<dyn AIExternalService>,
|
||||
rag_ids: Vec<String>,
|
||||
) -> FlowyResult<()> {
|
||||
if rag_ids.is_empty() {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let uid = user_service.user_id()?;
|
||||
let conn = user_service.sqlite_connection(uid)?;
|
||||
let metadata_map = batch_select_collab_metadata(conn, &rag_ids)?;
|
||||
|
||||
let user_service = user_service.clone();
|
||||
tokio::spawn(async move {
|
||||
if let Ok(workspace_id) = user_service.workspace_id() {
|
||||
if let Ok(metadatas) = external_service
|
||||
.sync_rag_documents(&workspace_id, rag_ids, metadata_map)
|
||||
.await
|
||||
{
|
||||
if let Ok(uid) = user_service.user_id() {
|
||||
if let Ok(conn) = user_service.sqlite_connection(uid) {
|
||||
info!("sync rag documents success: {}", metadatas.len());
|
||||
batch_insert_collab_metadata(conn, &metadatas).unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn save_chat(conn: DBConnection, chat_id: &str) -> FlowyResult<()> {
|
||||
let row = ChatTable {
|
||||
chat_id: chat_id.to_string(),
|
||||
|
@ -5,11 +5,11 @@ use base64::Engine;
|
||||
use semver::Version;
|
||||
use tracing::{error, info};
|
||||
|
||||
use crate::log_filter::create_log_filter;
|
||||
use flowy_server_pub::af_cloud_config::AFCloudConfiguration;
|
||||
use flowy_user::services::entities::URL_SAFE_ENGINE;
|
||||
use lib_infra::file_util::copy_dir_recursive;
|
||||
use lib_infra::util::OperatingSystem;
|
||||
use crate::log_filter::create_log_filter;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct AppFlowyCoreConfig {
|
||||
|
@ -1,4 +1,10 @@
|
||||
use collab::core::collab::DataSource;
|
||||
use collab::core::origin::CollabOrigin;
|
||||
use collab::preclude::updates::decoder::Decode;
|
||||
use collab::preclude::{Collab, StateVector};
|
||||
use collab::util::is_change_since_sv;
|
||||
use collab_entity::CollabType;
|
||||
use collab_integrate::persistence::collab_metadata_sql::AFCollabMetadata;
|
||||
use flowy_ai::ai_manager::{AIExternalService, AIManager, AIUserService};
|
||||
use flowy_ai_pub::cloud::ChatCloudService;
|
||||
use flowy_error::FlowyError;
|
||||
@ -10,6 +16,8 @@ use flowy_sqlite::DBConnection;
|
||||
use flowy_storage_pub::storage::StorageService;
|
||||
use flowy_user::services::authenticate_user::AuthenticateUser;
|
||||
use lib_infra::async_trait::async_trait;
|
||||
use lib_infra::util::timestamp;
|
||||
use std::collections::HashMap;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::{Arc, Weak};
|
||||
use tracing::{error, info};
|
||||
@ -62,36 +70,70 @@ impl AIExternalService for ChatQueryServiceImpl {
|
||||
|
||||
Ok(ids)
|
||||
}
|
||||
|
||||
async fn sync_rag_documents(
|
||||
&self,
|
||||
workspace_id: &str,
|
||||
rag_ids: Vec<String>,
|
||||
) -> Result<(), FlowyError> {
|
||||
info!("sync_rag_documents: {:?}", rag_ids);
|
||||
mut rag_metadata_map: HashMap<String, AFCollabMetadata>,
|
||||
) -> Result<Vec<AFCollabMetadata>, FlowyError> {
|
||||
let mut result = Vec::new();
|
||||
|
||||
for rag_id in rag_ids.iter() {
|
||||
if let Some(query_collab) = self
|
||||
for rag_id in rag_ids {
|
||||
// Retrieve the collab object for the current rag_id
|
||||
let query_collab = match self
|
||||
.folder_service
|
||||
.get_collab(rag_id, CollabType::Document)
|
||||
.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),
|
||||
Some(collab) => collab,
|
||||
None => {
|
||||
continue;
|
||||
},
|
||||
};
|
||||
|
||||
// Check if the state vector exists and detect changes
|
||||
if let Some(metadata) = rag_metadata_map.remove(&rag_id) {
|
||||
if let Ok(prev_sv) = StateVector::decode_v1(&metadata.prev_sync_state_vector) {
|
||||
let collab = Collab::new_with_source(
|
||||
CollabOrigin::Empty,
|
||||
&rag_id,
|
||||
DataSource::DocStateV1(query_collab.encoded_collab.doc_state.to_vec()),
|
||||
vec![],
|
||||
false,
|
||||
)?;
|
||||
|
||||
if !is_change_since_sv(&collab, &prev_sv) {
|
||||
info!("[Chat] no change since sv: {}", rag_id);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Perform full sync if changes are detected or no state vector is found
|
||||
let params = FullSyncCollabParams {
|
||||
object_id: rag_id.clone(),
|
||||
collab_type: CollabType::Document,
|
||||
encoded_collab: query_collab.encoded_collab.clone(),
|
||||
};
|
||||
|
||||
if let Err(err) = self
|
||||
.folder_cloud_service
|
||||
.full_sync_collab_object(workspace_id, params)
|
||||
.await
|
||||
{
|
||||
error!("Failed to sync rag document: {} error: {}", rag_id, err);
|
||||
} else {
|
||||
info!("[Chat] full sync rag document: {}", rag_id);
|
||||
result.push(AFCollabMetadata {
|
||||
object_id: rag_id,
|
||||
updated_at: timestamp(),
|
||||
prev_sync_state_vector: query_collab.encoded_collab.state_vector.to_vec(),
|
||||
collab_type: CollabType::Document as i32,
|
||||
});
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
async fn notify_did_send_message(&self, chat_id: &str, message: &str) -> Result<(), FlowyError> {
|
||||
|
@ -1,4 +1,3 @@
|
||||
use std::sync::Arc;
|
||||
use bytes::Bytes;
|
||||
use collab::entity::EncodedCollab;
|
||||
use collab_folder::ViewLayout;
|
||||
@ -8,71 +7,72 @@ use flowy_folder::entities::CreateViewParams;
|
||||
use flowy_folder::share::ImportType;
|
||||
use flowy_folder::view_operation::{FolderOperationHandler, ImportedData};
|
||||
use lib_infra::async_trait::async_trait;
|
||||
use std::sync::Arc;
|
||||
|
||||
pub struct ChatFolderOperation(pub Arc<AIManager>);
|
||||
|
||||
#[async_trait]
|
||||
impl FolderOperationHandler for ChatFolderOperation {
|
||||
fn name(&self) -> &str {
|
||||
"ChatFolderOperationHandler"
|
||||
}
|
||||
fn name(&self) -> &str {
|
||||
"ChatFolderOperationHandler"
|
||||
}
|
||||
|
||||
async fn open_view(&self, view_id: &str) -> Result<(), FlowyError> {
|
||||
self.0.open_chat(view_id).await
|
||||
}
|
||||
async fn open_view(&self, view_id: &str) -> Result<(), FlowyError> {
|
||||
self.0.open_chat(view_id).await
|
||||
}
|
||||
|
||||
async fn close_view(&self, view_id: &str) -> Result<(), FlowyError> {
|
||||
self.0.close_chat(view_id).await
|
||||
}
|
||||
async fn close_view(&self, view_id: &str) -> Result<(), FlowyError> {
|
||||
self.0.close_chat(view_id).await
|
||||
}
|
||||
|
||||
async fn delete_view(&self, view_id: &str) -> Result<(), FlowyError> {
|
||||
self.0.delete_chat(view_id).await
|
||||
}
|
||||
async fn delete_view(&self, view_id: &str) -> Result<(), FlowyError> {
|
||||
self.0.delete_chat(view_id).await
|
||||
}
|
||||
|
||||
async fn duplicate_view(&self, _view_id: &str) -> Result<Bytes, FlowyError> {
|
||||
Err(FlowyError::not_support())
|
||||
}
|
||||
async fn duplicate_view(&self, _view_id: &str) -> Result<Bytes, FlowyError> {
|
||||
Err(FlowyError::not_support())
|
||||
}
|
||||
|
||||
async fn create_view_with_view_data(
|
||||
&self,
|
||||
_user_id: i64,
|
||||
_params: CreateViewParams,
|
||||
) -> Result<Option<EncodedCollab>, FlowyError> {
|
||||
Err(FlowyError::not_support())
|
||||
}
|
||||
async fn create_view_with_view_data(
|
||||
&self,
|
||||
_user_id: i64,
|
||||
_params: CreateViewParams,
|
||||
) -> Result<Option<EncodedCollab>, FlowyError> {
|
||||
Err(FlowyError::not_support())
|
||||
}
|
||||
|
||||
async fn create_default_view(
|
||||
&self,
|
||||
user_id: i64,
|
||||
parent_view_id: &str,
|
||||
view_id: &str,
|
||||
_name: &str,
|
||||
_layout: ViewLayout,
|
||||
) -> Result<(), FlowyError> {
|
||||
self
|
||||
.0
|
||||
.create_chat(&user_id, parent_view_id, view_id)
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
async fn create_default_view(
|
||||
&self,
|
||||
user_id: i64,
|
||||
parent_view_id: &str,
|
||||
view_id: &str,
|
||||
_name: &str,
|
||||
_layout: ViewLayout,
|
||||
) -> Result<(), FlowyError> {
|
||||
self
|
||||
.0
|
||||
.create_chat(&user_id, parent_view_id, view_id)
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn import_from_bytes(
|
||||
&self,
|
||||
_uid: i64,
|
||||
_view_id: &str,
|
||||
_name: &str,
|
||||
_import_type: ImportType,
|
||||
_bytes: Vec<u8>,
|
||||
) -> Result<Vec<ImportedData>, FlowyError> {
|
||||
Err(FlowyError::not_support())
|
||||
}
|
||||
async fn import_from_bytes(
|
||||
&self,
|
||||
_uid: i64,
|
||||
_view_id: &str,
|
||||
_name: &str,
|
||||
_import_type: ImportType,
|
||||
_bytes: Vec<u8>,
|
||||
) -> Result<Vec<ImportedData>, FlowyError> {
|
||||
Err(FlowyError::not_support())
|
||||
}
|
||||
|
||||
async fn import_from_file_path(
|
||||
&self,
|
||||
_view_id: &str,
|
||||
_name: &str,
|
||||
_path: String,
|
||||
) -> Result<(), FlowyError> {
|
||||
Err(FlowyError::not_support())
|
||||
}
|
||||
async fn import_from_file_path(
|
||||
&self,
|
||||
_view_id: &str,
|
||||
_name: &str,
|
||||
_path: String,
|
||||
) -> Result<(), FlowyError> {
|
||||
Err(FlowyError::not_support())
|
||||
}
|
||||
}
|
||||
|
@ -1,86 +1,88 @@
|
||||
use std::collections::HashMap;
|
||||
use std::path::Path;
|
||||
use std::sync::Arc;
|
||||
use bytes::Bytes;
|
||||
use collab::entity::EncodedCollab;
|
||||
use collab_entity::CollabType;
|
||||
use collab_folder::{View, ViewLayout};
|
||||
use collab_plugins::local_storage::kv::KVTransactionDB;
|
||||
use flowy_database2::DatabaseManager;
|
||||
use flowy_database2::entities::DatabaseLayoutPB;
|
||||
use flowy_database2::services::share::csv::CSVFormat;
|
||||
use flowy_database2::template::{make_default_board, make_default_calendar, make_default_grid};
|
||||
use flowy_database2::DatabaseManager;
|
||||
use flowy_error::FlowyError;
|
||||
use flowy_folder::entities::{CreateViewParams, ViewLayoutPB};
|
||||
use flowy_folder::manager::FolderUser;
|
||||
use flowy_folder::share::ImportType;
|
||||
use flowy_folder::view_operation::{DatabaseEncodedCollab, FolderOperationHandler, GatherEncodedCollab, ImportedData, ViewData};
|
||||
use flowy_folder::view_operation::{
|
||||
DatabaseEncodedCollab, FolderOperationHandler, GatherEncodedCollab, ImportedData, ViewData,
|
||||
};
|
||||
use flowy_user::services::data_import::{load_collab_by_object_id, load_collab_by_object_ids};
|
||||
use lib_infra::async_trait::async_trait;
|
||||
use std::collections::HashMap;
|
||||
use std::path::Path;
|
||||
use std::sync::Arc;
|
||||
|
||||
pub struct DatabaseFolderOperation(pub Arc<DatabaseManager>);
|
||||
|
||||
#[async_trait]
|
||||
impl FolderOperationHandler for DatabaseFolderOperation {
|
||||
async fn open_view(&self, view_id: &str) -> Result<(), FlowyError> {
|
||||
self.0.open_database_view(view_id).await?;
|
||||
Ok(())
|
||||
async fn open_view(&self, view_id: &str) -> Result<(), FlowyError> {
|
||||
self.0.open_database_view(view_id).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn close_view(&self, view_id: &str) -> Result<(), FlowyError> {
|
||||
self.0.close_database_view(view_id).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn delete_view(&self, view_id: &str) -> Result<(), FlowyError> {
|
||||
match self.0.delete_database_view(view_id).await {
|
||||
Ok(_) => tracing::trace!("Delete database view: {}", view_id),
|
||||
Err(e) => tracing::error!("🔴delete database failed: {}", e),
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn close_view(&self, view_id: &str) -> Result<(), FlowyError> {
|
||||
self.0.close_database_view(view_id).await?;
|
||||
Ok(())
|
||||
}
|
||||
async fn gather_publish_encode_collab(
|
||||
&self,
|
||||
user: &Arc<dyn FolderUser>,
|
||||
view_id: &str,
|
||||
) -> Result<GatherEncodedCollab, FlowyError> {
|
||||
let workspace_id = user.workspace_id()?;
|
||||
// get the collab_object_id for the database.
|
||||
//
|
||||
// the collab object_id for the database is not the view_id,
|
||||
// we should use the view_id to get the database_id
|
||||
let oid = self.0.get_database_id_with_view_id(view_id).await?;
|
||||
let row_oids = self.0.get_database_row_ids_with_view_id(view_id).await?;
|
||||
let row_metas = self
|
||||
.0
|
||||
.get_database_row_metas_with_view_id(view_id, row_oids.clone())
|
||||
.await?;
|
||||
let row_document_ids = row_metas
|
||||
.iter()
|
||||
.filter_map(|meta| meta.document_id.clone())
|
||||
.collect::<Vec<_>>();
|
||||
let row_oids = row_oids
|
||||
.into_iter()
|
||||
.map(|oid| oid.into_inner())
|
||||
.collect::<Vec<_>>();
|
||||
let database_metas = self.0.get_all_databases_meta().await;
|
||||
|
||||
async fn delete_view(&self, view_id: &str) -> Result<(), FlowyError> {
|
||||
match self.0.delete_database_view(view_id).await {
|
||||
Ok(_) => tracing::trace!("Delete database view: {}", view_id),
|
||||
Err(e) => tracing::error!("🔴delete database failed: {}", e),
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
let uid = user
|
||||
.user_id()
|
||||
.map_err(|e| e.with_context("unable to get the uid: {}"))?;
|
||||
|
||||
async fn gather_publish_encode_collab(
|
||||
&self,
|
||||
user: &Arc<dyn FolderUser>,
|
||||
view_id: &str,
|
||||
) -> Result<GatherEncodedCollab, FlowyError> {
|
||||
let workspace_id = user.workspace_id()?;
|
||||
// get the collab_object_id for the database.
|
||||
//
|
||||
// the collab object_id for the database is not the view_id,
|
||||
// we should use the view_id to get the database_id
|
||||
let oid = self.0.get_database_id_with_view_id(view_id).await?;
|
||||
let row_oids = self.0.get_database_row_ids_with_view_id(view_id).await?;
|
||||
let row_metas = self
|
||||
.0
|
||||
.get_database_row_metas_with_view_id(view_id, row_oids.clone())
|
||||
.await?;
|
||||
let row_document_ids = row_metas
|
||||
.iter()
|
||||
.filter_map(|meta| meta.document_id.clone())
|
||||
.collect::<Vec<_>>();
|
||||
let row_oids = row_oids
|
||||
.into_iter()
|
||||
.map(|oid| oid.into_inner())
|
||||
.collect::<Vec<_>>();
|
||||
let database_metas = self.0.get_all_databases_meta().await;
|
||||
// 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 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",
|
||||
)
|
||||
})?;
|
||||
|
||||
tokio::task::spawn_blocking(move || {
|
||||
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| {
|
||||
@ -143,196 +145,194 @@ impl FolderOperationHandler for DatabaseFolderOperation {
|
||||
}))
|
||||
})
|
||||
.await?
|
||||
}
|
||||
}
|
||||
|
||||
async fn duplicate_view(&self, view_id: &str) -> Result<Bytes, FlowyError> {
|
||||
Ok(Bytes::from(view_id.to_string()))
|
||||
}
|
||||
async fn duplicate_view(&self, view_id: &str) -> Result<Bytes, FlowyError> {
|
||||
Ok(Bytes::from(view_id.to_string()))
|
||||
}
|
||||
|
||||
/// Create a database view with duplicated data.
|
||||
/// If the ext contains the {"database_id": "xx"}, then it will link
|
||||
/// to the existing database.
|
||||
async fn create_view_with_view_data(
|
||||
&self,
|
||||
_user_id: i64,
|
||||
params: CreateViewParams,
|
||||
) -> Result<Option<EncodedCollab>, FlowyError> {
|
||||
match CreateDatabaseExtParams::from_map(params.meta.clone()) {
|
||||
None => match params.initial_data {
|
||||
ViewData::DuplicateData(data) => {
|
||||
let duplicated_view_id =
|
||||
String::from_utf8(data.to_vec()).map_err(|_| FlowyError::invalid_data())?;
|
||||
let encoded_collab = self
|
||||
.0
|
||||
.duplicate_database(&duplicated_view_id, ¶ms.view_id)
|
||||
.await?;
|
||||
Ok(Some(encoded_collab))
|
||||
},
|
||||
ViewData::Data(data) => {
|
||||
let encoded_collab = self
|
||||
.0
|
||||
.create_database_with_data(¶ms.view_id, data.to_vec())
|
||||
.await?;
|
||||
Ok(Some(encoded_collab))
|
||||
},
|
||||
ViewData::Empty => Ok(None),
|
||||
},
|
||||
Some(database_params) => {
|
||||
let layout = match params.layout {
|
||||
ViewLayoutPB::Board => DatabaseLayoutPB::Board,
|
||||
ViewLayoutPB::Calendar => DatabaseLayoutPB::Calendar,
|
||||
ViewLayoutPB::Grid => DatabaseLayoutPB::Grid,
|
||||
ViewLayoutPB::Document | ViewLayoutPB::Chat => {
|
||||
return Err(FlowyError::not_support());
|
||||
},
|
||||
};
|
||||
let name = params.name.to_string();
|
||||
let database_view_id = params.view_id.to_string();
|
||||
let database_parent_view_id = params.parent_view_id.to_string();
|
||||
self
|
||||
.0
|
||||
.create_linked_view(
|
||||
name,
|
||||
layout.into(),
|
||||
database_params.database_id,
|
||||
database_view_id,
|
||||
database_parent_view_id,
|
||||
)
|
||||
.await?;
|
||||
Ok(None)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a database view with build-in data.
|
||||
/// If the ext contains the {"database_id": "xx"}, then it will link to
|
||||
/// the existing database. The data of the database will be shared within
|
||||
/// these references views.
|
||||
async fn create_default_view(
|
||||
&self,
|
||||
_user_id: i64,
|
||||
_parent_view_id: &str,
|
||||
view_id: &str,
|
||||
name: &str,
|
||||
layout: ViewLayout,
|
||||
) -> Result<(), FlowyError> {
|
||||
let name = name.to_string();
|
||||
let data = match layout {
|
||||
ViewLayout::Grid => make_default_grid(view_id, &name),
|
||||
ViewLayout::Board => make_default_board(view_id, &name),
|
||||
ViewLayout::Calendar => make_default_calendar(view_id, &name),
|
||||
ViewLayout::Document | ViewLayout::Chat => {
|
||||
return Err(
|
||||
FlowyError::internal().with_context(format!("Can't handle {:?} layout type", layout)),
|
||||
);
|
||||
},
|
||||
};
|
||||
let result = self.0.import_database(data).await;
|
||||
match result {
|
||||
Ok(_) => Ok(()),
|
||||
Err(err) => {
|
||||
if err.is_already_exists() {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(err)
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
async fn import_from_bytes(
|
||||
&self,
|
||||
_uid: i64,
|
||||
view_id: &str,
|
||||
_name: &str,
|
||||
import_type: ImportType,
|
||||
bytes: Vec<u8>,
|
||||
) -> Result<Vec<ImportedData>, FlowyError> {
|
||||
let format = match import_type {
|
||||
ImportType::CSV => CSVFormat::Original,
|
||||
ImportType::AFDatabase => CSVFormat::META,
|
||||
_ => CSVFormat::Original,
|
||||
};
|
||||
let content = tokio::task::spawn_blocking(move || {
|
||||
String::from_utf8(bytes).map_err(|err| FlowyError::internal().with_context(err))
|
||||
})
|
||||
.await??;
|
||||
let result = self
|
||||
/// Create a database view with duplicated data.
|
||||
/// If the ext contains the {"database_id": "xx"}, then it will link
|
||||
/// to the existing database.
|
||||
async fn create_view_with_view_data(
|
||||
&self,
|
||||
_user_id: i64,
|
||||
params: CreateViewParams,
|
||||
) -> Result<Option<EncodedCollab>, FlowyError> {
|
||||
match CreateDatabaseExtParams::from_map(params.meta.clone()) {
|
||||
None => match params.initial_data {
|
||||
ViewData::DuplicateData(data) => {
|
||||
let duplicated_view_id =
|
||||
String::from_utf8(data.to_vec()).map_err(|_| FlowyError::invalid_data())?;
|
||||
let encoded_collab = self
|
||||
.0
|
||||
.import_csv(view_id.to_string(), content, format)
|
||||
.duplicate_database(&duplicated_view_id, ¶ms.view_id)
|
||||
.await?;
|
||||
Ok(
|
||||
result
|
||||
.encoded_collabs
|
||||
.into_iter()
|
||||
.map(|encoded| {
|
||||
(
|
||||
encoded.object_id,
|
||||
encoded.collab_type,
|
||||
encoded.encoded_collab,
|
||||
)
|
||||
})
|
||||
.collect(),
|
||||
)
|
||||
}
|
||||
|
||||
async fn import_from_file_path(
|
||||
&self,
|
||||
view_id: &str,
|
||||
_name: &str,
|
||||
path: String,
|
||||
) -> Result<(), FlowyError> {
|
||||
let file_path = Path::new(&path);
|
||||
if !file_path.exists() {
|
||||
return Err(FlowyError::record_not_found().with_context("File not found"));
|
||||
}
|
||||
|
||||
let data = tokio::fs::read(file_path).await?;
|
||||
let content =
|
||||
String::from_utf8(data).map_err(|e| FlowyError::invalid_data().with_context(e))?;
|
||||
let _ = self
|
||||
Ok(Some(encoded_collab))
|
||||
},
|
||||
ViewData::Data(data) => {
|
||||
let encoded_collab = self
|
||||
.0
|
||||
.import_csv(view_id.to_string(), content, CSVFormat::Original)
|
||||
.create_database_with_data(¶ms.view_id, data.to_vec())
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn did_update_view(&self, old: &View, new: &View) -> Result<(), FlowyError> {
|
||||
let database_layout = match new.layout {
|
||||
ViewLayout::Document | ViewLayout::Chat => {
|
||||
return Err(FlowyError::internal().with_context("Can't handle document layout type"));
|
||||
},
|
||||
ViewLayout::Grid => DatabaseLayoutPB::Grid,
|
||||
ViewLayout::Board => DatabaseLayoutPB::Board,
|
||||
ViewLayout::Calendar => DatabaseLayoutPB::Calendar,
|
||||
Ok(Some(encoded_collab))
|
||||
},
|
||||
ViewData::Empty => Ok(None),
|
||||
},
|
||||
Some(database_params) => {
|
||||
let layout = match params.layout {
|
||||
ViewLayoutPB::Board => DatabaseLayoutPB::Board,
|
||||
ViewLayoutPB::Calendar => DatabaseLayoutPB::Calendar,
|
||||
ViewLayoutPB::Grid => DatabaseLayoutPB::Grid,
|
||||
ViewLayoutPB::Document | ViewLayoutPB::Chat => {
|
||||
return Err(FlowyError::not_support());
|
||||
},
|
||||
};
|
||||
let name = params.name.to_string();
|
||||
let database_view_id = params.view_id.to_string();
|
||||
let database_parent_view_id = params.parent_view_id.to_string();
|
||||
self
|
||||
.0
|
||||
.create_linked_view(
|
||||
name,
|
||||
layout.into(),
|
||||
database_params.database_id,
|
||||
database_view_id,
|
||||
database_parent_view_id,
|
||||
)
|
||||
.await?;
|
||||
Ok(None)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
if old.layout != new.layout {
|
||||
self
|
||||
.0
|
||||
.update_database_layout(&new.id, database_layout)
|
||||
.await?;
|
||||
Ok(())
|
||||
/// Create a database view with build-in data.
|
||||
/// If the ext contains the {"database_id": "xx"}, then it will link to
|
||||
/// the existing database. The data of the database will be shared within
|
||||
/// these references views.
|
||||
async fn create_default_view(
|
||||
&self,
|
||||
_user_id: i64,
|
||||
_parent_view_id: &str,
|
||||
view_id: &str,
|
||||
name: &str,
|
||||
layout: ViewLayout,
|
||||
) -> Result<(), FlowyError> {
|
||||
let name = name.to_string();
|
||||
let data = match layout {
|
||||
ViewLayout::Grid => make_default_grid(view_id, &name),
|
||||
ViewLayout::Board => make_default_board(view_id, &name),
|
||||
ViewLayout::Calendar => make_default_calendar(view_id, &name),
|
||||
ViewLayout::Document | ViewLayout::Chat => {
|
||||
return Err(
|
||||
FlowyError::internal().with_context(format!("Can't handle {:?} layout type", layout)),
|
||||
);
|
||||
},
|
||||
};
|
||||
let result = self.0.import_database(data).await;
|
||||
match result {
|
||||
Ok(_) => Ok(()),
|
||||
Err(err) => {
|
||||
if err.is_already_exists() {
|
||||
Ok(())
|
||||
} else {
|
||||
Ok(())
|
||||
Err(err)
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
async fn import_from_bytes(
|
||||
&self,
|
||||
_uid: i64,
|
||||
view_id: &str,
|
||||
_name: &str,
|
||||
import_type: ImportType,
|
||||
bytes: Vec<u8>,
|
||||
) -> Result<Vec<ImportedData>, FlowyError> {
|
||||
let format = match import_type {
|
||||
ImportType::CSV => CSVFormat::Original,
|
||||
ImportType::AFDatabase => CSVFormat::META,
|
||||
_ => CSVFormat::Original,
|
||||
};
|
||||
let content = tokio::task::spawn_blocking(move || {
|
||||
String::from_utf8(bytes).map_err(|err| FlowyError::internal().with_context(err))
|
||||
})
|
||||
.await??;
|
||||
let result = self
|
||||
.0
|
||||
.import_csv(view_id.to_string(), content, format)
|
||||
.await?;
|
||||
Ok(
|
||||
result
|
||||
.encoded_collabs
|
||||
.into_iter()
|
||||
.map(|encoded| {
|
||||
(
|
||||
encoded.object_id,
|
||||
encoded.collab_type,
|
||||
encoded.encoded_collab,
|
||||
)
|
||||
})
|
||||
.collect(),
|
||||
)
|
||||
}
|
||||
|
||||
async fn import_from_file_path(
|
||||
&self,
|
||||
view_id: &str,
|
||||
_name: &str,
|
||||
path: String,
|
||||
) -> Result<(), FlowyError> {
|
||||
let file_path = Path::new(&path);
|
||||
if !file_path.exists() {
|
||||
return Err(FlowyError::record_not_found().with_context("File not found"));
|
||||
}
|
||||
|
||||
fn name(&self) -> &str {
|
||||
"DatabaseFolderOperationHandler"
|
||||
let data = tokio::fs::read(file_path).await?;
|
||||
let content =
|
||||
String::from_utf8(data).map_err(|e| FlowyError::invalid_data().with_context(e))?;
|
||||
let _ = self
|
||||
.0
|
||||
.import_csv(view_id.to_string(), content, CSVFormat::Original)
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn did_update_view(&self, old: &View, new: &View) -> Result<(), FlowyError> {
|
||||
let database_layout = match new.layout {
|
||||
ViewLayout::Document | ViewLayout::Chat => {
|
||||
return Err(FlowyError::internal().with_context("Can't handle document layout type"));
|
||||
},
|
||||
ViewLayout::Grid => DatabaseLayoutPB::Grid,
|
||||
ViewLayout::Board => DatabaseLayoutPB::Board,
|
||||
ViewLayout::Calendar => DatabaseLayoutPB::Calendar,
|
||||
};
|
||||
|
||||
if old.layout != new.layout {
|
||||
self
|
||||
.0
|
||||
.update_database_layout(&new.id, database_layout)
|
||||
.await?;
|
||||
Ok(())
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn name(&self) -> &str {
|
||||
"DatabaseFolderOperationHandler"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[derive(Debug, serde::Deserialize)]
|
||||
struct CreateDatabaseExtParams {
|
||||
database_id: String,
|
||||
database_id: String,
|
||||
}
|
||||
|
||||
impl CreateDatabaseExtParams {
|
||||
pub fn from_map(map: HashMap<String, String>) -> Option<Self> {
|
||||
let value = serde_json::to_value(map).ok()?;
|
||||
serde_json::from_value::<Self>(value).ok()
|
||||
}
|
||||
pub fn from_map(map: HashMap<String, String>) -> Option<Self> {
|
||||
let value = serde_json::to_value(map).ok()?;
|
||||
serde_json::from_value::<Self>(value).ok()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,11 +1,9 @@
|
||||
use std::convert::TryFrom;
|
||||
use std::sync::Arc;
|
||||
use crate::deps_resolve::folder_deps::get_encoded_collab_v1_from_disk;
|
||||
use bytes::Bytes;
|
||||
use collab::entity::EncodedCollab;
|
||||
use collab_entity::CollabType;
|
||||
use collab_folder::hierarchy_builder::NestedViewBuilder;
|
||||
use collab_folder::ViewLayout;
|
||||
use tokio::sync::RwLock;
|
||||
use flowy_document::entities::DocumentDataPB;
|
||||
use flowy_document::manager::DocumentManager;
|
||||
use flowy_document::parser::json::parser::JsonToDocumentParser;
|
||||
@ -13,148 +11,152 @@ use flowy_error::FlowyError;
|
||||
use flowy_folder::entities::{CreateViewParams, ViewLayoutPB};
|
||||
use flowy_folder::manager::FolderUser;
|
||||
use flowy_folder::share::ImportType;
|
||||
use flowy_folder::view_operation::{FolderOperationHandler, GatherEncodedCollab, ImportedData, ViewData};
|
||||
use flowy_folder::view_operation::{
|
||||
FolderOperationHandler, GatherEncodedCollab, ImportedData, ViewData,
|
||||
};
|
||||
use lib_dispatch::prelude::ToBytes;
|
||||
use lib_infra::async_trait::async_trait;
|
||||
use crate::deps_resolve::folder_deps::get_encoded_collab_v1_from_disk;
|
||||
use std::convert::TryFrom;
|
||||
use std::sync::Arc;
|
||||
use tokio::sync::RwLock;
|
||||
|
||||
pub struct DocumentFolderOperation(pub Arc<DocumentManager>);
|
||||
#[async_trait]
|
||||
impl FolderOperationHandler for DocumentFolderOperation {
|
||||
fn name(&self) -> &str {
|
||||
"DocumentFolderOperationHandler"
|
||||
}
|
||||
fn name(&self) -> &str {
|
||||
"DocumentFolderOperationHandler"
|
||||
}
|
||||
|
||||
async fn create_workspace_view(
|
||||
&self,
|
||||
uid: i64,
|
||||
workspace_view_builder: Arc<RwLock<NestedViewBuilder>>,
|
||||
) -> Result<(), FlowyError> {
|
||||
let manager = self.0.clone();
|
||||
let mut write_guard = workspace_view_builder.write().await;
|
||||
// Create a view named "Getting started" with an icon ⭐️ and the built-in README data.
|
||||
// Don't modify this code unless you know what you are doing.
|
||||
write_guard
|
||||
.with_view_builder(|view_builder| async {
|
||||
let view = view_builder
|
||||
.with_name("Getting started")
|
||||
.with_icon("⭐️")
|
||||
.build();
|
||||
// create a empty document
|
||||
let json_str = include_str!("../../../assets/read_me.json");
|
||||
let document_pb = JsonToDocumentParser::json_str_to_document(json_str).unwrap();
|
||||
manager
|
||||
.create_document(uid, &view.view.id, Some(document_pb.into()))
|
||||
.await
|
||||
.unwrap();
|
||||
view
|
||||
})
|
||||
.await;
|
||||
Ok(())
|
||||
}
|
||||
async fn create_workspace_view(
|
||||
&self,
|
||||
uid: i64,
|
||||
workspace_view_builder: Arc<RwLock<NestedViewBuilder>>,
|
||||
) -> Result<(), FlowyError> {
|
||||
let manager = self.0.clone();
|
||||
let mut write_guard = workspace_view_builder.write().await;
|
||||
// Create a view named "Getting started" with an icon ⭐️ and the built-in README data.
|
||||
// Don't modify this code unless you know what you are doing.
|
||||
write_guard
|
||||
.with_view_builder(|view_builder| async {
|
||||
let view = view_builder
|
||||
.with_name("Getting started")
|
||||
.with_icon("⭐️")
|
||||
.build();
|
||||
// create a empty document
|
||||
let json_str = include_str!("../../../assets/read_me.json");
|
||||
let document_pb = JsonToDocumentParser::json_str_to_document(json_str).unwrap();
|
||||
manager
|
||||
.create_document(uid, &view.view.id, Some(document_pb.into()))
|
||||
.await
|
||||
.unwrap();
|
||||
view
|
||||
})
|
||||
.await;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn open_view(&self, view_id: &str) -> Result<(), FlowyError> {
|
||||
self.0.open_document(view_id).await?;
|
||||
Ok(())
|
||||
}
|
||||
async fn open_view(&self, view_id: &str) -> Result<(), FlowyError> {
|
||||
self.0.open_document(view_id).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Close the document view.
|
||||
async fn close_view(&self, view_id: &str) -> Result<(), FlowyError> {
|
||||
self.0.close_document(view_id).await?;
|
||||
Ok(())
|
||||
}
|
||||
/// Close the document view.
|
||||
async fn close_view(&self, view_id: &str) -> Result<(), FlowyError> {
|
||||
self.0.close_document(view_id).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn delete_view(&self, view_id: &str) -> Result<(), FlowyError> {
|
||||
match self.0.delete_document(view_id).await {
|
||||
Ok(_) => tracing::trace!("Delete document: {}", view_id),
|
||||
Err(e) => tracing::error!("🔴delete document failed: {}", e),
|
||||
async fn delete_view(&self, view_id: &str) -> Result<(), FlowyError> {
|
||||
match self.0.delete_document(view_id).await {
|
||||
Ok(_) => tracing::trace!("Delete document: {}", view_id),
|
||||
Err(e) => tracing::error!("🔴delete document failed: {}", e),
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn duplicate_view(&self, view_id: &str) -> Result<Bytes, FlowyError> {
|
||||
let data: DocumentDataPB = self.0.get_document_data(view_id).await?.into();
|
||||
let data_bytes = data.into_bytes().map_err(|_| FlowyError::invalid_data())?;
|
||||
Ok(data_bytes)
|
||||
}
|
||||
|
||||
async fn gather_publish_encode_collab(
|
||||
&self,
|
||||
user: &Arc<dyn FolderUser>,
|
||||
view_id: &str,
|
||||
) -> Result<GatherEncodedCollab, FlowyError> {
|
||||
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,
|
||||
params: CreateViewParams,
|
||||
) -> Result<Option<EncodedCollab>, FlowyError> {
|
||||
debug_assert_eq!(params.layout, ViewLayoutPB::Document);
|
||||
let data = match params.initial_data {
|
||||
ViewData::DuplicateData(data) => Some(DocumentDataPB::try_from(data)?),
|
||||
ViewData::Data(data) => Some(DocumentDataPB::try_from(data)?),
|
||||
ViewData::Empty => None,
|
||||
};
|
||||
let encoded_collab = self
|
||||
.0
|
||||
.create_document(user_id, ¶ms.view_id, data.map(|d| d.into()))
|
||||
.await?;
|
||||
Ok(Some(encoded_collab))
|
||||
}
|
||||
|
||||
/// Create a view with built-in data.
|
||||
async fn create_default_view(
|
||||
&self,
|
||||
user_id: i64,
|
||||
_parent_view_id: &str,
|
||||
view_id: &str,
|
||||
_name: &str,
|
||||
layout: ViewLayout,
|
||||
) -> Result<(), FlowyError> {
|
||||
debug_assert_eq!(layout, ViewLayout::Document);
|
||||
match self.0.create_document(user_id, view_id, None).await {
|
||||
Ok(_) => Ok(()),
|
||||
Err(err) => {
|
||||
if err.is_already_exists() {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(err)
|
||||
}
|
||||
Ok(())
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
async fn duplicate_view(&self, view_id: &str) -> Result<Bytes, FlowyError> {
|
||||
let data: DocumentDataPB = self.0.get_document_data(view_id).await?.into();
|
||||
let data_bytes = data.into_bytes().map_err(|_| FlowyError::invalid_data())?;
|
||||
Ok(data_bytes)
|
||||
}
|
||||
async fn import_from_bytes(
|
||||
&self,
|
||||
uid: i64,
|
||||
view_id: &str,
|
||||
_name: &str,
|
||||
_import_type: ImportType,
|
||||
bytes: Vec<u8>,
|
||||
) -> Result<Vec<ImportedData>, FlowyError> {
|
||||
let data = DocumentDataPB::try_from(Bytes::from(bytes))?;
|
||||
let encoded_collab = self
|
||||
.0
|
||||
.create_document(uid, view_id, Some(data.into()))
|
||||
.await?;
|
||||
Ok(vec![(
|
||||
view_id.to_string(),
|
||||
CollabType::Document,
|
||||
encoded_collab,
|
||||
)])
|
||||
}
|
||||
|
||||
async fn gather_publish_encode_collab(
|
||||
&self,
|
||||
user: &Arc<dyn FolderUser>,
|
||||
view_id: &str,
|
||||
) -> Result<GatherEncodedCollab, FlowyError> {
|
||||
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,
|
||||
params: CreateViewParams,
|
||||
) -> Result<Option<EncodedCollab>, FlowyError> {
|
||||
debug_assert_eq!(params.layout, ViewLayoutPB::Document);
|
||||
let data = match params.initial_data {
|
||||
ViewData::DuplicateData(data) => Some(DocumentDataPB::try_from(data)?),
|
||||
ViewData::Data(data) => Some(DocumentDataPB::try_from(data)?),
|
||||
ViewData::Empty => None,
|
||||
};
|
||||
let encoded_collab = self
|
||||
.0
|
||||
.create_document(user_id, ¶ms.view_id, data.map(|d| d.into()))
|
||||
.await?;
|
||||
Ok(Some(encoded_collab))
|
||||
}
|
||||
|
||||
/// Create a view with built-in data.
|
||||
async fn create_default_view(
|
||||
&self,
|
||||
user_id: i64,
|
||||
_parent_view_id: &str,
|
||||
view_id: &str,
|
||||
_name: &str,
|
||||
layout: ViewLayout,
|
||||
) -> Result<(), FlowyError> {
|
||||
debug_assert_eq!(layout, ViewLayout::Document);
|
||||
match self.0.create_document(user_id, view_id, None).await {
|
||||
Ok(_) => Ok(()),
|
||||
Err(err) => {
|
||||
if err.is_already_exists() {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(err)
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
async fn import_from_bytes(
|
||||
&self,
|
||||
uid: i64,
|
||||
view_id: &str,
|
||||
_name: &str,
|
||||
_import_type: ImportType,
|
||||
bytes: Vec<u8>,
|
||||
) -> Result<Vec<ImportedData>, FlowyError> {
|
||||
let data = DocumentDataPB::try_from(Bytes::from(bytes))?;
|
||||
let encoded_collab = self
|
||||
.0
|
||||
.create_document(uid, view_id, Some(data.into()))
|
||||
.await?;
|
||||
Ok(vec![(
|
||||
view_id.to_string(),
|
||||
CollabType::Document,
|
||||
encoded_collab,
|
||||
)])
|
||||
}
|
||||
|
||||
async fn import_from_file_path(
|
||||
&self,
|
||||
_view_id: &str,
|
||||
_name: &str,
|
||||
_path: String,
|
||||
) -> Result<(), FlowyError> {
|
||||
// TODO(lucas): import file from local markdown file
|
||||
Ok(())
|
||||
}
|
||||
async fn import_from_file_path(
|
||||
&self,
|
||||
_view_id: &str,
|
||||
_name: &str,
|
||||
_path: String,
|
||||
) -> Result<(), FlowyError> {
|
||||
// TODO(lucas): import file from local markdown file
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ mod folder_deps_chat_impl;
|
||||
mod folder_deps_database_impl;
|
||||
mod folder_deps_doc_impl;
|
||||
|
||||
use crate::server_layer::ServerProvider;
|
||||
use collab_entity::{CollabType, EncodedCollab};
|
||||
use collab_integrate::collab_builder::AppFlowyCollabBuilder;
|
||||
use collab_integrate::CollabKVDB;
|
||||
@ -9,239 +10,238 @@ use flowy_ai::ai_manager::AIManager;
|
||||
use flowy_database2::DatabaseManager;
|
||||
use flowy_document::manager::DocumentManager;
|
||||
use flowy_error::{internal_error, FlowyError, FlowyResult};
|
||||
use flowy_folder::entities::{ UpdateViewParams};
|
||||
use flowy_folder::entities::UpdateViewParams;
|
||||
use flowy_folder::manager::{FolderManager, FolderUser};
|
||||
use flowy_folder::ViewLayout;
|
||||
use flowy_search::folder::indexer::FolderIndexManagerImpl;
|
||||
use flowy_sqlite::kv::KVStorePreferences;
|
||||
use flowy_user::services::authenticate_user::AuthenticateUser;
|
||||
use flowy_user::services::data_import::{load_collab_by_object_id};
|
||||
use flowy_user::services::data_import::load_collab_by_object_id;
|
||||
use std::sync::{Arc, Weak};
|
||||
use crate::server_layer::ServerProvider;
|
||||
|
||||
use collab_plugins::local_storage::kv::KVTransactionDB;
|
||||
use flowy_folder_pub::query::{FolderQueryService, FolderService, FolderViewEdit, QueryCollab};
|
||||
use lib_infra::async_trait::async_trait;
|
||||
use crate::deps_resolve::folder_deps::folder_deps_chat_impl::ChatFolderOperation;
|
||||
use crate::deps_resolve::folder_deps::folder_deps_database_impl::DatabaseFolderOperation;
|
||||
use crate::deps_resolve::folder_deps::folder_deps_doc_impl::DocumentFolderOperation;
|
||||
use collab_plugins::local_storage::kv::KVTransactionDB;
|
||||
use flowy_folder_pub::query::{FolderQueryService, FolderService, FolderViewEdit, QueryCollab};
|
||||
use lib_infra::async_trait::async_trait;
|
||||
|
||||
pub struct FolderDepsResolver();
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
impl FolderDepsResolver {
|
||||
pub async fn resolve(
|
||||
authenticate_user: Weak<AuthenticateUser>,
|
||||
collab_builder: Arc<AppFlowyCollabBuilder>,
|
||||
server_provider: Arc<ServerProvider>,
|
||||
folder_indexer: Arc<FolderIndexManagerImpl>,
|
||||
store_preferences: Arc<KVStorePreferences>,
|
||||
) -> Arc<FolderManager> {
|
||||
let user: Arc<dyn FolderUser> = Arc::new(FolderUserImpl {
|
||||
authenticate_user: authenticate_user.clone(),
|
||||
});
|
||||
pub async fn resolve(
|
||||
authenticate_user: Weak<AuthenticateUser>,
|
||||
collab_builder: Arc<AppFlowyCollabBuilder>,
|
||||
server_provider: Arc<ServerProvider>,
|
||||
folder_indexer: Arc<FolderIndexManagerImpl>,
|
||||
store_preferences: Arc<KVStorePreferences>,
|
||||
) -> Arc<FolderManager> {
|
||||
let user: Arc<dyn FolderUser> = Arc::new(FolderUserImpl {
|
||||
authenticate_user: authenticate_user.clone(),
|
||||
});
|
||||
|
||||
Arc::new(
|
||||
FolderManager::new(
|
||||
user.clone(),
|
||||
collab_builder,
|
||||
server_provider.clone(),
|
||||
folder_indexer,
|
||||
store_preferences,
|
||||
)
|
||||
.unwrap(),
|
||||
)
|
||||
}
|
||||
Arc::new(
|
||||
FolderManager::new(
|
||||
user.clone(),
|
||||
collab_builder,
|
||||
server_provider.clone(),
|
||||
folder_indexer,
|
||||
store_preferences,
|
||||
)
|
||||
.unwrap(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn register_handlers(
|
||||
folder_manager: &Arc<FolderManager>,
|
||||
document_manager: Arc<DocumentManager>,
|
||||
database_manager: Arc<DatabaseManager>,
|
||||
chat_manager: Arc<AIManager>,
|
||||
folder_manager: &Arc<FolderManager>,
|
||||
document_manager: Arc<DocumentManager>,
|
||||
database_manager: Arc<DatabaseManager>,
|
||||
chat_manager: Arc<AIManager>,
|
||||
) {
|
||||
let document_folder_operation = Arc::new(DocumentFolderOperation(document_manager));
|
||||
folder_manager.register_operation_handler(ViewLayout::Document, document_folder_operation);
|
||||
let document_folder_operation = Arc::new(DocumentFolderOperation(document_manager));
|
||||
folder_manager.register_operation_handler(ViewLayout::Document, document_folder_operation);
|
||||
|
||||
let database_folder_operation = Arc::new(DatabaseFolderOperation(database_manager));
|
||||
let chat_folder_operation = Arc::new(ChatFolderOperation(chat_manager));
|
||||
folder_manager.register_operation_handler(ViewLayout::Board, database_folder_operation.clone());
|
||||
folder_manager.register_operation_handler(ViewLayout::Grid, database_folder_operation.clone());
|
||||
folder_manager.register_operation_handler(ViewLayout::Calendar, database_folder_operation);
|
||||
folder_manager.register_operation_handler(ViewLayout::Chat, chat_folder_operation);
|
||||
let database_folder_operation = Arc::new(DatabaseFolderOperation(database_manager));
|
||||
let chat_folder_operation = Arc::new(ChatFolderOperation(chat_manager));
|
||||
folder_manager.register_operation_handler(ViewLayout::Board, database_folder_operation.clone());
|
||||
folder_manager.register_operation_handler(ViewLayout::Grid, database_folder_operation.clone());
|
||||
folder_manager.register_operation_handler(ViewLayout::Calendar, database_folder_operation);
|
||||
folder_manager.register_operation_handler(ViewLayout::Chat, chat_folder_operation);
|
||||
}
|
||||
|
||||
struct FolderUserImpl {
|
||||
authenticate_user: Weak<AuthenticateUser>,
|
||||
authenticate_user: Weak<AuthenticateUser>,
|
||||
}
|
||||
|
||||
impl FolderUserImpl {
|
||||
fn upgrade_user(&self) -> Result<Arc<AuthenticateUser>, FlowyError> {
|
||||
let user = self
|
||||
.authenticate_user
|
||||
.upgrade()
|
||||
.ok_or(FlowyError::internal().with_context("Unexpected error: UserSession is None"))?;
|
||||
Ok(user)
|
||||
}
|
||||
fn upgrade_user(&self) -> Result<Arc<AuthenticateUser>, FlowyError> {
|
||||
let user = self
|
||||
.authenticate_user
|
||||
.upgrade()
|
||||
.ok_or(FlowyError::internal().with_context("Unexpected error: UserSession is None"))?;
|
||||
Ok(user)
|
||||
}
|
||||
}
|
||||
|
||||
impl FolderUser for FolderUserImpl {
|
||||
fn user_id(&self) -> Result<i64, FlowyError> {
|
||||
self.upgrade_user()?.user_id()
|
||||
}
|
||||
fn user_id(&self) -> Result<i64, FlowyError> {
|
||||
self.upgrade_user()?.user_id()
|
||||
}
|
||||
|
||||
fn workspace_id(&self) -> Result<String, FlowyError> {
|
||||
self.upgrade_user()?.workspace_id()
|
||||
}
|
||||
fn workspace_id(&self) -> Result<String, FlowyError> {
|
||||
self.upgrade_user()?.workspace_id()
|
||||
}
|
||||
|
||||
fn collab_db(&self, uid: i64) -> Result<Weak<CollabKVDB>, FlowyError> {
|
||||
self.upgrade_user()?.get_collab_db(uid)
|
||||
}
|
||||
fn collab_db(&self, uid: i64) -> Result<Weak<CollabKVDB>, FlowyError> {
|
||||
self.upgrade_user()?.get_collab_db(uid)
|
||||
}
|
||||
|
||||
fn is_folder_exist_on_disk(&self, uid: i64, workspace_id: &str) -> FlowyResult<bool> {
|
||||
self.upgrade_user()?.is_collab_on_disk(uid, workspace_id)
|
||||
}
|
||||
fn is_folder_exist_on_disk(&self, uid: i64, workspace_id: &str) -> FlowyResult<bool> {
|
||||
self.upgrade_user()?.is_collab_on_disk(uid, workspace_id)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct FolderServiceImpl {
|
||||
folder_manager: Weak<FolderManager>,
|
||||
user: Arc<dyn FolderUser>,
|
||||
folder_manager: Weak<FolderManager>,
|
||||
user: Arc<dyn FolderUser>,
|
||||
}
|
||||
impl FolderService for FolderServiceImpl {}
|
||||
|
||||
impl FolderServiceImpl {
|
||||
pub fn new(
|
||||
folder_manager: Weak<FolderManager>,
|
||||
authenticate_user: Weak<AuthenticateUser>,
|
||||
) -> Self {
|
||||
let user: Arc<dyn FolderUser> = Arc::new(FolderUserImpl { authenticate_user });
|
||||
Self {
|
||||
folder_manager,
|
||||
user,
|
||||
}
|
||||
pub fn new(
|
||||
folder_manager: Weak<FolderManager>,
|
||||
authenticate_user: Weak<AuthenticateUser>,
|
||||
) -> Self {
|
||||
let user: Arc<dyn FolderUser> = Arc::new(FolderUserImpl { authenticate_user });
|
||||
Self {
|
||||
folder_manager,
|
||||
user,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
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 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_surrounding_view_ids_with_view_layout(
|
||||
&self,
|
||||
parent_view_id: &str,
|
||||
view_layout: ViewLayout,
|
||||
) -> Vec<String> {
|
||||
let folder_manager = match self.folder_manager.upgrade() {
|
||||
Some(folder_manager) => folder_manager,
|
||||
None => return vec![],
|
||||
};
|
||||
async fn get_surrounding_view_ids_with_view_layout(
|
||||
&self,
|
||||
parent_view_id: &str,
|
||||
view_layout: ViewLayout,
|
||||
) -> Vec<String> {
|
||||
let folder_manager = match self.folder_manager.upgrade() {
|
||||
Some(folder_manager) => folder_manager,
|
||||
None => return vec![],
|
||||
};
|
||||
|
||||
if let Ok(view) = folder_manager.get_view(parent_view_id).await {
|
||||
if view.space_info().is_some() {
|
||||
return vec![];
|
||||
if let Ok(view) = folder_manager.get_view(parent_view_id).await {
|
||||
if view.space_info().is_some() {
|
||||
return vec![];
|
||||
}
|
||||
}
|
||||
|
||||
match folder_manager
|
||||
.get_untrashed_views_belong_to(parent_view_id)
|
||||
.await
|
||||
{
|
||||
Ok(views) => {
|
||||
let mut children = views
|
||||
.into_iter()
|
||||
.filter_map(|child| {
|
||||
if child.layout == view_layout {
|
||||
Some(child.id.clone())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
match folder_manager
|
||||
.get_untrashed_views_belong_to(parent_view_id)
|
||||
.await
|
||||
{
|
||||
Ok(views) => {
|
||||
let mut children = views
|
||||
.into_iter()
|
||||
.filter_map(|child| {
|
||||
if child.layout == view_layout {
|
||||
Some(child.id.clone())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
children.push(parent_view_id.to_string());
|
||||
children
|
||||
},
|
||||
_ => vec![],
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
children.push(parent_view_id.to_string());
|
||||
children
|
||||
},
|
||||
_ => vec![],
|
||||
}
|
||||
}
|
||||
|
||||
async fn get_collab(&self, object_id: &str, collab_type: CollabType) -> Option<QueryCollab> {
|
||||
let encode_collab = get_encoded_collab_v1_from_disk(&self.user, object_id, collab_type.clone())
|
||||
.await
|
||||
.ok();
|
||||
async fn get_collab(&self, object_id: &str, collab_type: CollabType) -> Option<QueryCollab> {
|
||||
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,
|
||||
})
|
||||
}
|
||||
encode_collab.map(|encoded_collab| QueryCollab {
|
||||
collab_type,
|
||||
encoded_collab,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
async fn get_encoded_collab_v1_from_disk(
|
||||
user: &Arc<dyn FolderUser>,
|
||||
view_id: &str,
|
||||
collab_type: CollabType,
|
||||
user: &Arc<dyn FolderUser>,
|
||||
view_id: &str,
|
||||
collab_type: CollabType,
|
||||
) -> Result<EncodedCollab, FlowyError> {
|
||||
let workspace_id = user.workspace_id()?;
|
||||
let uid = user
|
||||
.user_id()
|
||||
.map_err(|e| e.with_context("unable to get the uid: {}"))?;
|
||||
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",
|
||||
)
|
||||
// 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))
|
||||
})?;
|
||||
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)?
|
||||
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)?
|
||||
}
|
||||
|
@ -10,10 +10,10 @@ mod collab_deps;
|
||||
mod document_deps;
|
||||
|
||||
mod chat_deps;
|
||||
mod cloud_service_impl;
|
||||
mod database_deps;
|
||||
pub mod file_storage_deps;
|
||||
mod folder_deps;
|
||||
pub(crate) mod reminder_deps;
|
||||
mod search_deps;
|
||||
mod user_deps;
|
||||
mod folder_deps;
|
||||
mod cloud_service_impl;
|
||||
pub(crate) mod reminder_deps;
|
||||
|
@ -32,17 +32,17 @@ use module::make_plugins;
|
||||
use crate::config::AppFlowyCoreConfig;
|
||||
use crate::deps_resolve::file_storage_deps::FileStorageResolver;
|
||||
use crate::deps_resolve::*;
|
||||
use deps_resolve::reminder_deps::CollabInteractImpl;
|
||||
use user_state_callback::UserStatusCallbackImpl;
|
||||
use crate::log_filter::init_log;
|
||||
use crate::server_layer::{current_server_type, Server, ServerProvider};
|
||||
use deps_resolve::reminder_deps::CollabInteractImpl;
|
||||
use user_state_callback::UserStatusCallbackImpl;
|
||||
|
||||
pub mod config;
|
||||
mod deps_resolve;
|
||||
pub mod module;
|
||||
pub(crate) mod user_state_callback;
|
||||
pub(crate) mod server_layer;
|
||||
mod log_filter;
|
||||
pub mod module;
|
||||
pub(crate) mod server_layer;
|
||||
pub(crate) mod user_state_callback;
|
||||
|
||||
/// This name will be used as to identify the current [AppFlowyCore] instance.
|
||||
/// Don't change this.
|
||||
|
@ -43,7 +43,6 @@ getrandom = { version = "0.2", features = ["js"] }
|
||||
[dev-dependencies]
|
||||
tempfile = "3.4.0"
|
||||
tracing-subscriber = { version = "0.3.3", features = ["env-filter"] }
|
||||
collab-integrate = { workspace = true }
|
||||
tokio = { workspace = true, features = ["rt", "rt-multi-thread"] }
|
||||
|
||||
[build-dependencies]
|
||||
|
@ -36,7 +36,7 @@ client-api = { workspace = true, optional = true }
|
||||
tantivy = { version = "0.22.0", optional = true }
|
||||
|
||||
[features]
|
||||
default = ["impl_from_dispatch_error", "impl_from_serde", "impl_from_reqwest"]
|
||||
default = ["impl_from_dispatch_error", "impl_from_serde", "impl_from_reqwest", "impl_from_sqlite"]
|
||||
impl_from_dispatch_error = ["lib-dispatch"]
|
||||
impl_from_serde = []
|
||||
impl_from_reqwest = ["reqwest"]
|
||||
|
@ -0,0 +1,2 @@
|
||||
-- This file should undo anything in `up.sql`
|
||||
DROP TABLE af_collab_metadata;
|
@ -0,0 +1,7 @@
|
||||
-- Your SQL goes here
|
||||
CREATE TABLE af_collab_metadata (
|
||||
object_id TEXT PRIMARY KEY NOT NULL,
|
||||
updated_at BIGINT NOT NULL,
|
||||
prev_sync_state_vector BLOB NOT NULL,
|
||||
collab_type INTEGER NOT NULL
|
||||
);
|
@ -1,5 +1,14 @@
|
||||
// @generated automatically by Diesel CLI.
|
||||
|
||||
diesel::table! {
|
||||
af_collab_metadata (object_id) {
|
||||
object_id -> Text,
|
||||
updated_at -> BigInt,
|
||||
prev_sync_state_vector -> Binary,
|
||||
collab_type -> Integer,
|
||||
}
|
||||
}
|
||||
|
||||
diesel::table! {
|
||||
chat_local_setting_table (chat_id) {
|
||||
chat_id -> Text,
|
||||
@ -119,6 +128,7 @@ diesel::table! {
|
||||
}
|
||||
|
||||
diesel::allow_tables_to_appear_in_same_query!(
|
||||
af_collab_metadata,
|
||||
chat_local_setting_table,
|
||||
chat_message_table,
|
||||
chat_table,
|
||||
|
@ -36,7 +36,7 @@ use crate::migrations::workspace_trash_v1::WorkspaceTrashMapToSectionMigration;
|
||||
use crate::migrations::AnonUser;
|
||||
use crate::services::authenticate_user::AuthenticateUser;
|
||||
use crate::services::cloud_config::get_cloud_config;
|
||||
use crate::services::collab_interact::{UserReminder, DefaultCollabInteract};
|
||||
use crate::services::collab_interact::{DefaultCollabInteract, UserReminder};
|
||||
|
||||
use super::manager_user_workspace::save_user_workspace;
|
||||
use crate::migrations::doc_key_with_workspace::CollabDocKeyWithWorkspaceIdMigration;
|
||||
|
Reference in New Issue
Block a user