Skip to content

Commit 7d81194

Browse files
committed
fix: remove false duplicate shortcut errors across different groups
Form validation was checking shortcuts globally using flattenCommands(), causing false duplicate errors for shortcuts in completely separate groups. Shortcuts only need to be unique within the same group (QuickPick menu), so form-level validation is removed and delegated to runtime validation in command-executor.ts which correctly scopes validation per group.
1 parent ca5de14 commit 7d81194

3 files changed

Lines changed: 7 additions & 48 deletions

File tree

src/view/src/components/command-form-dialog.tsx

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,10 @@ import {
1414

1515
import { CommandForm } from "./command-form";
1616
import { useCommandForm } from "../context/command-form-context.tsx";
17-
import { useVscodeCommand } from "../context/vscode-command-context.tsx";
1817

1918
export const CommandFormDialog = () => {
2019
const { t } = useTranslation();
2120
const { closeForm, editingCommand, handleSave, resetFormState, showForm } = useCommandForm();
22-
const { commands } = useVscodeCommand();
2321
const formId = useId();
2422

2523
const handleOpenChange = (open: boolean) => {
@@ -50,12 +48,7 @@ export const CommandFormDialog = () => {
5048
</DialogDescription>
5149
</DialogHeader>
5250
<DialogBody>
53-
<CommandForm
54-
command={editingCommand}
55-
commands={commands}
56-
formId={formId}
57-
onSave={handleSave}
58-
/>
51+
<CommandForm command={editingCommand} formId={formId} onSave={handleSave} />
5952
</DialogBody>
6053
<DialogFooter>
6154
<Button onClick={closeForm} type="button" variant="outline">

src/view/src/components/command-form.tsx

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@ import { parseVSCodeIconName } from "../utils/parse-vscode-icon-name";
3535

3636
type CommandFormProps = {
3737
command?: (ButtonConfig & { index?: number }) | null;
38-
commands: ButtonConfig[];
3938
formId?: string;
4039
onSave: (command: ButtonConfig) => void;
4140
};
@@ -68,13 +67,12 @@ const buildCommandConfig = (data: ButtonConfigDraft, isGroup: boolean): ButtonCo
6867
return isGroup ? toGroupButton(normalized) : toCommandButton(normalized);
6968
};
7069

71-
export const CommandForm = ({ command, commands, formId, onSave }: CommandFormProps) => {
70+
export const CommandForm = ({ command, formId, onSave }: CommandFormProps) => {
7271
const { t } = useTranslation();
7372

74-
const schema = useMemo(
75-
() => createCommandFormSchema(commands, command?.id),
76-
[commands, command?.id]
77-
);
73+
// Note: Shortcut uniqueness validation is handled at runtime in command-executor.ts
74+
// Shortcuts only need to be unique within the same group (QuickPick menu)
75+
const schema = useMemo(() => createCommandFormSchema(), []);
7876

7977
const {
8078
control,

src/view/src/schemas/command-form-schema.ts

Lines changed: 2 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,6 @@ import { z } from "zod";
22

33
import { type ButtonConfig } from "../types";
44

5-
export const getDuplicateShortcutErrorMessage = (shortcut: string) =>
6-
`Shortcut "${shortcut}" is already used by another command`;
7-
85
/**
96
* Type assertion for Zod v4 recursive schema constraints
107
*
@@ -35,14 +32,7 @@ const buttonConfigSchema = z.lazy(() =>
3532
})
3633
) as unknown as z.ZodType<ButtonConfig>;
3734

38-
const flattenCommands = (cmds: ButtonConfig[]): ButtonConfig[] => {
39-
return cmds.flatMap((cmd) => (cmd.group ? [cmd, ...flattenCommands(cmd.group)] : [cmd]));
40-
};
41-
42-
export const createCommandFormSchema = (
43-
commands: ButtonConfig[],
44-
editingCommandId?: string
45-
): z.ZodType<ButtonConfig> => {
35+
export const createCommandFormSchema = (): z.ZodType<ButtonConfig> => {
4636
return z.object({
4737
color: z.string().optional(),
4838
command: z.string().optional(),
@@ -51,29 +41,7 @@ export const createCommandFormSchema = (
5141
id: z.string(),
5242
insertOnly: z.boolean().optional(),
5343
name: z.string().min(1, "Command name is required"),
54-
shortcut: z
55-
.string()
56-
.optional()
57-
.superRefine((value, ctx) => {
58-
if (!value || !value.trim()) return;
59-
60-
const normalizedShortcut = value.toLowerCase().trim();
61-
const allCommands = flattenCommands(commands);
62-
63-
const isDuplicate = allCommands.some((cmd) => {
64-
if (editingCommandId !== undefined && cmd.id === editingCommandId) {
65-
return false;
66-
}
67-
return cmd.shortcut?.toLowerCase().trim() === normalizedShortcut;
68-
});
69-
70-
if (isDuplicate) {
71-
ctx.addIssue({
72-
code: "custom",
73-
message: getDuplicateShortcutErrorMessage(value),
74-
});
75-
}
76-
}),
44+
shortcut: z.string().optional(),
7745
terminalName: z.string().optional(),
7846
useVsCodeApi: z.boolean().optional(),
7947
}) as unknown as z.ZodType<ButtonConfig>;

0 commit comments

Comments
 (0)