Right drawer: retire the More fold — all sections list flat, collapsed by default

This commit is contained in:
Rohit C Prasad
2026-08-21 10:14:01 -07:00
parent 2c9fb7490b
commit d88a196172
8 changed files with 17 additions and 48 deletions
-3
View File
@@ -19,7 +19,6 @@ test("no topbar opener; the Access header IS the ambient glance; expanding edits
// The trust surface is ambient once More is unfolded: the collapsed header always shows
// the summary — and no nudge text ever renders at rest (§23's rule carried over).
await page.getByTestId("rail-more-toggle").click();
const section = page.getByTestId("access-section");
await expect(section.getByTestId("access-summary")).toHaveText("Browser, Slack +1 · 1 folder");
await expect(section.getByText(/recommended/i)).toHaveCount(0);
@@ -45,7 +44,6 @@ test("+ Add a source: full catalog on focus, filter as you type → connect-in-c
}) => {
await page.goto("/");
await page.getByText("Draft the launch note").first().click();
await page.getByTestId("rail-more-toggle").click();
await page.getByTestId("access-toggle").click();
// Focusing the empty input shows the FULL catalog (FB-012) — every available connector
@@ -88,7 +86,6 @@ test("per-session mute round-trips; the summary follows", async ({ page }) => {
await page.goto("/");
await page.getByText("Draft the launch note").first().click();
await page.getByTestId("rail-more-toggle").click();
const section = page.getByTestId("access-section");
await section.getByTestId("access-toggle").click();
const body = page.getByRole("region", { name: "Session access" });
+1 -2
View File
@@ -147,11 +147,10 @@ test("Add a note is a pure append — it lands in the timeline, state untouched"
await expect(detail.getByRole("button", { name: "Mark done" })).toBeVisible();
});
test("journal folds behind More; expanding lists cases once a board exists", async ({ page }) => {
test("journal section lists cases once a board exists", async ({ page }) => {
await planTheWork(page);
// Journal is not a primary section — it sits behind the quiet More row.
await expect(page.getByTestId("rail-toggle-journal")).toHaveCount(0);
await page.getByTestId("rail-more-toggle").click();
await page.getByTestId("rail-toggle-journal").click();
const journal = page.getByTestId("journal-list");
await expect(journal).toBeVisible();
@@ -9,7 +9,6 @@ import { test } from "./fixtures";
const openGmailPane = async (page: import("@playwright/test").Page) => {
await page.goto("/");
await page.getByText("Draft the launch note").first().click();
await page.getByTestId("rail-more-toggle").click(); // Access folds behind More (17th pass)
await page.getByTestId("access-toggle").click();
await page.getByTestId("access-add-source").click();
await page.getByTestId("access-add-gmail").click();
+4 -5
View File
@@ -1,6 +1,6 @@
// UX-037: Files — an explorer over the session's roots behind the More fold. Each root
// opens in the artifact viewer (breadcrumb "Files"), whose folder listings click through
// to subfolders and files. Artifacts stays the curated scratch-only surface beside it.
// UX-037: Files — an explorer over the session's roots. Each root opens in the artifact
// viewer (breadcrumb "Files"), whose folder listings click through to subfolders and
// files. Artifacts stays the curated scratch-only surface beside it.
import { expect } from "@playwright/test";
import { test } from "./fixtures";
@@ -10,8 +10,7 @@ test("Files lists the session roots and browses into a file", async ({ page }) =
await page.getByRole("button", { name: "Send" }).click();
await expect(page.getByText(/Echo: hello/)).toBeVisible();
// Behind More, collapsed by default like every section.
await page.getByTestId("rail-more-toggle").click();
// Collapsed by default like every section (the More fold is gone — owner 2026-08-20).
await page.getByTestId("rail-toggle-files").click();
const row = page.getByTestId("files-root-row").first();
await expect(row).toContainText("scratch");
-1
View File
@@ -10,7 +10,6 @@ test("working directories: add folders with the read-only / read-write gate", as
await page.getByText("Draft the launch note").first().click();
// Expand the rail's Access section.
await page.getByTestId("rail-more-toggle").click(); // Access folds behind More (17th pass)
await page.getByTestId("access-toggle").click();
const dirs = page.getByTestId("drawer-directories");
await expect(dirs.getByText("Folders")).toBeVisible();
-2
View File
@@ -50,7 +50,6 @@ test("channel typeahead: a NAME resolves to the workspace's id-address", async (
}) => {
await page.goto("/");
await page.getByText("Draft the launch note").first().click();
await page.getByTestId("rail-more-toggle").click(); // Access folds behind More (17th pass)
await page.getByTestId("access-toggle").click();
await page.getByRole("button", { name: /Channels · 0/ }).click();
@@ -72,7 +71,6 @@ test("channel typeahead: a NAME resolves to the workspace's id-address", async (
test("channel typeahead: private and not-a-member states are honest", async ({ page }) => {
await page.goto("/");
await page.getByText("Draft the launch note").first().click();
await page.getByTestId("rail-more-toggle").click(); // Access folds behind More (17th pass)
await page.getByTestId("access-toggle").click();
await page.getByRole("button", { name: /Channels · 0/ }).click();
@@ -8,7 +8,6 @@ test("Slack channels drill-down: gating, add (auto-prefixed), remove", async ({
// Open the pinned cowork session, then expand the rail's Access section.
await page.getByText("Draft the launch note").first().click();
await page.getByTestId("rail-more-toggle").click(); // Access folds behind More (17th pass)
await page.getByTestId("access-toggle").click();
const body = page.getByRole("region", { name: "Session access" });
@@ -43,7 +42,6 @@ test("Slack channels drill-down: gating, add (auto-prefixed), remove", async ({
test("recent channels popover: opens on focus, filters, picks", async ({ page }) => {
await page.goto("/");
await page.getByText("Draft the launch note").first().click();
await page.getByTestId("rail-more-toggle").click(); // Access folds behind More (17th pass)
await page.getByTestId("access-toggle").click();
await page.getByRole("button", { name: /Channels · 0/ }).click();
@@ -82,7 +80,6 @@ test("channel add: link URLs resolve, bare #names are rejected with a hint", asy
}) => {
await page.goto("/");
await page.getByText("Draft the launch note").first().click();
await page.getByTestId("rail-more-toggle").click(); // Access folds behind More (17th pass)
await page.getByTestId("access-toggle").click();
await page.getByRole("button", { name: /Channels · 0/ }).click();
+12 -31
View File
@@ -52,9 +52,8 @@ interface Props {
// Fires when a full artifact preview opens/closes, so the app can auto-collapse the left nav
// to give the preview (PDF/webpage/sheet) more room (#3).
onPreviewChange?: (open: boolean) => void;
// §32: the rail is the ONE session panel for every non-chat persona. Artifacts stays
// cowork-only (deliverables; code-family gets "Files" later — slot reserved); the Access
// section (the former Session-settings drawer) renders for all.
// §32: the rail is the ONE session panel for every persona. Artifacts (scratch-side
// deliverables), Files (all roots), and Access all render for every session (UX-036/037).
showArtifacts?: boolean;
personaId?: string;
projectScoped?: boolean;
@@ -119,8 +118,6 @@ export function RightRail({
team: false,
files: false,
});
// Journal + Access sit behind a quiet "More" row (three primary sections max).
const [moreOpen, setMoreOpen] = useState(false);
const autoOpenedProgress = useRef(false);
useEffect(() => {
if (!isLead && running && todo.length > 0 && !autoOpenedProgress.current) {
@@ -135,16 +132,9 @@ export function RightRail({
seenBoardKey.current = openBoardKey;
setOpen((prev) => ({ ...prev, board: true }));
}, [openBoardKey]);
// Access deep links (intro "Configure " etc.) must survive the More fold.
const seenAccessKey = useRef(openAccessKey);
useEffect(() => {
if (openAccessKey === seenAccessKey.current) return;
seenAccessKey.current = openAccessKey;
setMoreOpen(true);
}, [openAccessKey]);
const [artifacts, setArtifacts] = useState<ArtifactInfo[]>([]);
// UX-037 Files: the session's roots (workspace/scratch/grants) — the entry points of
// the file explorer. Fetched lazily when the More fold opens.
// the file explorer.
const [rootDirs, setRootDirs] = useState<RootInfo[]>([]);
const [journal, setJournal] = useState<JournalCase[]>([]);
const [selected, setSelected] = useState<ArtifactInfo | null>(null);
@@ -158,9 +148,9 @@ export function RightRail({
}, [active, sessionId, refreshKey, showArtifacts]);
useEffect(() => {
if (!active || !moreOpen) return;
if (!active) return;
getRoots(sessionId).then(setRootDirs).catch(() => setRootDirs([]));
}, [active, moreOpen, sessionId, refreshKey]);
}, [active, sessionId, refreshKey]);
// Journal cases surface only when a board exists — same visibility rule as the
// Board section, so plain sessions carry zero team chrome.
@@ -372,17 +362,10 @@ export function RightRail({
</RailSection>
)}
{/* Seventeenth pass: three primary sections max — Journal and Access fold
behind a quiet "More" row. Deep links (Access openKey) unfold it. */}
<button
className="rail-more-row"
data-testid="rail-more-toggle"
onClick={() => setMoreOpen((v) => !v)}
>
<Icon name={moreOpen ? "chevronDown" : "chevronRight"} size={13} className="rail-chev" />
<span>More</span>
</button>
{moreOpen && board?.space && journal.length > 0 && (
{/* The More fold is gone (owner call 2026-08-20): every section lists flat,
collapsed by default — with Files added, one extra click hid half the
drawer for no gain. */}
{board?.space && journal.length > 0 && (
<RailSection
title="Journal"
count={String(journal.length)}
@@ -403,7 +386,7 @@ export function RightRail({
{/* UX-037: Files — an explorer over the session's roots. Each root opens in
the artifact viewer, whose folder listings already click through; the
Artifacts section stays the curated scratch-only surface. */}
{moreOpen && rootDirs.length > 0 && (
{rootDirs.length > 0 && (
<RailSection
title="Files"
count={String(rootDirs.length)}
@@ -447,10 +430,8 @@ export function RightRail({
)}
{/* §32: Access — the former Session-settings drawer, one section among peers.
key: its data ownership resets with the conversation, like the old row did.
Stays MOUNTED behind the More fold (hidden, not unmounted) so its openKey
deep links (intro "Configure ", onboarding "Start working") keep firing. */}
<div style={moreOpen ? undefined : { display: "none" }}>
key: its data ownership resets with the conversation, like the old row did. */}
<div>
<AccessSection
key={sessionId}
sessionId={sessionId}