Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 4 additions & 7 deletions src/extension/src/command-executor.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import * as vscode from "vscode";
import { MESSAGES } from "../../shared/constants";
import { TerminalExecutor, QuickPickCreator } from "./adapters";
import { findMatchingShortcut } from "./keyboard-layout-converter";
import { ButtonConfig } from "./types";
Expand Down Expand Up @@ -85,11 +86,7 @@ export const createQuickPickWithShortcuts = (
const duplicates = validateShortcuts(config.items);

if (duplicates.length > 0) {
vscode.window.showErrorMessage(
`Duplicate shortcuts detected: ${duplicates.join(
", "
)}. Please ensure each shortcut is unique.`
);
vscode.window.showErrorMessage(MESSAGES.ERROR.duplicateShortcuts(duplicates));
return;
}

Expand Down Expand Up @@ -183,8 +180,8 @@ const showGroupQuickPick = (
createQuickPickWithShortcuts(
{
items: items,
placeholder: "Select a command to execute",
title: `${button.name} Commands`,
placeholder: MESSAGES.INFO.selectCommand,
title: MESSAGES.INFO.groupCommands(button.name),
},
terminalExecutor,
quickPickCreator
Expand Down
20 changes: 6 additions & 14 deletions src/extension/src/config-constants.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,15 @@
import * as vscode from "vscode";
import { CONFIG, CONFIGURATION_TARGET } from "../../shared/constants";

export const CONFIG_SECTION = "quickCommandButtons";

export const CONFIG_KEYS = {
BUTTONS: "buttons",
CONFIGURATION_TARGET: "configurationTarget",
REFRESH_BUTTON: "refreshButton",
} as const;

export const CONFIGURATION_TARGETS = {
GLOBAL: "global",
WORKSPACE: "workspace",
} as const;
export const CONFIG_SECTION = CONFIG.SECTION;
export const CONFIG_KEYS = CONFIG.KEYS;
export const CONFIGURATION_TARGETS = CONFIGURATION_TARGET;

export const VS_CODE_CONFIGURATION_TARGETS = {
[CONFIGURATION_TARGETS.GLOBAL]: vscode.ConfigurationTarget.Global,
[CONFIGURATION_TARGETS.WORKSPACE]: vscode.ConfigurationTarget.Workspace,
} as const;

export type ConfigurationTargetType =
(typeof CONFIGURATION_TARGETS)[keyof typeof CONFIGURATION_TARGETS];
export type ConfigKeyType = (typeof CONFIG_KEYS)[keyof typeof CONFIG_KEYS];
(typeof CONFIGURATION_TARGET)[keyof typeof CONFIGURATION_TARGET];
export type ConfigKeyType = (typeof CONFIG.KEYS)[keyof typeof CONFIG.KEYS];
11 changes: 7 additions & 4 deletions src/extension/src/show-all-commands.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
import * as vscode from "vscode";
import { MESSAGES } from "../../shared/constants";
import { ConfigReader, QuickPickCreator, TerminalExecutor } from "./adapters";
import { createQuickPickWithShortcuts, QuickPickItem } from "./command-executor";
import { ButtonConfig } from "./types";

export const createQuickPickItemsFromButtons = (buttons: ButtonConfig[]): QuickPickItem[] => {
return buttons.map((button) => ({
command: button,
description: button.group ? `${button.group.length} commands` : button.command || "",
description: button.group
? MESSAGES.INFO.commandsCount(button.group.length)
: button.command || "",
label: button.shortcut ? `${button.name} (${button.shortcut})` : button.name,
}));
};
Expand All @@ -20,7 +23,7 @@ export const createShowAllCommandsCommand = (
const buttons = configReader.getButtons();

if (buttons.length === 0) {
vscode.window.showInformationMessage("No commands found");
vscode.window.showInformationMessage(MESSAGES.ERROR.noCommands);
return;
}

Expand All @@ -29,8 +32,8 @@ export const createShowAllCommandsCommand = (
createQuickPickWithShortcuts(
{
items: items,
placeholder: "Select a command/group to execute (or type shortcut key)",
title: "Quick Commands",
placeholder: MESSAGES.INFO.selectCommandOrGroup,
title: MESSAGES.INFO.quickCommands,
},
terminalExecutor,
quickPickCreator
Expand Down
38 changes: 38 additions & 0 deletions src/shared/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
export const CONFIG = {
SECTION: "quickCommandButtons",
KEYS: {
BUTTONS: "buttons",
CONFIGURATION_TARGET: "configurationTarget",
REFRESH_BUTTON: "refreshButton",
},
} as const;

export const CONFIGURATION_TARGET = {
GLOBAL: "global",
WORKSPACE: "workspace",
} as const;

export const MESSAGE_TYPE = {
GET_CONFIG: "getConfig",
SET_CONFIG: "setConfig",
SET_CONFIGURATION_TARGET: "setConfigurationTarget",
CONFIG_DATA: "configData",
CONFIGURATION_TARGET_CHANGED: "configurationTargetChanged",
} as const;
Comment thread
kubrickcode marked this conversation as resolved.

export const MESSAGES = {
ERROR: {
contextRequired: (hookName: string) =>
`${hookName} must be used within a VscodeCommandProvider`,
duplicateShortcuts: (shortcuts: string[]) =>
`Duplicate shortcuts detected: ${shortcuts.join(", ")}. Please ensure each shortcut is unique.`,
noCommands: "No commands found",
},
INFO: {
selectCommand: "Select a command to execute",
selectCommandOrGroup: "Select a command/group to execute (or type shortcut key)",
quickCommands: "Quick Commands",
groupCommands: (buttonName: string) => `${buttonName} Commands`,
commandsCount: (count: number) => `${count} commands`,
},
Comment thread
kubrickcode marked this conversation as resolved.
} as const;
14 changes: 9 additions & 5 deletions src/web-view/src/components/header.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Button } from "~/core";

import { CONFIGURATION_TARGET } from "../../../shared/constants";
import { useCommandForm } from "../context/command-form-context.tsx";
import { useVscodeCommand } from "../context/vscode-command-context.tsx";
import { useDarkMode } from "../hooks/use-dark-mode.tsx";
Expand All @@ -10,7 +11,10 @@ export const Header = () => {
const { isDark, toggleTheme } = useDarkMode();

const toggleConfigurationTarget = () => {
const newTarget = configurationTarget === "workspace" ? "global" : "workspace";
const newTarget =
configurationTarget === CONFIGURATION_TARGET.WORKSPACE
? CONFIGURATION_TARGET.GLOBAL
: CONFIGURATION_TARGET.WORKSPACE;
setConfigurationTarget(newTarget);
};

Expand All @@ -36,12 +40,12 @@ export const Header = () => {
<div className="flex flex-col">
<span className="text-sm font-medium text-foreground">Configuration Scope</span>
<span className="text-xs text-muted-foreground">
{configurationTarget === "workspace"
{configurationTarget === CONFIGURATION_TARGET.WORKSPACE
? "📁 Workspace: Project-specific commands shared with team"
: "🌐 Global: Personal commands across all projects"}
</span>
<div className="text-xs text-muted-foreground/70 mt-1">
{configurationTarget === "workspace"
{configurationTarget === CONFIGURATION_TARGET.WORKSPACE
? "Saved to .vscode/settings.json • Best for team collaboration"
: "Saved to user settings • Best for personal workflow"}
</div>
Expand All @@ -50,13 +54,13 @@ export const Header = () => {
className="border-border hover:bg-accent"
onClick={toggleConfigurationTarget}
title={
configurationTarget === "workspace"
configurationTarget === CONFIGURATION_TARGET.WORKSPACE
? "Switch to Global settings (personal commands)"
: "Switch to Workspace settings (team commands)"
}
variant="outline"
>
{configurationTarget === "workspace" ? "📁 Workspace" : "🌐 Global"}
{configurationTarget === CONFIGURATION_TARGET.WORKSPACE ? "📁 Workspace" : "🌐 Global"}
</Button>
</div>
</div>
Expand Down
21 changes: 12 additions & 9 deletions src/web-view/src/context/vscode-command-context.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { createContext, useContext, useEffect, useState, type ReactNode } from "react";

import { MESSAGE_TYPE, MESSAGES, CONFIGURATION_TARGET } from "../../../shared/constants";
import { vscodeApi, isDevelopment } from "../core/vscode-api.tsx";
import { mockCommands } from "../mock/mock-data.tsx";
import { type ButtonConfig } from "../types";
Expand All @@ -20,7 +21,7 @@ const VscodeCommandContext = createContext<VscodeCommandContextType | undefined>
export const useVscodeCommand = () => {
const context = useContext(VscodeCommandContext);
if (context === undefined) {
throw new Error("useVscodeCommand must be used within a VscodeCommandProvider");
throw new Error(MESSAGES.ERROR.contextRequired("useVscodeCommand"));
}
return context;
};
Expand All @@ -31,7 +32,9 @@ type VscodeCommandProviderProps = {

export const VscodeCommandProvider = ({ children }: VscodeCommandProviderProps) => {
const [commands, setCommands] = useState<ButtonConfig[]>([]);
const [configurationTarget, setConfigurationTargetState] = useState<string>("workspace");
const [configurationTarget, setConfigurationTargetState] = useState<string>(
CONFIGURATION_TARGET.WORKSPACE
);

useEffect(() => {
if (isDevelopment) {
Expand All @@ -40,18 +43,18 @@ export const VscodeCommandProvider = ({ children }: VscodeCommandProviderProps)
}

const requestConfig = () => {
vscodeApi.postMessage({ type: "getConfig" });
vscodeApi.postMessage({ type: MESSAGE_TYPE.GET_CONFIG });
};

const handleMessage = (event: MessageEvent) => {
const message = event.data;
if (message?.type === "configData") {
if (message?.type === MESSAGE_TYPE.CONFIG_DATA) {
if (message.data && typeof message.data === "object" && message.data.buttons) {
// New format with configurationTarget
setCommands(message.data.buttons || []);
setConfigurationTargetState(message.data.configurationTarget || "workspace");
setConfigurationTargetState(
message.data.configurationTarget || CONFIGURATION_TARGET.WORKSPACE
);
} else {
// Old format (backward compatibility)
setCommands(message.data || []);
}
}
Expand All @@ -68,7 +71,7 @@ export const VscodeCommandProvider = ({ children }: VscodeCommandProviderProps)
vscodeApi.setCurrentData(commands);
return;
}
vscodeApi.postMessage({ data: commands, type: "setConfig" });
vscodeApi.postMessage({ data: commands, type: MESSAGE_TYPE.SET_CONFIG });
};

const addCommand = (command: ButtonConfig) => {
Expand All @@ -94,7 +97,7 @@ export const VscodeCommandProvider = ({ children }: VscodeCommandProviderProps)
const setConfigurationTarget = (target: string) => {
setConfigurationTargetState(target);
if (!isDevelopment) {
vscodeApi.postMessage({ target, type: "setConfigurationTarget" });
vscodeApi.postMessage({ target, type: MESSAGE_TYPE.SET_CONFIGURATION_TARGET });
}
};

Expand Down