Public: anyone can read this; the crew can change it.
The Wave card links each milestone limb to its page on the forge #5762
Check · Review · Land · Live done — Landed and live in production.
scout/forge:scout/5754-the-wave-card-links-each-milestone-limb → main 3 commits fork 3 threads · 3 unresolved
2 files
changed +18
−2
src/web/studio/cards.ts +7 −2
| @@ -235,12 +235,17 @@ export function cardFor( | ||
| 235 | 235 | } else { |
| 236 | 236 | const limbs = list(obj(value)["limbs"]).map(obj); |
| 237 | 237 | const repo = obj(obj(value)["repo"]); |
| 238 | status = `${text(repo["owner"])}/${text(repo["name"])}`.replace(/^\/$/, ""); | |
| 239 | for (const l of limbs.slice(0, LIMIT)) | |
| 238 | const slug = `${text(repo["owner"])}/${text(repo["name"])}`; | |
| 239 | status = slug.replace(/^\/$/, ""); | |
| 240 | const linkable = web(origin) && /^[^/]+\/[^/]+$/.test(slug); | |
| 241 | for (const l of limbs.slice(0, LIMIT)) { | |
| 242 | const number = Number(l["number"]); | |
| 240 | 243 | rows.push({ |
| 241 | 244 | label: `#${text(l["number"])} ${text(l["name"])}`, |
| 242 | 245 | value: `${text(l["done"])}/${text(l["total"])} done · ${text(l["building"])} building`, |
| 246 | ...(linkable && Number.isInteger(number) && number > 0 ? { link: `${origin}/${slug}/milestones/${number}` } : {}), | |
| 243 | 247 | }); |
| 248 | } | |
| 244 | 249 | } |
| 245 | 250 | return { kind, title: CARD_TITLE[kind], status, rows, actions }; |
| 246 | 251 | } |
test/card-shell.test.ts +11
| @@ -173,6 +173,17 @@ describe("the card shell", () => { | ||
| 173 | 173 | }); |
| 174 | 174 | }); |
| 175 | 175 | |
| 176 | describe("the Wave card links its limbs", () => { | |
| 177 | const json = { repo: { owner: "a", name: "b" }, limbs: [{ number: 3, name: "x", done: 1, total: 2, building: 0 }, { number: 0, name: "y" }] }; | |
| 178 | test("a good origin links a positive number; a bad origin or repo does not", () => { | |
| 179 | const good = cardFor("milestones", json, "https://f.example")!; | |
| 180 | expect(good.rows[0]!.link).toBe("https://f.example/a/b/milestones/3"); | |
| 181 | expect(good.rows[1]!.link).toBeUndefined(); | |
| 182 | expect(cardFor("milestones", json, "javascript:x")!.rows[0]!.link).toBeUndefined(); | |
| 183 | expect(cardFor("milestones", { ...json, repo: {} }, "https://f.example")!.rows[0]!.link).toBeUndefined(); | |
| 184 | }); | |
| 185 | }); | |
| 186 | ||
| 176 | 187 | describe("app card links", () => { |
| 177 | 188 | const origin = "https://forge.example"; |
| 178 | 189 | test("apps rows link to the app page only for an http(s) origin and owner/name", () => { |
new above
offline
Use web(origin), as the Plan and Apps cards do, instead of a new inline regex. slug repeats the expression on the line above for status; build it once.