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

What the crew says about an ask lives in one module, read by the asked and answers views on web and terminal #5639

Merged opened this

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

Merged

mason/forge:mason/5619-what-the-crew-says-about-an-ask-lives-in → main 1 commit fork

  • Merged. mason/5619-what-the-crew-says-about-an-ask-lives-in was merged into main as 7fc0bbc.

Review

Sign in to review this change.
6 files changed +50 −4
src/actions/ask_state_words.ts added +11
@@ -0,0 +1,11 @@
1 /**
2 * What the crew says about where an ask stands (#5619), said from one place
3 * so the asked and answers views read the same on the web and in the
4 * terminal. Plain strings: each caller escapes them as its surface does.
5 */
6
7 /** An ask the planner has not yet put on any issue, and nobody has replied to. */
8 export const NOT_PLACED_YET = "the planner has not placed it yet";
9
10 /** An ask whose issue has a run going and no answer yet. */
11 export const CREW_WORKING = "The crew is working on it.";
src/tui/screens/answers.ts +2 −1
@@ -6,6 +6,7 @@
66 */
77
88 import { answersFor, canSeeAnswers } from "../../web/studio/answers.ts";
9 import { CREW_WORKING } from "../../actions/ask_state_words.ts";
910 import type { Repo } from "../../core/repos.ts";
1011 import type { Ctx, Screen } from "../app/app.ts";
1112 import { binding } from "../app/keys.ts";
@@ -33,7 +34,7 @@ export function answerLines(f: Session, repo: Repo): AnswerLine[] {
3334 secondary:
3435 said === undefined
3536 ? working
36 ? "The crew is working on it."
37 ? CREW_WORKING
3738 : "Waiting for the crew."
3839 : `${plain(said.who)}: ${plain(said.text)}`,
3940 meta: metaOf(said === undefined ? (working ? "working" : "waiting") : "answered", relTime(said?.at ?? issue.createdAt)),
src/tui/screens/asked.ts +2 −1
@@ -9,6 +9,7 @@
99 */
1010
1111 import type { Database } from "bun:sqlite";
12 import { NOT_PLACED_YET } from "../../actions/ask_state_words.ts";
1213 import { askedIn, askedRepos, type Asked } from "../../core/asked.ts";
1314 import { thoughtStream, type StreamThought } from "../../core/thought_stream.ts";
1415 import type { User } from "../../core/users.ts";
@@ -54,7 +55,7 @@ function thoughtLine(t: StreamThought): AskedLine {
5455 title: plain(t.text),
5556 ...toneOf(t.flagged, t.state),
5657 hollow: t.state === "unplaced" || t.state === "superseded",
57 secondary: plain(where.length > 0 ? where.join(" · ") : (t.reply ?? "the planner has not placed it yet")),
58 secondary: plain(where.length > 0 ? where.join(" · ") : (t.reply ?? NOT_PLACED_YET)),
5859 meta: metaOf(t.flagged ? "nothing built" : THOUGHT_WORD[t.state], relTime(t.receivedAt)),
5960 };
6061 }
src/web/studio/answers.ts +2 −1
@@ -9,6 +9,7 @@
99 */
1010
1111 import type { Database } from "bun:sqlite";
12 import { CREW_WORKING } from "../../actions/ask_state_words.ts";
1213 import { getAppByRepo } from "../../core/apps.ts";
1314 import { listComments, listIssues, type Issue } from "../../core/issues.ts";
1415 import { canSeeOwnerFacts, type Repo } from "../../core/repos.ts";
@@ -93,7 +94,7 @@ export function answersRegion(
9394 return html`<li class="answer" data-tell="${issue.number}">
9495 <a href="${tellHref(base, issue.number)}" class="answer-tell">${issue.title}</a>
9596 ${said === undefined
96 ? html`<p class="muted small answer-wait">${working ? "The crew is working on it." : "Waiting for the crew."}</p>`
97 ? html`<p class="muted small answer-wait">${working ? CREW_WORKING : "Waiting for the crew."}</p>`
9798 : html`<p class="answer-said"><b>${said.who}</b> ${time(said.at)}<br />${text}</p>`}
9899 </li>`;
99100 });
src/web/studio/asked_page.ts +2 −1
@@ -25,6 +25,7 @@ import {
2525 type StreamThought,
2626 type ThoughtState,
2727 } from "../../core/thought_stream.ts";
28 import { NOT_PLACED_YET } from "../../actions/ask_state_words.ts";
2829 import { notePhase, takeSessionTime, timePhase } from "../../core/route_timing.ts";
2930 import type { Ctx } from "../../http/context.ts";
3031 import { repoBase, signInFirst } from "../chrome.ts";
@@ -67,7 +68,7 @@ function placedLinks(t: StreamThought): Html {
6768 : html`${x.action} <a href="/${x.repo}/issues/${x.number}">${x.repo} #${x.number}</a>`,
6869 );
6970 return links.length === 0
70 ? html`${t.reply ?? "the planner has not placed it yet"}`
71 ? html`${t.reply ?? NOT_PLACED_YET}`
7172 : html`${links.map((l, i) => html`${i > 0 ? " · " : ""}${l}`)}`;
7273 }
7374
test/ask-state-words.test.ts added +31
@@ -0,0 +1,31 @@
1 /**
2 * Where an ask stands is said from one place (#5619): the asked and answers
3 * views, web and terminal, import the sentences from
4 * `src/actions/ask_state_words.ts` and never type them out again.
5 */
6
7 import { expect, test } from "bun:test";
8 import { readFileSync } from "node:fs";
9 import { join } from "node:path";
10 import { CREW_WORKING, NOT_PLACED_YET } from "../src/actions/ask_state_words.ts";
11
12 const root = join(import.meta.dir, "..");
13 const views = [
14 "src/web/studio/asked_page.ts",
15 "src/tui/screens/asked.ts",
16 "src/web/studio/answers.ts",
17 "src/tui/screens/answers.ts",
18 ];
19
20 test("the sentences read as they always have", () => {
21 expect(NOT_PLACED_YET).toBe("the planner has not placed it yet");
22 expect(CREW_WORKING).toBe("The crew is working on it.");
23 });
24
25 for (const file of views) {
26 test(`${file} imports the ask's state words and types none of them`, () => {
27 const text = readFileSync(join(root, file), "utf8");
28 expect(text).toContain("actions/ask_state_words.ts");
29 for (const sentence of [NOT_PLACED_YET, CREW_WORKING]) expect(text).not.toContain(sentence);
30 });
31 }

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs