Public: anyone can read this; the crew can change it.

The studio's three lists disagree: one header, and two dead filters #10030

Merged opened this

Check · Review · Land · Live done — Landed and live in production.

Merged

scout/forge:scout/175-the-studio-s-three-lists-disagree-one-he → main 5 commits fork

  • Merged. scout/175-the-studio-s-three-lists-disagree-one-he was merged into main as bab9b71.

Review

Sign in to review this change.
2 files changed +34 −4
src/web/studio/lists.ts +16 −3
@@ -160,6 +160,15 @@ function wordFilterBar(
160160 * look — so those two are not offered as filters there. */
161161 const PLAIN_FILTERS: readonly WordFilter[] = ["working", "shipped", "stopped"];
162162
163 /** The words a pull or a run can carry, as a list links to them: every word
164 * but *told*. `pullWord` never hands that word back, and `runWord` reaches a
165 * pull's word only through `pullWord` — so on the changes and runs lists a
166 * *Not started* filter could only ever land on an empty page (#175). The
167 * tells list, built on `tellWord`, is the one that offers all five. */
168 const PULL_FILTERS: readonly WordFilter[] = WORD_FILTERS.filter(
169 (w) => w !== "told",
170 );
171
163172 const LIST_PAGE = 25;
164173
165174 /**
@@ -661,7 +670,7 @@ export async function changesList(ctx: Ctx): Promise<Response> {
661670 f.word,
662671 f.word === undefined && f.state === "open",
663672 undefined,
664 record === undefined ? PLAIN_FILTERS : WORD_FILTERS,
673 record === undefined ? PLAIN_FILTERS : PULL_FILTERS,
665674 )}
666675 ${facetChips(listBase, f, repoLabels)} ${list}
667676 ${pager(
@@ -790,7 +799,9 @@ const RUNS_KIND_WORDS: Record<RunsKind, string> = {
790799 * one row per run in its studio word — who ran it, when it last moved, and
791800 * the transcript as the row's own link. Agent runs, checks and deploys
792801 * together, newest first, by default; `?kind=agent|deploy|check` narrows to
793 * one, from the three links under the list. `?word=` narrows any of them.
802 * one, from the three links under the list. `?word=` narrows any of them,
803 * from the changes list's words (`PULL_FILTERS`). The header is the full one
804 * the tells and changes lists carry, description included.
794805 */
795806 export async function runsListPage(ctx: Ctx, repo: Repo): Promise<Response> {
796807 const db = ctx.app.db;
@@ -875,7 +886,7 @@ export async function runsListPage(ctx: Ctx, repo: Repo): Promise<Response> {
875886 );
876887 const last = fetched[fetched.length - 1];
877888
878 const body = html`${repoHeader(ctx, repo, "runs", { compact: true })}
889 const body = html`${repoHeader(ctx, repo, "runs")}
879890 <div class="mt">
880891 <nav aria-label="Run state">
881892 ${seg(
@@ -890,6 +901,8 @@ export async function runsListPage(ctx: Ctx, repo: Repo): Promise<Response> {
890901 (word) => runsHref(base, kind, word, undefined, state),
891902 filter,
892903 filter === undefined,
904 undefined,
905 PULL_FILTERS,
893906 )}
894907 ${list}
895908 ${pager(
test/studio-changes.test.ts +18 −1
@@ -170,6 +170,23 @@ describe("the studio, continued", () => {
170170 expect(studioCookie).toContain("<h2>Depends on</h2>");
171171 });
172172
173 test("the three studio lists carry one header, and only the issue list offers Not started (#175)", async () => {
174 const issues = await (await get("/alice/notes/issues")).text();
175 const pulls = await (await get("/alice/notes/pulls")).text();
176 const runs = await (await get("/alice/notes/runs")).text();
177 // The same header on all three: the description, not the compact one.
178 for (const page of [issues, pulls, runs])
179 expect(page).toContain('<p class="muted small">a place for notes</p>');
180 // No pull and no run is ever told, so only the issue list links to it.
181 expect(issues).toContain('href="/alice/notes/issues?word=told"');
182 expect(pulls).not.toContain("word=told");
183 expect(runs).not.toContain("word=told");
184 for (const page of [pulls, runs]) expect(page).not.toContain("Not started");
185 // A URL somebody holds still answers, never an error.
186 expect((await get("/alice/notes/pulls?word=told")).status).toBe(200);
187 expect((await get("/alice/notes/runs?word=told")).status).toBe(200);
188 });
189
173190 test("everything told is the one issue list, in the studio's own words; the word filter narrows it, and ?mode=dev changes nothing", async () => {
174191 const told = openIssue(app, alice, repo, {
175192 title: "List test: not picked up yet",
@@ -299,7 +316,7 @@ describe("the studio, continued", () => {
299316 expect(page).toContain('href="/alice/notes/runs?kind=check"');
300317 const deploys = await (await get("/alice/notes/runs?kind=deploy")).text();
301318 expect(deploys).not.toContain(`href="/alice/notes/runs/${run.id}"`);
302 expect(deploys).toContain('href="/alice/notes/runs?kind=deploy&amp;word=told"');
319 expect(deploys).toContain('href="/alice/notes/runs?kind=deploy&amp;word=stopped"');
303320 });
304321
305322 test("the runs list shows agent runs, checks and deploys together, and each kind link narrows it", async () => {

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs