mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
feat: add support for renaming and updating the icon for workspaces (#4806)
This commit is contained in:
parent
f8962edfd7
commit
2af93a9bcb
2
frontend/appflowy_tauri/src-tauri/Cargo.lock
generated
2
frontend/appflowy_tauri/src-tauri/Cargo.lock
generated
@ -1201,7 +1201,7 @@ dependencies = [
|
|||||||
"cssparser-macros",
|
"cssparser-macros",
|
||||||
"dtoa-short",
|
"dtoa-short",
|
||||||
"itoa 1.0.6",
|
"itoa 1.0.6",
|
||||||
"phf 0.8.0",
|
"phf 0.11.2",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
18
frontend/appflowy_web/wasm-libs/Cargo.lock
generated
18
frontend/appflowy_web/wasm-libs/Cargo.lock
generated
@ -900,7 +900,7 @@ dependencies = [
|
|||||||
"cssparser-macros",
|
"cssparser-macros",
|
||||||
"dtoa-short",
|
"dtoa-short",
|
||||||
"itoa",
|
"itoa",
|
||||||
"phf 0.8.0",
|
"phf 0.11.2",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -2779,7 +2779,7 @@ version = "0.8.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3dfb61232e34fcb633f43d12c58f83c1df82962dcdfa565a4e866ffc17dafe12"
|
checksum = "3dfb61232e34fcb633f43d12c58f83c1df82962dcdfa565a4e866ffc17dafe12"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"phf_macros",
|
"phf_macros 0.8.0",
|
||||||
"phf_shared 0.8.0",
|
"phf_shared 0.8.0",
|
||||||
"proc-macro-hack",
|
"proc-macro-hack",
|
||||||
]
|
]
|
||||||
@ -2799,6 +2799,7 @@ version = "0.11.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc"
|
checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"phf_macros 0.11.2",
|
||||||
"phf_shared 0.11.2",
|
"phf_shared 0.11.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -2866,6 +2867,19 @@ dependencies = [
|
|||||||
"syn 1.0.109",
|
"syn 1.0.109",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "phf_macros"
|
||||||
|
version = "0.11.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3444646e286606587e49f3bcf1679b8cef1dc2c5ecc29ddacaffc305180d464b"
|
||||||
|
dependencies = [
|
||||||
|
"phf_generator 0.11.2",
|
||||||
|
"phf_shared 0.11.2",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.48",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "phf_shared"
|
name = "phf_shared"
|
||||||
version = "0.8.0"
|
version = "0.8.0"
|
||||||
|
18
frontend/rust-lib/Cargo.lock
generated
18
frontend/rust-lib/Cargo.lock
generated
@ -1103,7 +1103,7 @@ dependencies = [
|
|||||||
"cssparser-macros",
|
"cssparser-macros",
|
||||||
"dtoa-short",
|
"dtoa-short",
|
||||||
"itoa",
|
"itoa",
|
||||||
"phf 0.8.0",
|
"phf 0.11.2",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -3641,7 +3641,7 @@ version = "0.8.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3dfb61232e34fcb633f43d12c58f83c1df82962dcdfa565a4e866ffc17dafe12"
|
checksum = "3dfb61232e34fcb633f43d12c58f83c1df82962dcdfa565a4e866ffc17dafe12"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"phf_macros",
|
"phf_macros 0.8.0",
|
||||||
"phf_shared 0.8.0",
|
"phf_shared 0.8.0",
|
||||||
"proc-macro-hack",
|
"proc-macro-hack",
|
||||||
]
|
]
|
||||||
@ -3661,6 +3661,7 @@ version = "0.11.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc"
|
checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"phf_macros 0.11.2",
|
||||||
"phf_shared 0.11.2",
|
"phf_shared 0.11.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -3728,6 +3729,19 @@ dependencies = [
|
|||||||
"syn 1.0.109",
|
"syn 1.0.109",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "phf_macros"
|
||||||
|
version = "0.11.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3444646e286606587e49f3bcf1679b8cef1dc2c5ecc29ddacaffc305180d464b"
|
||||||
|
dependencies = [
|
||||||
|
"phf_generator 0.11.2",
|
||||||
|
"phf_shared 0.11.2",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.47",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "phf_shared"
|
name = "phf_shared"
|
||||||
version = "0.8.0"
|
version = "0.8.0"
|
||||||
|
@ -4,12 +4,14 @@ use std::sync::Arc;
|
|||||||
|
|
||||||
use bytes::Bytes;
|
use bytes::Bytes;
|
||||||
|
|
||||||
|
use flowy_folder::entities::{RepeatedViewPB, WorkspacePB};
|
||||||
use nanoid::nanoid;
|
use nanoid::nanoid;
|
||||||
use protobuf::ProtobufError;
|
use protobuf::ProtobufError;
|
||||||
use tokio::sync::broadcast::{channel, Sender};
|
use tokio::sync::broadcast::{channel, Sender};
|
||||||
use tracing::error;
|
use tracing::error;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
|
use flowy_folder::event_map::FolderEvent;
|
||||||
use flowy_notification::entities::SubscribeObject;
|
use flowy_notification::entities::SubscribeObject;
|
||||||
use flowy_notification::NotificationSender;
|
use flowy_notification::NotificationSender;
|
||||||
use flowy_server::af_cloud::define::{USER_DEVICE_ID, USER_EMAIL, USER_SIGN_IN_URL, USER_UUID};
|
use flowy_server::af_cloud::define::{USER_DEVICE_ID, USER_EMAIL, USER_SIGN_IN_URL, USER_UUID};
|
||||||
@ -17,12 +19,12 @@ use flowy_server_pub::af_cloud_config::AFCloudConfiguration;
|
|||||||
use flowy_server_pub::AuthenticatorType;
|
use flowy_server_pub::AuthenticatorType;
|
||||||
use flowy_user::entities::{
|
use flowy_user::entities::{
|
||||||
AuthenticatorPB, CloudSettingPB, CreateWorkspacePB, ImportAppFlowyDataPB, OauthSignInPB,
|
AuthenticatorPB, CloudSettingPB, CreateWorkspacePB, ImportAppFlowyDataPB, OauthSignInPB,
|
||||||
RepeatedUserWorkspacePB, SignInUrlPB, SignInUrlPayloadPB, SignUpPayloadPB, UpdateCloudConfigPB,
|
RenameWorkspacePB, RepeatedUserWorkspacePB, SignInUrlPB, SignInUrlPayloadPB, SignUpPayloadPB,
|
||||||
UpdateUserProfilePayloadPB, UserProfilePB, UserWorkspaceIdPB, UserWorkspacePB,
|
UpdateCloudConfigPB, UpdateUserProfilePayloadPB, UserProfilePB, UserWorkspaceIdPB,
|
||||||
|
UserWorkspacePB,
|
||||||
};
|
};
|
||||||
use flowy_user::errors::{FlowyError, FlowyResult};
|
use flowy_user::errors::{FlowyError, FlowyResult};
|
||||||
use flowy_user::event_map::UserEvent;
|
use flowy_user::event_map::UserEvent;
|
||||||
use flowy_user::event_map::UserEvent::*;
|
|
||||||
use lib_dispatch::prelude::{af_spawn, AFPluginDispatcher, AFPluginRequest, ToBytes};
|
use lib_dispatch::prelude::{af_spawn, AFPluginDispatcher, AFPluginRequest, ToBytes};
|
||||||
|
|
||||||
use crate::event_builder::EventBuilder;
|
use crate::event_builder::EventBuilder;
|
||||||
@ -31,7 +33,7 @@ use crate::EventIntegrationTest;
|
|||||||
impl EventIntegrationTest {
|
impl EventIntegrationTest {
|
||||||
pub async fn enable_encryption(&self) -> String {
|
pub async fn enable_encryption(&self) -> String {
|
||||||
let config = EventBuilder::new(self.clone())
|
let config = EventBuilder::new(self.clone())
|
||||||
.event(GetCloudConfig)
|
.event(UserEvent::GetCloudConfig)
|
||||||
.async_send()
|
.async_send()
|
||||||
.await
|
.await
|
||||||
.parse::<CloudSettingPB>();
|
.parse::<CloudSettingPB>();
|
||||||
@ -40,7 +42,7 @@ impl EventIntegrationTest {
|
|||||||
enable_encrypt: Some(true),
|
enable_encrypt: Some(true),
|
||||||
};
|
};
|
||||||
let error = EventBuilder::new(self.clone())
|
let error = EventBuilder::new(self.clone())
|
||||||
.event(SetCloudConfig)
|
.event(UserEvent::SetCloudConfig)
|
||||||
.payload(update)
|
.payload(update)
|
||||||
.async_send()
|
.async_send()
|
||||||
.await
|
.await
|
||||||
@ -68,7 +70,7 @@ impl EventIntegrationTest {
|
|||||||
.into_bytes()
|
.into_bytes()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let request = AFPluginRequest::new(SignUp).payload(payload);
|
let request = AFPluginRequest::new(UserEvent::SignUp).payload(payload);
|
||||||
let user_profile = AFPluginDispatcher::async_send(&self.appflowy_core.dispatcher(), request)
|
let user_profile = AFPluginDispatcher::async_send(&self.appflowy_core.dispatcher(), request)
|
||||||
.await
|
.await
|
||||||
.parse::<UserProfilePB, FlowyError>()
|
.parse::<UserProfilePB, FlowyError>()
|
||||||
@ -95,7 +97,7 @@ impl EventIntegrationTest {
|
|||||||
};
|
};
|
||||||
|
|
||||||
EventBuilder::new(self.clone())
|
EventBuilder::new(self.clone())
|
||||||
.event(OauthSignIn)
|
.event(UserEvent::OauthSignIn)
|
||||||
.payload(payload)
|
.payload(payload)
|
||||||
.async_send()
|
.async_send()
|
||||||
.await
|
.await
|
||||||
@ -104,7 +106,7 @@ impl EventIntegrationTest {
|
|||||||
|
|
||||||
pub async fn sign_out(&self) {
|
pub async fn sign_out(&self) {
|
||||||
EventBuilder::new(self.clone())
|
EventBuilder::new(self.clone())
|
||||||
.event(SignOut)
|
.event(UserEvent::SignOut)
|
||||||
.async_send()
|
.async_send()
|
||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
@ -119,7 +121,7 @@ impl EventIntegrationTest {
|
|||||||
|
|
||||||
pub async fn get_user_profile(&self) -> Result<UserProfilePB, FlowyError> {
|
pub async fn get_user_profile(&self) -> Result<UserProfilePB, FlowyError> {
|
||||||
EventBuilder::new(self.clone())
|
EventBuilder::new(self.clone())
|
||||||
.event(GetUserProfile)
|
.event(UserEvent::GetUserProfile)
|
||||||
.async_send()
|
.async_send()
|
||||||
.await
|
.await
|
||||||
.try_parse::<UserProfilePB>()
|
.try_parse::<UserProfilePB>()
|
||||||
@ -127,7 +129,7 @@ impl EventIntegrationTest {
|
|||||||
|
|
||||||
pub async fn update_user_profile(&self, params: UpdateUserProfilePayloadPB) {
|
pub async fn update_user_profile(&self, params: UpdateUserProfilePayloadPB) {
|
||||||
EventBuilder::new(self.clone())
|
EventBuilder::new(self.clone())
|
||||||
.event(UpdateUserProfile)
|
.event(UserEvent::UpdateUserProfile)
|
||||||
.payload(params)
|
.payload(params)
|
||||||
.async_send()
|
.async_send()
|
||||||
.await;
|
.await;
|
||||||
@ -139,7 +141,7 @@ impl EventIntegrationTest {
|
|||||||
authenticator: AuthenticatorPB::AppFlowyCloud,
|
authenticator: AuthenticatorPB::AppFlowyCloud,
|
||||||
};
|
};
|
||||||
let sign_in_url = EventBuilder::new(self.clone())
|
let sign_in_url = EventBuilder::new(self.clone())
|
||||||
.event(GenerateSignInURL)
|
.event(UserEvent::GenerateSignInURL)
|
||||||
.payload(payload)
|
.payload(payload)
|
||||||
.async_send()
|
.async_send()
|
||||||
.await
|
.await
|
||||||
@ -155,7 +157,7 @@ impl EventIntegrationTest {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let user_profile = EventBuilder::new(self.clone())
|
let user_profile = EventBuilder::new(self.clone())
|
||||||
.event(OauthSignIn)
|
.event(UserEvent::OauthSignIn)
|
||||||
.payload(payload)
|
.payload(payload)
|
||||||
.async_send()
|
.async_send()
|
||||||
.await
|
.await
|
||||||
@ -182,7 +184,7 @@ impl EventIntegrationTest {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let user_profile = EventBuilder::new(self.clone())
|
let user_profile = EventBuilder::new(self.clone())
|
||||||
.event(OauthSignIn)
|
.event(UserEvent::OauthSignIn)
|
||||||
.payload(payload)
|
.payload(payload)
|
||||||
.async_send()
|
.async_send()
|
||||||
.await
|
.await
|
||||||
@ -217,16 +219,53 @@ impl EventIntegrationTest {
|
|||||||
name: name.to_string(),
|
name: name.to_string(),
|
||||||
};
|
};
|
||||||
EventBuilder::new(self.clone())
|
EventBuilder::new(self.clone())
|
||||||
.event(CreateWorkspace)
|
.event(UserEvent::CreateWorkspace)
|
||||||
.payload(payload)
|
.payload(payload)
|
||||||
.async_send()
|
.async_send()
|
||||||
.await
|
.await
|
||||||
.parse::<UserWorkspacePB>()
|
.parse::<UserWorkspacePB>()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn rename_workspace(
|
||||||
|
&self,
|
||||||
|
workspace_id: &str,
|
||||||
|
new_name: &str,
|
||||||
|
) -> Result<(), FlowyError> {
|
||||||
|
let payload = RenameWorkspacePB {
|
||||||
|
workspace_id: workspace_id.to_owned(),
|
||||||
|
new_name: new_name.to_owned(),
|
||||||
|
};
|
||||||
|
match EventBuilder::new(self.clone())
|
||||||
|
.event(UserEvent::RenameWorkspace)
|
||||||
|
.payload(payload)
|
||||||
|
.async_send()
|
||||||
|
.await
|
||||||
|
.error()
|
||||||
|
{
|
||||||
|
Some(err) => Err(err),
|
||||||
|
None => Ok(()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn folder_read_current_workspace(&self) -> WorkspacePB {
|
||||||
|
EventBuilder::new(self.clone())
|
||||||
|
.event(FolderEvent::ReadCurrentWorkspace)
|
||||||
|
.async_send()
|
||||||
|
.await
|
||||||
|
.parse()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn folder_read_workspace_views(&self) -> RepeatedViewPB {
|
||||||
|
EventBuilder::new(self.clone())
|
||||||
|
.event(FolderEvent::ReadWorkspaceViews)
|
||||||
|
.async_send()
|
||||||
|
.await
|
||||||
|
.parse()
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn get_all_workspaces(&self) -> RepeatedUserWorkspacePB {
|
pub async fn get_all_workspaces(&self) -> RepeatedUserWorkspacePB {
|
||||||
EventBuilder::new(self.clone())
|
EventBuilder::new(self.clone())
|
||||||
.event(GetAllWorkspace)
|
.event(UserEvent::GetAllWorkspace)
|
||||||
.async_send()
|
.async_send()
|
||||||
.await
|
.await
|
||||||
.parse::<RepeatedUserWorkspacePB>()
|
.parse::<RepeatedUserWorkspacePB>()
|
||||||
@ -237,7 +276,7 @@ impl EventIntegrationTest {
|
|||||||
workspace_id: workspace_id.to_string(),
|
workspace_id: workspace_id.to_string(),
|
||||||
};
|
};
|
||||||
EventBuilder::new(self.clone())
|
EventBuilder::new(self.clone())
|
||||||
.event(DeleteWorkspace)
|
.event(UserEvent::DeleteWorkspace)
|
||||||
.payload(payload)
|
.payload(payload)
|
||||||
.async_send()
|
.async_send()
|
||||||
.await;
|
.await;
|
||||||
@ -248,7 +287,7 @@ impl EventIntegrationTest {
|
|||||||
workspace_id: workspace_id.to_string(),
|
workspace_id: workspace_id.to_string(),
|
||||||
};
|
};
|
||||||
EventBuilder::new(self.clone())
|
EventBuilder::new(self.clone())
|
||||||
.event(OpenWorkspace)
|
.event(UserEvent::OpenWorkspace)
|
||||||
.payload(payload)
|
.payload(payload)
|
||||||
.async_send()
|
.async_send()
|
||||||
.await;
|
.await;
|
||||||
|
@ -2,11 +2,26 @@ use std::time::Duration;
|
|||||||
|
|
||||||
use event_integration::user_event::user_localhost_af_cloud;
|
use event_integration::user_event::user_localhost_af_cloud;
|
||||||
use event_integration::EventIntegrationTest;
|
use event_integration::EventIntegrationTest;
|
||||||
use flowy_user::entities::RepeatedUserWorkspacePB;
|
use flowy_user::entities::{RepeatedUserWorkspacePB, UserWorkspacePB};
|
||||||
use flowy_user::protobuf::UserNotification;
|
use flowy_user::protobuf::UserNotification;
|
||||||
|
|
||||||
use crate::util::receive_with_timeout;
|
use crate::util::receive_with_timeout;
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn af_cloud_workspace_name_change() {
|
||||||
|
user_localhost_af_cloud().await;
|
||||||
|
let test = EventIntegrationTest::new().await;
|
||||||
|
let user_profile_pb = test.af_cloud_sign_up().await;
|
||||||
|
let workspaces = test.get_all_workspaces().await;
|
||||||
|
let workspace_id = workspaces.items[0].workspace_id.as_str();
|
||||||
|
test
|
||||||
|
.rename_workspace(workspace_id, "new_workspace_name")
|
||||||
|
.await
|
||||||
|
.expect("failed to rename workspace");
|
||||||
|
let workspaces = get_synced_workspaces(&test, user_profile_pb.id).await;
|
||||||
|
assert_eq!(workspaces[0].name, "new_workspace_name".to_string());
|
||||||
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn af_cloud_create_workspace_test() {
|
async fn af_cloud_create_workspace_test() {
|
||||||
user_localhost_af_cloud().await;
|
user_localhost_af_cloud().await;
|
||||||
@ -14,22 +29,34 @@ async fn af_cloud_create_workspace_test() {
|
|||||||
let user_profile_pb = test.af_cloud_sign_up().await;
|
let user_profile_pb = test.af_cloud_sign_up().await;
|
||||||
|
|
||||||
let workspaces = test.get_all_workspaces().await.items;
|
let workspaces = test.get_all_workspaces().await.items;
|
||||||
|
let first_workspace_id = workspaces[0].workspace_id.as_str();
|
||||||
assert_eq!(workspaces.len(), 1);
|
assert_eq!(workspaces.len(), 1);
|
||||||
|
|
||||||
test.create_workspace("my second workspace").await;
|
let created_workspace = test.create_workspace("my second workspace").await;
|
||||||
let _workspaces = test.get_all_workspaces().await.items;
|
assert_eq!(created_workspace.name, "my second workspace");
|
||||||
|
|
||||||
let a = user_profile_pb.id.to_string();
|
|
||||||
let rx = test
|
|
||||||
.notification_sender
|
|
||||||
.subscribe::<RepeatedUserWorkspacePB>(&a, UserNotification::DidUpdateUserWorkspaces as i32);
|
|
||||||
let workspaces = receive_with_timeout(rx, Duration::from_secs(30))
|
|
||||||
.await
|
|
||||||
.unwrap()
|
|
||||||
.items;
|
|
||||||
|
|
||||||
|
let workspaces = get_synced_workspaces(&test, user_profile_pb.id).await;
|
||||||
assert_eq!(workspaces.len(), 2);
|
assert_eq!(workspaces.len(), 2);
|
||||||
assert_eq!(workspaces[1].name, "my second workspace".to_string());
|
assert_eq!(workspaces[1].name, "my second workspace".to_string());
|
||||||
|
|
||||||
|
{
|
||||||
|
// before opening new workspace
|
||||||
|
let folder_ws = test.folder_read_current_workspace().await;
|
||||||
|
assert_eq!(&folder_ws.id, first_workspace_id);
|
||||||
|
let views = test.folder_read_workspace_views().await;
|
||||||
|
assert_eq!(views.items[0].parent_view_id.as_str(), first_workspace_id);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
// after opening new workspace
|
||||||
|
test.open_workspace(&created_workspace.workspace_id).await;
|
||||||
|
let folder_ws = test.folder_read_current_workspace().await;
|
||||||
|
assert_eq!(folder_ws.id, created_workspace.workspace_id);
|
||||||
|
let views = test.folder_read_workspace_views().await;
|
||||||
|
assert_eq!(
|
||||||
|
views.items[0].parent_view_id.as_str(),
|
||||||
|
created_workspace.workspace_id
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@ -50,3 +77,18 @@ async fn af_cloud_open_workspace_test() {
|
|||||||
assert_eq!(views[1].name, "my first document".to_string());
|
assert_eq!(views[1].name, "my first document".to_string());
|
||||||
assert_eq!(views[2].name, "my second document".to_string());
|
assert_eq!(views[2].name, "my second document".to_string());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn get_synced_workspaces(test: &EventIntegrationTest, user_id: i64) -> Vec<UserWorkspacePB> {
|
||||||
|
let _workspaces = test.get_all_workspaces().await.items;
|
||||||
|
let sub_id = user_id.to_string();
|
||||||
|
let rx = test
|
||||||
|
.notification_sender
|
||||||
|
.subscribe::<RepeatedUserWorkspacePB>(
|
||||||
|
&sub_id,
|
||||||
|
UserNotification::DidUpdateUserWorkspaces as i32,
|
||||||
|
);
|
||||||
|
receive_with_timeout(rx, Duration::from_secs(30))
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
.items
|
||||||
|
}
|
||||||
|
@ -3,7 +3,7 @@ use std::sync::Arc;
|
|||||||
|
|
||||||
use anyhow::{anyhow, Error};
|
use anyhow::{anyhow, Error};
|
||||||
use client_api::entity::workspace_dto::{
|
use client_api::entity::workspace_dto::{
|
||||||
CreateWorkspaceMember, CreateWorkspaceParam, WorkspaceMemberChangeset,
|
CreateWorkspaceMember, CreateWorkspaceParam, PatchWorkspaceParam, WorkspaceMemberChangeset,
|
||||||
};
|
};
|
||||||
use client_api::entity::{AFRole, AFWorkspace, AuthProvider, CollabParams, CreateCollabParams};
|
use client_api::entity::{AFRole, AFWorkspace, AuthProvider, CollabParams, CreateCollabParams};
|
||||||
use client_api::{Client, ClientConfiguration};
|
use client_api::{Client, ClientConfiguration};
|
||||||
@ -16,6 +16,7 @@ use flowy_user_pub::cloud::{UserCloudService, UserCollabParams, UserUpdate, User
|
|||||||
use flowy_user_pub::entities::*;
|
use flowy_user_pub::entities::*;
|
||||||
use lib_infra::box_any::BoxAny;
|
use lib_infra::box_any::BoxAny;
|
||||||
use lib_infra::future::FutureResult;
|
use lib_infra::future::FutureResult;
|
||||||
|
use uuid::Uuid;
|
||||||
|
|
||||||
use crate::af_cloud::define::USER_SIGN_IN_URL;
|
use crate::af_cloud::define::USER_SIGN_IN_URL;
|
||||||
use crate::af_cloud::impls::user::dto::{
|
use crate::af_cloud::impls::user::dto::{
|
||||||
@ -320,6 +321,32 @@ where
|
|||||||
Ok(())
|
Ok(())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn patch_workspace(
|
||||||
|
&self,
|
||||||
|
workspace_id: &str,
|
||||||
|
new_workspace_name: Option<&str>,
|
||||||
|
new_workspace_icon: Option<&str>,
|
||||||
|
) -> FutureResult<(), FlowyError> {
|
||||||
|
let try_get_client = self.server.try_get_client();
|
||||||
|
let owned_workspace_id = workspace_id.to_owned();
|
||||||
|
let owned_workspace_name = new_workspace_name.map(|s| s.to_owned());
|
||||||
|
let owned_workspace_icon = new_workspace_icon.map(|s| s.to_owned());
|
||||||
|
FutureResult::new(async move {
|
||||||
|
let workspace_id: Uuid = owned_workspace_id
|
||||||
|
.parse()
|
||||||
|
.map_err(|_| ErrorCode::InvalidParams)?;
|
||||||
|
let client = try_get_client?;
|
||||||
|
client
|
||||||
|
.patch_workspace(PatchWorkspaceParam {
|
||||||
|
workspace_id,
|
||||||
|
workspace_name: owned_workspace_name,
|
||||||
|
workspace_icon: owned_workspace_icon,
|
||||||
|
})
|
||||||
|
.await?;
|
||||||
|
Ok(())
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_admin_client(client: &Arc<AFCloudClient>) -> FlowyResult<Client> {
|
async fn get_admin_client(client: &Arc<AFCloudClient>) -> FlowyResult<Client> {
|
||||||
|
@ -179,7 +179,7 @@ impl UserCloudService for LocalServerUserAuthServiceImpl {
|
|||||||
FutureResult::new(async {
|
FutureResult::new(async {
|
||||||
Err(
|
Err(
|
||||||
FlowyError::local_version_not_support()
|
FlowyError::local_version_not_support()
|
||||||
.with_context("local server doesn't support mulitple workspaces"),
|
.with_context("local server doesn't support multiple workspaces"),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -188,7 +188,21 @@ impl UserCloudService for LocalServerUserAuthServiceImpl {
|
|||||||
FutureResult::new(async {
|
FutureResult::new(async {
|
||||||
Err(
|
Err(
|
||||||
FlowyError::local_version_not_support()
|
FlowyError::local_version_not_support()
|
||||||
.with_context("local server doesn't support mulitple workspaces"),
|
.with_context("local server doesn't support multiple workspaces"),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn patch_workspace(
|
||||||
|
&self,
|
||||||
|
_workspace_id: &str,
|
||||||
|
_new_workspace_name: Option<&str>,
|
||||||
|
_new_workspace_icon: Option<&str>,
|
||||||
|
) -> FutureResult<(), FlowyError> {
|
||||||
|
FutureResult::new(async {
|
||||||
|
Err(
|
||||||
|
FlowyError::local_version_not_support()
|
||||||
|
.with_context("local server doesn't support multiple workspaces"),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -372,6 +372,20 @@ where
|
|||||||
)
|
)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn patch_workspace(
|
||||||
|
&self,
|
||||||
|
_workspace_id: &str,
|
||||||
|
_new_workspace_name: Option<&str>,
|
||||||
|
_new_workspace_icon: Option<&str>,
|
||||||
|
) -> FutureResult<(), FlowyError> {
|
||||||
|
FutureResult::new(async {
|
||||||
|
Err(
|
||||||
|
FlowyError::local_version_not_support()
|
||||||
|
.with_context("supabase server doesn't support mulitple workspaces"),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct CreateCollabAction {
|
pub struct CreateCollabAction {
|
||||||
|
@ -171,6 +171,14 @@ pub trait UserCloudService: Send + Sync + 'static {
|
|||||||
/// Returns the new workspace if successful
|
/// Returns the new workspace if successful
|
||||||
fn create_workspace(&self, workspace_name: &str) -> FutureResult<UserWorkspace, FlowyError>;
|
fn create_workspace(&self, workspace_name: &str) -> FutureResult<UserWorkspace, FlowyError>;
|
||||||
|
|
||||||
|
// Updates the workspace name and icon
|
||||||
|
fn patch_workspace(
|
||||||
|
&self,
|
||||||
|
workspace_id: &str,
|
||||||
|
new_workspace_name: Option<&str>,
|
||||||
|
new_workspace_icon: Option<&str>,
|
||||||
|
) -> FutureResult<(), FlowyError>;
|
||||||
|
|
||||||
/// Deletes a workspace owned by the user.
|
/// Deletes a workspace owned by the user.
|
||||||
fn delete_workspace(&self, workspace_id: &str) -> FutureResult<(), FlowyError>;
|
fn delete_workspace(&self, workspace_id: &str) -> FutureResult<(), FlowyError>;
|
||||||
|
|
||||||
|
@ -225,6 +225,9 @@ pub struct UserWorkspacePB {
|
|||||||
|
|
||||||
#[pb(index = 2)]
|
#[pb(index = 2)]
|
||||||
pub name: String,
|
pub name: String,
|
||||||
|
|
||||||
|
#[pb(index = 3)]
|
||||||
|
pub created_at_timestamp: i64,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<UserWorkspace> for UserWorkspacePB {
|
impl From<UserWorkspace> for UserWorkspacePB {
|
||||||
@ -232,6 +235,7 @@ impl From<UserWorkspace> for UserWorkspacePB {
|
|||||||
Self {
|
Self {
|
||||||
workspace_id: value.id,
|
workspace_id: value.id,
|
||||||
name: value.name,
|
name: value.name,
|
||||||
|
created_at_timestamp: value.created_at.timestamp(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -116,3 +116,24 @@ pub struct CreateWorkspacePB {
|
|||||||
#[validate(custom = "required_not_empty_str")]
|
#[validate(custom = "required_not_empty_str")]
|
||||||
pub name: String,
|
pub name: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(ProtoBuf, Default, Clone, Validate)]
|
||||||
|
pub struct RenameWorkspacePB {
|
||||||
|
#[pb(index = 1)]
|
||||||
|
#[validate(custom = "required_not_empty_str")]
|
||||||
|
pub workspace_id: String,
|
||||||
|
|
||||||
|
#[pb(index = 2)]
|
||||||
|
#[validate(custom = "required_not_empty_str")]
|
||||||
|
pub new_name: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(ProtoBuf, Default, Clone, Validate)]
|
||||||
|
pub struct ChangeWorkspaceIconPB {
|
||||||
|
#[pb(index = 1)]
|
||||||
|
#[validate(custom = "required_not_empty_str")]
|
||||||
|
pub workspace_id: String,
|
||||||
|
|
||||||
|
#[pb(index = 2)]
|
||||||
|
pub new_icon: String,
|
||||||
|
}
|
||||||
|
@ -683,3 +683,29 @@ pub async fn delete_workspace_handler(
|
|||||||
manager.delete_workspace(&workspace_id).await?;
|
manager.delete_workspace(&workspace_id).await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tracing::instrument(level = "debug", skip_all, err)]
|
||||||
|
pub async fn rename_workspace_handler(
|
||||||
|
rename_workspace_param: AFPluginData<RenameWorkspacePB>,
|
||||||
|
manager: AFPluginState<Weak<UserManager>>,
|
||||||
|
) -> Result<(), FlowyError> {
|
||||||
|
let params = rename_workspace_param.try_into_inner()?;
|
||||||
|
let manager = upgrade_manager(manager)?;
|
||||||
|
manager
|
||||||
|
.patch_workspace(¶ms.workspace_id, Some(¶ms.new_name), None)
|
||||||
|
.await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tracing::instrument(level = "debug", skip_all, err)]
|
||||||
|
pub async fn change_workspace_icon_handler(
|
||||||
|
change_workspace_icon_param: AFPluginData<ChangeWorkspaceIconPB>,
|
||||||
|
manager: AFPluginState<Weak<UserManager>>,
|
||||||
|
) -> Result<(), FlowyError> {
|
||||||
|
let params = change_workspace_icon_param.try_into_inner()?;
|
||||||
|
let manager = upgrade_manager(manager)?;
|
||||||
|
manager
|
||||||
|
.patch_workspace(¶ms.workspace_id, None, Some(¶ms.new_icon))
|
||||||
|
.await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
@ -62,6 +62,8 @@ pub fn init(user_manager: Weak<UserManager>) -> AFPlugin {
|
|||||||
.event(UserEvent::GetAllWorkspace, get_all_workspace_handler)
|
.event(UserEvent::GetAllWorkspace, get_all_workspace_handler)
|
||||||
.event(UserEvent::CreateWorkspace, create_workspace_handler)
|
.event(UserEvent::CreateWorkspace, create_workspace_handler)
|
||||||
.event(UserEvent::DeleteWorkspace, delete_workspace_handler)
|
.event(UserEvent::DeleteWorkspace, delete_workspace_handler)
|
||||||
|
.event(UserEvent::RenameWorkspace, rename_workspace_handler)
|
||||||
|
.event(UserEvent::ChangeWorkspaceIcon, change_workspace_icon_handler)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, Debug, Display, Hash, ProtoBuf_Enum, Flowy_Event)]
|
#[derive(Clone, Copy, PartialEq, Eq, Debug, Display, Hash, ProtoBuf_Enum, Flowy_Event)]
|
||||||
@ -200,6 +202,12 @@ pub enum UserEvent {
|
|||||||
|
|
||||||
#[event(input = "UserWorkspaceIdPB")]
|
#[event(input = "UserWorkspaceIdPB")]
|
||||||
DeleteWorkspace = 43,
|
DeleteWorkspace = 43,
|
||||||
|
|
||||||
|
#[event(input = "RenameWorkspacePB")]
|
||||||
|
RenameWorkspace = 44,
|
||||||
|
|
||||||
|
#[event(input = "ChangeWorkspaceIconPB")]
|
||||||
|
ChangeWorkspaceIcon = 45,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait UserStatusCallback: Send + Sync + 'static {
|
pub trait UserStatusCallback: Send + Sync + 'static {
|
||||||
|
@ -167,6 +167,21 @@ impl UserManager {
|
|||||||
Ok(new_workspace)
|
Ok(new_workspace)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn patch_workspace(
|
||||||
|
&self,
|
||||||
|
workspace_id: &str,
|
||||||
|
new_workspace_name: Option<&str>,
|
||||||
|
new_workspace_icon: Option<&str>,
|
||||||
|
) -> FlowyResult<()> {
|
||||||
|
self
|
||||||
|
.cloud_services
|
||||||
|
.get_user_service()?
|
||||||
|
.patch_workspace(workspace_id, new_workspace_name, new_workspace_icon)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn delete_workspace(&self, workspace_id: &str) -> FlowyResult<()> {
|
pub async fn delete_workspace(&self, workspace_id: &str) -> FlowyResult<()> {
|
||||||
self
|
self
|
||||||
.cloud_services
|
.cloud_services
|
||||||
|
Loading…
Reference in New Issue
Block a user