fix(tui): run dialog actions without selection (#36711)

This commit is contained in:
Kit Langton 2026-07-13 15:19:40 -04:00 committed by GitHub
commit 41349ff20a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 185 additions and 22 deletions

View file

@ -132,6 +132,7 @@ export function DialogModel(props: { providerID?: string }) {
{
command: "model.dialog.provider",
title: connected() ? "Connect integration" : "View all integrations",
selection: "none",
onTrigger() {
dialog.replace(() => (
<DialogIntegration

View file

@ -345,6 +345,7 @@ export function DialogMoveSession(props: DialogMoveSessionProps) {
{
command: "dialog.move_session.new",
title: "new",
selection: "none",
onTrigger: () => void create(),
},
{
@ -360,6 +361,7 @@ export function DialogMoveSession(props: DialogMoveSessionProps) {
{
command: "dialog.move_session.refresh",
title: "refresh",
selection: "none",
onTrigger: () => void refetch(),
},
]

View file

@ -217,6 +217,7 @@ function View(props: { api: TuiPluginApi }) {
{
title: "install",
command: "dialog.plugins.install",
selection: "none",
hidden: lock(),
onTrigger: () => {
showInstall(props.api)

View file

@ -36,14 +36,7 @@ export interface DialogSelectProps<T> {
renderFilter?: boolean
locked?: boolean
preserveSelection?: boolean
actions?: {
command: string
title: string
side?: "left" | "right"
hidden?: boolean
disabled?: boolean | ((option: DialogSelectOption<T> | undefined) => boolean)
onTrigger: (option: DialogSelectOption<T>) => void
}[]
actions?: DialogSelectAction<T>[]
footerHints?: {
title: string
label: string
@ -54,6 +47,24 @@ export interface DialogSelectProps<T> {
focusCurrent?: boolean
}
type DialogSelectActionBase<T> = {
command: string
title: string
side?: "left" | "right"
hidden?: boolean
disabled?: boolean | ((option: DialogSelectOption<T> | undefined) => boolean)
}
type DialogSelectAction<T> =
| (DialogSelectActionBase<T> & {
selection?: "required"
onTrigger: (option: DialogSelectOption<T>) => void
})
| (DialogSelectActionBase<T> & {
selection: "none"
onTrigger: () => void
})
export interface DialogSelectOption<T = any> {
title: string
titleView?: JSX.Element
@ -350,7 +361,7 @@ export function DialogSelect<T>(props: DialogSelectProps<T>) {
setStore("input", "keyboard")
const index = focusedAction()
if (index !== undefined) {
triggerAction(actionItems()[index])
trigger(actionItems()[index])
return
}
const option = selected()
@ -441,14 +452,7 @@ export function DialogSelect<T>(props: DialogSelectProps<T>) {
name: item.command,
title: item.title,
category: "Dialog",
run() {
if (props.locked) return
if (isActionDisabled(item)) return
setStore("input", "keyboard")
const option = selected()
if (!option) return
item.onTrigger(option)
},
run: () => trigger(item),
})),
],
bindings: [
@ -504,10 +508,13 @@ export function DialogSelect<T>(props: DialogSelectProps<T>) {
const left = createMemo(() => visibleActions().filter((item) => item.side !== "right"))
const right = createMemo(() => visibleActions().filter((item) => item.side === "right"))
function triggerAction(item: VisibleAction | undefined) {
if (props.locked) return
if (!item || !isActionItem(item) || isActionDisabled(item)) return
function trigger(item: Action | undefined) {
if (props.locked || !item || isActionDisabled(item)) return
setStore("input", "keyboard")
if (item.selection === "none") {
item.onTrigger()
return
}
const option = selected()
if (!option) return
item.onTrigger(option)
@ -518,7 +525,9 @@ export function DialogSelect<T>(props: DialogSelectProps<T>) {
}
function isActionDisabled(item: Action) {
return typeof item.disabled === "function" ? item.disabled(selected()) : item.disabled
const option = selected()
if (item.selection !== "none" && !option) return true
return typeof item.disabled === "function" ? item.disabled(option) : item.disabled
}
function isActionFocused(item: VisibleAction) {
@ -545,7 +554,7 @@ export function DialogSelect<T>(props: DialogSelectProps<T>) {
<box
flexDirection="row"
backgroundColor={active() ? theme.primary : RGBA.fromInts(0, 0, 0, 0)}
onMouseUp={() => triggerAction(item)}
onMouseUp={() => trigger(item)}
>
<text
fg={disabled() ? theme.textMuted : active() ? fg : theme.text}