app/routes/workspace.runs.tsx
65 lines and 6 functions in DrDustinEdwards/dustinedwards-info, at commit 1590ba4 on 2026-10-24. This file on GitHub.
Functions
| Function | Lines | Complexity | Covered | CRAP | Mutation |
|---|---|---|---|---|---|
| meta | 14 to 16 | 1 | No data: no coverage report in this map | No data: no coverage report in this map | No data: no mutants in this code |
| requireRecorder | 20 to 22 | 2 | No data: no coverage report in this map | No data: no coverage report in this map | No data: no mutants in this code |
| loader | 24 to 28 | 1 | No data: no coverage report in this map | No data: no coverage report in this map | No data: no mutants in this code |
| action | 31 to 37 | 3 | No data: no coverage report in this map | No data: no coverage report in this map | No data: no mutants in this code |
| LabRuns | 39 to 72 | 4 | No data: no coverage report in this map | No data: no coverage report in this map | No data: no mutants in this code |
| <anonymous:52> | 52 to 64 | 4 | No data: no coverage report in this map | No data: no coverage report in this map | No data: no mutants in this code |
Imports
It imports app/components/lab/lab-ui.tsx, app/components/lab/run-form.tsx, app/lab/actor.server.ts, app/lab/runs.server.ts, app/lab/titles.mjs, app/lib/context.ts. No module of this repo imports it.
Source
import { Link, data, redirect } from "react-router";
import { can } from "@dustinedwards/site-runtime/members";
import { Panel } from "capsomer/react/panel";
import { PageHead } from "capsomer/react/page-head";
import { LabTable, Result } from "~/components/lab/lab-ui";
import { RunForm } from "~/components/lab/run-form";
import { labActorContext } from "~/lab/actor.server";
import { recordRun, runsPage } from "~/lab/runs.server";
import { PERMISSION } from "~/lab/titles.mjs";
import { getEnv } from "~/lib/context";
import type { Route } from "./+types/workspace.runs";
export function meta() {
return [{ title: "Runs ยท Lab" }, { name: "robots", content: "noindex" }];
}
const PRIVATE = { "cache-control": "private, no-store" };
function requireRecorder(actor: Parameters<typeof can>[0]) {
if (!can(actor, PERMISSION.recordRun)) throw data("Not found.", { status: 404, headers: PRIVATE });
}
export async function loader({ context }: Route.LoaderArgs) {
const actor = context.get(labActorContext);
requireRecorder(actor);
return data(await runsPage(getEnv(context), actor), { headers: PRIVATE });
}
/** A recorded run opens on its own page; a refusal comes back here with its words. */
export async function action({ context, request }: Route.ActionArgs) {
const actor = context.get(labActorContext);
requireRecorder(actor);
const result = await recordRun(getEnv(context), actor, await request.formData(), Date.now());
if (result.ok && result.runId) throw redirect(`/lab/runs/${result.runId}`, { headers: PRIVATE });
return data(result, { headers: PRIVATE });
}
export default function LabRuns({ loaderData, actionData }: Route.ComponentProps) {
const { runs, procedures, lots, all, lotRows } = loaderData;
return (
<>
<PageHead
title="Runs"
lead={`${all ? "Every run recorded in the lab" : "The runs you recorded"}, with the lots each used. A saved run is never changed: a correction is a new run that names it.`}
/>
<Result result={actionData} />
{runs.length === 0 ? (
<p className="cap-muted">No runs recorded yet.</p>
) : (
<LabTable label="Runs" head={["Run", "Protocol", "Day", "Outcome", ...(all ? ["By"] : [])]}>
{runs.map((r) => (
<tr key={r.id}>
<th scope="row">
<Link to={`/lab/runs/${r.id}`}>Run {r.id}</Link>
{r.replaced_by ? <span className="cap-muted">, corrected by run {r.replaced_by}</span> : null}
{r.replaces_run_id ? <span className="cap-muted">, corrects run {r.replaces_run_id}</span> : null}
</th>
<td>{r.title}</td>
<td>{r.run_on}</td>
<td>{r.outcome}</td>
{all ? <td>{r.actor}</td> : null}
</tr>
))}
</LabTable>
)}
<Panel title="Record a run">
<RunForm procedures={procedures} lots={lots} lotRows={lotRows} />
</Panel>
</>
);
}