ReleasesIndexPage
is an async component
Every package the codebase has, each a link to its own page (releaseHref): its latest release and when, and
whether a release waits (something under its namespace changed since its latest), not worked out further here (its
page says what version, and why); those waiting first, then those up to date, then those never released, the
codebase's own first among its kind. q narrows them to names and descriptions with it.
import { publishingList, unchangedSince } from "#codebase/tcmts/cli/release_pages"; import { ago, at, Html, markdownHtml, projectNow, shareNow } from "#codebase/tcmts/share"; import { releaseHref, StudioFrame, studioShare } from "#codebase/tcmts/studio"; export async function ReleasesIndexPage({ q }: { q: string }) { studioShare(); const s = shareNow(); if (!s.signedIn) return ( <StudioFrame tab="releases" title="Sign in"> {null} </StudioFrame> ); const own = projectNow(s).name; const words = q.trim().toLowerCase(); const all = publishingList(s.cb).map((p) => { const latest = s.cb.store.releases(p.name)[0]; const state: "waits" | "current" | "new" = !latest ? "new" : unchangedSince(s.cb, latest.causal, p.namespace) ? "current" : "waits"; return { ...p, state }; }); const order = { waits: 0, current: 1, new: 2 }; const shown = all .filter((p) => !words || `${p.name} ${p.description ?? ""}`.toLowerCase().includes(words)) .sort( (a, b) => order[a.state] - order[b.state] || Number(b.name === own) - Number(a.name === own) || a.name.localeCompare(b.name), ); const waiting = all.filter((p) => p.state === "waits").length; return ( <StudioFrame tab="releases" title="Releases"> <div className="pagehead"> <h2 className="title">Releases</h2> <span className="muted"> {all.length} package{all.length === 1 ? "" : "s"} {waiting ? `, ${waiting} with changes since their latest release` : ""} </span> {all.length > 6 && ( <form className="right" action={at("/releases")} method="get"> <input className="field" type="search" name="q" defaultValue={q} placeholder="Find a package" aria-label="Find a package" style={{ height: 30 }} /> </form> )} </div> {!all.length ? ( <div className="box"> <div className="empty"> No packages yet: a <code>manifest</code> says what one holds ( <a href="https://tcm.codes/docs/publishing.html">publishing</a>). </div> </div> ) : ( <div className="box"> {shown.map((p) => ( <a className="lib relrow" key={p.name} href={releaseHref(p.name)}> <div> <span className="name mono">{p.name}</span>{" "} <span className="muted mono" style={{ fontSize: 12.5 }}> {p.namespace} </span> {p.description && ( <Html className="desc md" html={markdownHtml(s.cb, p.description.split("\n")[0]!)} /> )} </div> <div className="stat"> {p.latest ? ( <> <b className="mono">{p.latest.version}</b> {ago(p.latest.ts)} </> ) : ( <span className="muted">not released</span> )} </div> <div className="meta"> {p.state === "waits" ? ( <span className="warn">changed since {p.latest?.version}: a release waits</span> ) : p.state === "current" ? ( <span className="ok">up to date</span> ) : ( <span>its first release would be 0.1.0</span> )} <span> {p.releases} release{p.releases === 1 ? "" : "s"} </span> </div> </a> ))} {!shown.length && ( <div className="empty">No package has “{q}” in its name or description.</div> )} </div> )} </StudioFrame> ); }
uses
- tcmts.cli.release_pages.publishingList
- tcmts.cli.release_pages.unchangedSince
- tcmts.share.Html
- tcmts.share.ago
- tcmts.share.at
- tcmts.share.markdownHtml
- tcmts.share.projectNow
- tcmts.share.shareNow
- tcmts.studio.StudioFrame
- tcmts.studio.releaseHref
- tcmts.studio.studioShare