mirror of
https://github.com/zed-industries/zed.git
synced 2026-06-01 03:14:56 +07:00
client: Use cloud as source of truth for the selected organization (#57140)
Now that the cloud platform exposes a system-settings endpoint for the user's selected organization, switch `UserStore` over to it and drop the local database persistence. The server already returns the current selected organization for `get_authenticated_user()`. set_current_organization becomes a optimistic, with the in-memory selection updated immediately. hen a background task POSTs to the system settings endpoint. Stale current_organization_id rows from older installs are left dangling — harmless and not worth a migration. This is the second step in moving organization selection to cloud; the first added the update_system_settings client method. Part of CLO-716 Release Notes: - N/A --------- Co-authored-by: Marshall Bowers <git@maxdeviant.com>
This commit is contained in:
parent
0f6ebdd269
commit
5656f3eb3f
4 changed files with 45 additions and 41 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
|
@ -3006,7 +3006,6 @@ dependencies = [
|
|||
"cloud_llm_client",
|
||||
"collections",
|
||||
"credentials_provider",
|
||||
"db",
|
||||
"derive_more",
|
||||
"feature_flags",
|
||||
"fs",
|
||||
|
|
|
|||
|
|
@ -27,7 +27,6 @@ cloud_api_types.workspace = true
|
|||
cloud_llm_client.workspace = true
|
||||
collections.workspace = true
|
||||
credentials_provider.workspace = true
|
||||
db.workspace = true
|
||||
derive_more.workspace = true
|
||||
feature_flags.workspace = true
|
||||
fs.workspace = true
|
||||
|
|
|
|||
|
|
@ -4,19 +4,19 @@ use chrono::{DateTime, Utc};
|
|||
use cloud_api_client::websocket_protocol::MessageToClient;
|
||||
use cloud_api_client::{
|
||||
GetAuthenticatedUserResponse, KnownOrUnknown, Organization, OrganizationId, Plan, PlanInfo,
|
||||
UpdateSystemSettingsBody,
|
||||
};
|
||||
use cloud_api_types::OrganizationConfiguration;
|
||||
use cloud_llm_client::{
|
||||
EDIT_PREDICTIONS_USAGE_AMOUNT_HEADER_NAME, EDIT_PREDICTIONS_USAGE_LIMIT_HEADER_NAME, UsageLimit,
|
||||
};
|
||||
use collections::{HashMap, HashSet, hash_map::Entry};
|
||||
use db::kvp::KeyValueStore;
|
||||
use derive_more::Deref;
|
||||
use feature_flags::FeatureFlagAppExt;
|
||||
use futures::{Future, StreamExt, channel::mpsc};
|
||||
use gpui::{
|
||||
App, AsyncApp, Context, Entity, EventEmitter, SharedString, SharedUri, Task, TaskExt,
|
||||
WeakEntity,
|
||||
App, AppContext as _, AsyncApp, Context, Entity, EventEmitter, SharedString, SharedUri, Task,
|
||||
TaskExt, WeakEntity,
|
||||
};
|
||||
use http_client::http::{HeaderMap, HeaderValue};
|
||||
use postage::{sink::Sink, watch};
|
||||
|
|
@ -28,8 +28,6 @@ use std::{
|
|||
use text::ReplicaId;
|
||||
use util::{ResultExt, TryFutureExt as _};
|
||||
|
||||
const CURRENT_ORGANIZATION_ID_KEY: &str = "current_organization_id";
|
||||
|
||||
pub type LegacyUserId = u64;
|
||||
|
||||
#[derive(
|
||||
|
|
@ -708,24 +706,41 @@ impl UserStore {
|
|||
&mut self,
|
||||
organization: Arc<Organization>,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
) -> Task<Result<()>> {
|
||||
let is_same_organization = self
|
||||
.current_organization
|
||||
.as_ref()
|
||||
.is_some_and(|current| current.id == organization.id);
|
||||
|
||||
if !is_same_organization {
|
||||
let organization_id = organization.id.0.to_string();
|
||||
self.current_organization.replace(organization);
|
||||
cx.emit(Event::OrganizationChanged);
|
||||
cx.notify();
|
||||
|
||||
let kvp = KeyValueStore::global(cx);
|
||||
db::write_and_log(cx, move || async move {
|
||||
kvp.write_kvp(CURRENT_ORGANIZATION_ID_KEY.into(), organization_id)
|
||||
.await
|
||||
});
|
||||
if is_same_organization {
|
||||
return Task::ready(Ok(()));
|
||||
}
|
||||
|
||||
let organization_id = organization.id.clone();
|
||||
self.current_organization.replace(organization);
|
||||
cx.emit(Event::OrganizationChanged);
|
||||
cx.notify();
|
||||
|
||||
let Some(client) = self.client.upgrade() else {
|
||||
return Task::ready(Ok(()));
|
||||
};
|
||||
let Some(system_id) = client.telemetry().system_id().map(|id| id.to_string()) else {
|
||||
// Without a system ID we have no addressable target row on the
|
||||
// server, so the selection stays purely session-local.
|
||||
return Task::ready(Ok(()));
|
||||
};
|
||||
let cloud_client = client.cloud_client();
|
||||
|
||||
cx.background_spawn(async move {
|
||||
let body = UpdateSystemSettingsBody {
|
||||
selected_organization_id: Some(organization_id),
|
||||
};
|
||||
cloud_client
|
||||
.update_system_settings(system_id, body)
|
||||
.await
|
||||
.context("failed to persist selected organization")?;
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
pub fn organizations(&self) -> &Vec<Arc<Organization>> {
|
||||
|
|
@ -861,29 +876,15 @@ impl UserStore {
|
|||
}
|
||||
|
||||
self.organizations = response.organizations.into_iter().map(Arc::new).collect();
|
||||
let persisted_org_id = KeyValueStore::global(cx)
|
||||
.read_kvp(CURRENT_ORGANIZATION_ID_KEY)
|
||||
.log_err()
|
||||
.flatten()
|
||||
.map(|id| OrganizationId(Arc::from(id)));
|
||||
|
||||
self.current_organization = persisted_org_id
|
||||
.and_then(|persisted_id| {
|
||||
self.current_organization = response
|
||||
.default_organization_id
|
||||
.and_then(|default_organization_id| {
|
||||
self.organizations
|
||||
.iter()
|
||||
.find(|org| org.id == persisted_id)
|
||||
.find(|organization| organization.id == default_organization_id)
|
||||
.cloned()
|
||||
})
|
||||
.or_else(|| {
|
||||
response
|
||||
.default_organization_id
|
||||
.and_then(|default_organization_id| {
|
||||
self.organizations
|
||||
.iter()
|
||||
.find(|organization| organization.id == default_organization_id)
|
||||
.cloned()
|
||||
})
|
||||
})
|
||||
.or_else(|| self.organizations.first().cloned());
|
||||
self.plans_by_organization = response
|
||||
.plans_by_organization
|
||||
|
|
|
|||
|
|
@ -51,7 +51,8 @@ use ui::{
|
|||
use update_version::UpdateVersion;
|
||||
use util::ResultExt;
|
||||
use workspace::{
|
||||
MultiWorkspace, ToggleWorktreeSecurity, Workspace, notifications::NotifyResultExt,
|
||||
MultiWorkspace, ToggleWorktreeSecurity, Workspace,
|
||||
notifications::{NotifyResultExt, NotifyTaskExt as _},
|
||||
};
|
||||
|
||||
use zed_actions::OpenRemote;
|
||||
|
|
@ -1159,6 +1160,7 @@ impl TitleBar {
|
|||
let show_update_button = self.update_version.read(cx).show_update_in_menu_bar();
|
||||
|
||||
let user_store = self.user_store.clone();
|
||||
let workspace = self.workspace.clone();
|
||||
let user_store_read = user_store.read(cx);
|
||||
let user = user_store_read.current_user();
|
||||
|
||||
|
|
@ -1225,6 +1227,7 @@ impl TitleBar {
|
|||
let current_organization = current_organization.clone();
|
||||
let organizations = organizations.clone();
|
||||
let user_store = user_store.clone();
|
||||
let workspace = workspace.clone();
|
||||
|
||||
let ai_enabled = !project::DisableAiSettings::get_global(cx).disable_ai;
|
||||
let current_layout = AgentSettings::get_layout(cx);
|
||||
|
|
@ -1316,11 +1319,13 @@ impl TitleBar {
|
|||
{
|
||||
let user_store = user_store.clone();
|
||||
let organization = organization.clone();
|
||||
move |_window, cx| {
|
||||
user_store.update(cx, |user_store, cx| {
|
||||
let workspace = workspace.clone();
|
||||
move |window, cx| {
|
||||
let task = user_store.update(cx, |user_store, cx| {
|
||||
user_store
|
||||
.set_current_organization(organization.clone(), cx);
|
||||
.set_current_organization(organization.clone(), cx)
|
||||
});
|
||||
task.detach_and_notify_err(workspace.clone(), window, cx);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
|
|
|||
Loading…
Reference in a new issue