-
Notifications
You must be signed in to change notification settings - Fork 4.7k
Implement auth secret deletion from selector menu #11241
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -5,7 +5,10 @@ use std::{fmt, vec}; | |
| use crate::safe_triangle::SafeTriangle; | ||
| use crate::themes::theme::Fill; | ||
| use crate::util::time_format::format_approx_duration_from_now_sentence_case; | ||
| use crate::{appearance::Appearance, ui_components::icons}; | ||
| use crate::{ | ||
| appearance::Appearance, | ||
| ui_components::{buttons::icon_button_with_color, icons}, | ||
| }; | ||
| use chrono::{DateTime, Local}; | ||
| use pathfinder_color::ColorU; | ||
| use pathfinder_geometry::rect::RectF; | ||
|
|
@@ -416,6 +419,20 @@ pub struct MenuItemFields<A: Action + Clone> { | |
| tooltip_position: MenuTooltipPosition, | ||
| right_side_label: Option<RightSideLabel>, | ||
| right_side_icon: Option<(icons::Icon, Option<Fill>)>, | ||
| /// Optional action dispatched when the right-side icon is clicked. When | ||
| /// set, the right-side icon becomes its own hit target: clicking it | ||
| /// dispatches this action without firing the row's own `on_select_action`, | ||
| /// and prevents the row click from propagating. | ||
| right_side_icon_action: Option<A>, | ||
| /// Optional accessibility label for the right-side icon hit target. | ||
| right_side_icon_a11y_label: Option<String>, | ||
| /// When true, the right-side icon is rendered as disabled (no hover, | ||
| /// no click action). Used to lock the affordance while a pending | ||
| /// request is in flight. | ||
| right_side_icon_disabled: bool, | ||
| /// Optional mouse state for the right-side icon so its hover state is | ||
| /// tracked independently from the row. | ||
| right_side_icon_mouse_state: MouseStateHandle, | ||
|
Comment on lines
421
to
+435
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What do you think about bundling these 6 fields into a struct RightSideIconConfig<A> {
icon: icons::Icon,
override_color: Option<Fill>,
action: Option<A>,
a11y_label: Option<String>,
disabled: bool,
mouse_state: MouseStateHandle,
} |
||
| /// Optional override for the background color | ||
| /// hovered or selected. When `None`, the default hover/selected background | ||
| /// from the theme is used (accent or dark overlay, depending on | ||
|
|
@@ -467,6 +484,10 @@ impl<A: Action + Clone> MenuItemFields<A> { | |
| tooltip_position: MenuTooltipPosition::default(), | ||
| right_side_label: None, | ||
| right_side_icon: None, | ||
| right_side_icon_action: None, | ||
| right_side_icon_a11y_label: None, | ||
| right_side_icon_disabled: false, | ||
| right_side_icon_mouse_state: MouseStateHandle::default(), | ||
| override_hover_background_color: None, | ||
| icon_size_override: None, | ||
| clip_config: None, | ||
|
|
@@ -497,6 +518,10 @@ impl<A: Action + Clone> MenuItemFields<A> { | |
| tooltip_position: MenuTooltipPosition::default(), | ||
| right_side_label: None, | ||
| right_side_icon: None, | ||
| right_side_icon_action: None, | ||
| right_side_icon_a11y_label: None, | ||
| right_side_icon_disabled: false, | ||
| right_side_icon_mouse_state: MouseStateHandle::default(), | ||
| override_hover_background_color: None, | ||
| icon_size_override: None, | ||
| clip_config: None, | ||
|
|
@@ -530,6 +555,10 @@ impl<A: Action + Clone> MenuItemFields<A> { | |
| tooltip_position: MenuTooltipPosition::default(), | ||
| right_side_label: None, | ||
| right_side_icon: None, | ||
| right_side_icon_action: None, | ||
| right_side_icon_a11y_label: None, | ||
| right_side_icon_disabled: false, | ||
| right_side_icon_mouse_state: MouseStateHandle::default(), | ||
| override_hover_background_color: None, | ||
| icon_size_override: None, | ||
| clip_config: None, | ||
|
|
@@ -566,6 +595,10 @@ impl<A: Action + Clone> MenuItemFields<A> { | |
| tooltip_position: MenuTooltipPosition::default(), | ||
| right_side_label: None, | ||
| right_side_icon: None, | ||
| right_side_icon_action: None, | ||
| right_side_icon_a11y_label: None, | ||
| right_side_icon_disabled: false, | ||
| right_side_icon_mouse_state: MouseStateHandle::default(), | ||
| override_hover_background_color: None, | ||
| icon_size_override: None, | ||
| clip_config: None, | ||
|
|
@@ -600,6 +633,10 @@ impl<A: Action + Clone> MenuItemFields<A> { | |
| tooltip_position: MenuTooltipPosition::default(), | ||
| right_side_label: None, | ||
| right_side_icon: None, | ||
| right_side_icon_action: None, | ||
| right_side_icon_a11y_label: None, | ||
| right_side_icon_disabled: false, | ||
| right_side_icon_mouse_state: MouseStateHandle::default(), | ||
| override_hover_background_color: None, | ||
| icon_size_override: None, | ||
| clip_config: None, | ||
|
|
@@ -633,6 +670,10 @@ impl<A: Action + Clone> MenuItemFields<A> { | |
| tooltip_position: MenuTooltipPosition::default(), | ||
| right_side_label: None, | ||
| right_side_icon: None, | ||
| right_side_icon_action: None, | ||
| right_side_icon_a11y_label: None, | ||
| right_side_icon_disabled: false, | ||
| right_side_icon_mouse_state: MouseStateHandle::default(), | ||
| override_hover_background_color: None, | ||
| icon_size_override: None, | ||
| clip_config: None, | ||
|
|
@@ -663,6 +704,10 @@ impl<A: Action + Clone> MenuItemFields<A> { | |
| tooltip_position: MenuTooltipPosition::default(), | ||
| right_side_label: None, | ||
| right_side_icon: None, | ||
| right_side_icon_action: None, | ||
| right_side_icon_a11y_label: None, | ||
| right_side_icon_disabled: false, | ||
| right_side_icon_mouse_state: MouseStateHandle::default(), | ||
| override_hover_background_color: None, | ||
| icon_size_override: None, | ||
| clip_config: None, | ||
|
|
@@ -709,6 +754,14 @@ impl<A: Action + Clone> MenuItemFields<A> { | |
| tooltip_position: self.tooltip_position, | ||
| right_side_label: self.right_side_label, | ||
| right_side_icon: self.right_side_icon, | ||
| // The right-side icon action is `Option<A>`; we can't safely | ||
| // map it to `Option<B>` here, so drop it. Callers that need | ||
| // the right-side action must set it via | ||
| // `with_right_side_icon_action` after conversion. | ||
| right_side_icon_action: None, | ||
| right_side_icon_a11y_label: self.right_side_icon_a11y_label, | ||
| right_side_icon_disabled: self.right_side_icon_disabled, | ||
| right_side_icon_mouse_state: self.right_side_icon_mouse_state, | ||
| override_hover_background_color: self.override_hover_background_color, | ||
| icon_size_override: self.icon_size_override, | ||
| clip_config: self.clip_config, | ||
|
|
@@ -848,6 +901,25 @@ impl<A: Action + Clone> MenuItemFields<A> { | |
| self | ||
| } | ||
|
|
||
| /// Sets a separate action that fires when the right-side icon is | ||
| /// clicked. The action is independent from the row's | ||
| /// `on_select_action`: clicking the icon dispatches this action and | ||
| /// the row click is suppressed. | ||
| pub fn with_right_side_icon_action(mut self, action: A) -> Self { | ||
| self.right_side_icon_action = Some(action); | ||
| self | ||
| } | ||
|
|
||
| pub fn with_right_side_icon_a11y_label(mut self, label: impl Into<String>) -> Self { | ||
| self.right_side_icon_a11y_label = Some(label.into()); | ||
| self | ||
| } | ||
|
|
||
| pub fn with_right_side_icon_disabled(mut self, disabled: bool) -> Self { | ||
| self.right_side_icon_disabled = disabled; | ||
| self | ||
| } | ||
|
|
||
| pub fn into_item(self) -> MenuItem<A> { | ||
| MenuItem::Item(self) | ||
| } | ||
|
|
@@ -984,26 +1056,49 @@ impl<A: Action + Clone> MenuItemFields<A> { | |
| &self, | ||
| appearance: &Appearance, | ||
| color: Fill, | ||
| dispatch_item_actions: bool, | ||
| ) -> Option<Box<dyn Element>> { | ||
| let (icon, override_color) = self.right_side_icon.as_ref()?; | ||
| let icon_size = self | ||
| .icon_size_override | ||
| .unwrap_or_else(|| appearance.ui_font_size()); | ||
| let icon_color = override_color.unwrap_or(color); | ||
| Some( | ||
| Shrinkable::new( | ||
| 1., | ||
| Container::new( | ||
| ConstrainedBox::new(icon.to_warpui_icon(icon_color).finish()) | ||
| .with_width(icon_size) | ||
| .with_height(icon_size) | ||
| .finish(), | ||
| ) | ||
| if let Some(action) = &self.right_side_icon_action { | ||
| let mut button = icon_button_with_color( | ||
| appearance, | ||
| icon.clone(), | ||
| false, | ||
| self.right_side_icon_mouse_state.clone(), | ||
| icon_color, | ||
| ); | ||
| if self.right_side_icon_disabled { | ||
| button = button.disabled(); | ||
| } | ||
| let mut hoverable = button.build(); | ||
| if !self.right_side_icon_disabled { | ||
| let action = action.clone(); | ||
| hoverable = hoverable.on_click(move |ctx, _, _| { | ||
| if dispatch_item_actions { | ||
| ctx.dispatch_typed_action(action.clone()); | ||
| } | ||
| }); | ||
| // Swallow mouse-down too so the row's click handler | ||
| // doesn't latch onto the press that targets the icon. | ||
| hoverable = hoverable.on_mouse_down(|_, _, _| {}); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This also seems legit - if I click the "x" and then click cancel, the key I "x"ed is now selected |
||
| } | ||
| let element = Container::new(hoverable.finish()) | ||
| .with_margin_left(icon_size / 2.) | ||
| .finish(), | ||
| ) | ||
| .finish(), | ||
| ) | ||
| .finish(); | ||
| return Some(Shrinkable::new(1., Align::new(element).right().finish()).finish()); | ||
| } | ||
| let icon_element = ConstrainedBox::new(icon.to_warpui_icon(icon_color).finish()) | ||
| .with_width(icon_size) | ||
| .with_height(icon_size) | ||
| .finish(); | ||
| let container = Container::new(icon_element) | ||
| .with_margin_left(icon_size / 2.) | ||
| .finish(); | ||
| Some(Shrinkable::new(1., container).finish()) | ||
| } | ||
|
|
||
| fn render_right_aligned_chevron( | ||
|
|
@@ -1197,7 +1292,9 @@ impl<A: Action + Clone> MenuItemFields<A> { | |
| )); | ||
| } | ||
|
|
||
| if let Some(right_icon) = self.render_right_side_icon(appearance, primary_color) { | ||
| if let Some(right_icon) = | ||
| self.render_right_side_icon(appearance, primary_color, dispatch_item_actions) | ||
| { | ||
| label_row.add_child(right_icon); | ||
| } | ||
| } | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(owner, name), but this removes every cached secret with the same name for the harness. If a user and team secret share a name, deleting one hides both locally until a refetch; retain by both name and owner and include owner in the deletion event/state.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🤨 it seems after a quick look in warp-server that this statement about uniqueness is, in fact, correct