Make the command center stable and workspace-aware (#2749)
* feat(app): expand command center actions Keep command center navigation stable by revealing only clipped rows without smooth centering. Prioritize a concise default list while making workspace, Git, pane, and creation actions searchable through the existing contribution and action-policy paths. * test(app): search for query-only command action Add project is intentionally absent from the unfiltered command center. Exercise the overlay flow through search before selecting it.
This commit is contained in:
@@ -0,0 +1,175 @@
|
||||
import type { GitAction, GitActions } from "@/git/policy";
|
||||
import type { KeyboardActionDefinition } from "@/keyboard/keyboard-action-dispatcher";
|
||||
import type { ShortcutKey } from "@/utils/format-shortcut";
|
||||
import type { CommandCenterContribution, CommandCenterIcon } from "./contributions";
|
||||
|
||||
export interface WorkspaceCommandCenterLabels {
|
||||
section: string;
|
||||
newAgent: string;
|
||||
newTerminal: string;
|
||||
newBrowser: string;
|
||||
splitRight: string;
|
||||
splitDown: string;
|
||||
}
|
||||
|
||||
export interface WorkspaceCommandCenterIcons {
|
||||
newAgent?: CommandCenterIcon;
|
||||
newTerminal?: CommandCenterIcon;
|
||||
newBrowser?: CommandCenterIcon;
|
||||
splitRight?: CommandCenterIcon;
|
||||
splitDown?: CommandCenterIcon;
|
||||
git?(action: GitAction): CommandCenterIcon | undefined;
|
||||
}
|
||||
|
||||
export interface WorkspaceCommandCenterShortcuts {
|
||||
newAgent?: ShortcutKey[][];
|
||||
newTerminal?: ShortcutKey[][];
|
||||
splitRight?: ShortcutKey[][];
|
||||
splitDown?: ShortcutKey[][];
|
||||
archiveWorkspace?: ShortcutKey[][];
|
||||
}
|
||||
|
||||
export interface WorkspaceCommandCenterSource {
|
||||
gitActions: GitActions;
|
||||
labels: WorkspaceCommandCenterLabels;
|
||||
icons: WorkspaceCommandCenterIcons;
|
||||
shortcuts: WorkspaceCommandCenterShortcuts;
|
||||
capabilities: {
|
||||
canSplitPanes: boolean;
|
||||
canOpenBrowserTabs: boolean;
|
||||
};
|
||||
dispatch(action: KeyboardActionDefinition): void;
|
||||
runGitAction(action: GitAction): void;
|
||||
}
|
||||
|
||||
function buildGitContribution(
|
||||
source: WorkspaceCommandCenterSource,
|
||||
action: GitAction,
|
||||
rank: number,
|
||||
visibility: "always" | "query",
|
||||
): CommandCenterContribution {
|
||||
return {
|
||||
id: `git:${action.id}`,
|
||||
group: "workspace",
|
||||
groupRank: -1,
|
||||
rank,
|
||||
keywords: [action.id, "git"],
|
||||
visibility,
|
||||
run: () => source.runGitAction(action),
|
||||
presentation: {
|
||||
kind: "action",
|
||||
title: action.label,
|
||||
sectionTitle: source.labels.section,
|
||||
icon: source.icons.git?.(action),
|
||||
shortcutKeys:
|
||||
action.id === "archive-workspace" ? source.shortcuts.archiveWorkspace : undefined,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function buildWorkspaceAction(input: {
|
||||
source: WorkspaceCommandCenterSource;
|
||||
id: string;
|
||||
rank: number;
|
||||
title: string;
|
||||
keywords: readonly string[];
|
||||
icon?: CommandCenterIcon;
|
||||
shortcutKeys?: ShortcutKey[][];
|
||||
action: KeyboardActionDefinition;
|
||||
visibility: "always" | "query";
|
||||
}): CommandCenterContribution {
|
||||
return {
|
||||
id: input.id,
|
||||
group: "workspace",
|
||||
groupRank: -1,
|
||||
rank: input.rank,
|
||||
keywords: input.keywords,
|
||||
visibility: input.visibility,
|
||||
run: () => input.source.dispatch(input.action),
|
||||
presentation: {
|
||||
kind: "action",
|
||||
title: input.title,
|
||||
sectionTitle: input.source.labels.section,
|
||||
icon: input.icon,
|
||||
shortcutKeys: input.shortcutKeys,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export function buildWorkspaceCommandCenterContributions(
|
||||
source: WorkspaceCommandCenterSource,
|
||||
): CommandCenterContribution[] {
|
||||
const contributions: CommandCenterContribution[] = [
|
||||
buildWorkspaceAction({
|
||||
source,
|
||||
id: "tab:new-agent",
|
||||
rank: 0,
|
||||
title: source.labels.newAgent,
|
||||
keywords: ["tab", "new", "agent", "chat"],
|
||||
icon: source.icons.newAgent,
|
||||
shortcutKeys: source.shortcuts.newAgent,
|
||||
action: { id: "workspace.tab.new", scope: "workspace" },
|
||||
visibility: "always",
|
||||
}),
|
||||
];
|
||||
const primary = source.gitActions.primary;
|
||||
if (primary) contributions.push(buildGitContribution(source, primary, 1, "always"));
|
||||
contributions.push(
|
||||
buildWorkspaceAction({
|
||||
source,
|
||||
id: "tab:new-terminal",
|
||||
rank: 2,
|
||||
title: source.labels.newTerminal,
|
||||
keywords: ["terminal", "shell", "console"],
|
||||
icon: source.icons.newTerminal,
|
||||
shortcutKeys: source.shortcuts.newTerminal,
|
||||
action: { id: "workspace.terminal.new", scope: "workspace" },
|
||||
visibility: "query",
|
||||
}),
|
||||
);
|
||||
if (source.capabilities.canOpenBrowserTabs) {
|
||||
contributions.push(
|
||||
buildWorkspaceAction({
|
||||
source,
|
||||
id: "tab:new-browser",
|
||||
rank: 3,
|
||||
title: source.labels.newBrowser,
|
||||
keywords: ["browser", "web", "preview"],
|
||||
icon: source.icons.newBrowser,
|
||||
action: { id: "workspace.browser.new", scope: "workspace" },
|
||||
visibility: "query",
|
||||
}),
|
||||
);
|
||||
}
|
||||
if (source.capabilities.canSplitPanes) {
|
||||
contributions.push(
|
||||
buildWorkspaceAction({
|
||||
source,
|
||||
id: "pane:split-right",
|
||||
rank: 4,
|
||||
title: source.labels.splitRight,
|
||||
keywords: ["split", "pane", "vertical"],
|
||||
icon: source.icons.splitRight,
|
||||
shortcutKeys: source.shortcuts.splitRight,
|
||||
action: { id: "workspace.pane.split.right", scope: "workspace" },
|
||||
visibility: "query",
|
||||
}),
|
||||
buildWorkspaceAction({
|
||||
source,
|
||||
id: "pane:split-down",
|
||||
rank: 5,
|
||||
title: source.labels.splitDown,
|
||||
keywords: ["split", "pane", "horizontal"],
|
||||
icon: source.icons.splitDown,
|
||||
shortcutKeys: source.shortcuts.splitDown,
|
||||
action: { id: "workspace.pane.split.down", scope: "workspace" },
|
||||
visibility: "query",
|
||||
}),
|
||||
);
|
||||
}
|
||||
for (const [index, action] of source.gitActions.secondary.entries()) {
|
||||
if (action.id === primary?.id) continue;
|
||||
contributions.push(buildGitContribution(source, action, 10 + index, "query"));
|
||||
}
|
||||
return contributions;
|
||||
}
|
||||
Reference in New Issue
Block a user