feature_flags.rs

  1use feature_flags::{FeatureFlagDescriptor, FeatureFlagStore, FeatureFlagVariant};
  2use fs::Fs;
  3use gpui::{ScrollHandle, prelude::*};
  4use ui::{Checkbox, ToggleState, prelude::*};
  5
  6use crate::SettingsWindow;
  7
  8pub(crate) fn render_feature_flags_page(
  9    _settings_window: &SettingsWindow,
 10    scroll_handle: &ScrollHandle,
 11    _window: &mut Window,
 12    cx: &mut Context<SettingsWindow>,
 13) -> AnyElement {
 14    // Sort by flag name so the list is stable between renders even though
 15    // `inventory::iter` order depends on link order.
 16    let mut descriptors: Vec<&'static FeatureFlagDescriptor> =
 17        FeatureFlagStore::known_flags().collect();
 18    descriptors.sort_by_key(|descriptor| descriptor.name);
 19
 20    v_flex()
 21        .id("feature-flags-page")
 22        .min_w_0()
 23        .size_full()
 24        .pt_2p5()
 25        .px_8()
 26        .pb_16()
 27        .gap_4()
 28        .overflow_y_scroll()
 29        .track_scroll(scroll_handle)
 30        .children(
 31            descriptors
 32                .into_iter()
 33                .map(|descriptor| render_flag_row(descriptor, cx)),
 34        )
 35        .into_any_element()
 36}
 37
 38fn render_flag_row(
 39    descriptor: &'static FeatureFlagDescriptor,
 40    cx: &mut Context<SettingsWindow>,
 41) -> AnyElement {
 42    let forced_on = FeatureFlagStore::is_forced_on(descriptor);
 43    let resolved = cx.global::<FeatureFlagStore>().resolved_key(descriptor, cx);
 44    let has_override = FeatureFlagStore::override_for(descriptor.name, cx).is_some();
 45
 46    let header =
 47        h_flex()
 48            .justify_between()
 49            .items_center()
 50            .child(
 51                h_flex()
 52                    .gap_2()
 53                    .child(Label::new(descriptor.name).size(LabelSize::Default).color(
 54                        if forced_on {
 55                            Color::Muted
 56                        } else {
 57                            Color::Default
 58                        },
 59                    ))
 60                    .when(forced_on, |this| {
 61                        this.child(
 62                            Label::new("enabled for all")
 63                                .size(LabelSize::Small)
 64                                .color(Color::Muted),
 65                        )
 66                    }),
 67            )
 68            .when(has_override && !forced_on, |this| {
 69                let name = descriptor.name;
 70                this.child(
 71                    Button::new(SharedString::from(format!("reset-{}", name)), "Reset")
 72                        .label_size(LabelSize::Small)
 73                        .on_click(cx.listener(move |_, _, _, cx| {
 74                            FeatureFlagStore::clear_override(name, <dyn Fs>::global(cx), cx);
 75                        })),
 76                )
 77            });
 78
 79    v_flex()
 80        .id(SharedString::from(format!("flag-row-{}", descriptor.name)))
 81        .gap_1()
 82        .child(header)
 83        .child(render_flag_variants(descriptor, resolved, forced_on, cx))
 84        .into_any_element()
 85}
 86
 87fn render_flag_variants(
 88    descriptor: &'static FeatureFlagDescriptor,
 89    resolved: &'static str,
 90    forced_on: bool,
 91    cx: &mut Context<SettingsWindow>,
 92) -> impl IntoElement {
 93    let variants: Vec<FeatureFlagVariant> = (descriptor.variants)();
 94
 95    let row_items = variants.into_iter().map({
 96        let name = descriptor.name;
 97        move |variant| {
 98            let key = variant.override_key;
 99            let label = variant.label;
100            let selected = resolved == key;
101            let state = if selected {
102                ToggleState::Selected
103            } else {
104                ToggleState::Unselected
105            };
106            let checkbox_id = SharedString::from(format!("{}-{}", name, key));
107            let disabled = forced_on;
108            let mut checkbox = Checkbox::new(ElementId::from(checkbox_id), state)
109                .label(label)
110                .disabled(disabled);
111            if !disabled {
112                checkbox =
113                    checkbox.on_click(cx.listener(move |_, new_state: &ToggleState, _, cx| {
114                        // Clicking an already-selected option is a no-op rather than a
115                        // "deselect" — there's no valid "nothing selected" state.
116                        if *new_state == ToggleState::Unselected {
117                            return;
118                        }
119                        FeatureFlagStore::set_override(
120                            name,
121                            key.to_string(),
122                            <dyn Fs>::global(cx),
123                            cx,
124                        );
125                    }));
126            }
127            checkbox.into_any_element()
128        }
129    });
130
131    h_flex().gap_4().flex_wrap().children(row_items)
132}