Skip to the content

Capsid menu

app/routes/procedure.version.tsx

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

Functions

The functions of procedure.version.tsx
FunctionLinesComplexityCoveredCRAPMutation
headers30 to 321No data: no coverage report in this mapNo data: no coverage report in this mapNo data: no mutants in this code
loader34 to 487No data: no coverage report in this mapNo data: no coverage report in this mapNo data: no mutants in this code
meta50 to 582No data: no coverage report in this mapNo data: no coverage report in this mapNo data: no mutants in this code
ProcedureVersionRoute60 to 851No data: no coverage report in this mapNo data: no coverage report in this mapNo data: no mutants in this code
<anonymous:70>70 to 721No data: no coverage report in this mapNo data: no coverage report in this mapNo data: no mutants in this code

Imports

It imports app/components/breadcrumb.tsx, app/components/enhance.tsx, app/components/page-shell.tsx, app/components/procedure.tsx, app/db/procedure-versions.ts, app/db/procedures.ts, app/kb/procedures/cite.mjs, app/kb/procedures/json-ld.mjs, app/kb/procedures/lineage.server.ts, app/kb/procedures/route.ts, app/lib/context.ts, app/lib/json-ld.mjs, app/lib/seo.ts. No module of this repo imports it.

Source

import { data } from "react-router";

import { Breadcrumb } from "~/components/breadcrumb";
import { Enhance } from "~/components/enhance";
import { PageShell } from "~/components/page-shell";
import { ProcedureView, VersionNotice } from "~/components/procedure";
import { getFrozenVersion, listFrozenVersions } from "~/db/procedure-versions";
import { getProcedureByPath } from "~/db/procedures";
import { getEnv } from "~/lib/context";
import { jsonLd as serializeJsonLd } from "~/lib/json-ld.mjs";
import { versionPath } from "~/kb/procedures/cite.mjs";
import { procedureJsonLd } from "~/kb/procedures/json-ld.mjs";
import { lineageFor } from "~/kb/procedures/lineage.server";
import { procedureTrail, PROCEDURES_CACHE_TAG, readScale } from "~/kb/procedures/route";
import { SITE, SITE_ORIGIN, breadcrumbJsonLd, pageMeta, personId, publicHtmlHeaders } from "~/lib/seo";

import type { Route } from "./+types/procedure.version";

// prose.css is route-scoped: a page using `.prose` without importing it renders unstyled.
import "~/styles/prose.css";
import "~/styles/procedure.css";
import "~/styles/run.css";

/**
 * A procedure as it was when a version was published, at `<page>/v/<version>` (drizzle/0027_procedure_versions.sql).
 * The words are the frozen copy's and never change, so a printed sheet's QR code and a citation keep meaning what they
 * did. The page says which version is current when this is not, links to it, and puts its canonical on the plain page.
 * Only published versions are frozen, so there is no draft here to hide.
 */
export function headers() {
  return new Headers(publicHtmlHeaders(PROCEDURES_CACHE_TAG));
}

export async function loader({ request, context }: Route.LoaderArgs) {
  const env = getEnv(context);
  const url = new URL(request.url);
  const found = /^(.*)\/v\/([^/]+?)\/?$/.exec(url.pathname);
  if (!found) throw data(null, { status: 404 });
  const path = found[1] ?? "";
  const version = decodeURIComponent(found[2] ?? "");
  const frozen = await getFrozenVersion(env, path, version);
  if (!frozen) throw data(null, { status: 404 });
  // The live page tells this one what is current. A draft or a removed procedure has no current version.
  const live = await getProcedureByPath(env, path);
  const current = live && live.status === "published" ? { path, version: live.record.version } : null;
  const { count, factor, units } = readScale(frozen.record, url);
  return { record: frozen.record, current, count, factor, units, frozen: await listFrozenVersions(env, frozen.slug), lineage: await lineageFor(env, frozen.record) };
}

export function meta({ loaderData }: Route.MetaArgs) {
  if (!loaderData) return [];
  const { record } = loaderData;
  return [
    // The canonical is the plain page, so the copies are never competing results for the same words.
    ...pageMeta({ title: `${record.seoTitle} (version ${record.version})`, description: record.description, path: record.path }),
    { tagName: "link", rel: "alternate", type: "text/markdown", href: `${SITE_ORIGIN}${versionPath(record.path, String(record.version))}.md` },
  ];
}

export default function ProcedureVersionRoute({ loaderData }: Route.ComponentProps) {
  const { record, current, count, factor, units, frozen, lineage } = loaderData;
  const trail = procedureTrail(record);
  const person = { "@type": "Person", "@id": personId(SITE_ORIGIN), name: SITE.name, url: SITE_ORIGIN };
  const blocks = [breadcrumbJsonLd(SITE_ORIGIN, trail), procedureJsonLd(record, SITE_ORIGIN, person, lineage)];
  const basePath = versionPath(record.path, String(record.version));
  return (
    <PageShell
      trail={
        <>
          {blocks.map((block, i) => (
            <script key={i} type="application/ld+json" dangerouslySetInnerHTML={{ __html: serializeJsonLd(block) }} />
          ))}
        </>
      }
    >
      <Breadcrumb trail={trail} />
      <h1 className="page-title">{record.title}</h1>
      <VersionNotice record={record} current={current} />
      <ProcedureView record={record} count={count} factor={factor} units={units} basePath={basePath} sheetPath={`${basePath}/sheet`} frozen={frozen} lineage={lineage} />
      <Enhance module="run" />
      {/* Keep on this device (app/enhance/offline.ts): a copy that opens with no connection, only when the reader asks. */}
      <Enhance module="offline" />
    </PageShell>
  );
}