client: Persist last used organization (#52505)

Neel created

## Context

Persists last used organization through restart. Opted to do this via
`kvp` instead of `settings.json` since the value could change often, and
we would have to persist an ID rather than a friendly name.

Closes CLO-568.

## How to Review

<!-- Help reviewers focus their attention:
- For small PRs: note what to focus on (e.g., "error handling in
foo.rs")
- For large PRs (>400 LOC): provide a guided tour — numbered list of
files/commits to read in order. (The `large-pr` label is applied
automatically.)
     - See the review process guidelines for comment conventions -->

## Self-Review Checklist

<!-- Check before requesting review: -->
- [ ] I've reviewed my own diff for quality, security, and reliability
- [ ] Unsafe blocks (if any) have justifying comments
- [ ] The content is consistent with the [UI/UX
checklist](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)
- [ ] Tests cover the new/changed behavior
- [ ] Performance impact has been considered and is acceptable

Release Notes:

- N/A

Change summary

Cargo.lock                |  1 +
crates/client/Cargo.toml  |  1 +
crates/client/src/user.rs | 33 +++++++++++++++++++++++++++++----
3 files changed, 31 insertions(+), 4 deletions(-)

Detailed changes

Cargo.lock 🔗

@@ -2972,6 +2972,7 @@ dependencies = [
  "cloud_llm_client",
  "collections",
  "credentials_provider",
+ "db",
  "derive_more",
  "feature_flags",
  "fs",

crates/client/Cargo.toml 🔗

@@ -25,6 +25,7 @@ cloud_api_client.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

crates/client/src/user.rs 🔗

@@ -9,6 +9,7 @@ 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};
@@ -25,6 +26,8 @@ use std::{
 use text::ReplicaId;
 use util::{ResultExt, TryFutureExt as _};
 
+const CURRENT_ORGANIZATION_ID_KEY: &str = "current_organization_id";
+
 pub type UserId = u64;
 
 #[derive(
@@ -706,9 +709,16 @@ impl UserStore {
             .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
+            });
         }
     }
 
@@ -816,14 +826,29 @@ impl UserStore {
         }
 
         self.organizations = response.organizations.into_iter().map(Arc::new).collect();
-        self.current_organization = response
-            .default_organization_id
-            .and_then(|default_organization_id| {
+        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.organizations
                     .iter()
-                    .find(|organization| organization.id == default_organization_id)
+                    .find(|org| org.id == persisted_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