Skip to content

Commit 20fad7a

Browse files
committed
add files i forgot
1 parent a30cdf2 commit 20fad7a

File tree

7 files changed

+191
-787
lines changed

7 files changed

+191
-787
lines changed

apps/array/src/api/fetcher.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ export const buildApiFetcher: (config: {
44
apiToken: string;
55
onTokenRefresh?: () => Promise<string>;
66
}) => Parameters<typeof createApiClient>[0] = (config) => {
7+
let currentToken = config.apiToken;
8+
79
const makeRequest = async (
810
input: Parameters<Parameters<typeof createApiClient>[0]["fetch"]>[0],
911
token: string,
@@ -51,13 +53,14 @@ export const buildApiFetcher: (config: {
5153

5254
return {
5355
fetch: async (input) => {
54-
let response = await makeRequest(input, config.apiToken);
56+
let response = await makeRequest(input, currentToken);
5557

5658
// Handle 401 with automatic token refresh
5759
if (!response.ok && response.status === 401 && config.onTokenRefresh) {
5860
try {
5961
const newToken = await config.onTokenRefresh();
60-
response = await makeRequest(input, newToken);
62+
currentToken = newToken;
63+
response = await makeRequest(input, currentToken);
6164
} catch {
6265
// Token refresh failed - throw the original 401 error
6366
const errorResponse = await response.json();

apps/array/src/renderer/features/panels/store/panelLayoutStore.test.ts

Lines changed: 120 additions & 115 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,14 @@
11
import {
22
assertActiveTab,
3-
assertActiveTabInNestedPanel,
43
assertGroupStructure,
54
assertPanelLayout,
65
assertTabCount,
7-
assertTabInNestedPanel,
8-
closeMultipleTabs,
96
findPanelById,
107
type GroupNode,
118
getLayout,
129
getNestedPanel,
1310
getPanelTree,
1411
openMultipleFiles,
15-
splitAndAssert,
16-
testSizePreservation,
1712
withRootGroup,
1813
} from "@test/panelTestHelpers";
1914
import { beforeEach, describe, expect, it } from "vitest";
@@ -44,16 +39,17 @@ describe("panelLayoutStore", () => {
4439

4540
withRootGroup("task-1", (root: GroupNode) => {
4641
assertGroupStructure(root, {
47-
direction: "horizontal",
42+
direction: "vertical",
4843
childCount: 2,
4944
sizes: [70, 30],
5045
});
5146

5247
assertPanelLayout(root, [
48+
{ panelId: "main-panel", expectedTabs: ["logs"], activeTab: "logs" },
5349
{
54-
panelId: "main-panel",
55-
expectedTabs: ["logs", "shell"],
56-
activeTab: "logs",
50+
panelId: "terminal-panel",
51+
expectedTabs: ["shell"],
52+
activeTab: "shell",
5753
},
5854
]);
5955
});
@@ -68,11 +64,11 @@ describe("panelLayoutStore", () => {
6864
it("adds file tab to main panel", () => {
6965
usePanelLayoutStore.getState().openFile("task-1", "src/App.tsx");
7066

71-
assertTabCount(getPanelTree("task-1"), "main-panel", 3);
67+
assertTabCount(getPanelTree("task-1"), "main-panel", 2);
7268
assertPanelLayout(getPanelTree("task-1"), [
7369
{
7470
panelId: "main-panel",
75-
expectedTabs: ["logs", "shell", "file-src/App.tsx"],
71+
expectedTabs: ["logs", "file-src/App.tsx"],
7672
},
7773
]);
7874
});
@@ -173,13 +169,15 @@ describe("panelLayoutStore", () => {
173169
assertActiveTab(getPanelTree("task-1"), "main-panel", "file-src/App.tsx");
174170
});
175171

176-
it("falls back to shell when last file tab closed", () => {
177-
closeMultipleTabs("task-1", "main-panel", [
178-
"file-src/App.tsx",
179-
"file-src/Other.tsx",
180-
]);
172+
it("falls back to logs when last file tab closed", () => {
173+
usePanelLayoutStore
174+
.getState()
175+
.closeTab("task-1", "main-panel", "file-src/App.tsx");
176+
usePanelLayoutStore
177+
.getState()
178+
.closeTab("task-1", "main-panel", "file-src/Other.tsx");
181179

182-
assertActiveTab(getPanelTree("task-1"), "main-panel", "shell");
180+
assertActiveTab(getPanelTree("task-1"), "main-panel", "logs");
183181
});
184182
});
185183

@@ -222,48 +220,45 @@ describe("panelLayoutStore", () => {
222220
usePanelLayoutStore.getState().initializeTask("task-1");
223221
});
224222

225-
it(
226-
"preserves custom panel sizes when opening a file",
227-
testSizePreservation("opening a file", () => {
228-
openMultipleFiles("task-1", ["src/App.tsx"]);
229-
}, [50, 50]),
230-
);
223+
it("preserves custom panel sizes when opening a file", () => {
224+
usePanelLayoutStore
225+
.getState()
226+
.updateSizes("task-1", "left-group", [60, 40]);
231227

232-
it(
233-
"preserves custom panel sizes when switching tabs",
234-
testSizePreservation("switching tabs", () => {
235-
openMultipleFiles("task-1", ["src/App.tsx", "src/Other.tsx"]);
236-
usePanelLayoutStore
237-
.getState()
238-
.setActiveTab("task-1", "main-panel", "file-src/App.tsx");
239-
}, [60, 40]),
240-
);
228+
openMultipleFiles("task-1", ["src/App.tsx"]);
241229

242-
it(
243-
"preserves custom panel sizes when closing tabs",
244-
testSizePreservation("closing tabs", () => {
245-
openMultipleFiles("task-1", ["src/App.tsx", "src/Other.tsx"]);
246-
usePanelLayoutStore
247-
.getState()
248-
.closeTab("task-1", "main-panel", "file-src/Other.tsx");
249-
}),
250-
);
230+
withRootGroup("task-1", (root) => {
231+
expect(root.sizes).toEqual([60, 40]);
232+
});
233+
});
251234

252-
it(
253-
"preserves custom panel sizes in nested groups when splitting panels",
254-
testSizePreservation("splitting panels", () => {
255-
openMultipleFiles("task-1", ["src/App.tsx", "src/Other.tsx"]);
256-
usePanelLayoutStore
257-
.getState()
258-
.splitPanel(
259-
"task-1",
260-
"file-src/Other.tsx",
261-
"main-panel",
262-
"main-panel",
263-
"right",
264-
);
265-
}, [65, 35]),
266-
);
235+
it("preserves custom panel sizes when switching tabs", () => {
236+
usePanelLayoutStore
237+
.getState()
238+
.updateSizes("task-1", "left-group", [55, 45]);
239+
openMultipleFiles("task-1", ["src/App.tsx", "src/Other.tsx"]);
240+
usePanelLayoutStore
241+
.getState()
242+
.setActiveTab("task-1", "main-panel", "file-src/App.tsx");
243+
244+
withRootGroup("task-1", (root) => {
245+
expect(root.sizes).toEqual([55, 45]);
246+
});
247+
});
248+
249+
it("preserves custom panel sizes when closing tabs", () => {
250+
usePanelLayoutStore
251+
.getState()
252+
.updateSizes("task-1", "left-group", [80, 20]);
253+
openMultipleFiles("task-1", ["src/App.tsx", "src/Other.tsx"]);
254+
usePanelLayoutStore
255+
.getState()
256+
.closeTab("task-1", "main-panel", "file-src/Other.tsx");
257+
258+
withRootGroup("task-1", (root) => {
259+
expect(root.sizes).toEqual([80, 20]);
260+
});
261+
});
267262
});
268263

269264
describe("persistence", () => {
@@ -352,21 +347,23 @@ describe("panelLayoutStore", () => {
352347
});
353348

354349
it("reorders tabs within a panel", () => {
355-
usePanelLayoutStore.getState().reorderTabs("task-1", "main-panel", 2, 3);
350+
// tabs: [logs, file-src/App.tsx, file-src/Other.tsx, file-src/Third.tsx]
351+
// move index 1 to index 3
352+
usePanelLayoutStore.getState().reorderTabs("task-1", "main-panel", 1, 3);
356353

357354
const panel = findPanelById(getPanelTree("task-1"), "main-panel");
358355
const tabIds = panel?.content.tabs.map((t: { id: string }) => t.id);
359-
expect(tabIds?.[2]).toBe("file-src/Other.tsx");
356+
expect(tabIds?.[1]).toBe("file-src/Other.tsx");
360357
expect(tabIds?.[3]).toBe("file-src/App.tsx");
361358
});
362359

363360
it("preserves active tab after reorder", () => {
364361
usePanelLayoutStore
365362
.getState()
366363
.setActiveTab("task-1", "main-panel", "file-src/App.tsx");
367-
usePanelLayoutStore.getState().reorderTabs("task-1", "main-panel", 0, 2);
364+
usePanelLayoutStore.getState().reorderTabs("task-1", "main-panel", 1, 3);
368365

369-
assertActiveTabInNestedPanel("task-1", "file-src/App.tsx", "left");
366+
assertActiveTab(getPanelTree("task-1"), "main-panel", "file-src/App.tsx");
370367
});
371368
});
372369

@@ -376,39 +373,42 @@ describe("panelLayoutStore", () => {
376373
usePanelLayoutStore.getState().openFile("task-1", "src/App.tsx");
377374
});
378375

379-
it("moves tab to different panel", () => {
376+
it("moves tab between panels", () => {
380377
usePanelLayoutStore
381378
.getState()
382-
.moveTab("task-1", "file-src/App.tsx", "main-panel", "top-right");
379+
.moveTab("task-1", "file-src/App.tsx", "main-panel", "terminal-panel");
383380

384-
assertTabInNestedPanel("task-1", "file-src/App.tsx", false, "left");
385-
assertTabInNestedPanel(
386-
"task-1",
387-
"file-src/App.tsx",
388-
true,
389-
"right",
390-
"left",
381+
const mainPanel = findPanelById(getPanelTree("task-1"), "main-panel");
382+
const terminalPanel = findPanelById(
383+
getPanelTree("task-1"),
384+
"terminal-panel",
391385
);
386+
387+
expect(
388+
mainPanel?.content.tabs.find((t) => t.id === "file-src/App.tsx"),
389+
).toBeUndefined();
390+
expect(
391+
terminalPanel?.content.tabs.find((t) => t.id === "file-src/App.tsx"),
392+
).toBeDefined();
392393
});
393394

394395
it("sets moved tab as active in target panel", () => {
395396
usePanelLayoutStore
396397
.getState()
397-
.moveTab("task-1", "file-src/App.tsx", "main-panel", "top-right");
398+
.moveTab("task-1", "file-src/App.tsx", "main-panel", "terminal-panel");
398399

399-
assertActiveTabInNestedPanel(
400-
"task-1",
400+
assertActiveTab(
401+
getPanelTree("task-1"),
402+
"terminal-panel",
401403
"file-src/App.tsx",
402-
"right",
403-
"left",
404404
);
405405
});
406406
});
407407

408408
describe("splitPanel", () => {
409409
beforeEach(() => {
410410
usePanelLayoutStore.getState().initializeTask("task-1");
411-
usePanelLayoutStore.getState().openFile("task-1", "src/App.tsx");
411+
openMultipleFiles("task-1", ["src/App.tsx", "src/Other.tsx"]);
412412
});
413413

414414
it.each([
@@ -419,12 +419,23 @@ describe("panelLayoutStore", () => {
419419
] as const)(
420420
"splits panel %s creates %s layout",
421421
(direction, expectedDirection) => {
422-
splitAndAssert(
423-
"task-1",
424-
"file-src/App.tsx",
425-
direction,
426-
expectedDirection,
427-
);
422+
usePanelLayoutStore
423+
.getState()
424+
.splitPanel(
425+
"task-1",
426+
"file-src/App.tsx",
427+
"main-panel",
428+
"main-panel",
429+
direction,
430+
);
431+
432+
// After split, main-panel becomes a group
433+
const mainPanelNode = getNestedPanel("task-1", 0);
434+
expect(mainPanelNode.type).toBe("group");
435+
if (mainPanelNode.type === "group") {
436+
expect(mainPanelNode.direction).toBe(expectedDirection);
437+
expect(mainPanelNode.children).toHaveLength(2);
438+
}
428439
},
429440
);
430441

@@ -439,19 +450,19 @@ describe("panelLayoutStore", () => {
439450
"right",
440451
);
441452

442-
assertTabInNestedPanel(
443-
"task-1",
444-
"file-src/App.tsx",
445-
true,
446-
"left",
447-
"right",
448-
);
449-
assertActiveTabInNestedPanel(
450-
"task-1",
451-
"file-src/App.tsx",
452-
"left",
453-
"right",
454-
);
453+
// After right split: main-panel becomes a group with [original, new]
454+
const mainPanelNode = getNestedPanel("task-1", 0);
455+
expect(mainPanelNode.type).toBe("group");
456+
if (mainPanelNode.type === "group") {
457+
const newPanel = mainPanelNode.children[1];
458+
expect(newPanel.type).toBe("leaf");
459+
if (newPanel.type === "leaf") {
460+
expect(
461+
newPanel.content.tabs.some((t) => t.id === "file-src/App.tsx"),
462+
).toBe(true);
463+
expect(newPanel.content.activeTabId).toBe("file-src/App.tsx");
464+
}
465+
}
455466
});
456467
});
457468

@@ -461,31 +472,20 @@ describe("panelLayoutStore", () => {
461472
});
462473

463474
it("updates panel group sizes", () => {
464-
usePanelLayoutStore.getState().updateSizes("task-1", "root", [60, 40]);
465-
466-
withRootGroup("task-1", (root: GroupNode) => {
467-
expect(root.sizes).toEqual([60, 40]);
468-
});
469-
});
470-
471-
it("updates nested group sizes", () => {
472475
usePanelLayoutStore
473476
.getState()
474-
.updateSizes("task-1", "right-group", [30, 70]);
477+
.updateSizes("task-1", "left-group", [60, 40]);
475478

476-
const rightGroup = getNestedPanel("task-1", "right");
477-
assertGroupStructure(rightGroup, {
478-
direction: "vertical",
479-
childCount: 2,
480-
sizes: [30, 70],
479+
withRootGroup("task-1", (root: GroupNode) => {
480+
expect(root.sizes).toEqual([60, 40]);
481481
});
482482
});
483483
});
484484

485485
describe("tree cleanup", () => {
486486
beforeEach(() => {
487487
usePanelLayoutStore.getState().initializeTask("task-1");
488-
usePanelLayoutStore.getState().openFile("task-1", "src/App.tsx");
488+
openMultipleFiles("task-1", ["src/App.tsx", "src/Other.tsx"]);
489489
});
490490

491491
it("removes empty panels after closing all tabs", () => {
@@ -499,13 +499,18 @@ describe("panelLayoutStore", () => {
499499
"right",
500500
);
501501

502-
const newPanel = getNestedPanel("task-1", "left", "right");
503-
usePanelLayoutStore
504-
.getState()
505-
.closeTab("task-1", newPanel.id, "file-src/App.tsx");
502+
// Find the new panel and close its tab
503+
const mainPanelNode = getNestedPanel("task-1", 0);
504+
if (mainPanelNode.type === "group") {
505+
const newPanel = mainPanelNode.children[1];
506+
usePanelLayoutStore
507+
.getState()
508+
.closeTab("task-1", newPanel.id, "file-src/App.tsx");
509+
}
506510

507-
const updatedLeftPanel = getNestedPanel("task-1", "left");
508-
expect(updatedLeftPanel.type).toBe("leaf");
511+
// After closing, the group should simplify back to a leaf
512+
const updatedMainPanel = getNestedPanel("task-1", 0);
513+
expect(updatedMainPanel.type).toBe("leaf");
509514
});
510515
});
511516
});

0 commit comments

Comments
 (0)