feat: move snippets, keybinding actions and macros out of core into plugins

This commit is contained in:
LukeGus committed 2026-09-29 11:39:14 -05:00
1 parent d9bba10612
commit e0c30a4e6f
262 files changed
+9091 -10744

No files matched your search

@@ -42,7 +42,6 @@ function makeHost(overrides: Partial<Host>): Host {
ram: null,
lastAccess: "",
authType: "credential",
quickActions: [],
enableSsh: true,
sshPort: 22,
...overrides,
+3 -4
View File
@@ -428,17 +428,16 @@ describe("connectionOriginAppliesTo", () => {
});
describe("terminal fields", () => {
it("sends only the startup snippet in terminalConfig, and the SSH options on their own", () => {
it("sends no terminalConfig, and the SSH options on their own", () => {
const form = {
...createHostEditorForm(null),
startupSnippetId: 4,
keepaliveInterval: 30,
agentForwarding: true,
environmentVariables: [{ key: "LANG", value: "C" }],
};
const payload = buildHostEditorPayload(form, sshOnly);
expect(payload.terminalConfig).toEqual({ startupSnippetId: 4 });
expect(payload).not.toHaveProperty("terminalConfig");
expect(payload.sshOptions).toMatchObject({
keepaliveInterval: 30,
keepaliveCountMax: 5,
@@ -457,7 +456,7 @@ describe("terminal fields", () => {
expect(form.keepaliveInterval).toBe(15);
expect(form.allowLegacyAlgorithms).toBe(false);
expect(form.startupSnippetId).toBe(2);
expect(form).not.toHaveProperty("startupSnippetId");
});
it("leaves the terminal fields out with SSH off", () => {
@@ -0,0 +1,79 @@
import { afterEach, describe, expect, it, vi } from "vitest";
import { cleanup, fireEvent, render, screen } from "@testing-library/react";
const saved = vi.hoisted(() => ({ value: null as string | null }));
vi.mock("@/api/open-tabs-api", async (importOriginal) => ({
...(await importOriginal<Record<string, unknown>>()),
getUserPreferences: async () => ({ customKeybindings: saved.value }),
}));
vi.mock("@/main-axios", () => ({ saveUserPreferences: vi.fn() }));
const { KeybindingsDialog } = await import("../../sidebar/KeybindingsDialog");
const {
registerKeybindingAction,
registerKeybindingDefault,
resetKeybindingRegistry,
} = await import("../../shell/keybinding-registry");
afterEach(() => {
cleanup();
resetKeybindingRegistry();
saved.value = null;
});
const combo = {
key: "k",
isCode: false,
ctrl: true,
alt: false,
shift: false,
meta: false,
};
describe("KeybindingsDialog", () => {
it("lists registered defaults and keeps a binding whose plugin is off", async () => {
registerKeybindingDefault({
id: "default-x",
pluginId: "sample",
combo,
descriptionKey: "sample:builtInX",
});
saved.value = JSON.stringify([
{
id: "a",
combo,
action: { type: "gone.action" },
enabled: true,
createdAt: "",
updatedAt: "",
},
]);
render(<KeybindingsDialog open onOpenChange={() => {}} />);
expect(await screen.findByText("sample:builtInX")).toBeTruthy();
expect(
await screen.findByText("newUi.sidebar.keybindings.unavailableAction"),
).toBeTruthy();
});
it("offers every registered action and draws the chosen one's editor", async () => {
registerKeybindingAction({
id: "sample.send",
pluginId: "sample",
labelKey: "sample:send",
scope: "session",
editor: () => <span>sample editor</span>,
});
render(<KeybindingsDialog open onOpenChange={() => {}} />);
fireEvent.click(
await screen.findByText("newUi.sidebar.keybindings.addBinding"),
);
const select = (await screen.findByRole("option", { name: "sample:send" }))
.parentElement as HTMLSelectElement;
expect([...select.options].map((option) => option.value)).toContain(
"nextTab",
);
fireEvent.change(select, { target: { value: "sample.send" } });
expect(await screen.findByText("sample editor")).toBeTruthy();
});
});
@@ -14,7 +14,6 @@ const ALL_GROUPS = new Set<FieldGroup>([
"tags",
"proxy",
"jumpHosts",
"quickActions",
"featureFlags",
"advanced",
]);
+6 -7
View File
@@ -52,13 +52,12 @@ describe("RAIL_ITEMS", () => {
// "port-forwarding" to the tunnels plugin's, "serial" to the serial
// plugin's, "collab" to the session-sharing plugin's, and "session-logs"
// to the session-recording plugin's, "termix-id" to the termix-identity
// plugin's, "ssh-tools" to the ssh-terminal plugin's.
// plugin's, "ssh-tools" and "macros" to the ssh-terminal plugin's.
expect(RAIL_ITEMS.map((item) => item.id)).toEqual([
"hosts",
"credentials",
"connections",
"quick-connect",
"macros",
"sync",
]);
});
@@ -80,7 +79,7 @@ describe("RAIL_ITEMS", () => {
[...RAIL_ITEMS, ...RAIL_UTILITY_ITEMS]
.filter((item) => item.promotable)
.map((item) => item.id),
).toEqual(["macros"]);
).toEqual([]);
});
it("derives promotableIds from the promotable flag", () => {
@@ -117,7 +116,7 @@ describe("RAIL_ITEMS", () => {
});
it("only offers reference panels in the right dock", () => {
expect(rightDockableIds()).toEqual(["connections", "macros"]);
expect(rightDockableIds()).toEqual(["connections"]);
});
});
@@ -131,10 +130,10 @@ describe("registered rail items", () => {
});
it("places items after their anchor, keeping their own order", () => {
registerRailItem(item("second", { after: "macros", order: 2 }));
registerRailItem(item("first", { after: "macros", order: 1 }));
registerRailItem(item("second", { after: "connections", order: 2 }));
registerRailItem(item("first", { after: "connections", order: 1 }));
const ids = visibleRailItems().map((entry) => entry.id);
const at = ids.indexOf("macros");
const at = ids.indexOf("connections");
expect(ids.slice(at + 1, at + 3)).toEqual(["first", "second"]);
});
@@ -25,7 +25,6 @@ function host(id: string, name: string): Host {
authType: "password",
pin: false,
enableSsh: true,
quickActions: [],
} as Host;
}
@@ -69,7 +69,6 @@ const baseHost: Host = {
enableRdp: true,
enableVnc: true,
enableTelnet: true,
quickActions: [],
} as unknown as Host;
const noop = () => {};