mirror of
https://github.com/Termix-SSH/Termix.git
synced 2026-10-31 23:55:23 +00:00
* feat: shell controller, TabStage, layout and theme plugins with repair view * feat: move the classic layout into its own bundled plugin * feat: move color themes into a bundled themes plugin * fix: plugin tests and type checks work with a linked sdk * fix: home tab, layout switch and missing layout fallbacks for looks * chore: add classic layout and themes to the readme * chore: drop example plugin links from the plugin guide * feat: plugin filters by type, paged browse, hide plugins needing newer termix * feat: move desktop, status, import, audit and branding features into plugins * feat: host lock api so a plugin can load hosts from a config file (#1581) * chore: add hosts config to the plugin table * feat: login policy hook for plugins and optional https redirect (#1584) * chore: add login security to the plugin table * feat: api key socket tickets so a master can open remote sessions (#1654) * feat: sync moves to a plugin, desktop gets multiple accounts (#1580, #1654) * chore: add sync to the plugin table * feat: move the sync screens and wizard out of core into the plugin (#1580) * fix: add a neutral linked desktop hook for plugins (#1580) * fix: show the linked account's name and admin flag in the app (#1580) * feat: ssh transport providers, core ssh relay and plugin folders api * feat: support FIDO2 security keys through ssh agent * feat: add companion panels beside host tabs * feat: mTLS client certificates for desktop server links * feat: native web view for plugins in the desktop app * fix: detect the desktop link window by Electron's default user agent Fixes #1675 * fix: changelog for desktop link fix * fix: keep text primary keys in the plugin data export * fix: ship sharp binaries for Windows arm64 builds * feat: client cert on the sync link types (sdk 1.0.18) * chore: update translations * feat: themed title bar for the desktop app (#1690) * chore: changelog for the themed title bar * fix: draw the title bar in the sidebar color * feat: per host layout for the terminal panel bar * chore: sdk 1.0.19 for the panel bar layout * chore: bundle all 43 plugins for 26.10.3 * chore: update translations --------- Co-authored-by: SirHephaistos <60616553+SirHephaistos@users.noreply.github.com> Co-authored-by: Giovanny Aranda <garanda21@gmail.com>
122 lines
3.4 KiB
TypeScript
122 lines
3.4 KiB
TypeScript
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
|
|
const index = vi.hoisted(() => ({ ids: [] as string[] }));
|
|
vi.mock("../../plugins/bundled-index.js", () => ({
|
|
defaultLookPluginIds: () => index.ids,
|
|
}));
|
|
|
|
import {
|
|
installedLayoutIds,
|
|
resolveDefaultLook,
|
|
safeLayoutForced,
|
|
unavailableLooks,
|
|
} from "../../plugins/looks.js";
|
|
import type { SkippedPlugin } from "../../plugins/loader.js";
|
|
|
|
type Contributes = Record<string, unknown>;
|
|
|
|
function loaderWith(
|
|
plugins: Record<string, Contributes>,
|
|
skipped: SkippedPlugin[] = [],
|
|
) {
|
|
return {
|
|
get: (id: string) =>
|
|
plugins[id]
|
|
? ({ manifest: { contributes: plugins[id] } } as never)
|
|
: undefined,
|
|
list: () =>
|
|
Object.values(plugins).map(
|
|
(contributes) => ({ manifest: { contributes } }) as never,
|
|
),
|
|
skipped: () => skipped,
|
|
};
|
|
}
|
|
|
|
beforeEach(() => {
|
|
index.ids = [];
|
|
});
|
|
afterEach(() => {
|
|
delete process.env.TERMIX_SAFE_LAYOUT;
|
|
});
|
|
|
|
describe("resolveDefaultLook", () => {
|
|
it("is empty without a default-look plugin", () => {
|
|
expect(resolveDefaultLook(loaderWith({}))).toEqual({
|
|
layout: null,
|
|
theme: null,
|
|
});
|
|
});
|
|
|
|
it("takes the layout marked default and its theme", () => {
|
|
index.ids = ["look-a"];
|
|
const loader = loaderWith({
|
|
"look-a": {
|
|
layouts: [
|
|
{ id: "first", label: "First", defaultTheme: "one" },
|
|
{ id: "main", label: "Main", defaultTheme: "two", default: true },
|
|
],
|
|
},
|
|
});
|
|
expect(resolveDefaultLook(loader)).toEqual({
|
|
layout: "main",
|
|
theme: "two",
|
|
});
|
|
});
|
|
|
|
it("takes the first layout, and a theme from a themes-only plugin", () => {
|
|
index.ids = ["look-a", "look-b"];
|
|
const loader = loaderWith({
|
|
"look-a": { themes: [{ id: "paper", label: "Paper" }] },
|
|
"look-b": { layouts: [{ id: "solo", label: "Solo" }] },
|
|
});
|
|
expect(resolveDefaultLook(loader)).toEqual({
|
|
layout: "solo",
|
|
theme: "paper",
|
|
});
|
|
});
|
|
|
|
it("skips a default-look plugin that did not load", () => {
|
|
index.ids = ["gone"];
|
|
expect(resolveDefaultLook(loaderWith({}))).toEqual({
|
|
layout: null,
|
|
theme: null,
|
|
});
|
|
});
|
|
});
|
|
|
|
describe("unavailableLooks", () => {
|
|
it("lists only skipped plugins that brought a layout or theme", () => {
|
|
const skipped: SkippedPlugin[] = [
|
|
{ id: "a", version: "1.0.0", layouts: ["x"], themes: [], error: "e" },
|
|
{ id: "b", version: null, layouts: [], themes: [], error: "e" },
|
|
{ id: "c", version: "2.0.0", layouts: [], themes: ["t"], error: "e" },
|
|
];
|
|
expect(
|
|
unavailableLooks(loaderWith({}, skipped)).map((plugin) => plugin.id),
|
|
).toEqual(["a", "c"]);
|
|
});
|
|
});
|
|
|
|
describe("safeLayoutForced", () => {
|
|
it("reads TERMIX_SAFE_LAYOUT", () => {
|
|
expect(safeLayoutForced()).toBe(false);
|
|
process.env.TERMIX_SAFE_LAYOUT = "1";
|
|
expect(safeLayoutForced()).toBe(true);
|
|
process.env.TERMIX_SAFE_LAYOUT = "true";
|
|
expect(safeLayoutForced()).toBe(true);
|
|
process.env.TERMIX_SAFE_LAYOUT = "0";
|
|
expect(safeLayoutForced()).toBe(false);
|
|
});
|
|
});
|
|
|
|
describe("installedLayoutIds", () => {
|
|
it("lists layouts of loaded and skipped plugins", () => {
|
|
const ids = installedLayoutIds(
|
|
loaderWith({ a: { layouts: [{ id: "one" }], themes: [{ id: "t" }] } }, [
|
|
{ id: "b", version: null, layouts: ["two"], themes: [], error: "x" },
|
|
]),
|
|
);
|
|
expect([...ids].sort()).toEqual(["one", "two"]);
|
|
});
|
|
});
|