Merge pull request #231 from hZsFN/fix/observation-tab-missing-splits

fix(client): guard observationTabOpen against a missing right-column tree (DSH 0.1.5 / better-sidebar 0.19+)
This commit is contained in:
Zhang GH
2026-09-12 11:59:14 +08:00
committed by GitHub
2 changed files with 21 additions and 2 deletions
@@ -64,7 +64,12 @@ export interface SidebarSplitLike {
export type SidebarNodeLike = SidebarLeafLike | SidebarSplitLike;
export interface SidebarStateLike {
splits: SidebarNodeLike;
/**
* Right-column split tree. DSH 0.1.5 (better-sidebar 0.19+) moved the right
* column to dsh's native Sidebar and no longer emits this field, so it is
* optional here; earlier versions always provide it.
*/
splits?: SidebarNodeLike;
bottomSplits: SidebarNodeLike;
/** Whether the right panel is expanded (the merged drawer on narrow screens). */
panelOpen?: boolean;
@@ -170,7 +175,11 @@ function* leafNodes(node: SidebarNodeLike): Generator<SidebarLeafLike> {
/** Whether a tab of our type is already open in either sidebar workbench. */
export function observationTabOpen(state: SidebarStateLike | undefined): boolean {
if (state === undefined) return false;
// A root may be absent even when the snapshot exists: `splits` is gone on
// DSH 0.1.5+ (better-sidebar 0.19+), where the right column belongs to dsh's
// native Sidebar. Guard before walking so we do not dereference undefined.
for (const root of [state.splits, state.bottomSplits]) {
if (root === undefined) continue;
for (const leaf of leafNodes(root)) {
if (leaf.tabs.some((tab) => tab.type === OBSERVATION_TAB_TYPE)) return true;
}
@@ -117,7 +117,7 @@ function withTabOpened(state: SidebarStateLike, type: string): SidebarStateLike
}
return { ...node, children: node.children.map(walk) };
};
return { ...state, splits: walk(state.splits) };
return { ...state, splits: state.splits === undefined ? undefined : walk(state.splits) };
}
function makeSidebar(
@@ -280,6 +280,16 @@ describe("observationTabOpen", () => {
};
expect(observationTabOpen(inBottom)).toBe(true);
});
it("does not crash when the right-column tree is absent (DSH 0.1.5+)", () => {
// better-sidebar 0.19+ no longer emits `splits` (the right column moved to
// dsh's native Sidebar); the walk must skip absent roots, not dereference.
const noSplits: SidebarStateLike = {
bottomSplits: { kind: "leaf", id: "p2", active: null, tabs: [] },
};
expect(() => observationTabOpen(noSplits)).not.toThrow();
expect(observationTabOpen(noSplits)).toBe(false);
});
});
describe("ObservationSidebarTab", () => {