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:
ZacharyZcR authored and GitHub committed 2026-09-27 17:36:01 -05:00
1 parent 4e652720af
commit 107cf55d8c
3 files changed
+103 -2

No files matched your search

+98
View File
@@ -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
View File
@@ -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 = {