Files
paseo/packages/app/src/panels/panel-manifest.test.ts
T
Mohamed Boudraandpaseo-bot[bot] e135e9c101 Open files and subagents in a closable sheet on phones (#6827)
* feat(app): open files and subagents in a closable sheet on compact

On phones, opening a file, a provider subagent, or a Paseo subagent now shows it
in a bottom sheet over the current tab instead of adding a tab, so the tab strip
stays for terminals and root agents. Paseo subagents get "Open as tab" to move
the same tab (same tabId and state) into a full tab with a composer; agents in a
sheet hide the composer.

The decision lives in the workspace layout store's openTab, driven by a
per-kind `compactSheet` rule in the panel manifest, so every open path (chat
links, Explorer, subagents track, notifications, plugins) follows it without
call-site branching, and a new kind opts in with one manifest entry. The app
shell publishes the layout mode (compact / single-pane / split-panes) once, so
callers stop passing isCompact for placement.

A sheet holding unsaved edits is never implicitly displaced; later opens go to
tabs underneath, and closing it goes through the existing discard guard. The
editor host is position: sticky because CodeMirror's scrollIntoView otherwise
scrolls the bottom sheet's container and drags the sheet to full height.

* test(app): fail the compact sheet snap check when the sheet is oversized

---------

Co-authored-by: paseo-bot[bot] <paseo-bot[bot]@users.noreply.github.com>
2026-10-14 00:20:10 +07:00

55 lines
2.5 KiB
TypeScript

import { describe, expect, it } from "vitest";
import {
getPanelManifest,
panelCanLaunchInPane,
panelResourceKey,
panelSupportsHost,
} from "@/panels/panel-manifest";
describe("panel manifest", () => {
it("answers host support without React panel registration", () => {
expect(panelSupportsHost("agent", "main")).toBe(true);
expect(panelSupportsHost("agent", "explorer")).toBe(true);
expect(panelSupportsHost("file", "explorer")).toBe(true);
expect(panelSupportsHost("working_diff", "explorer")).toBe(true);
expect(panelSupportsHost("new_tab", "explorer")).toBe(true);
expect(panelSupportsHost("files", "explorer")).toBe(true);
expect(panelSupportsHost("files", "main")).toBe(false);
expect(panelSupportsHost("setup", "explorer")).toBe(false);
});
it("supports the sheet exactly for kinds with a compact sheet rule", () => {
expect(panelSupportsHost("file", "sheet")).toBe(true);
expect(panelSupportsHost("agent", "sheet")).toBe(true);
expect(panelSupportsHost("provider_subagent", "sheet")).toBe(true);
expect(panelSupportsHost("terminal", "sheet")).toBe(false);
expect(panelSupportsHost("plugin", "sheet")).toBe(false);
});
it("lets navigation tabs hide their close button without losing their close action", () => {
expect(getPanelManifest("files").showCloseButton).toBe(false);
expect(getPanelManifest("changes_tree").showCloseButton).toBe(false);
expect(getPanelManifest("agent").showCloseButton).toBe(true);
expect(getPanelManifest("terminal").showCloseButton).toBe(true);
expect(getPanelManifest("file").showCloseButton).toBe(true);
expect(getPanelManifest("working_diff").showCloseButton).toBe(true);
});
it("hides a singleton launch only when it already exists in the destination pane", () => {
expect(panelCanLaunchInPane("files", ["files"])).toBe(false);
expect(panelCanLaunchInPane("changes_tree", ["changes_tree"])).toBe(false);
expect(panelCanLaunchInPane("files", ["changes_tree"])).toBe(true);
expect(panelCanLaunchInPane("files", [])).toBe(true);
expect(panelCanLaunchInPane("terminal", ["terminal"])).toBe(true);
});
it("keeps durable resource identity separate from transient target input", () => {
expect(
panelResourceKey({ kind: "working_diff", focusPath: "src/a.ts", focusRequestId: 1 }),
).toBe(panelResourceKey({ kind: "working_diff", focusPath: "src/b.ts", focusRequestId: 2 }));
expect(panelResourceKey({ kind: "file", path: "src/a.ts" })).not.toBe(
panelResourceKey({ kind: "file", path: "src/b.ts" }),
);
});
});