Compare commits

..

1 Commits

Author SHA1 Message Date
Kit Langton 536b99bbdc feat(tui): add pairing password toggle 2026-08-06 19:56:43 -04:00
8 changed files with 32 additions and 12 deletions
@@ -128,7 +128,6 @@ export function DialogMcp() {
{
title: toggleTitle(),
command: "dialog.mcp.toggle",
variant: toggleTitle() === "disconnect" ? "destructive" : "primary",
onTrigger: (option) => {
setFocused(option.value as string)
toggle(option.value as string)
@@ -372,7 +372,6 @@ export function DialogMoveSession(props: DialogMoveSessionProps) {
{
command: "dialog.move_session.delete",
title: "delete",
variant: "destructive",
disabled: (option) => {
const value = option?.value
if (!value || value.type !== "directory" || value.subdirectory) return true
+22 -1
View File
@@ -3,6 +3,7 @@ import { useTerminalDimensions } from "@opentui/solid"
import { createMemo, createResource, createSignal, For, Show } from "solid-js"
import { renderUnicodeCompact } from "uqr"
import { useClient } from "../context/client"
import { Keymap } from "../context/keymap"
import { useTheme } from "../context/theme"
import { useDialog } from "../ui/dialog"
import { errorMessage } from "../util/error"
@@ -20,6 +21,22 @@ export function DialogPair(props: { credentials?: DialogPairCredentials }) {
const [loadError, setLoadError] = createSignal<unknown>()
const [showPassword, setShowPassword] = createSignal(false)
const [passwordHover, setPasswordHover] = createSignal(false)
const shortcuts = Keymap.useShortcuts()
const togglePassword = () => {
setShowPassword((current) => !current)
}
Keymap.createLayer(() => ({
mode: "modal",
commands: [
{
id: "dialog.pair.toggle_password",
title: showPassword() ? "Hide pairing password" : "Show pairing password",
group: "Dialog",
run: togglePassword,
},
],
}))
dialog.setSize("large")
dialog.setCentered(true)
@@ -61,10 +78,14 @@ export function DialogPair(props: { credentials?: DialogPairCredentials }) {
wrapMode="word"
onMouseOver={() => setPasswordHover(true)}
onMouseOut={() => setPasswordHover(false)}
onMouseUp={() => setShowPassword((current) => !current)}
onMouseUp={togglePassword}
>
{showPassword() ? value.password : "************"}
</text>
<text fg={theme.text.default} onMouseUp={togglePassword}>
{shortcuts.get("dialog.pair.toggle_password")} {" "}
<span style={{ fg: theme.text.subdued }}>{showPassword() ? "hide password" : "show password"}</span>
</text>
</box>
<Show when={value.urls.some((url) => ["localhost", "127.0.0.1", "[::1]"].includes(new URL(url).hostname))}>
<text fg={theme.text.subdued} wrapMode="word">
@@ -236,7 +236,6 @@ export function DialogSessionList() {
{
command: "session.delete",
title: "delete",
variant: "destructive",
onTrigger: (option: { value: string }) => {
if (toDelete() !== option.value) {
setToDelete(option.value)
@@ -75,7 +75,6 @@ export function DialogStash(props: { onSelect: (entry: StashEntry) => void }) {
{
command: "stash.delete",
title: "delete",
variant: "destructive",
onTrigger: (option) => {
if (toDelete() === option.value) {
stash.remove(option.value)
+1
View File
@@ -220,6 +220,7 @@ export const Definitions = {
"dialog.move_session.new": keybind("ctrl+m", "New project copy"),
"dialog.move_session.delete": keybind("ctrl+d", "Delete project copy"),
"dialog.move_session.refresh": keybind("ctrl+r", "Refresh project copies"),
"dialog.pair.toggle_password": keybind("space", "Show or hide pairing password"),
"prompt.autocomplete.prev": keybind("up,ctrl+p", "Move to previous autocomplete item"),
"prompt.autocomplete.next": keybind("down,ctrl+n", "Move to next autocomplete item"),
"prompt.autocomplete.hide": keybind("escape", "Hide autocomplete"),
+5 -7
View File
@@ -45,7 +45,6 @@ export interface DialogSelectProps<T> {
type DialogSelectActionBase<T> = {
command: string
title: string
variant?: "primary" | "destructive"
side?: "left" | "right"
hidden?: boolean
disabled?: boolean | ((option: DialogSelectOption<T> | undefined) => boolean)
@@ -552,19 +551,18 @@ export function DialogSelect<T>(props: DialogSelectProps<T>) {
const item = action.item
const active = createMemo(() => isActionFocused(item))
const disabled = createMemo(() => isActionDisabled(item))
const variant = () => item.variant ?? "primary"
return (
<box
flexDirection="row"
backgroundColor={active() ? theme.background.action[variant()].focused : RGBA.fromInts(0, 0, 0, 0)}
backgroundColor={active() ? theme.background.action.primary.focused : RGBA.fromInts(0, 0, 0, 0)}
onMouseUp={() => trigger(item)}
>
<text
fg={
disabled()
? theme.text.action[variant()].disabled
? theme.text.action.primary.disabled
: active()
? theme.text.action[variant()].focused
? theme.text.action.primary.focused
: theme.text.default
}
attributes={active() ? TextAttributes.BOLD : undefined}
@@ -574,9 +572,9 @@ export function DialogSelect<T>(props: DialogSelectProps<T>) {
<text
fg={
disabled()
? theme.text.action[variant()].disabled
? theme.text.action.primary.disabled
: active()
? theme.text.action[variant()].focused
? theme.text.action.primary.focused
: theme.text.subdued
}
>
+4
View File
@@ -5,3 +5,7 @@ test("binds agent cycling only to shift+tab by default", () => {
expect(TuiKeybind.Definitions.agent_cycle.default).toBe("shift+tab")
expect(TuiKeybind.Definitions.agent_cycle_reverse.default).toBe("none")
})
test("binds pairing password visibility to space by default", () => {
expect(TuiKeybind.Definitions["dialog.pair.toggle_password"].default).toBe("space")
})