mirror of
https://github.com/Termix-SSH/Termix.git
synced 2026-10-28 06:05:24 +00:00
fix(split-screen): allow layout creation without randomUUID (#1490)
* fix(split-screen): allow layout creation without randomUUID * test(credentials): avoid flaky Ed25519 key generation
This commit is contained in:
1 parent
4e652720af
commit
107cf55d8c
3 files changed
+103
-2
No files matched your search
@@ -0,0 +1,98 @@
|
|||||||
|
import { readFileSync } from "node:fs";
|
||||||
|
import { runInNewContext } from "node:vm";
|
||||||
|
import ts from "typescript";
|
||||||
|
import { expect, it, vi } from "vitest";
|
||||||
|
import {
|
||||||
|
assignTabsToSplit,
|
||||||
|
createSplitConfig,
|
||||||
|
} from "../src/ui/shell/splitTabUtils";
|
||||||
|
import type { Tab, SplitMode } from "../src/types/ui-types";
|
||||||
|
|
||||||
|
const source = readFileSync(
|
||||||
|
new URL("../src/ui/AppShell.tsx", import.meta.url),
|
||||||
|
"utf8",
|
||||||
|
);
|
||||||
|
const ast = ts.createSourceFile(
|
||||||
|
"AppShell.tsx",
|
||||||
|
source,
|
||||||
|
ts.ScriptTarget.Latest,
|
||||||
|
true,
|
||||||
|
ts.ScriptKind.TSX,
|
||||||
|
);
|
||||||
|
const functions: string[] = [];
|
||||||
|
function visit(node: ts.Node) {
|
||||||
|
if (
|
||||||
|
ts.isFunctionDeclaration(node) &&
|
||||||
|
["splitTabQuick", "selectSplitMode"].includes(node.name?.text ?? "")
|
||||||
|
)
|
||||||
|
functions.push(node.getText(ast));
|
||||||
|
ts.forEachChild(node, visit);
|
||||||
|
}
|
||||||
|
visit(ast);
|
||||||
|
const code = ts.transpileModule(functions.join("\n"), {
|
||||||
|
compilerOptions: { target: ts.ScriptTarget.ES2022 },
|
||||||
|
}).outputText;
|
||||||
|
|
||||||
|
function shell(crypto: object, activeTabId = "terminal-1") {
|
||||||
|
let tabs = [
|
||||||
|
{ id: "dashboard", type: "dashboard" },
|
||||||
|
{ id: "terminal-1", type: "terminal" },
|
||||||
|
{ id: "terminal-2", type: "terminal" },
|
||||||
|
] as Tab[];
|
||||||
|
const setActiveTabId = vi.fn();
|
||||||
|
const setSplitMode = vi.fn();
|
||||||
|
const context = {
|
||||||
|
tabs,
|
||||||
|
activeTabId,
|
||||||
|
crypto,
|
||||||
|
PANE_COUNTS: { "2-way": 2, "4-way": 4 },
|
||||||
|
defaultSizes: () => ({ rowSizes: [100], rowColSizes: [[50, 50]] }),
|
||||||
|
assignTabsToSplit,
|
||||||
|
createSplitConfig,
|
||||||
|
setTabs: (update: (tabs: Tab[]) => Tab[]) => {
|
||||||
|
tabs = update(tabs);
|
||||||
|
},
|
||||||
|
setActiveTabId,
|
||||||
|
setSplitMode,
|
||||||
|
setPaneTabIds: vi.fn(),
|
||||||
|
setRowSizes: vi.fn(),
|
||||||
|
setRowColSizes: vi.fn(),
|
||||||
|
changeSplitMode: vi.fn(),
|
||||||
|
doCloseTab: vi.fn(),
|
||||||
|
};
|
||||||
|
const select = runInNewContext(`${code}\nselectSplitMode`, context) as (
|
||||||
|
mode: SplitMode,
|
||||||
|
) => void;
|
||||||
|
return { select, getTabs: () => tabs, setActiveTabId, setSplitMode };
|
||||||
|
}
|
||||||
|
|
||||||
|
it.each(["terminal-1", "dashboard"])(
|
||||||
|
"selects a split layout without randomUUID from %s",
|
||||||
|
(active) => {
|
||||||
|
const state = shell({}, active);
|
||||||
|
state.select("2-way");
|
||||||
|
const tabs = state.getTabs();
|
||||||
|
const split = tabs.find((tab) => tab.type === "split-screen")!;
|
||||||
|
expect(split).toBeDefined();
|
||||||
|
expect(split.instanceId).toBeTruthy();
|
||||||
|
expect(split.splitConfig?.paneTabIds.slice(0, 2)).toEqual([
|
||||||
|
"terminal-1",
|
||||||
|
"terminal-2",
|
||||||
|
]);
|
||||||
|
expect(tabs.find((tab) => tab.id === "terminal-1")?.parentSplitTabId).toBe(
|
||||||
|
split.id,
|
||||||
|
);
|
||||||
|
expect(state.setActiveTabId).toHaveBeenCalledWith(split.id);
|
||||||
|
expect(state.setSplitMode).toHaveBeenCalledWith("2-way");
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
it("uses native UUIDs when available", () => {
|
||||||
|
const randomUUID = vi.fn(() => "native-id");
|
||||||
|
const state = shell({ randomUUID });
|
||||||
|
state.select("2-way");
|
||||||
|
expect(randomUUID).toHaveBeenCalledOnce();
|
||||||
|
expect(
|
||||||
|
state.getTabs().find((tab) => tab.type === "split-screen")?.instanceId,
|
||||||
|
).toBe("native-id");
|
||||||
|
});
|
||||||
@@ -328,7 +328,7 @@ describe("ctx.credentials.registerSecretResolver", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe("ctx.credentials.listSshKeys", () => {
|
describe("ctx.credentials.listSshKeys", () => {
|
||||||
const pair = ssh2.utils.generateKeyPairSync("ed25519");
|
const pair = ssh2.utils.generateKeyPairSync("rsa", { bits: 2048 });
|
||||||
const derived = (() => {
|
const derived = (() => {
|
||||||
const parsed = ssh2.utils.parseKey(pair.private);
|
const parsed = ssh2.utils.parseKey(pair.private);
|
||||||
const key = Array.isArray(parsed) ? parsed[0] : parsed;
|
const key = Array.isArray(parsed) ? parsed[0] : parsed;
|
||||||
|
|||||||
+4
-1
@@ -1926,7 +1926,10 @@ export function AppShell({
|
|||||||
}
|
}
|
||||||
const splitNumber =
|
const splitNumber =
|
||||||
tabs.filter((tab) => tab.type === "split-screen").length + 1;
|
tabs.filter((tab) => tab.type === "split-screen").length + 1;
|
||||||
const instanceId = crypto.randomUUID();
|
const instanceId =
|
||||||
|
typeof crypto.randomUUID === "function"
|
||||||
|
? crypto.randomUUID()
|
||||||
|
: `${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}-${Math.random().toString(36).slice(2)}`;
|
||||||
const id = `split-${instanceId}`;
|
const id = `split-${instanceId}`;
|
||||||
const sizes = defaultSizes(mode);
|
const sizes = defaultSizes(mode);
|
||||||
const splitTab: Tab = {
|
const splitTab: Tab = {
|
||||||
|
|||||||
Reference in new issue
Block a user