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

The command palette and the nav's repository list leave archived repositories out #3482

Merged opened this

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

Merged

scout/forge:scout/3475-the-command-palette-and-the-nav-s-reposi → main 1 commit fork 1 thread · 1 unresolved

  • Merged. scout/3475-the-command-palette-and-the-nav-s-reposi was merged into main as b38af38.

Review

Sign in to review this change.
2 files changed +75 −1
src/web/layout.ts +3 −1
@@ -295,10 +295,12 @@ function paletteIndex(ctx: Ctx, extra: PaletteItem[]): Html {
295295 // One forge (#603): a conversation's remote row is built with the
296296 // studio's nouns, which answer for every repository.
297297 const studio = true;
298 // Apps first, then the other repositories, thirty in all.
298 // Apps first, then the other repositories, thirty in all; archived ones
299 // are put away, found by typing the full name into search.
299300 const repos = listReposVisibleTo(ctx.app.db, ctx.auth.user, {
300301 limit: 30,
301302 appsFirst: true,
303 withoutArchived: true,

Good: reuses the existing option. The comment says archived repos are found by typing the full name into search, but nothing in the palette does that; either test it or reword to point at explore.

302304 });
303305 const apps = appsForRepos(
304306 ctx.app.db,
test/palette-archived.test.ts added +72
@@ -0,0 +1,72 @@
1 /**
2 * The palette's repository rows leave an archived repository out and bring
3 * it back when it is woken; its own page still answers 200.
4 */
5 import { afterAll, beforeAll, expect, test } from "bun:test";
6 import { mkdtemp, rm } from "node:fs/promises";
7 import { tmpdir } from "node:os";
8 import { join } from "node:path";
9 import { createApp, type App } from "../src/app.ts";
10 import { createRepo } from "../src/actions/repos.ts";
11 import type { Repo } from "../src/core/repos.ts";
12 import { createUser } from "../src/core/users.ts";
13 import { serve, type Servers } from "../src/http/server.ts";
14 import { setArchivedIn } from "./helpers/archive.ts";
15 import { quietLogs } from "./helpers/globals.ts";
16
17 quietLogs();
18
19 let dataDir = "";
20 let app: App;
21 let servers: Servers;
22 let cookie = "";
23 let sleeper: Repo;
24
25 beforeAll(async () => {
26 dataDir = await mkdtemp(join(tmpdir(), "forge-palette-archived-"));
27 app = createApp({ dataDir, port: 0 });
28 servers = await serve(app);
29 const made = await createUser(app.db, {
30 origin: "seed",
31 trusted: true,
32 username: "alice",
33 email: "[email protected]",
34 password: "a-long-palette-passphrase",
35 adminIfFirst: true,
36 });
37 if (!made.ok) throw new Error(made.error);
38 const res = await fetch(`${servers.url}/signin`, {
39 method: "POST",
40 body: new URLSearchParams({ username: "alice", password: "a-long-palette-passphrase" }),
41 redirect: "manual",
42 });
43 cookie = (res.headers.get("set-cookie") ?? "").split(";")[0]!;
44 for (const name of ["awake", "sleeper"]) {
45 const r = await createRepo(app, made.value, { name, visibility: "public" });
46 if (!r.ok) throw new Error(String(r.error));
47 if (name === "sleeper") sleeper = r.value;
48 }
49 }, 30_000);
50
51 afterAll(async () => {
52 await servers.stop();
53 await rm(dataDir, { recursive: true, force: true });
54 });
55
56 const rows = async (): Promise<string[]> => {
57 const html = await (await fetch(`${servers.url}/explore`, { headers: { cookie } })).text();
58 const m = /<script type="application\/json" id="palette-index">([\s\S]*?)<\/script>/.exec(html);
59 if (m === null) throw new Error("no palette index");
60 return (JSON.parse(m[1]!) as { items: { t: string }[] }).items.map((i) => i.t);
61 };
62
63 test("archived leaves the palette, waking brings it back, its page answers 200", async () => {
64 expect(await rows()).toContain("alice/sleeper");
65 setArchivedIn(app.db, sleeper, true);
66 const away = await rows();
67 expect(away).toContain("alice/awake");
68 expect(away).not.toContain("alice/sleeper");
69 expect((await fetch(`${servers.url}/alice/sleeper`, { headers: { cookie } })).status).toBe(200);
70 setArchivedIn(app.db, sleeper, false);
71 expect(await rows()).toContain("alice/sleeper");
72 });

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs