Fix composer send shortcut conflicts
This commit is contained in:
@@ -54,7 +54,7 @@ import { useDismissKeyboardOnOpen } from "@/components/ui/keyboard-dismiss";
|
|||||||
import { useWebElementScrollbar } from "@/components/use-web-scrollbar";
|
import { useWebElementScrollbar } from "@/components/use-web-scrollbar";
|
||||||
import { useShortcutKeys } from "@/hooks/use-shortcut-keys";
|
import { useShortcutKeys } from "@/hooks/use-shortcut-keys";
|
||||||
import { useIosHardwareKeyboardSubmit } from "@/hooks/use-ios-hardware-keyboard-submit";
|
import { useIosHardwareKeyboardSubmit } from "@/hooks/use-ios-hardware-keyboard-submit";
|
||||||
import { formatShortcut } from "@/utils/format-shortcut";
|
import { formatShortcut, type ShortcutKey } from "@/utils/format-shortcut";
|
||||||
import { getShortcutOs } from "@/utils/shortcut-platform";
|
import { getShortcutOs } from "@/utils/shortcut-platform";
|
||||||
import type { MessageInputKeyboardActionKind } from "@/keyboard/actions";
|
import type { MessageInputKeyboardActionKind } from "@/keyboard/actions";
|
||||||
import { isImeComposingKeyboardEvent } from "@/utils/keyboard-ime";
|
import { isImeComposingKeyboardEvent } from "@/utils/keyboard-ime";
|
||||||
@@ -67,7 +67,9 @@ import {
|
|||||||
resolveVoiceAccessibilityLabel,
|
resolveVoiceAccessibilityLabel,
|
||||||
resolveVoiceTooltipText,
|
resolveVoiceTooltipText,
|
||||||
} from "./labels";
|
} from "./labels";
|
||||||
import { computeCanStartDictation } from "./state";
|
import { computeCanStartDictation, runAlternateSendAction, runDefaultSendAction } from "./state";
|
||||||
|
|
||||||
|
const DEFAULT_SEND_KEYS: ShortcutKey[][] = [["Enter"]];
|
||||||
|
|
||||||
export interface AttachmentMenuItem {
|
export interface AttachmentMenuItem {
|
||||||
id: string;
|
id: string;
|
||||||
@@ -1123,32 +1125,6 @@ function computeSendButtonState(input: SendButtonStateInput): SendButtonStateOut
|
|||||||
return { canPressLoadingButton, isSendButtonDisabled, defaultActionQueues };
|
return { canPressLoadingButton, isSendButtonDisabled, defaultActionQueues };
|
||||||
}
|
}
|
||||||
|
|
||||||
interface DefaultSendActionContext {
|
|
||||||
defaultSendBehavior: "interrupt" | "queue";
|
|
||||||
isAgentRunning: boolean;
|
|
||||||
onQueue: ((payload: MessagePayload) => void) | undefined;
|
|
||||||
handleSendMessage: () => void;
|
|
||||||
handleQueueMessage: () => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
function runDefaultSendAction(ctx: DefaultSendActionContext): void {
|
|
||||||
if (ctx.defaultSendBehavior === "queue" && ctx.isAgentRunning && ctx.onQueue) {
|
|
||||||
ctx.handleQueueMessage();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
ctx.handleSendMessage();
|
|
||||||
}
|
|
||||||
|
|
||||||
function runAlternateSendAction(ctx: DefaultSendActionContext): void {
|
|
||||||
if (ctx.defaultSendBehavior === "queue") {
|
|
||||||
ctx.handleSendMessage();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (ctx.onQueue) {
|
|
||||||
ctx.handleQueueMessage();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
interface ResolvedMessageInputProps {
|
interface ResolvedMessageInputProps {
|
||||||
value: string;
|
value: string;
|
||||||
onChangeText: (text: string) => void;
|
onChangeText: (text: string) => void;
|
||||||
@@ -1282,7 +1258,6 @@ export const MessageInput = forwardRef<MessageInputRef, MessageInputProps>(
|
|||||||
const buttonIconSize = isWeb ? ICON_SIZE.md : ICON_SIZE.lg;
|
const buttonIconSize = isWeb ? ICON_SIZE.md : ICON_SIZE.lg;
|
||||||
const toast = useToast();
|
const toast = useToast();
|
||||||
const voice = useVoiceOptional();
|
const voice = useVoiceOptional();
|
||||||
const sendKeys = useShortcutKeys("message-input-send");
|
|
||||||
const voiceMuteToggleKeys = useShortcutKeys("voice-mute-toggle");
|
const voiceMuteToggleKeys = useShortcutKeys("voice-mute-toggle");
|
||||||
const dictationToggleKeys = useShortcutKeys("dictation-toggle");
|
const dictationToggleKeys = useShortcutKeys("dictation-toggle");
|
||||||
const focusInputKeys = useShortcutKeys("focus-message-input");
|
const focusInputKeys = useShortcutKeys("focus-message-input");
|
||||||
@@ -1898,7 +1873,7 @@ export const MessageInput = forwardRef<MessageInputRef, MessageInputProps>(
|
|||||||
isSubmitLoading={isSubmitLoading}
|
isSubmitLoading={isSubmitLoading}
|
||||||
submitIcon={submitIcon}
|
submitIcon={submitIcon}
|
||||||
buttonIconSize={buttonIconSize}
|
buttonIconSize={buttonIconSize}
|
||||||
sendKeys={sendKeys}
|
sendKeys={DEFAULT_SEND_KEYS}
|
||||||
sendTooltipLabel={sendTooltipLabel}
|
sendTooltipLabel={sendTooltipLabel}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { describe, expect, it } from "vitest";
|
import { describe, expect, it } from "vitest";
|
||||||
import { computeCanStartDictation } from "./state";
|
import { computeCanStartDictation, runAlternateSendAction, runDefaultSendAction } from "./state";
|
||||||
|
|
||||||
const connected = { isConnected: true } as never;
|
const connected = { isConnected: true } as never;
|
||||||
const disconnected = { isConnected: false } as never;
|
const disconnected = { isConnected: false } as never;
|
||||||
@@ -91,3 +91,61 @@ describe("computeCanStartDictation", () => {
|
|||||||
).toBe(false);
|
).toBe(false);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("composer send behavior", () => {
|
||||||
|
function actions() {
|
||||||
|
const calls: string[] = [];
|
||||||
|
return {
|
||||||
|
calls,
|
||||||
|
handleSendMessage: () => calls.push("send"),
|
||||||
|
handleQueueMessage: () => calls.push("queue"),
|
||||||
|
onQueue: () => undefined,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
it("uses Enter to interrupt and Mod+Enter to queue when interrupt is selected", () => {
|
||||||
|
const defaultAction = actions();
|
||||||
|
runDefaultSendAction({
|
||||||
|
defaultSendBehavior: "interrupt",
|
||||||
|
isAgentRunning: true,
|
||||||
|
onQueue: defaultAction.onQueue,
|
||||||
|
handleSendMessage: defaultAction.handleSendMessage,
|
||||||
|
handleQueueMessage: defaultAction.handleQueueMessage,
|
||||||
|
});
|
||||||
|
|
||||||
|
const alternateAction = actions();
|
||||||
|
runAlternateSendAction({
|
||||||
|
defaultSendBehavior: "interrupt",
|
||||||
|
isAgentRunning: true,
|
||||||
|
onQueue: alternateAction.onQueue,
|
||||||
|
handleSendMessage: alternateAction.handleSendMessage,
|
||||||
|
handleQueueMessage: alternateAction.handleQueueMessage,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(defaultAction.calls).toEqual(["send"]);
|
||||||
|
expect(alternateAction.calls).toEqual(["queue"]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("uses Enter to queue and Mod+Enter to submit when queue is selected", () => {
|
||||||
|
const defaultAction = actions();
|
||||||
|
runDefaultSendAction({
|
||||||
|
defaultSendBehavior: "queue",
|
||||||
|
isAgentRunning: true,
|
||||||
|
onQueue: defaultAction.onQueue,
|
||||||
|
handleSendMessage: defaultAction.handleSendMessage,
|
||||||
|
handleQueueMessage: defaultAction.handleQueueMessage,
|
||||||
|
});
|
||||||
|
|
||||||
|
const alternateAction = actions();
|
||||||
|
runAlternateSendAction({
|
||||||
|
defaultSendBehavior: "queue",
|
||||||
|
isAgentRunning: true,
|
||||||
|
onQueue: alternateAction.onQueue,
|
||||||
|
handleSendMessage: alternateAction.handleSendMessage,
|
||||||
|
handleQueueMessage: alternateAction.handleQueueMessage,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(defaultAction.calls).toEqual(["queue"]);
|
||||||
|
expect(alternateAction.calls).toEqual(["send"]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
@@ -1,4 +1,15 @@
|
|||||||
import type { DaemonClient } from "@getpaseo/client/internal/daemon-client";
|
import type { DaemonClient } from "@getpaseo/client/internal/daemon-client";
|
||||||
|
import type { MessagePayload } from "@/composer/types";
|
||||||
|
|
||||||
|
export type SendBehavior = "interrupt" | "queue";
|
||||||
|
|
||||||
|
interface SendActionContext {
|
||||||
|
defaultSendBehavior: SendBehavior;
|
||||||
|
isAgentRunning: boolean;
|
||||||
|
onQueue: ((payload: MessagePayload) => void) | undefined;
|
||||||
|
handleSendMessage: () => void;
|
||||||
|
handleQueueMessage: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
export function computeCanStartDictation(input: {
|
export function computeCanStartDictation(input: {
|
||||||
client: DaemonClient | null;
|
client: DaemonClient | null;
|
||||||
@@ -12,3 +23,21 @@ export function computeCanStartDictation(input: {
|
|||||||
socketConnected && readyForDictation && !input.disabled && !input.dictationUnavailableMessage
|
socketConnected && readyForDictation && !input.disabled && !input.dictationUnavailableMessage
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function runDefaultSendAction(ctx: SendActionContext): void {
|
||||||
|
if (ctx.defaultSendBehavior === "queue" && ctx.isAgentRunning && ctx.onQueue) {
|
||||||
|
ctx.handleQueueMessage();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ctx.handleSendMessage();
|
||||||
|
}
|
||||||
|
|
||||||
|
export function runAlternateSendAction(ctx: SendActionContext): void {
|
||||||
|
if (ctx.defaultSendBehavior === "queue") {
|
||||||
|
ctx.handleSendMessage();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (ctx.isAgentRunning && ctx.onQueue) {
|
||||||
|
ctx.handleQueueMessage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -236,7 +236,7 @@ describe("translation resources", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("includes workspace Git and review keys for the Batch 4B migration", () => {
|
it("includes workspace Git and review keys for the Batch 4B migration", () => {
|
||||||
expect(en.workspace.tabs.actions.newAgent).toBe("New agent tab");
|
expect(en.workspace.tabs.actions.newAgent).toBe("New agent");
|
||||||
expect(en.workspace.header.actions.copyPath).toBe("Copy workspace path");
|
expect(en.workspace.header.actions.copyPath).toBe("Copy workspace path");
|
||||||
expect(en.workspace.scripts.actions.run).toBe("Run");
|
expect(en.workspace.scripts.actions.run).toBe("Run");
|
||||||
expect(en.workspace.git.actions.commit.label).toBe("Commit");
|
expect(en.workspace.git.actions.commit.label).toBe("Commit");
|
||||||
|
|||||||
@@ -1362,7 +1362,11 @@ export const ar: TranslationResources = {
|
|||||||
title: "عام",
|
title: "عام",
|
||||||
defaultSend: {
|
defaultSend: {
|
||||||
label: "إرسال افتراضي",
|
label: "إرسال افتراضي",
|
||||||
description: "ماذا يحدث عند الضغط على Enter أثناء تشغيل الوكيل",
|
descriptions: {
|
||||||
|
interrupt:
|
||||||
|
"عند تشغيل الوكيل، يوقف Enter التشغيل. Command/Ctrl+Enter يضيف إلى قائمة الانتظار.",
|
||||||
|
queue: "عند تشغيل الوكيل، يضيف Enter إلى قائمة الانتظار. Command/Ctrl+Enter يرسل.",
|
||||||
|
},
|
||||||
options: {
|
options: {
|
||||||
interrupt: "مقاطعة",
|
interrupt: "مقاطعة",
|
||||||
queue: "طابور",
|
queue: "طابور",
|
||||||
|
|||||||
@@ -1368,7 +1368,10 @@ export const en = {
|
|||||||
title: "General",
|
title: "General",
|
||||||
defaultSend: {
|
defaultSend: {
|
||||||
label: "Default send",
|
label: "Default send",
|
||||||
description: "What happens when you press Enter while the agent is running",
|
descriptions: {
|
||||||
|
interrupt: "When the agent is running, Enter interrupts. Command/Ctrl+Enter queues.",
|
||||||
|
queue: "When the agent is running, Enter queues. Command/Ctrl+Enter submits.",
|
||||||
|
},
|
||||||
options: {
|
options: {
|
||||||
interrupt: "Interrupt",
|
interrupt: "Interrupt",
|
||||||
queue: "Queue",
|
queue: "Queue",
|
||||||
|
|||||||
@@ -1397,7 +1397,12 @@ export const es: TranslationResources = {
|
|||||||
title: "General",
|
title: "General",
|
||||||
defaultSend: {
|
defaultSend: {
|
||||||
label: "Envío predeterminado",
|
label: "Envío predeterminado",
|
||||||
description: "¿Qué sucede cuando presiona Enter mientras el agente se está ejecutando?",
|
descriptions: {
|
||||||
|
interrupt:
|
||||||
|
"Cuando el agente se está ejecutando, Enter interrumpe. Command/Ctrl+Enter pone en cola.",
|
||||||
|
queue:
|
||||||
|
"Cuando el agente se está ejecutando, Enter pone en cola. Command/Ctrl+Enter envía.",
|
||||||
|
},
|
||||||
options: {
|
options: {
|
||||||
interrupt: "Interrumpir",
|
interrupt: "Interrumpir",
|
||||||
queue: "Cola",
|
queue: "Cola",
|
||||||
|
|||||||
@@ -1400,8 +1400,12 @@ export const fr: TranslationResources = {
|
|||||||
title: "Général",
|
title: "Général",
|
||||||
defaultSend: {
|
defaultSend: {
|
||||||
label: "Envoi par défaut",
|
label: "Envoi par défaut",
|
||||||
description:
|
descriptions: {
|
||||||
"Que se passe-t-il lorsque vous appuyez sur Entrée alors que l'agent est en cours d'exécution?",
|
interrupt:
|
||||||
|
"Lorsque l'agent est en cours d'exécution, Entrée interrompt. Commande/Ctrl+Entrée met en file d'attente.",
|
||||||
|
queue:
|
||||||
|
"Lorsque l'agent est en cours d'exécution, Entrée met en file d'attente. Commande/Ctrl+Entrée envoie.",
|
||||||
|
},
|
||||||
options: {
|
options: {
|
||||||
interrupt: "Interrompre",
|
interrupt: "Interrompre",
|
||||||
queue: "File d'attente",
|
queue: "File d'attente",
|
||||||
|
|||||||
@@ -1389,7 +1389,10 @@ export const ru: TranslationResources = {
|
|||||||
title: "Общий",
|
title: "Общий",
|
||||||
defaultSend: {
|
defaultSend: {
|
||||||
label: "Отправка по умолчанию",
|
label: "Отправка по умолчанию",
|
||||||
description: "Что произойдет, если вы нажмете Enter во время работы агента",
|
descriptions: {
|
||||||
|
interrupt: "Когда агент работает, Enter прерывает. Command/Ctrl+Enter ставит в очередь.",
|
||||||
|
queue: "Когда агент работает, Enter ставит в очередь. Command/Ctrl+Enter отправляет.",
|
||||||
|
},
|
||||||
options: {
|
options: {
|
||||||
interrupt: "Прерывать",
|
interrupt: "Прерывать",
|
||||||
queue: "Очередь",
|
queue: "Очередь",
|
||||||
|
|||||||
@@ -1345,7 +1345,10 @@ export const zhCN: TranslationResources = {
|
|||||||
title: "通用",
|
title: "通用",
|
||||||
defaultSend: {
|
defaultSend: {
|
||||||
label: "默认发送",
|
label: "默认发送",
|
||||||
description: "Agent 运行时按 Enter 的行为",
|
descriptions: {
|
||||||
|
interrupt: "Agent 运行时,Enter 会中断。Command/Ctrl+Enter 会排队。",
|
||||||
|
queue: "Agent 运行时,Enter 会排队。Command/Ctrl+Enter 会提交。",
|
||||||
|
},
|
||||||
options: {
|
options: {
|
||||||
interrupt: "中断",
|
interrupt: "中断",
|
||||||
queue: "排队",
|
queue: "排队",
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ export type KeyboardFocusScope =
|
|||||||
export type MessageInputKeyboardActionKind =
|
export type MessageInputKeyboardActionKind =
|
||||||
| "focus"
|
| "focus"
|
||||||
| "send"
|
| "send"
|
||||||
| "queue"
|
|
||||||
| "dictation-toggle"
|
| "dictation-toggle"
|
||||||
| "dictation-cancel"
|
| "dictation-cancel"
|
||||||
| "dictation-confirm"
|
| "dictation-confirm"
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { describe, expect, it, vi } from "vitest";
|
|||||||
import {
|
import {
|
||||||
buildKeyboardShortcutHelpSections,
|
buildKeyboardShortcutHelpSections,
|
||||||
buildEffectiveBindings,
|
buildEffectiveBindings,
|
||||||
|
getBindingIdForAction,
|
||||||
resolveKeyboardShortcut,
|
resolveKeyboardShortcut,
|
||||||
type ChordState,
|
type ChordState,
|
||||||
type KeyboardShortcutContext,
|
type KeyboardShortcutContext,
|
||||||
@@ -413,6 +414,16 @@ describe("keyboard-shortcuts", () => {
|
|||||||
event: { key: "d", code: "KeyD", metaKey: true },
|
event: { key: "d", code: "KeyD", metaKey: true },
|
||||||
context: { isMac: true, focusScope: "terminal" },
|
context: { isMac: true, focusScope: "terminal" },
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "does not bind Cmd+Enter as a rebindable message queue shortcut",
|
||||||
|
event: { key: "Enter", code: "Enter", metaKey: true },
|
||||||
|
context: { isMac: true, focusScope: "message-input" },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "does not bind Ctrl+Enter as a rebindable message queue shortcut",
|
||||||
|
event: { key: "Enter", code: "Enter", ctrlKey: true },
|
||||||
|
context: { isMac: false, focusScope: "message-input" },
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "does not interrupt agent when terminal is focused",
|
name: "does not interrupt agent when terminal is focused",
|
||||||
event: { key: "Escape", code: "Escape" },
|
event: { key: "Escape", code: "Escape" },
|
||||||
@@ -600,4 +611,17 @@ describe("keyboard-shortcut help sections", () => {
|
|||||||
expect(openProject?.label).toBe("Open project");
|
expect(openProject?.label).toBe("Open project");
|
||||||
expect(showShortcuts?.noteKey).toBe("settings.shortcuts.helpNotes.showKeyboardShortcuts");
|
expect(showShortcuts?.noteKey).toBe("settings.shortcuts.helpNotes.showKeyboardShortcuts");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("does not expose Enter send behavior as rebindable shortcut rows", () => {
|
||||||
|
const sections = buildKeyboardShortcutHelpSections({ isMac: true, isDesktop: true });
|
||||||
|
|
||||||
|
expect(findRow(sections, "message-input-send")).toBeNull();
|
||||||
|
expect(findRow(sections, "message-input-queue")).toBeNull();
|
||||||
|
expect(
|
||||||
|
getBindingIdForAction("message-input-send", { isMac: true, isDesktop: true }),
|
||||||
|
).toBeNull();
|
||||||
|
expect(
|
||||||
|
getBindingIdForAction("message-input-queue", { isMac: true, isDesktop: true }),
|
||||||
|
).toBeNull();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -154,8 +154,6 @@ const SHORTCUT_HELP_LABEL_KEYS: Record<string, string> = {
|
|||||||
"voice-toggle": "settings.shortcuts.help.toggleVoiceMode",
|
"voice-toggle": "settings.shortcuts.help.toggleVoiceMode",
|
||||||
"dictation-toggle": "settings.shortcuts.help.startStopDictation",
|
"dictation-toggle": "settings.shortcuts.help.startStopDictation",
|
||||||
"agent-interrupt": "settings.shortcuts.help.interruptAgent",
|
"agent-interrupt": "settings.shortcuts.help.interruptAgent",
|
||||||
"message-input-send": "settings.shortcuts.help.sendMessage",
|
|
||||||
"message-input-queue": "settings.shortcuts.help.queueMessage",
|
|
||||||
"voice-mute-toggle": "settings.shortcuts.help.muteUnmuteVoiceMode",
|
"voice-mute-toggle": "settings.shortcuts.help.muteUnmuteVoiceMode",
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -953,52 +951,6 @@ const SHORTCUT_BINDINGS: readonly ShortcutBinding[] = [
|
|||||||
keys: ["Esc"],
|
keys: ["Esc"],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
id: "message-input-send-enter",
|
|
||||||
action: "message-input.action",
|
|
||||||
combo: "Enter",
|
|
||||||
when: { focusScope: "message-input", commandCenter: false },
|
|
||||||
payload: { type: "message-input", kind: "send" },
|
|
||||||
preventDefault: false,
|
|
||||||
stopPropagation: false,
|
|
||||||
help: {
|
|
||||||
id: "message-input-send",
|
|
||||||
section: "agent-input",
|
|
||||||
label: "Send message",
|
|
||||||
keys: ["Enter"],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "message-input-queue-cmd-enter-mac",
|
|
||||||
action: "message-input.action",
|
|
||||||
combo: "Cmd+Enter",
|
|
||||||
when: { mac: true, focusScope: "message-input", commandCenter: false },
|
|
||||||
payload: { type: "message-input", kind: "queue" },
|
|
||||||
preventDefault: false,
|
|
||||||
stopPropagation: false,
|
|
||||||
help: {
|
|
||||||
id: "message-input-queue",
|
|
||||||
section: "agent-input",
|
|
||||||
label: "Queue message",
|
|
||||||
keys: ["mod", "Enter"],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "message-input-queue-ctrl-enter-non-mac",
|
|
||||||
action: "message-input.action",
|
|
||||||
combo: "Ctrl+Enter",
|
|
||||||
when: { mac: false, focusScope: "message-input", commandCenter: false },
|
|
||||||
payload: { type: "message-input", kind: "queue" },
|
|
||||||
preventDefault: false,
|
|
||||||
stopPropagation: false,
|
|
||||||
help: {
|
|
||||||
id: "message-input-queue",
|
|
||||||
section: "agent-input",
|
|
||||||
label: "Queue message",
|
|
||||||
keys: ["mod", "Enter"],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
{
|
||||||
id: "message-input-dictation-confirm-enter",
|
id: "message-input-dictation-confirm-enter",
|
||||||
action: "message-input.action",
|
action: "message-input.action",
|
||||||
|
|||||||
@@ -284,15 +284,6 @@ describe("routeKeyboardShortcut — message-input.action", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("returns none for unsupported message-input kinds (queue)", () => {
|
|
||||||
expect(
|
|
||||||
routeKeyboardShortcut(
|
|
||||||
{ action: "message-input.action", payload: { kind: "queue" } },
|
|
||||||
makeCtx(),
|
|
||||||
),
|
|
||||||
).toEqual<ShortcutAction>({ kind: "none" });
|
|
||||||
});
|
|
||||||
|
|
||||||
it("returns none when kind is missing", () => {
|
it("returns none when kind is missing", () => {
|
||||||
expect(
|
expect(
|
||||||
routeKeyboardShortcut({ action: "message-input.action", payload: null }, makeCtx()),
|
routeKeyboardShortcut({ action: "message-input.action", payload: null }, makeCtx()),
|
||||||
|
|||||||
@@ -81,7 +81,6 @@ const MESSAGE_INPUT_DISPATCH: Record<
|
|||||||
"dictation-confirm": { id: "message-input.dictation-confirm", scope: "message-input" },
|
"dictation-confirm": { id: "message-input.dictation-confirm", scope: "message-input" },
|
||||||
"voice-toggle": { id: "message-input.voice-toggle", scope: "message-input" },
|
"voice-toggle": { id: "message-input.voice-toggle", scope: "message-input" },
|
||||||
"voice-mute-toggle": { id: "message-input.voice-mute-toggle", scope: "message-input" },
|
"voice-mute-toggle": { id: "message-input.voice-mute-toggle", scope: "message-input" },
|
||||||
queue: null,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
function hasPayloadKey<K extends "index" | "delta" | "kind">(
|
function hasPayloadKey<K extends "index" | "delta" | "kind">(
|
||||||
|
|||||||
@@ -317,6 +317,10 @@ function GeneralSection({
|
|||||||
const activeLocale = getActiveLocale(i18n.language);
|
const activeLocale = getActiveLocale(i18n.language);
|
||||||
const iconColor = theme.colors.foregroundMuted;
|
const iconColor = theme.colors.foregroundMuted;
|
||||||
const sendBehaviorOptions = useMemo(() => getSendBehaviorOptions(t), [t]);
|
const sendBehaviorOptions = useMemo(() => getSendBehaviorOptions(t), [t]);
|
||||||
|
const sendBehaviorDescriptionKey =
|
||||||
|
settings.sendBehavior === "interrupt"
|
||||||
|
? "settings.general.defaultSend.descriptions.interrupt"
|
||||||
|
: "settings.general.defaultSend.descriptions.queue";
|
||||||
const selectedLanguageOption = LANGUAGE_OPTIONS.find(
|
const selectedLanguageOption = LANGUAGE_OPTIONS.find(
|
||||||
(option) => option.value === settings.language,
|
(option) => option.value === settings.language,
|
||||||
);
|
);
|
||||||
@@ -358,9 +362,7 @@ function GeneralSection({
|
|||||||
<View style={settingsStyles.row}>
|
<View style={settingsStyles.row}>
|
||||||
<View style={settingsStyles.rowContent}>
|
<View style={settingsStyles.rowContent}>
|
||||||
<Text style={settingsStyles.rowTitle}>{t("settings.general.defaultSend.label")}</Text>
|
<Text style={settingsStyles.rowTitle}>{t("settings.general.defaultSend.label")}</Text>
|
||||||
<Text style={settingsStyles.rowHint}>
|
<Text style={settingsStyles.rowHint}>{t(sendBehaviorDescriptionKey)}</Text>
|
||||||
{t("settings.general.defaultSend.description")}
|
|
||||||
</Text>
|
|
||||||
</View>
|
</View>
|
||||||
<SegmentedControl
|
<SegmentedControl
|
||||||
size="sm"
|
size="sm"
|
||||||
|
|||||||
Reference in New Issue
Block a user