* 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.
140 lines
4.9 KiB
TypeScript
140 lines
4.9 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
import type { GitAction, GitActions } from "@/git/policy";
|
|
import type { KeyboardActionDefinition } from "@/keyboard/keyboard-action-dispatcher";
|
|
import {
|
|
buildWorkspaceCommandCenterContributions,
|
|
type WorkspaceCommandCenterSource,
|
|
} from "./workspace-contributions";
|
|
|
|
function gitAction(id: GitAction["id"], label: string): GitAction {
|
|
return {
|
|
id,
|
|
label,
|
|
pendingLabel: `${label} pending`,
|
|
successLabel: `${label} complete`,
|
|
disabled: false,
|
|
status: "idle",
|
|
startsGroup: false,
|
|
handler: () => undefined,
|
|
};
|
|
}
|
|
|
|
function source(gitActions: GitActions): {
|
|
value: WorkspaceCommandCenterSource;
|
|
runGitActions: GitAction[];
|
|
dispatched: KeyboardActionDefinition[];
|
|
} {
|
|
const runGitActions: GitAction[] = [];
|
|
const dispatched: KeyboardActionDefinition[] = [];
|
|
return {
|
|
value: {
|
|
gitActions,
|
|
labels: {
|
|
section: "Workspace actions",
|
|
newAgent: "New agent",
|
|
newTerminal: "New terminal",
|
|
newBrowser: "New browser",
|
|
splitRight: "Split pane right",
|
|
splitDown: "Split pane down",
|
|
},
|
|
icons: {},
|
|
shortcuts: {},
|
|
capabilities: { canSplitPanes: true, canOpenBrowserTabs: true },
|
|
dispatch: (action) => dispatched.push(action),
|
|
runGitAction: (action) => runGitActions.push(action),
|
|
},
|
|
runGitActions,
|
|
dispatched,
|
|
};
|
|
}
|
|
|
|
describe("workspace command center contributions", () => {
|
|
it("makes only the policy-selected primary Git action default-visible and runs it", () => {
|
|
const primary = gitAction("commit", "Commit");
|
|
const fixture = source({
|
|
primary,
|
|
secondary: [gitAction("push", "Push")],
|
|
menu: [],
|
|
});
|
|
|
|
const contributions = buildWorkspaceCommandCenterContributions(fixture.value);
|
|
const gitContributions = contributions.filter((item) => item.id.startsWith("git:"));
|
|
const defaultGitContributions = gitContributions.filter((item) => item.visibility === "always");
|
|
|
|
expect(defaultGitContributions.map((item) => item.id)).toEqual(["git:commit"]);
|
|
defaultGitContributions[0].run();
|
|
expect(fixture.runGitActions).toEqual([primary]);
|
|
});
|
|
|
|
it("does not duplicate a primary action retained in the secondary policy list", () => {
|
|
const primary = gitAction("pull", "Pull");
|
|
const fixture = source({
|
|
primary,
|
|
secondary: [primary, gitAction("push", "Push")],
|
|
menu: [],
|
|
});
|
|
|
|
const contributions = buildWorkspaceCommandCenterContributions(fixture.value);
|
|
|
|
expect(contributions.filter((item) => item.id === "git:pull")).toHaveLength(1);
|
|
});
|
|
|
|
it("orders New agent before Git and keeps terminal, browser, and splits search-only", () => {
|
|
const fixture = source({
|
|
primary: gitAction("commit", "Commit"),
|
|
secondary: [],
|
|
menu: [],
|
|
});
|
|
|
|
const contributions = buildWorkspaceCommandCenterContributions(fixture.value);
|
|
|
|
expect(contributions.map(({ id, rank, visibility }) => ({ id, rank, visibility }))).toEqual([
|
|
{ id: "tab:new-agent", rank: 0, visibility: "always" },
|
|
{ id: "git:commit", rank: 1, visibility: "always" },
|
|
{ id: "tab:new-terminal", rank: 2, visibility: "query" },
|
|
{ id: "tab:new-browser", rank: 3, visibility: "query" },
|
|
{ id: "pane:split-right", rank: 4, visibility: "query" },
|
|
{ id: "pane:split-down", rank: 5, visibility: "query" },
|
|
]);
|
|
});
|
|
|
|
it("omits browser and split actions when their existing capabilities are unavailable", () => {
|
|
const fixture = source({ primary: null, secondary: [], menu: [] });
|
|
fixture.value.capabilities = { canSplitPanes: false, canOpenBrowserTabs: false };
|
|
|
|
const contributions = buildWorkspaceCommandCenterContributions(fixture.value);
|
|
|
|
expect(contributions.map((item) => item.id)).toEqual(["tab:new-agent", "tab:new-terminal"]);
|
|
});
|
|
|
|
it("dispatches every tab and pane command to the workspace scope", () => {
|
|
const fixture = source({ primary: null, secondary: [], menu: [] });
|
|
const contributions = buildWorkspaceCommandCenterContributions(fixture.value);
|
|
|
|
for (const contribution of contributions) contribution.run();
|
|
|
|
expect(fixture.dispatched).toEqual([
|
|
{ id: "workspace.tab.new", scope: "workspace" },
|
|
{ id: "workspace.terminal.new", scope: "workspace" },
|
|
{ id: "workspace.browser.new", scope: "workspace" },
|
|
{ id: "workspace.pane.split.right", scope: "workspace" },
|
|
{ id: "workspace.pane.split.down", scope: "workspace" },
|
|
]);
|
|
});
|
|
|
|
it("keeps workspace creation commands available outside Git", () => {
|
|
const fixture = source({ primary: null, secondary: [], menu: [] });
|
|
|
|
const contributions = buildWorkspaceCommandCenterContributions(fixture.value);
|
|
|
|
expect(contributions.map((item) => item.id)).toEqual([
|
|
"tab:new-agent",
|
|
"tab:new-terminal",
|
|
"tab:new-browser",
|
|
"pane:split-right",
|
|
"pane:split-down",
|
|
]);
|
|
expect(contributions.some((item) => item.id.startsWith("git:"))).toBe(false);
|
|
});
|
|
});
|