Bring a revealed sheet to the top instead of duplicating it as a tab

This commit is contained in:
Mohamed Boudra
2026-10-14 17:58:43 +02:00
parent 6abf6e4690
commit d61a6d2880
3 changed files with 25 additions and 13 deletions
+2 -1
View File
@@ -31,7 +31,8 @@ switcher keeps only agents and terminals. A panel kind opts in with `compactShee
sheet and tab, so callers open targets the same way on every layout. Each sheet holds one ordinary
`WorkspaceTab`, and sheets stack: a target opened from a sheet covers it, and closing the top sheet
(drag, Close, backdrop, or Android Back) uncovers the one below. Revealing a target that already has
a sheet drops the sheets above it. Opening a sheet as a tab dismisses the sheets above it, since the
a sheet brings that sheet back to the top and closes the sheets above it, except ones holding unsaved
work. Opening a sheet as a tab dismisses the sheets above it, since the
tab would sit under them. The stack is not persisted.
Sheets are modal and cover the whole compact column, header included. A sheet's header is its drag
@@ -4878,19 +4878,26 @@ describe("compact workspace sheet", () => {
});
});
it("opens a stacked target as a tab rather than dropping a modified sheet above it", () => {
it("brings a covered sheet back to the top and keeps a modified sheet above it beneath", () => {
const store = createCompactStore();
const otherTarget = { kind: "file" as const, path: "src/other.ts" };
store.getState().openTab({ workspaceKey, target: otherTarget, intent: "reveal" });
const otherTabId = store
.getState()
.openTab({ workspaceKey, target: otherTarget, intent: "reveal" });
const modifiedSheetTabId = openModifiedFileSheet(store);
const focusedBefore = focusedTabId(store);
const tabId = store
.getState()
.openTab({ workspaceKey, target: otherTarget, intent: "reveal" });
expect(sheetTabId(store)).toBe(modifiedSheetTabId);
expect(stripTab(store, tabId ?? "")).toMatchObject({ target: otherTarget });
expect(focusedTabId(store)).toBe(tabId);
expect(tabId).toBe(otherTabId);
expect(sheetTargets(store)).toEqual([fileTarget, otherTarget]);
expect(store.getState().sheetsByWorkspace[workspaceKey]?.[0]?.tab.tabId).toBe(
modifiedSheetTabId,
);
expect(stripTab(store, tabId ?? "")).toBeNull();
expect(focusedTabId(store)).toBe(focusedBefore);
});
it("opens a tab target under a modified sheet without closing it", () => {
@@ -864,7 +864,7 @@ function sheetHoldsUnsavedWork(workspaceKey: string, sheet: WorkspaceSheet): boo
/**
* Where an open lands in the sheet stack, or null when it opens as a tab. A new target goes on
* top. A reveal of a resource a sheet already shows keeps that sheet's tab and brings it back to
* the top, closing the sheets above it, unless one of those holds unsaved work.
* the top; the sheets above it close, except ones holding unsaved work, which stay beneath it.
*/
function resolveSheetPlacement(
state: WorkspaceLayoutStore,
@@ -878,11 +878,7 @@ function resolveSheetPlacement(
const sheets = getSheets(state, workspaceKey);
const resourceKey = panelResourceKey(target);
const index = sheets.findIndex((sheet) => panelResourceKey(sheet.tab.target) === resourceKey);
if (index === -1) return { policy, keptIndex: null };
const above = sheets.slice(index + 1);
return above.some((sheet) => sheetHoldsUnsavedWork(workspaceKey, sheet))
? null
: { policy, keptIndex: index };
return { policy, keptIndex: index === -1 ? null : index };
}
/** Closes the sheets because navigation moved on underneath them, except ones with unsaved work. */
@@ -1005,7 +1001,15 @@ export function createWorkspaceLayoutStore(
parentTabId,
state: input.state,
});
const below = keptIndex === null ? sheets : sheets.slice(0, keptIndex);
const below =
keptIndex === null
? sheets
: [
...sheets.slice(0, keptIndex),
...sheets
.slice(keptIndex + 1)
.filter((above) => sheetHoldsUnsavedWork(normalizedWorkspaceKey, above)),
];
set((state) => withSheets(state, normalizedWorkspaceKey, [...below, sheet]));
return sheet.tab.tabId;
}