feature_flags: Fix issue where staff is not automatically signed into collab (#54332)

Follow up to #54206

`on_flags_ready` relied on the fact that the `FeatureFlagStore` was only
set once the flags had been received from the server.
However, after #54206 the global gets instantiated earlier, without the
flags being resolved.

Self-Review Checklist:

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

Release Notes:

- N/A
This commit is contained in:
Bennet Bo Fenner authored and GitHub committed 2026-04-20 18:09:43 +02:00
1 parent c3de71f39f
commit cfd9773a27
2 files changed
+42 -6

No files matched your search

+8 -6
View File
@@ -259,12 +259,14 @@ impl FeatureFlagAppExt for App {
{
self.observe_global::<FeatureFlagStore>(move |cx| {
let store = cx.global::<FeatureFlagStore>();
callback(
OnFlagsReady {
is_staff: store.is_staff(),
},
cx,
);
if store.server_flags_received() {
callback(
OnFlagsReady {
is_staff: store.is_staff(),
},
cx,
);
}
})
}
+34
View File
@@ -70,6 +70,7 @@ macro_rules! register_feature_flag {
pub struct FeatureFlagStore {
staff: bool,
server_flags: HashMap<String, String>,
server_flags_received: bool,
_settings_subscription: Option<Subscription>,
}
@@ -95,12 +96,17 @@ impl FeatureFlagStore {
self.staff
}
pub fn server_flags_received(&self) -> bool {
self.server_flags_received
}
pub fn set_staff(&mut self, staff: bool) {
self.staff = staff;
}
pub fn update_server_flags(&mut self, staff: bool, flags: Vec<String>) {
self.staff = staff;
self.server_flags_received = true;
self.server_flags.clear();
for flag in flags {
self.server_flags.insert(flag.clone(), flag);
@@ -371,4 +377,32 @@ mod tests {
assert_eq!(store.try_flag_value::<DemoFlag>(cx), None);
assert_eq!(PresenceFlag::default(), PresenceFlag::Off);
}
#[gpui::test]
fn on_flags_ready_waits_for_server_flags(cx: &mut gpui::TestAppContext) {
use crate::FeatureFlagAppExt;
use std::cell::Cell;
use std::rc::Rc;
cx.update(|cx| {
init_settings_store(cx);
FeatureFlagStore::init(cx);
});
let fired = Rc::new(Cell::new(false));
cx.update({
let fired = fired.clone();
|cx| cx.on_flags_ready(move |_, _| fired.set(true)).detach()
});
// Settings-triggered no-op touch must not fire on_flags_ready.
cx.update(|cx| cx.update_default_global::<FeatureFlagStore, _>(|_, _| {}));
cx.run_until_parked();
assert!(!fired.get());
// Server flags arrive — now it should fire.
cx.update(|cx| cx.update_flags(true, vec![]));
cx.run_until_parked();
assert!(fired.get());
}
}