From 3484c2c71ba2d3a758ea02018b969357b3b6df7c Mon Sep 17 00:00:00 2001 From: Ren Amamiya Date: Fri, 13 Nov 2026 08:25:17 +0700 Subject: [PATCH] add experimental tags and group experimental settings --- crates/nip60_ui/src/wallet.rs | 1 + crates/ui/src/form.rs | 54 +++++++++ crates/workspace/src/dialogs/onboarding.rs | 8 +- crates/workspace/src/dialogs/settings.rs | 130 +++++++++++---------- docs/audit-stable-release.md | 4 +- 5 files changed, 132 insertions(+), 65 deletions(-) diff --git a/crates/nip60_ui/src/wallet.rs b/crates/nip60_ui/src/wallet.rs index 67efb3e7..30ee50d8 100644 --- a/crates/nip60_ui/src/wallet.rs +++ b/crates/nip60_ui/src/wallet.rs @@ -853,6 +853,7 @@ impl Panel for WalletPanel { .text_color(cx.theme().muted_foreground), ) .child(self.name.clone()) + .child(ui::experimental_tag(cx)) .into_any_element() } } diff --git a/crates/ui/src/form.rs b/crates/ui/src/form.rs index 5d7499b2..3a5077a6 100644 --- a/crates/ui/src/form.rs +++ b/crates/ui/src/form.rs @@ -60,3 +60,57 @@ pub fn settings_block( ) .child(control) } + +/// An amber marker for features that are not ready for prime time. +pub fn experimental_tag(cx: &App) -> Div { + div() + .flex_shrink_0() + .px_1p5() + .rounded_full() + .bg(cx.theme().warning.opacity(0.15)) + .text_color(cx.theme().warning) + .text_xs() + .font_medium() + .child("Experimental") +} + +/// A [`settings_row`] whose label carries a tag, e.g. [`experimental_tag`]. +pub fn settings_row_tagged( + label: impl Into, + tag: Div, + description: impl Into, + control: impl IntoElement, + cx: &App, +) -> Div { + h_flex() + .w_full() + .gap_4() + .items_center() + .justify_between() + .child( + v_flex() + .flex_1() + .min_w_0() + .child( + h_flex() + .gap_1p5() + .items_center() + .child(div().text_sm().font_semibold().child(label.into())) + .child(tag), + ) + .child( + div() + .text_xs() + .text_color(cx.theme().muted_foreground) + .child(description.into()), + ), + ) + .child( + h_flex() + .w_40() + .flex_shrink_0() + .justify_end() + .items_center() + .child(control), + ) +} diff --git a/crates/workspace/src/dialogs/onboarding.rs b/crates/workspace/src/dialogs/onboarding.rs index a5535c8c..7def2b79 100644 --- a/crates/workspace/src/dialogs/onboarding.rs +++ b/crates/workspace/src/dialogs/onboarding.rs @@ -19,7 +19,7 @@ use gpui_kit::prelude::FluentBuilder; use rand::seq::IndexedRandom; use settings::AppSettings; use smallvec::{SmallVec, smallvec}; -use ui::{settings_block, settings_row}; +use ui::{experimental_tag, settings_block, settings_row, settings_row_tagged}; use super::settings::{FONT_SIZE_RANGE, RADIUS_RANGE}; @@ -400,8 +400,9 @@ impl Render for Onboarding { }), cx, )) - .child(settings_row( + .child(settings_row_tagged( "Decoupling Encryption Key", + experimental_tag(cx), NIP4E, Switch::new("onboarding-nip4e").checked(nip4e).on_click( move |checked, _window, cx| { @@ -412,8 +413,9 @@ impl Render for Onboarding { )); #[cfg(not(target_arch = "wasm32"))] - let features = features.child(settings_row( + let features = features.child(settings_row_tagged( "Wallet", + experimental_tag(cx), WALLET, Switch::new("onboarding-wallet") .checked(AppSettings::get_wallet(cx)) diff --git a/crates/workspace/src/dialogs/settings.rs b/crates/workspace/src/dialogs/settings.rs index 439faa1c..68662503 100644 --- a/crates/workspace/src/dialogs/settings.rs +++ b/crates/workspace/src/dialogs/settings.rs @@ -14,6 +14,7 @@ use gpui::{ Subscription, Window, div, }; use gpui_kit::assets::IconName; +use gpui_kit::base::StyledExt as _; use gpui_kit::component::button::{Button, ButtonVariants}; use gpui_kit::component::input::{Input, InputEvent, InputState, NumberInput}; use gpui_kit::component::kbd::Kbd; @@ -218,10 +219,10 @@ impl Preferences { fn render_wallet( &mut self, #[cfg_attr(target_arch = "wasm32", allow(unused_variables))] cx: &mut Context, - ) -> AnyElement { + ) -> Option { #[cfg(target_arch = "wasm32")] { - return div().into_any_element(); + return None; } #[cfg(not(target_arch = "wasm32"))] @@ -230,39 +231,41 @@ impl Preferences { let enabled = AppSettings::get_wallet(cx); let has_wallet = nip60::WalletRegistry::global(cx).read(cx).has_wallet(); - v_flex() - .w_full() - .gap_3() - .child(settings_row( - "Wallet", - "Show the wallet and allow ecash payments.", - Switch::new("wallet") - .checked(enabled) - .on_click(move |checked, _window, cx| { - AppSettings::update_wallet(*checked, cx); - }), - cx, - )) - .when(enabled, |this| { - this.child(settings_block( - "Mint", - WALLET, - h_flex() - .gap_1() - .child(div().flex_1().child(Input::new(&self.mint_input))) - .child( - Button::new("setup-mint") - .label(if has_wallet { "Add" } else { "Set up" }) - .ghost() - .size_8() - .on_click(cx.listener(move |this, _ev, window, cx| { - this.setup_mint(window, cx); - })), - ), + Some( + v_flex() + .w_full() + .gap_3() + .child(settings_row( + "Wallet", + "Show the wallet and allow ecash payments.", + Switch::new("wallet").checked(enabled).on_click( + move |checked, _window, cx| { + AppSettings::update_wallet(*checked, cx); + }, + ), cx, )) - }) - .into_any_element() + .when(enabled, |this| { + this.child(settings_block( + "Mint", + WALLET, + h_flex() + .gap_1() + .child(div().flex_1().child(Input::new(&self.mint_input))) + .child( + Button::new("setup-mint") + .label(if has_wallet { "Add" } else { "Set up" }) + .ghost() + .size_8() + .on_click(cx.listener(move |this, _ev, window, cx| { + this.setup_mint(window, cx); + })), + ), + cx, + )) + }) + .into_any_element(), + ) } } @@ -656,32 +659,39 @@ impl Render for Preferences { )), ) .child(Separator::horizontal()) - .child(settings_row( - "Decoupling Encryption Key", - NIP4E, - Switch::new("nip4e") - .checked(nip4e) - .on_click(move |_, _window, cx| { - AppSettings::update_nip4e(!nip4e, cx); - }), - cx, - )) - .child(settings_row( - "Rotate Encryption Key", - NIP4E_ROTATION, - Switch::new("nip4e_rotation") - .checked(nip4e_rotation_days.is_some()) - .on_click(move |_, _window, cx| { - let enabled = AppSettings::get_nip4e_rotation_days(cx).is_some(); - let days = if enabled { - None - } else { - Some(NIP4E_ROTATION_DEFAULT_DAYS) - }; - AppSettings::update_nip4e_rotation_days(days, cx); - }), - cx, - )) + .child( + v_flex() + .w_full() + .gap_3() + .child(div().text_sm().font_semibold().child("Experimental")) + .child(settings_row( + "Decoupling Encryption Key", + NIP4E, + Switch::new("nip4e") + .checked(nip4e) + .on_click(move |_, _window, cx| { + AppSettings::update_nip4e(!nip4e, cx); + }), + cx, + )) + .child(settings_row( + "Rotate Encryption Key", + NIP4E_ROTATION, + Switch::new("nip4e_rotation") + .checked(nip4e_rotation_days.is_some()) + .on_click(move |_, _window, cx| { + let enabled = AppSettings::get_nip4e_rotation_days(cx).is_some(); + let days = if enabled { + None + } else { + Some(NIP4E_ROTATION_DEFAULT_DAYS) + }; + AppSettings::update_nip4e_rotation_days(days, cx); + }), + cx, + )) + .when_some(self.render_wallet(cx), |this, wallet| this.child(wallet)), + ) .child(Separator::horizontal()) .child(self.render_speech(cx)) .child(self.render_dictation_shortcut(window, cx)) @@ -703,7 +713,5 @@ impl Render for Preferences { ), cx, )) - .child(Separator::horizontal()) - .child(self.render_wallet(cx)) } } diff --git a/docs/audit-stable-release.md b/docs/audit-stable-release.md index 61a91108..32a8c678 100644 --- a/docs/audit-stable-release.md +++ b/docs/audit-stable-release.md @@ -1056,4 +1056,6 @@ request. Validation after the full batch: `cargo clippy --workspace --all-target - Element ids: two known residuals documented (inbox.rs contact p-tag dedupe; `HashSet` equality includes relay/alias, so the same pubkey with a different relay could render twice in the contact picker). -- S1/S2 (task-handle containers, `.ok()`/`let _ =` sweeps) remain open by request. +- S1/S2 (task-handle containers, `.ok()`/`let _ =` sweeps): reviewed and **declined** — judged not + worth the churn; the affected sites are benign (entity-dropped-at-shutdown cases) and the + containers are bounded in practice.