Skip to the content

Capsid menu

app/routes/admin._index.tsx

189 lines and 12 functions in DrDustinEdwards/dustinedwards-info, at commit 1590ba4 on 2026-10-24. This file on GitHub.

Functions

The functions of admin._index.tsx
FunctionLinesComplexityCoveredCRAPMutation
meta20 to 221No data: no coverage report in this mapNo data: no coverage report in this mapNo data: no mutants in this code
loader25 to 491No data: no coverage report in this mapNo data: no coverage report in this mapNo data: no mutants in this code
<anonymous:26>26 to 481No data: no coverage report in this mapNo data: no coverage report in this mapNo data: no mutants in this code
<anonymous:31>31 to 311No data: no coverage report in this mapNo data: no coverage report in this mapNo data: no mutants in this code
<anonymous:32>32 to 321No data: no coverage report in this mapNo data: no coverage report in this mapNo data: no mutants in this code
PassingChecks54 to 652No data: no coverage report in this mapNo data: no coverage report in this mapNo data: no mutants in this code
<anonymous:58>58 to 611No data: no coverage report in this mapNo data: no coverage report in this mapNo data: no mutants in this code
AdminOverview67 to 20617No data: no coverage report in this mapNo data: no coverage report in this mapNo data: no mutants in this code
<anonymous:70>70 to 701No data: no coverage report in this mapNo data: no coverage report in this mapNo data: no mutants in this code
<anonymous:74>74 to 741No data: no coverage report in this mapNo data: no coverage report in this mapNo data: no mutants in this code
<anonymous:117>117 to 1392No data: no coverage report in this mapNo data: no coverage report in this mapNo data: no mutants in this code
<anonymous:189>189 to 2001No data: no coverage report in this mapNo data: no coverage report in this mapNo data: no mutants in this code

Imports

It imports app/lib/admin/check-copy.mjs, app/lib/context.ts, app/lib/health/checks.server.ts, app/lib/operator/api.server.ts, app/lib/search/ask.server.ts, app/lib/timing.ts. No module of this repo imports it.

Source

import { Form, data } from "react-router";

import { Banner } from "capsomer/react/banner";
import { Button } from "capsomer/react/button";
import { Disclosure } from "capsomer/react/disclosure";
import { Panel } from "capsomer/react/panel";
import { Row, RowList } from "capsomer/react/row-list";
import { Pill, Status } from "capsomer/react/status";
import { StatTile, StatTiles } from "capsomer/react/stat-tile";

import { PageHead } from "capsomer/react/page-head";
import { timed, timedLoader } from "~/lib/timing";
import { humanCheck, statusSentence } from "~/lib/admin/check-copy.mjs";
import { runHealthChecks } from "~/lib/health/checks.server";
import { syncStatus } from "~/lib/operator/api.server";
import { getEnv } from "~/lib/context";
import { askStatusContext } from "~/lib/search/ask.server";
import type { Route } from "./+types/admin._index";

export function meta() {
  return [{ title: "Overview ยท Admin" }, { name: "robots", content: "noindex" }];
}

/** Reads the same instruments as /api/health and the operator tool, so it cannot disagree with them. */
export async function loader({ context }: Route.LoaderArgs) {
  return timedLoader(context, async (timings) => {
    const env = getEnv(context);

    const [health, stores] = await Promise.all([
      /* The same memoized Ask listing the layout's badge uses, so the page lists the index once, not twice. */
      timed(timings, "overview_health", () => runHealthChecks(env, { timings, askStatus: context.get(askStatusContext) })),
      timed(timings, "overview_stores", () => syncStatus(env)),
    ]);

    return data({
      checks: health.checks,
      stores: {
        headSha: stores.headSha,
        artifactPosts: stores.artifactPosts,
        d1Posts: stores.d1Posts,
        d1PubliclyVisible: stores.d1PubliclyVisible,
        searchIndexDocs: stores.searchIndexDocs,
        askConfigured: stores.askConfigured,
        githubConfigured: stores.githubConfigured,
        divergences: stores.divergences,
      },
    });
  });
}

type Check = Route.ComponentProps["loaderData"]["checks"][number];

/** The passing checks, each named in words with what it found, folded away: nothing in it needs a person. */
function PassingChecks({ checks }: { checks: Check[] }) {
  return (
    <Disclosure summary={`The ${checks.length} passing check${checks.length === 1 ? "" : "s"}`}>
      <RowList label="Passing checks" gap="xs">
        {checks.map((check) => {
          const copy = humanCheck(check);
          return <Row key={check.name} size="sm" title={copy.name} detail={copy.finding} />;
        })}
      </RowList>
    </Disclosure>
  );
}

export default function AdminOverview({ loaderData }: Route.ComponentProps) {
  const { checks, stores } = loaderData;

  const failing = checks.filter((check) => !check.ok);
  const worst = failing[0];
  const worstCopy = worst ? humanCheck(worst) : null;

  const passing = checks.filter((check) => check.ok);
  const lag = stores.d1Posts === stores.artifactPosts;

  return (
    <div className="app-page">
      <PageHead title="Overview" lead={statusSentence(checks)} />

      {/* A banner, not an alert: a standing condition is not announced on every load. */}
      {worst && worstCopy ? (
        <Banner
          tone="crit"
          title={`${worstCopy.name} needs attention`}
          actions={
            worstCopy.repair ? (
              <Form method="post" action={worstCopy.repair.action}>
                <input type="hidden" name="intent" value={worstCopy.repair.intent} />
                <Button type="submit">{worstCopy.repair.label}</Button>
              </Form>
            ) : null
          }
        >
          {worstCopy.finding}
        </Banner>
      ) : null}

      {/* Failures first and loud; the passing checks are a count in the heading and a list one click away
          (Dustin's review, 2026-10-11: a green pill on every row hid the one red one). A repair sits with the
          finding it repairs, so there is no column that is empty whenever nothing fails. */}
      <Panel
        title={failing.length > 0 ? `Checks: ${failing.length} failing, ${passing.length} passing` : `Checks: all ${checks.length} passing`}
        flush={failing.length > 0}
        footer={failing.length > 0 && passing.length > 0 ? <PassingChecks checks={passing} /> : undefined}
      >
        {failing.length > 0 ? (
          <div className="cap-table-wrap" role="region" aria-label="Failing checks" tabIndex={0}>
            <table className="cap-table">
              <thead>
                <tr>
                  <th scope="col">Check</th>
                  <th scope="col">What it found</th>
                </tr>
              </thead>
              <tbody>
                {failing.map((check) => {
                  const copy = humanCheck(check);
                  return (
                    <tr key={check.name}>
                      <th scope="row">
                        {copy.name}
                        {/* Word, shape and colour: three channels, so it still reads under forced-colors. */}
                        <Status tone="crit">failing</Status>
                      </th>
                      <td>
                        {copy.finding}
                        {copy.repair ? (
                          <Form method="post" action={copy.repair.action}>
                            <input type="hidden" name="intent" value={copy.repair.intent} />
                            <Button type="submit" size="sm" aria-label={`${copy.repair.label}: ${copy.name}`}>
                              {copy.repair.label}
                            </Button>
                          </Form>
                        ) : null}
                      </td>
                    </tr>
                  );
                })}
              </tbody>
            </table>
          </div>
        ) : (
          <PassingChecks checks={passing} />
        )}
      </Panel>

      <StatTiles label="Content">
        <StatTile
          label="In the repository"
          figure={stores.artifactPosts}
          unit="posts"
          detail="posts written and committed"
        />
        <StatTile
          label="Live on the site"
          tone={lag ? "ok" : "warn"}
          figure={stores.d1Posts}
          unit="posts"
          word={lag ? undefined : "Out of step"}
          detail={`${stores.d1PubliclyVisible} of them public to readers`}
        />
      </StatTiles>

      <Disclosure summary="Everything else this page could show">
        <dl>
          <dt>Search records</dt>
          <dd>{stores.searchIndexDocs} entries.</dd>
          <dt>Connections</dt>
          <dd>
            {stores.askConfigured && stores.githubConfigured
              ? "Search and the repository are both configured."
              : `Search ${stores.askConfigured ? "is" : "is NOT"} configured, the repository ${
                  stores.githubConfigured ? "is" : "is NOT"
                }.`}
          </dd>
        </dl>
        <p>
          Both are read from the same function the operator tool calls. They sit
          here rather than at the top because neither has ever been the answer to
          a question this page was opened with.
        </p>
      </Disclosure>

      {/* No block is not evidence of health: `known: false` means unreadable, not empty. */}
      {stores.divergences.known && stores.divergences.entries.length > 0 ? (
        <Panel title="Changes the site did not pick up" count={stores.divergences.entries.length} flush>
          <RowList label="Changes the site did not pick up">
            {stores.divergences.entries.map((entry) => (
              <Row
                key={`${entry.slug}-${entry.commitSha}`}
                title={
                  <>
                    {entry.slug} <Pill variant="outline">{entry.commitSha.slice(0, 7)}</Pill>
                  </>
                }
                detail={entry.error}
                status={<Status tone="crit">not updated</Status>}
              />
            ))}
          </RowList>
        </Panel>
      ) : null}
    </div>
  );
}