OPERATOR

Asset Management

The maintenance desk at fictional Northbank Works keeps ten equipment records across the process hall, utilities bay, loading dock and maintenance shop. Find an asset, check its owner and inspection evidence, then update its assignment or next service action. Cooling water pump B opens selected, with a bearing inspection and its open service record.

Interactive product exampleOpen workspace ↗

Asset register

Equipment ownership, inspections and service records

Northbank Works Plant maintenance

Maintenance desk · Priya Shah

10 of 10 assets 02 Oct 2026, 08:30 UTC

Asset register
EquipmentLocationOwnerConditionService due
Process hallPriya ShahReady2026-10-09
Maintenance shopPriya ShahMaintenance2026-10-02
Utilities bayMarcus ReedReady2026-10-07
Loading dockTheo WalkerRestricted2026-10-03
Process hallElena RuizReady2026-10-12
Utilities bayElena RuizReady2026-10-14
Loading dockTheo WalkerReady2026-10-06
Maintenance shopMarcus ReedMaintenance2026-10-02
Process hallElena RuizReady2026-10-08
Utilities bayMarcus ReedReady2026-10-16

10 ROWS

PAGE 1 OF 1

Fictional Northbank Works register · changes are stored in this session.

Use the asset register

  • Search by identifier, name, equipment type, owner or location. Combine search with Needs attention, Ready, a location and an owner. Filters apply to the complete supplied collection before table pagination.
  • Select equipment to inspect ownership, condition, service due date and recorded evidence. The inspector stays open when filters exclude the selected asset, with an explicit notice.
  • Inspection & service records show the supplied record ID, result, description, recorder and UTC timestamp. Register history records assignment edits separately. An edit does not complete a service job or change its historical evidence.
  • Edit asset changes ownership, location, condition, service date and note. Add asset also asks for an identifier, name and equipment type. Invalid fields retain the draft; leaving a changed draft asks for confirmation.
  • Export CSV includes exactly the current filtered results, with revisions and service notes. The browser download request neutralizes spreadsheet formula prefixes. Download completion is owned by the browser.

Application ownership

AssetManagement accepts the complete records snapshot and an asynchronous onSave. It supplies the industrial context. The application owns records and accepts or declines each request. A request carries the domain, stable identifier, expected revision and edited values; a new record uses a null expected revision. Only an accepted response with the matching identifier and a newer revision closes the editor. Rejections, conflicts and failures preserve the draft.

The included applyResourceSave adapter validates fields, rejects duplicate identifiers and checks the expected revision before changing a record. It preserves supplied serviceRecords on assignment edits. Service evidence is optional; a newly created asset explicitly shows that no evidence has been supplied. A host can connect these records to its inspection and maintenance systems.

The demo applies the transaction to an in-memory collection. Reloading starts a fresh Northbank register, including search, selection and local edits. There is no network save or cross-tab synchronization. The original ResourceManagement API and its parameterized fixtures remain available for existing integrations and internal regression coverage.

The inspector composes EntityPreview; the equipment register composes DataGrid. Source freshness, condition, inspection results and service due dates are separate supplied values. The application remains responsible for access controls, service-side validation and authoritative timestamps.

Copy the recipe

import { AssetManagementDemo } from "./patterns/resource-management";

<AssetManagementDemo />
View recipe source (10 files)

Copy all files into your app, preserving their relative paths.

Package imports: @operator-ds/react, react.

patterns/resource-management/index.ts

export {
  AssetManagement,
  type AssetManagementProps,
  ResourceManagement,
  type ResourceManagementProps,
} from "./resource-management";
export { AssetManagementDemo, ResourceManagementDemo } from "./demo";
export {
  createResourceRecords,
  type ManagedResource,
  type ResourceCondition,
  type AssetServiceRecord,
} from "./fixtures";
export {
  applyResourceSave,
  validateResource,
  type ResourceSaveRequest,
  type ResourceSaveResult,
  type ResourceValues,
} from "./state";

patterns/resource-management/resource-management.tsx

"use client";

import { useLayoutEffect, useRef, useState } from "react";
import {
  Badge,
  Button,
  CollectionState,
  CopyButton,
  DataGrid,
  EntityPreview,
  Input,
  Inspector,
  Select,
  SelectOption,
  type DataGridColumn,
} from "@operator-ds/react";
import { formatUtcInstant, type OperationalDomain } from "../operational-domain";
import { requestArtifactDownload, transferCsvCell } from "../resource-transfer/export";
import {
  conditionLabels,
  resourceScenarios,
  type ManagedResource,
  type ResourceCondition,
} from "./fixtures";
import { ResourceForm } from "./resource-form";
import type { ResourceSaveRequest, ResourceSaveResult } from "./state";

export type ResourceManagementProps = {
  domain: OperationalDomain;
  records: readonly ManagedResource[];
  /** Resolve only when the application has accepted or declined the exact revision. */
  onSave: (request: ResourceSaveRequest) => Promise<ResourceSaveResult>;
};
export type AssetManagementProps = Omit<ResourceManagementProps, "domain">;

/** Dedicated industrial register; the host owns the equipment snapshot and save adapter. */
export function AssetManagement(props: AssetManagementProps) {
  return <ResourceRegister {...props} domain="industrial" asset />;
}

/** Compatibility recipe for internal contexts and existing consumers. */
export function ResourceManagement(props: ResourceManagementProps) {
  return <ResourceRegister {...props} />;
}

type Scope = "all" | "attention" | "ready";
const variants: Record<ResourceCondition, "success" | "warning" | "neutral"> = {
  ready: "success",
  restricted: "warning",
  maintenance: "neutral",
};
/** The open asset is shown by a tint and a 3 px bar (Highlight in forced colors), never by color alone. */
const selectedRowStyle =
  "[&_tr:has(button[aria-pressed=true])]:bg-oprt-surface-3 [&_tr:has(button[aria-pressed=true])_td:first-child]:relative [&_tr:has(button[aria-pressed=true])_td:first-child]:before:absolute [&_tr:has(button[aria-pressed=true])_td:first-child]:before:inset-y-0 [&_tr:has(button[aria-pressed=true])_td:first-child]:before:left-0 [&_tr:has(button[aria-pressed=true])_td:first-child]:before:w-[3px] [&_tr:has(button[aria-pressed=true])_td:first-child]:before:bg-oprt-accent [&_tr:has(button[aria-pressed=true])_td:first-child]:forced-colors:before:bg-[Highlight]";
const focusStyle =
  "outline-none focus-visible:shadow-oprt-focus focus-visible:outline focus-visible:outline-2 focus-visible:outline-oprt-border-focus";

/** Mount with a domain key when switching application contexts. */
function ResourceRegister({
  domain,
  records,
  onSave,
  asset = false,
}: ResourceManagementProps & { asset?: boolean }) {
  const scenario = resourceScenarios[domain];
  const subject = asset ? "asset" : "resource";
  const label = asset ? "Asset" : "Resource";
  const [query, setQuery] = useState("");
  const [scope, setScope] = useState<Scope>("all");
  const [location, setLocation] = useState("all");
  const [owner, setOwner] = useState("all");
  const [selectedId, setSelectedId] = useState<string | null>(() =>
    records.some((record) => record.id === scenario.selectedId)
      ? scenario.selectedId
      : (records[0]?.id ?? null),
  );
  const [editor, setEditor] = useState<{ record: ManagedResource | null } | null>(null);
  const [notice, setNotice] = useState("");
  const [exportError, setExportError] = useState("");
  const inspector = useRef<HTMLElement>(null);
  const register = useRef<HTMLElement>(null);
  const selectionOrigin = useRef<HTMLElement | null>(null);
  const focusRequested = useRef(false);
  const selected = records.find((record) => record.id === selectedId);
  const search = query.trim().toLocaleLowerCase();
  const visible = records.filter(
    (record) =>
      (scope === "all" ||
        (scope === "attention" ? record.condition !== "ready" : record.condition === "ready")) &&
      (location === "all" || record.location === location) &&
      (owner === "all" || record.owner === owner) &&
      (!search ||
        [record.id, record.name, record.category, record.owner, record.location].some((value) =>
          value.toLocaleLowerCase().includes(search),
        )),
  );
  const attentionCount = records.filter((record) => record.condition !== "ready").length;

  useLayoutEffect(() => {
    if (focusRequested.current) {
      inspector.current?.focus();
      focusRequested.current = false;
    }
  }, [selectedId]);

  /** A saved or exported confirmation describes the moment it happened, so it ends when the view moves on. */
  function dropConfirmations() {
    setNotice("");
    setExportError("");
  }
  function select(record: ManagedResource, origin?: HTMLElement) {
    selectionOrigin.current =
      origin ?? (document.activeElement instanceof HTMLElement ? document.activeElement : null);
    if (record.id === selectedId) {
      inspector.current?.focus();
      return;
    }
    focusRequested.current = true;
    dropConfirmations();
    setSelectedId(record.id);
  }
  function closeInspection() {
    setSelectedId(null);
    (selectionOrigin.current?.isConnected ? selectionOrigin.current : register.current)?.focus();
  }
  function clear() {
    dropConfirmations();
    setQuery("");
    setScope("all");
    setLocation("all");
    setOwner("all");
  }
  function exportRecords() {
    setExportError("");
    try {
      const header = [
        "id",
        "revision",
        "name",
        "type",
        "owner",
        "location",
        "condition",
        "service_due",
        "service_note",
      ];
      const rows = visible.map((record) => [
        record.id,
        record.revision,
        record.name,
        record.category,
        record.owner,
        record.location,
        conditionLabels[record.condition],
        record.serviceDue,
        record.note,
      ]);
      requestArtifactDownload({
        filename: asset ? "northbank-asset-register.csv" : `${domain}-resource-register.csv`,
        mediaType: "text/csv",
        content:
          [header, ...rows].map((row) => row.map(transferCsvCell).join(",")).join("\r\n") + "\r\n",
      });
      setNotice(
        `CSV prepared for ${visible.length} ${subject}${visible.length === 1 ? "" : "s"}. Download requested.`,
      );
    } catch {
      setExportError("The CSV could not be prepared. Try exporting the current results again.");
    }
  }
  const columns: DataGridColumn[] = [
    {
      key: "name",
      label: asset ? "Equipment" : "Resource",
      render: (_value, row) => {
        const record = row.record as ManagedResource;
        return (
          <Button
            variant="ghost"
            size="sm"
            aria-label={`Inspect ${record.name}, ${record.id}`}
            aria-pressed={record.id === selectedId}
            className="!h-auto min-h-5u w-full !justify-start !px-0 text-left !normal-case !tracking-normal"
            onClick={(event) => select(record, event.currentTarget)}
          >
            <span className="flex flex-col gap-0.5u">
              <span className="whitespace-nowrap font-medium">{record.name}</span>
              <span className="font-mono">{record.id}</span>
            </span>
          </Button>
        );
      },
    },
    {
      key: "location",
      label: "Location",
      render: (value) => <span className="whitespace-nowrap">{String(value)}</span>,
    },
    {
      key: "owner",
      label: "Owner",
      render: (value) => <span className="whitespace-nowrap">{String(value)}</span>,
    },
    {
      key: "condition",
      label: "Condition",
      render: (value) => (
        <Badge appearance="text" indicator="none" variant={variants[value as ResourceCondition]}>
          {conditionLabels[value as ResourceCondition]}
        </Badge>
      ),
    },
    {
      key: "serviceDue",
      label: "Service due",
      render: (value) => <span className="whitespace-nowrap font-mono">{String(value)}</span>,
    },
  ];

  return (
    <section
      ref={register}
      aria-label={`${scenario.title} ${subject} register`}
      tabIndex={-1}
      className={`not-prose flex w-full min-w-0 flex-col gap-3u font-sans text-oprt-base text-oprt-text ${focusStyle}`}
    >
      <header className="flex flex-wrap items-start justify-between gap-2u border-b border-oprt-border pb-3u">
        <div className="min-w-0">
          <h2 className="m-0 text-oprt-xl font-semibold normal-case tracking-normal">
            {label} register
          </h2>
          {asset && (
            <p className="m-0 mt-1u text-oprt-text-dim">
              Equipment ownership, inspections and service records
            </p>
          )}
          <p className="m-0 mt-1u text-oprt-text-dim">
            {scenario.title} <span aria-hidden="true">/</span> {scenario.department}
          </p>
        </div>
        <div className="flex flex-wrap gap-1u">
          <Button size="sm" variant="tertiary" disabled={!visible.length} onClick={exportRecords}>
            Export CSV
          </Button>
          <Button
            size="sm"
            onClick={() => {
              setEditor({ record: null });
              setNotice("");
            }}
          >
            Add {subject}
          </Button>
        </div>
      </header>
      <div className="flex flex-wrap items-center justify-between gap-2u">
        <div role="group" aria-label={`${label} scopes`} className="flex flex-wrap gap-1u">
          {(
            [
              ["all", `All ${subject}s`, records.length],
              ["attention", "Needs attention", attentionCount],
              ["ready", "Ready", records.length - attentionCount],
            ] as const
          ).map(([key, label, count]) => (
            <Button
              key={key}
              size="sm"
              variant={scope === key ? "secondary" : "ghost"}
              aria-pressed={scope === key}
              onClick={() => {
                dropConfirmations();
                setScope(key);
              }}
            >
              {label}
              <span className="ml-1u font-mono text-oprt-text-dim">{count}</span>
            </Button>
          ))}
        </div>
        <p className="m-0 text-oprt-text-dim">{scenario.role}</p>
      </div>
      <div className="flex flex-wrap items-center gap-1u">
        <Input
          type="search"
          aria-label={`Search ${subject}s`}
          placeholder="Search ID, name or owner"
          value={query}
          onChange={(event) => {
            dropConfirmations();
            setQuery(event.target.value);
          }}
          className="min-w-0 flex-1 basis-[16rem]"
        />
        <Select
          aria-label={`${label} location`}
          value={location}
          onValueChange={(value) => {
            dropConfirmations();
            setLocation(value);
          }}
          size="sm"
        >
          <SelectOption value="all">All locations</SelectOption>
          {scenario.locations.map((item) => (
            <SelectOption key={item} value={item}>
              {item}
            </SelectOption>
          ))}
        </Select>
        <Select
          aria-label={`${label} owner`}
          value={owner}
          onValueChange={(value) => {
            dropConfirmations();
            setOwner(value);
          }}
          size="sm"
        >
          <SelectOption value="all">All owners</SelectOption>
          {scenario.owners.map((item) => (
            <SelectOption key={item} value={item}>
              {item}
            </SelectOption>
          ))}
        </Select>
      </div>
      {notice && (
        <p role="status" className="m-0 border border-oprt-border bg-oprt-surface-2 p-2u">
          {notice}
        </p>
      )}
      {exportError && (
        <p role="alert" className="m-0 text-oprt-error">
          {exportError}
        </p>
      )}
      <div className="flex min-w-0 flex-wrap items-start gap-3u">
        <div className="min-w-0 flex-[999_1_35rem]">
          <p role="status" aria-label={`${label} count`} className="m-0 mb-2u text-oprt-text-dim">
            {visible.length} of {records.length} {subject}s <span aria-hidden="true">·</span>{" "}
            {scenario.date}, {scenario.time}
          </p>
          {!records.length ? (
            <CollectionState
              variant="empty"
              title={`Register your first ${subject}`}
              description="Add equipment with an owner, a location and its current condition."
              actions={<Button onClick={() => setEditor({ record: null })}>Add {subject}</Button>}
            />
          ) : visible.length === 0 ? (
            <CollectionState
              variant="no-results"
              title={`No ${subject}s match`}
              description="Try another identifier or clear the current search, scope and filters."
              actions={<Button onClick={clear}>Clear search and scope</Button>}
            />
          ) : (
            <DataGrid
              caption={`${label} register`}
              columns={columns}
              data={visible.map((record) => ({ ...record, record }))}
              getRowId={(row) => String(row.id)}
              pageSize={12}
              dense
              className={selectedRowStyle}
            />
          )}
        </div>
        {selectedId && (
          <Inspector
            ref={inspector}
            tabIndex={-1}
            title={`${label} details`}
            onClose={closeInspection}
            className={`min-w-0 flex-[1_1_24rem] ${focusStyle}`}
          >
            {selected ? (
              <>
                {!visible.some((record) => record.id === selectedId) && (
                  <p className="m-0 text-oprt-text-dim">
                    Selected {subject} is outside the current results.
                  </p>
                )}
                <EntityPreview
                  entity={{
                    id: selected.id,
                    name: selected.name,
                    typeLabel: selected.category,
                    facts: [
                      { id: "owner", label: "Owner", value: selected.owner },
                      { id: "location", label: "Location", value: selected.location },
                      {
                        id: "service",
                        label: "Service due",
                        value: selected.serviceDue,
                        mono: true,
                      },
                      {
                        id: "revision",
                        label: "Revision",
                        value: String(selected.revision).padStart(2, "0"),
                        mono: true,
                      },
                    ],
                    condition: {
                      label: conditionLabels[selected.condition],
                      variant: variants[selected.condition],
                    },
                    quality: {
                      state: "current",
                      source: scenario.source,
                      updatedAt: Date.parse(selected.updatedAt),
                    },
                  }}
                  actions={
                    <>
                      <Button
                        size="sm"
                        onClick={() => {
                          setEditor({ record: selected });
                          setNotice("");
                        }}
                      >
                        Edit {subject}
                      </Button>
                      <CopyButton size="sm" value={selected.id} label={`Copy ${subject} ID`} />
                    </>
                  }
                />
                <div className="border-t border-oprt-border pt-2u">
                  <h4 className="m-0 font-medium">Service note</h4>
                  <p className="m-0 mt-1u leading-relaxed text-oprt-text-dim">{selected.note}</p>
                </div>
                {asset && (
                  <section
                    aria-label="Inspection and service records"
                    className="border-t border-oprt-border pt-2u"
                  >
                    <h4 className="m-0 font-medium">Inspection &amp; service records</h4>
                    {selected.serviceRecords?.length ? (
                      <ol className="m-0 mt-2u list-none space-y-3u p-0">
                        {selected.serviceRecords.map((record) => (
                          <li key={record.id} className="space-y-1u">
                            <div className="flex flex-wrap items-center justify-between gap-1u">
                              <span className="font-mono">{record.id}</span>
                              <Badge
                                appearance="text"
                                indicator="none"
                                variant={record.result === "Complete" ? "success" : "warning"}
                              >
                                {record.result}
                              </Badge>
                            </div>
                            <p className="m-0 font-medium">{record.title}</p>
                            <p className="m-0 leading-relaxed text-oprt-text-dim">
                              {record.detail}
                            </p>
                            <p className="m-0 text-oprt-text-dim">
                              Recorded by {record.recordedBy}
                            </p>
                            <time
                              dateTime={record.recordedAt}
                              className="block font-mono text-oprt-text-dim"
                            >
                              {formatUtcInstant(record.recordedAt, { milliseconds: "never" })}
                            </time>
                          </li>
                        ))}
                      </ol>
                    ) : (
                      <p className="m-0 mt-1u text-oprt-text-dim">
                        No inspection or service evidence has been supplied for this asset.
                      </p>
                    )}
                  </section>
                )}
                <div className="border-t border-oprt-border pt-2u">
                  <h4 className="m-0 font-medium">
                    {asset ? "Register history" : "Recent activity"}
                  </h4>
                  <ol className="m-0 mt-2u list-none space-y-2u p-0">
                    {selected.activity.slice(0, 3).map((event) => (
                      <li key={event.id} className="space-y-0.5u">
                        <p className="m-0 text-oprt-text-dim">{event.detail}</p>
                        <time
                          dateTime={event.at}
                          className="font-mono text-oprt-sm text-oprt-text-dim"
                        >
                          {formatUtcInstant(event.at, { milliseconds: "never" })}
                        </time>
                      </li>
                    ))}
                  </ol>
                </div>
              </>
            ) : (
              <CollectionState
                variant="empty"
                title={`${label} no longer available`}
                description={`This ${subject} has left the current register. Choose another ${subject} to inspect its details.`}
              />
            )}
          </Inspector>
        )}
      </div>
      {asset && (
        <p className="m-0 text-oprt-text-dim">
          Fictional Northbank Works register · changes are stored in this session.
        </p>
      )}
      {editor && (
        <ResourceForm
          asset={asset}
          domain={domain}
          record={editor.record}
          onSave={onSave}
          onClose={() => setEditor(null)}
          onSaved={(record) => {
            setEditor(null);
            setSelectedId(record.id);
            setNotice(
              `${record.id} saved. ${record.name} is ${conditionLabels[record.condition].toLowerCase()}.`,
            );
          }}
        />
      )}
    </section>
  );
}

patterns/operational-domain.ts

/** Fixture context used by reusable application recipes. */
export type OperationalDomain = "military" | "industrial";

export interface UtcInstantOptions {
  /**
   * Whether the milliseconds are shown. "auto" (the default) shows them only when the supplied
   * instant carries a non-zero fraction, because sub-second timing matters only where it exists.
   */
  milliseconds?: "auto" | "always" | "never";
}

const INSTANT =
  /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})(?:\.(\d{1,3}))?(Z|[+-]\d{2}:\d{2})$/;

/**
 * Reads an ISO 8601 instant as "YYYY-MM-DD HH:MM:SS UTC", with ".mmm" after the seconds where the
 * options ask for it. Text that is not a real instant (an invented date such as 30 February, or
 * free text) is returned as supplied rather than reinterpreted. It never uses Intl, so the server
 * and every browser print the same characters.
 */
export function formatUtcInstant(value: string, options: UtcInstantOptions = {}): string {
  const parts = INSTANT.exec(value);
  if (!parts) return value;
  const [year, month, day, hour, minute, second] = parts.slice(1, 7).map(Number) as [
    number,
    number,
    number,
    number,
    number,
    number,
  ];
  const calendar = new Date(Date.UTC(year, month - 1, day));
  // Date rolls an invented day into the next month; compare it back to what was written.
  if (
    calendar.getUTCFullYear() !== year ||
    calendar.getUTCMonth() !== month - 1 ||
    calendar.getUTCDate() !== day ||
    hour > 23 ||
    minute > 59 ||
    second > 59
  )
    return value;
  const fraction = (parts[7] ?? "").padEnd(3, "0");
  const parsed = new Date(`${value.slice(0, 19)}.${fraction}${parts[8]}`);
  if (Number.isNaN(parsed.getTime())) return value;
  const { milliseconds = "auto" } = options;
  const showFraction = milliseconds === "always" || (milliseconds === "auto" && fraction !== "000");
  const iso = parsed.toISOString();
  return `${iso.slice(0, 10)} ${iso.slice(11, showFraction ? 23 : 19)} UTC`;
}

/**
 * Reads epoch milliseconds as "YYYY-MM-DD HH:MM:SS UTC", with the same options as
 * formatUtcInstant. A value that is not a real time reads "Unknown time" rather than throwing.
 */
export function formatUtcEpoch(ms: number, options: UtcInstantOptions = {}): string {
  const date = new Date(ms);
  if (!Number.isFinite(ms) || Number.isNaN(date.getTime())) return "Unknown time";
  return formatUtcInstant(date.toISOString(), options);
}

patterns/resource-transfer/export.ts

import type { TransferArtifact, TransferRequest } from "./transfer-state";
import type { ImportValidationRow } from "./csv";

/** Quote every cell and neutralize spreadsheet formula prefixes, including leading whitespace. */
export function transferCsvCell(value: string | number | boolean): string {
  let text = String(value);
  const firstMeaningful = [...text].find(
    (character) => character.charCodeAt(0) > 32 && character.trim() !== "",
  );
  if ((firstMeaningful && "=+@-".includes(firstMeaningful)) || /^[\t\r\n]/u.test(text))
    text = `'${text}`;
  return `"${text.replaceAll('"', '""')}"`;
}

export function prepareTransferExport(
  request: Extract<TransferRequest, { operation: "export" }>,
): TransferArtifact {
  const ids = new Set(request.selection.ids);
  if (
    ids.size === 0 ||
    ids.size !== request.selection.ids.length ||
    request.records.length !== ids.size ||
    new Set(request.records.map((record) => record.id)).size !== ids.size ||
    request.records.some((record) => !ids.has(record.id))
  )
    throw new Error("Export records do not match the reviewed selection scope.");
  const { context, selection } = request;
  const capturedAt = new Date(context.capturedAt).toISOString();
  const asOf =
    context.source.asOf === null ? "Unknown" : new Date(context.source.asOf).toISOString();
  const header = [
    "id",
    "record_revision",
    "name",
    "kind",
    "site",
    "inspection_required",
    "source_id",
    "source_revision",
    "source_label",
    "source_as_of",
    "exported_at",
    "time_zone",
    "selection_scope",
    "filter",
    "filter_description",
  ];
  const rows = request.records.map((record) => [
    record.id,
    record.revision,
    record.name,
    record.kind,
    record.site,
    record.inspectionRequired,
    context.source.id,
    context.source.revision,
    context.source.label,
    asOf,
    capturedAt,
    context.timeZone,
    selection.scope,
    JSON.stringify(context.filter),
    context.filterDescription,
  ]);
  return {
    filename: `equipment-export-${capturedAt.replace(/[.:]/g, "-")}.csv`,
    mediaType: "text/csv",
    content:
      [header, ...rows].map((row) => row.map(transferCsvCell).join(",")).join("\r\n") + "\r\n",
  };
}

export function prepareImportErrorReport(rows: readonly ImportValidationRow[]): TransferArtifact {
  const output: (string | number)[][] = [
    ["row_key", "source_line", "field", "message", "source_cells"],
  ];
  for (const row of rows) {
    for (const error of row.errors)
      output.push([row.key, error.line, error.field, error.message, JSON.stringify(row.cells)]);
  }
  return {
    filename: "equipment-import-errors.csv",
    mediaType: "text/csv",
    content: output.map((row) => row.map(transferCsvCell).join(",")).join("\r\n") + "\r\n",
  };
}

/** Requests a browser download. The browser does not report whether the file reached disk. */
export function requestArtifactDownload(artifact: TransferArtifact): void {
  if (!/^[A-Za-z0-9][A-Za-z0-9._-]{0,160}\.csv$/.test(artifact.filename))
    throw new Error("Invalid download filename.");
  if (artifact.mediaType !== "text/csv" || typeof artifact.content !== "string")
    throw new Error("Unsupported download artifact.");
  const blob = new Blob([artifact.content], { type: "text/csv;charset=utf-8" });
  const url = URL.createObjectURL(blob);
  const revoke = URL.revokeObjectURL.bind(URL);
  const link = document.createElement("a");
  link.href = url;
  link.download = artifact.filename;
  link.hidden = true;
  try {
    document.body.appendChild(link);
    link.click();
  } catch (error) {
    revoke(url);
    throw error;
  } finally {
    link.remove();
  }
  setTimeout(() => revoke(url), 1000);
}

patterns/resource-transfer/transfer-state.ts

import type { BulkSelectionSnapshot } from "@operator-ds/react";

export interface TransferRecord {
  id: string;
  revision: string;
  name: string;
  kind: "pump" | "fan" | "valve" | "gauge";
  site: "west" | "east";
  inspectionRequired: boolean;
}
export interface TransferSource {
  id: string;
  revision: string;
  label: string;
  asOf: number | null;
  complete: boolean;
  records: readonly TransferRecord[];
}
export interface TransferFilter {
  query: string;
  kind: TransferRecord["kind"] | "all";
  site: TransferRecord["site"] | "all";
}
export interface TransferContext {
  source: Omit<TransferSource, "records">;
  capturedAt: number;
  timeZone: string;
  filter: TransferFilter;
  filterDescription: string;
}
export type TransferImportValues = Pick<TransferRecord, "id" | "name" | "kind" | "site">;
interface TransferRequestBase {
  requestId: string;
  sessionId: string;
  context: TransferContext;
  selection: BulkSelectionSnapshot;
}
export type TransferRequest = TransferRequestBase &
  (
    | { operation: "import"; items: readonly { key: string; values: TransferImportValues }[] }
    | { operation: "flag-inspection"; records: readonly TransferRecord[] }
    | { operation: "export"; records: readonly TransferRecord[] }
  );
export interface TransferArtifact {
  filename: string;
  mediaType: "text/csv";
  content: string;
}
export type TransferItemResult =
  | { key: string; status: "applied"; record: TransferRecord }
  | { key: string; status: "failed"; message: string; retryable: boolean }
  | { key: string; status: "canceled" | "skipped"; message: string };
export type TransferResult =
  | {
      requestId: string;
      operation: "import" | "flag-inspection";
      status: "complete" | "partial" | "failed" | "canceled";
      items: readonly TransferItemResult[];
      message: string;
      sourceRevision: string | null;
    }
  | { requestId: string; operation: "export"; status: "complete"; artifact: TransferArtifact }
  | { requestId: string; operation: "export"; status: "failed" | "canceled"; message: string };
export interface TransferProgress {
  requestId: string;
  state: "queued" | "running" | "cancel-requested";
  completed: number | null;
  total: number | null;
  message?: string;
}
export type TransferCancelResult =
  | { requestId: string; status: "requested" }
  | { requestId: string; status: "rejected"; message: string };
export interface TransferRunOptions {
  signal: AbortSignal;
  onProgress(update: TransferProgress): void;
}
export type TransferParseResult<T> = { ok: true; value: T } | { ok: false; error: string };

const kinds = ["pump", "fan", "valve", "gauge"];
const sites = ["west", "east"];
function hasControlCharacters(value: string): boolean {
  return Array.from(value).some((character) => {
    const code = character.charCodeAt(0);
    return code < 32 || (code >= 127 && code <= 159);
  });
}
const invalid = (error: string): { ok: false; error: string } => ({ ok: false, error });
const text = (value: unknown, max = 256): value is string =>
  typeof value === "string" &&
  value.trim().length > 0 &&
  value.length <= max &&
  !hasControlCharacters(value);
const time = (value: unknown): value is number =>
  typeof value === "number" &&
  Number.isSafeInteger(value) &&
  value >= 0 &&
  value <= 8640000000000000;
function object(value: unknown): value is Record<string, unknown> {
  return (
    typeof value === "object" &&
    value !== null &&
    !Array.isArray(value) &&
    (Object.getPrototypeOf(value) === Object.prototype || Object.getPrototypeOf(value) === null)
  );
}
function keys(
  value: Record<string, unknown>,
  expected: readonly string[],
  optional: readonly string[] = [],
): boolean {
  return (
    expected.every((key) => Object.hasOwn(value, key)) &&
    Reflect.ownKeys(value).every(
      (key) => typeof key === "string" && (expected.includes(key) || optional.includes(key)),
    )
  );
}
function freezeCopy<T>(value: T): T {
  if (Array.isArray(value))
    return Object.freeze(value.map((item: unknown) => freezeCopy(item))) as T;
  if (value !== null && typeof value === "object")
    return Object.freeze(
      Object.fromEntries(Object.entries(value).map(([key, item]) => [key, freezeCopy(item)])),
    ) as T;
  return value;
}
function values(value: unknown): value is TransferImportValues {
  return (
    object(value) &&
    keys(value, ["id", "name", "kind", "site"]) &&
    text(value.id, 80) &&
    text(value.name, 120) &&
    typeof value.kind === "string" &&
    kinds.includes(value.kind) &&
    typeof value.site === "string" &&
    sites.includes(value.site)
  );
}
function record(value: unknown): value is TransferRecord {
  if (
    !object(value) ||
    !keys(value, ["id", "revision", "name", "kind", "site", "inspectionRequired"])
  )
    return false;
  return (
    values({ id: value.id, name: value.name, kind: value.kind, site: value.site }) &&
    text(value.revision) &&
    typeof value.inspectionRequired === "boolean"
  );
}
function equalRecord(a: TransferRecord, b: TransferRecord): boolean {
  return (
    a.id === b.id &&
    a.revision === b.revision &&
    a.name === b.name &&
    a.kind === b.kind &&
    a.site === b.site &&
    a.inspectionRequired === b.inspectionRequired
  );
}
function validFilter(value: unknown): value is TransferFilter {
  return (
    object(value) &&
    keys(value, ["query", "kind", "site"]) &&
    typeof value.query === "string" &&
    value.query.length <= 120 &&
    !hasControlCharacters(value.query) &&
    typeof value.kind === "string" &&
    ["all", ...kinds].includes(value.kind) &&
    typeof value.site === "string" &&
    ["all", ...sites].includes(value.site)
  );
}
function sameIds(a: readonly string[], b: readonly string[]): boolean {
  return a.length === b.length && a.every((id) => b.includes(id));
}
function sameFilter(a: TransferFilter, b: TransferFilter): boolean {
  return a.query === b.query && a.kind === b.kind && a.site === b.site;
}
function validZone(value: unknown): value is string {
  if (!text(value, 128) || /^[+-]/.test(value)) return false;
  try {
    new Intl.DateTimeFormat("en", { timeZone: value }).format(0);
    return true;
  } catch {
    return false;
  }
}

export function parseTransferSource(input: unknown): TransferParseResult<TransferSource> {
  try {
    if (
      !object(input) ||
      !keys(input, ["id", "revision", "label", "asOf", "complete", "records"]) ||
      !text(input.id) ||
      !text(input.revision) ||
      !text(input.label, 200) ||
      (input.asOf !== null && !time(input.asOf)) ||
      typeof input.complete !== "boolean" ||
      !Array.isArray(input.records) ||
      input.records.length > 1000 ||
      !input.records.every(record)
    )
      return invalid(
        "Inventory source or equipment records are malformed or exceed the 1,000-record limit.",
      );
    const ids = input.records.map((item) => (item as TransferRecord).id);
    if (new Set(ids).size !== ids.length) return invalid("Inventory record IDs must be unique.");
    return { ok: true, value: freezeCopy(input as unknown as TransferSource) };
  } catch {
    return invalid("Inventory source could not be read.");
  }
}

/** Captures a complete reviewed request; no caller object is retained by reference. */
export function createTransferRequest(
  input: TransferRequest,
  source: TransferSource,
  canWrite: boolean,
): TransferParseResult<TransferRequest> {
  try {
    const sourceResult = parseTransferSource(source);
    if (!sourceResult.ok) return sourceResult;
    if (
      !object(input) ||
      !text(input.requestId) ||
      !text(input.sessionId) ||
      !["import", "flag-inspection", "export"].includes(input.operation)
    )
      return invalid("Transfer request identity or operation is invalid.");
    if (
      !keys(input, [
        "requestId",
        "sessionId",
        "context",
        "selection",
        "operation",
        input.operation === "import" ? "items" : "records",
      ])
    )
      return invalid("Transfer request contains unexpected or missing fields.");
    const context = input.context;
    if (
      !object(context) ||
      !keys(context, ["source", "capturedAt", "timeZone", "filter", "filterDescription"]) ||
      !time(context.capturedAt) ||
      !validZone(context.timeZone) ||
      !validFilter(context.filter) ||
      context.filterDescription !== describeTransferFilter(context.filter) ||
      !object(context.source) ||
      !keys(context.source, ["id", "revision", "label", "asOf", "complete"])
    )
      return invalid("Transfer source, time or filter context is invalid.");
    const metadata = context.source;
    if (
      metadata.id !== source.id ||
      metadata.revision !== source.revision ||
      metadata.label !== source.label ||
      metadata.asOf !== source.asOf ||
      metadata.complete !== source.complete
    )
      return invalid("The source changed. Review the current inventory before continuing.");
    const selection = input.selection;
    if (
      !object(selection) ||
      !keys(selection, [
        "id",
        "scope",
        "ids",
        "sourceId",
        "sourceRevision",
        "filterDescription",
        "capturedAt",
      ]) ||
      !text(selection.id) ||
      !["visible", "selected", "all-matching"].includes(selection.scope) ||
      !Array.isArray(selection.ids) ||
      selection.ids.length === 0 ||
      selection.ids.length > 1000 ||
      !selection.ids.every((id) => text(id)) ||
      new Set(selection.ids).size !== selection.ids.length ||
      selection.sourceId !== source.id ||
      selection.sourceRevision !== source.revision ||
      selection.filterDescription !== context.filterDescription ||
      selection.capturedAt !== context.capturedAt
    )
      return invalid(
        "The selection snapshot is empty, malformed or belongs to another source or filter.",
      );
    if (input.operation !== "export" && !canWrite)
      return invalid("Write permission is required for this transfer.");
    if (selection.scope === "all-matching" && !source.complete)
      return invalid("All matching requires a complete supplied inventory.");
    if (input.operation === "import") {
      if (
        selection.scope !== "selected" ||
        !Array.isArray(input.items) ||
        input.items.length !== selection.ids.length ||
        !input.items.every(
          (item) =>
            object(item) && keys(item, ["key", "values"]) && text(item.key) && values(item.values),
        )
      )
        return invalid("Import candidates or row selection are invalid.");
      if (
        new Set(input.items.map((item) => item.key)).size !== input.items.length ||
        !sameIds(
          input.items.map((item) => item.key),
          selection.ids,
        ) ||
        new Set(input.items.map((item) => item.values.id)).size !== input.items.length ||
        input.items.some((item) => source.records.some((current) => current.id === item.values.id))
      )
        return invalid(
          "Import contains duplicate, existing or incorrectly selected equipment IDs.",
        );
    } else {
      if (
        !Array.isArray(input.records) ||
        input.records.length !== selection.ids.length ||
        !input.records.every(record) ||
        new Set(input.records.map((item) => item.id)).size !== input.records.length ||
        !sameIds(
          input.records.map((item) => item.id),
          selection.ids,
        )
      )
        return invalid("Selected records do not match the reviewed IDs.");
      if (
        input.records.some((item) => !source.records.some((current) => equalRecord(item, current)))
      )
        return invalid("A selected record changed or is no longer in the source. Review again.");
      if (
        selection.scope === "all-matching" &&
        !sameIds(
          selection.ids,
          filterTransferRecords(source.records, context.filter).map((item) => item.id),
        )
      )
        return invalid(
          "All matching must contain every matching record in the supplied inventory.",
        );
    }
    return { ok: true, value: freezeCopy(input) };
  } catch {
    return invalid("Transfer request could not be read.");
  }
}

export function getTransferAuthorityError(
  request: TransferRequest,
  source: TransferSource,
  filter: TransferFilter,
  canWrite: boolean,
): string | null {
  if (!validFilter(filter) || !sameFilter(request.context.filter, filter))
    return "The filters changed. Review the selection again.";
  const result = createTransferRequest(request, source, canWrite);
  return result.ok ? null : result.error;
}

/** Missing/unknown results are protocol errors, never implied successful or safe-to-retry items. */
export function parseTransferResult(
  input: unknown,
  request: TransferRequest,
): TransferParseResult<TransferResult> {
  try {
    if (
      !object(input) ||
      input.requestId !== request.requestId ||
      input.operation !== request.operation
    )
      return invalid(
        "The service returned an unrelated or malformed result; the remote outcome is unknown.",
      );
    if (request.operation === "export") {
      if (input.status === "complete") {
        const artifact = input.artifact;
        if (
          !keys(input, ["requestId", "operation", "status", "artifact"]) ||
          !object(artifact) ||
          !keys(artifact, ["filename", "mediaType", "content"]) ||
          !text(artifact.filename, 160) ||
          !/^[a-z0-9][a-z0-9_.-]*\.csv$/i.test(artifact.filename) ||
          artifact.mediaType !== "text/csv" ||
          typeof artifact.content !== "string" ||
          artifact.content.length > 8388608
        )
          return invalid("The service returned an invalid or oversized CSV export artifact.");
      } else if (
        !keys(input, ["requestId", "operation", "status", "message"]) ||
        (input.status !== "failed" && input.status !== "canceled") ||
        !text(input.message, 2000)
      )
        return invalid("The service returned an invalid export outcome.");
      return { ok: true, value: freezeCopy(input as unknown as TransferResult) };
    }
    if (
      !keys(input, ["requestId", "operation", "status", "items", "message", "sourceRevision"]) ||
      typeof input.status !== "string" ||
      !["complete", "partial", "failed", "canceled"].includes(input.status) ||
      !text(input.message, 2000) ||
      !Array.isArray(input.items) ||
      input.items.length !== request.selection.ids.length
    )
      return invalid(
        "The service did not report an explicit valid outcome for every requested item.",
      );
    const seen = new Set<string>();
    let accepted = 0,
      canceled = 0;
    for (const item of input.items) {
      if (
        !object(item) ||
        !text(item.key) ||
        seen.has(item.key) ||
        !request.selection.ids.includes(item.key)
      )
        return invalid("Service outcomes contain duplicate or unknown item identities.");
      seen.add(item.key);
      if (item.status === "applied") {
        if (
          !keys(item, ["key", "status", "record"]) ||
          !record(item.record) ||
          !item.record.inspectionRequired
        )
          return invalid("An applied item is missing a valid flagged equipment record.");
        const expected =
          request.operation === "import"
            ? request.items.find((row) => row.key === item.key)?.values
            : request.records.find((row) => row.id === item.key);
        if (
          !expected ||
          item.record.id !== expected.id ||
          item.record.name !== expected.name ||
          item.record.kind !== expected.kind ||
          item.record.site !== expected.site ||
          ("revision" in expected && item.record.revision === expected.revision)
        )
          return invalid(
            "An applied record does not match its requested item or has an unchanged revision.",
          );
        accepted++;
      } else if (item.status === "failed") {
        if (
          !keys(item, ["key", "status", "message", "retryable"]) ||
          !text(item.message, 2000) ||
          typeof item.retryable !== "boolean"
        )
          return invalid("A failed item needs an explicit message and retryability.");
      } else if (item.status === "canceled" || item.status === "skipped") {
        if (!keys(item, ["key", "status", "message"]) || !text(item.message, 2000))
          return invalid("An unprocessed item needs an explicit explanation.");
        if (item.status === "canceled") canceled++;
      } else return invalid("The service returned an unknown item outcome.");
    }
    if (
      (accepted > 0 &&
        (!text(input.sourceRevision) ||
          input.sourceRevision === request.context.source.revision)) ||
      (accepted === 0 && input.sourceRevision !== null)
    )
      return invalid(
        "Applied records require a new source revision; unsuccessful runs cannot advance the source.",
      );
    if (
      (input.status === "complete" && accepted !== input.items.length) ||
      (input.status === "partial" && (accepted === 0 || accepted === input.items.length)) ||
      (input.status === "failed" && accepted !== 0) ||
      (input.status === "canceled" && (canceled === 0 || accepted === input.items.length))
    )
      return invalid("The terminal summary does not agree with its item outcomes.");
    return { ok: true, value: freezeCopy(input as unknown as TransferResult) };
  } catch {
    return invalid("The service result could not be read; the remote outcome is unknown.");
  }
}

export function parseTransferProgress(
  input: unknown,
  request: TransferRequest,
): TransferParseResult<TransferProgress> {
  try {
    if (
      !object(input) ||
      !keys(input, ["requestId", "state", "completed", "total"], ["message"]) ||
      input.requestId !== request.requestId ||
      typeof input.state !== "string" ||
      !["queued", "running", "cancel-requested"].includes(input.state) ||
      (input.completed !== null &&
        (typeof input.completed !== "number" ||
          !Number.isSafeInteger(input.completed) ||
          input.completed < 0)) ||
      (input.total !== null &&
        (typeof input.total !== "number" ||
          !Number.isSafeInteger(input.total) ||
          input.total < 0)) ||
      (typeof input.completed === "number" &&
        typeof input.total === "number" &&
        input.completed > input.total) ||
      (input.message !== undefined && !text(input.message, 2000))
    )
      return invalid("Job progress is invalid or belongs to another request.");
    return { ok: true, value: freezeCopy(input as unknown as TransferProgress) };
  } catch {
    return invalid("Job progress could not be read.");
  }
}

export function parseTransferCancelResult(
  input: unknown,
  requestId: string,
): TransferParseResult<TransferCancelResult> {
  try {
    if (!object(input) || input.requestId !== requestId)
      return invalid("The cancellation acknowledgment belongs to another request.");
    const requested = input.status === "requested" && keys(input, ["requestId", "status"]);
    const rejected =
      input.status === "rejected" &&
      keys(input, ["requestId", "status", "message"]) &&
      text(input.message, 2000);
    if (!requested && !rejected)
      return invalid(
        "The service did not acknowledge this cancellation request. The job outcome is still pending.",
      );
    return { ok: true, value: freezeCopy(input as unknown as TransferCancelResult) };
  } catch {
    return invalid(
      "The cancellation response could not be read. The job outcome is still pending.",
    );
  }
}

export function filterTransferRecords(
  records: readonly TransferRecord[],
  filter: TransferFilter,
): TransferRecord[] {
  if (!validFilter(filter)) return [];
  const query = filter.query.toLocaleLowerCase("en-US");
  return records.filter(
    (item) =>
      (filter.kind === "all" || filter.kind === item.kind) &&
      (filter.site === "all" || filter.site === item.site) &&
      (item.name.toLocaleLowerCase("en-US").includes(query) ||
        item.id.toLocaleLowerCase("en-US").includes(query)),
  );
}
export function describeTransferFilter(filter: TransferFilter): string {
  if (!validFilter(filter)) return "Invalid filters";
  return (
    [
      filter.query ? `Name or ID contains “${filter.query}”` : "",
      filter.kind !== "all" ? `Kind: ${filter.kind}` : "",
      filter.site !== "all" ? `Site: ${filter.site}` : "",
    ]
      .filter(Boolean)
      .join("; ") || "All equipment"
  );
}
export function getRetryableTransferKeys(result: TransferResult): string[] {
  return result.operation === "export"
    ? []
    : result.items
        .filter((item) => item.status === "failed" && item.retryable)
        .map((item) => item.key);
}

patterns/resource-transfer/csv.ts

import type { TransferImportValues, TransferParseResult } from "./transfer-state";

export type ImportField = "id" | "name" | "kind" | "site";
export type ImportMapping = Partial<Record<ImportField, number>>;
export interface CsvTable {
  columns: readonly { index: number; label: string }[];
  rows: readonly { key: string; line: number; cells: readonly string[] }[];
}
export interface ImportRowError {
  field: ImportField;
  line: number;
  message: string;
}
export interface ImportValidationRow {
  key: string;
  line: number;
  cells: readonly string[];
  candidate: TransferImportValues | null;
  errors: readonly ImportRowError[];
}
export interface ImportValidation {
  errors: readonly string[];
  rows: readonly ImportValidationRow[];
  validCount: number;
  invalidCount: number;
}
export const CSV_MAX_BYTES = 1048576;
export const CSV_MAX_ROWS = 1000;
const fields: readonly ImportField[] = ["id", "name", "kind", "site"];
function hasControlCharacters(value: string): boolean {
  return Array.from(value).some((character) => {
    const code = character.charCodeAt(0);
    return code < 32 || (code >= 127 && code <= 159);
  });
}

/** UTF-8 byte length, without browser/Node globals. Unpaired surrogates encode as replacement characters. */
export function utf8ByteLength(text: string): number {
  let bytes = 0;
  for (const character of text) {
    const value = character.codePointAt(0)!;
    bytes += value < 0x80 ? 1 : value < 0x800 ? 2 : value < 0x10000 ? 3 : 4;
  }
  return bytes;
}

/** A strict, bounded CSV reader: syntax/width failure never returns a partial table. */
export function parseEquipmentCsv(text: string, fileId: string): TransferParseResult<CsvTable> {
  const fail = (error: string): TransferParseResult<CsvTable> => ({ ok: false, error });
  if (
    typeof text !== "string" ||
    text.length > CSV_MAX_BYTES ||
    utf8ByteLength(text) > CSV_MAX_BYTES
  )
    return fail("CSV files must be no larger than 1 MiB of UTF-8 text.");
  if (typeof fileId !== "string" || !fileId.trim() || fileId.length > 256)
    return fail("File identity is invalid.");
  const input = text.startsWith("\uFEFF") ? text.slice(1) : text;
  if (!input) return fail("The CSV needs a header row.");
  const rows: { line: number; cells: readonly string[] }[] = [];
  let cells: string[] = [],
    cell = "",
    quoted = false,
    closed = false,
    line = 1,
    startLine = 1;
  const finishCell = () => {
    cells.push(cell);
    cell = "";
    closed = false;
  };
  const finishRow = () => {
    finishCell();
    rows.push({ line: startLine, cells: Object.freeze(cells) });
    cells = [];
  };
  for (let index = 0; index < input.length; index++) {
    const character = input[index]!;
    if (character === "\r" && input[index + 1] !== "\n")
      return fail(`Unsupported line ending on line ${line}; use LF or CRLF.`);
    if (quoted) {
      if (character === '"') {
        if (input[index + 1] === '"') {
          cell += '"';
          index++;
        } else {
          quoted = false;
          closed = true;
        }
      } else {
        cell += character;
        if (character === "\n") line++;
      }
    } else if (character === '"') {
      if (cell !== "" || closed) return fail(`Unexpected quote on line ${line}.`);
      quoted = true;
    } else if (character === ",") {
      finishCell();
      if (cells.length >= 32) return fail("CSV supports at most 32 columns.");
    } else if (character === "\r" || character === "\n") {
      finishRow();
      if (character === "\r") index++;
      line++;
      startLine = line;
    } else {
      if (closed) return fail(`Unexpected text after a closing quote on line ${line}.`);
      cell += character;
    }
    if (cell.length > 4096) return fail(`Cell on line ${startLine} exceeds 4,096 characters.`);
    if (rows.length > CSV_MAX_ROWS + 1) return fail("CSV supports at most 1,000 data rows.");
  }
  if (quoted) return fail(`Unclosed quote starting on line ${startLine}.`);
  if (cell !== "" || closed || cells.length > 0 || !/[\r\n]$/.test(input)) finishRow();
  if (rows.length > CSV_MAX_ROWS + 1) return fail("CSV supports at most 1,000 data rows.");
  const header = rows[0];
  if (!header) return fail("The CSV needs a header row.");
  if (rows.some((row) => row.cells.length !== header.cells.length))
    return fail("Every CSV row must have the same number of columns as its header.");
  return {
    ok: true,
    value: Object.freeze({
      columns: Object.freeze(header.cells.map((label, index) => Object.freeze({ index, label }))),
      rows: Object.freeze(
        rows.slice(1).map((row) => Object.freeze({ key: `${fileId}:${row.line}`, ...row })),
      ),
    }),
  };
}

/** Mapping/domain errors retain all rows; only explicitly chosen valid candidates can be submitted. */
export function validateEquipmentImport(
  table: CsvTable,
  mapping: ImportMapping,
  existingIds: readonly string[],
): ImportValidation {
  const errors: string[] = [],
    used = new Set<number>();
  for (const field of fields) {
    const column = mapping[field];
    if (
      column === undefined ||
      !Number.isInteger(column) ||
      column < 0 ||
      column >= table.columns.length
    )
      errors.push(`Map ${field} to a source column.`);
    else if (used.has(column))
      errors.push(`The ${field} destination must use its own source column.`);
    else used.add(column);
  }
  const existing = new Set(existingIds),
    counts = new Map<string, number>();
  if (errors.length === 0)
    for (const row of table.rows) {
      const id = row.cells[mapping.id!]!;
      counts.set(id, (counts.get(id) ?? 0) + 1);
    }
  const rows: ImportValidationRow[] = table.rows.map((row) => {
    const rowErrors: ImportRowError[] = [];
    const add = (field: ImportField, message: string) =>
      rowErrors.push({ field, line: row.line, message });
    let candidate: TransferImportValues | null = null;
    if (errors.length === 0) {
      const id = row.cells[mapping.id!]!,
        name = row.cells[mapping.name!]!;
      const kind = row.cells[mapping.kind!]!,
        site = row.cells[mapping.site!]!;
      for (const field of fields)
        if (hasControlCharacters(row.cells[mapping[field]!]!))
          add(field, `${field} cannot contain control characters.`);
      if (!id.trim() || id.length > 80) add("id", "ID must contain 1–80 characters.");
      if (!name.trim() || name.length > 120) add("name", "Name must contain 1–120 characters.");
      if (!["pump", "fan", "valve", "gauge"].includes(kind))
        add("kind", "Kind must be pump, fan, valve or gauge.");
      if (site !== "west" && site !== "east") add("site", "Site must be west or east.");
      if ((counts.get(id) ?? 0) > 1) add("id", "ID occurs more than once in this file.");
      if (existing.has(id)) add("id", "ID already exists in the supplied inventory.");
      if (rowErrors.length === 0)
        candidate = Object.freeze({ id, name, kind, site }) as TransferImportValues;
    }
    return Object.freeze({
      ...row,
      candidate,
      errors: Object.freeze(rowErrors.map((error) => Object.freeze(error))),
    });
  });
  const validCount = rows.filter((row) => row.candidate !== null).length;
  return Object.freeze({
    errors: Object.freeze(errors),
    rows: Object.freeze(rows),
    validCount,
    invalidCount: rows.length - validCount,
  });
}

patterns/resource-management/fixtures.ts

import type { OperationalDomain } from "../operational-domain";

export type ResourceCondition = "ready" | "restricted" | "maintenance";
export type AssetServiceRecord = {
  id: string;
  kind: "inspection" | "service";
  title: string;
  recordedAt: string;
  recordedBy: string;
  result: "Complete" | "Action required" | "In progress";
  detail: string;
};
export type ManagedResource = {
  id: string;
  revision: number;
  name: string;
  category: string;
  owner: string;
  location: string;
  condition: ResourceCondition;
  serviceDue: string;
  note: string;
  updatedAt: string;
  /** Supplied evidence stays separate from editable assignment and service notes. */
  serviceRecords?: readonly AssetServiceRecord[];
  activity: readonly { id: string; at: string; detail: string }[];
};

export const conditionLabels: Record<ResourceCondition, string> = {
  ready: "Ready",
  restricted: "Restricted",
  maintenance: "Maintenance",
};

export const resourceScenarios = {
  military: {
    title: "Alder Garrison",
    department: "Sustainment company",
    role: "Logistics desk · Sgt. Maya Chen",
    source: "Alder logistics ledger",
    date: "02 Oct 2026",
    time: "08:30 UTC",
    owners: ["Sgt. Maya Chen", "Cpl. Noah Bennett", "Sgt. Leila Morgan", "Cpl. Evan Shaw"],
    locations: ["Vehicle park", "Power compound", "Supply yard", "Workshop 2"],
    categories: [
      "Cargo vehicle",
      "Power unit",
      "Water support",
      "Material handling",
      "Workshop equipment",
    ],
    selectedId: "GEN-018",
    idPlaceholder: "MTR-053",
  },
  industrial: {
    title: "Northbank Works",
    department: "Plant maintenance",
    role: "Maintenance desk · Priya Shah",
    source: "Northbank asset register",
    date: "02 Oct 2026",
    time: "08:30 UTC",
    owners: ["Priya Shah", "Marcus Reed", "Elena Ruiz", "Theo Walker"],
    locations: ["Process hall", "Utilities bay", "Loading dock", "Maintenance shop"],
    categories: [
      "Rotating equipment",
      "Compressed air",
      "Material handling",
      "Electrical",
      "Process control",
    ],
    selectedId: "PMP-204",
    idPlaceholder: "PMP-212",
  },
} as const;

type Seed = [string, string, string, string, string, ResourceCondition, string, string];
const seeds: Record<OperationalDomain, readonly Seed[]> = {
  military: [
    [
      "MTR-041",
      "Cargo truck 07",
      "Cargo vehicle",
      "Cpl. Noah Bennett",
      "Vehicle park",
      "ready",
      "2026-10-09",
      "Released after the weekly brake and fluid inspection. Assigned to the morning supply detail.",
    ],
    [
      "GEN-018",
      "Forward power unit",
      "Power unit",
      "Sgt. Maya Chen",
      "Workshop 2",
      "maintenance",
      "2026-10-02",
      "Replace the starter battery, then complete a 30-minute load test before release to the power compound.",
    ],
    [
      "WTR-009",
      "Water bowser 03",
      "Water support",
      "Sgt. Leila Morgan",
      "Supply yard",
      "ready",
      "2026-10-06",
      "Tank cleaned and seals checked. Potable-water certificate is filed with the supply desk.",
    ],
    [
      "FLT-012",
      "Rough-terrain forklift",
      "Material handling",
      "Cpl. Evan Shaw",
      "Supply yard",
      "restricted",
      "2026-10-03",
      "Use within the paved supply yard. Replace the left work lamp before night operations.",
    ],
    [
      "MTR-046",
      "Cargo truck 12",
      "Cargo vehicle",
      "Cpl. Noah Bennett",
      "Vehicle park",
      "ready",
      "2026-10-12",
      "Weekly inspection complete. Next assignment is the afternoon stores collection.",
    ],
    [
      "GEN-021",
      "Reserve generator",
      "Power unit",
      "Sgt. Maya Chen",
      "Power compound",
      "ready",
      "2026-10-08",
      "Fuel topped up and changeover test complete. Held as reserve for the east accommodation block.",
    ],
    [
      "TRL-033",
      "Stores trailer 06",
      "Cargo vehicle",
      "Sgt. Leila Morgan",
      "Vehicle park",
      "ready",
      "2026-10-14",
      "Tie-downs and coupling checked. Parked empty pending the next stores movement.",
    ],
    [
      "CMP-007",
      "Mobile air compressor",
      "Workshop equipment",
      "Cpl. Evan Shaw",
      "Workshop 2",
      "maintenance",
      "2026-10-02",
      "Outlet coupling leaks under pressure. Parts are held at the workshop counter for replacement.",
    ],
    [
      "WTR-011",
      "Water treatment skid",
      "Water support",
      "Sgt. Leila Morgan",
      "Supply yard",
      "ready",
      "2026-10-05",
      "Filter cartridges replaced on 30 September. Sample results are recorded in the treatment log.",
    ],
    [
      "LFT-004",
      "Workshop lifting set",
      "Workshop equipment",
      "Cpl. Evan Shaw",
      "Workshop 2",
      "ready",
      "2026-10-16",
      "Slings and shackles checked; inspection tags are present. Return to the marked storage rack after use.",
    ],
  ],
  industrial: [
    [
      "PMP-201",
      "Cooling water pump A",
      "Rotating equipment",
      "Priya Shah",
      "Process hall",
      "ready",
      "2026-10-09",
      "Duty pump. Seal check and vibration route are complete; the standby changeover is scheduled for Friday.",
    ],
    [
      "PMP-204",
      "Cooling water pump B",
      "Rotating equipment",
      "Priya Shah",
      "Maintenance shop",
      "maintenance",
      "2026-10-02",
      "Replace the drive-end bearing, align the coupling, then run the acceptance test before returning to standby.",
    ],
    [
      "AIR-031",
      "Instrument air compressor",
      "Compressed air",
      "Marcus Reed",
      "Utilities bay",
      "ready",
      "2026-10-07",
      "Dryer service complete. Duty pressure remains within the recorded operating range.",
    ],
    [
      "FLT-018",
      "Electric forklift 04",
      "Material handling",
      "Theo Walker",
      "Loading dock",
      "restricted",
      "2026-10-03",
      "Day shift use only until the rear work lamp is replaced. Charger bay 4 is reserved for this truck.",
    ],
    [
      "FAN-112",
      "Extraction fan 12",
      "Rotating equipment",
      "Elena Ruiz",
      "Process hall",
      "ready",
      "2026-10-12",
      "Belt tension checked on the last route. Next inspection includes the guard fasteners.",
    ],
    [
      "MCC-022",
      "Motor control cabinet 2",
      "Electrical",
      "Elena Ruiz",
      "Utilities bay",
      "ready",
      "2026-10-14",
      "Quarterly inspection complete. The updated circuit schedule is stored inside the door.",
    ],
    [
      "CNV-006",
      "Dispatch conveyor",
      "Material handling",
      "Theo Walker",
      "Loading dock",
      "ready",
      "2026-10-06",
      "Tracking adjusted and stops tested. Cleared for the morning dispatch window.",
    ],
    [
      "VLV-087",
      "Steam isolation valve",
      "Process control",
      "Marcus Reed",
      "Maintenance shop",
      "maintenance",
      "2026-10-02",
      "Packing replacement in progress. Bench leak test is required before the valve is returned to utilities.",
    ],
    [
      "SNS-042",
      "Level transmitter 42",
      "Process control",
      "Elena Ruiz",
      "Process hall",
      "ready",
      "2026-10-08",
      "Calibration verified against the workshop reference. Next route includes a cable-gland check.",
    ],
    [
      "AIR-034",
      "Standby air compressor",
      "Compressed air",
      "Marcus Reed",
      "Utilities bay",
      "ready",
      "2026-10-16",
      "Weekly start test complete. Available for the next duty rotation after the receiver is drained.",
    ],
  ],
};

const inspectionNotes: Record<string, string> = {
  "PMP-201": "Seal inspection and vibration route complete. No defects recorded.",
  "PMP-204":
    "Drive-end bearing vibration measured above the plant limit. Removed from standby duty.",
  "AIR-031": "Dryer outlet and duty pressure checked within the recorded operating range.",
  "FLT-018": "Rear work lamp failed the shift inspection. Day shift restriction recorded.",
  "FAN-112": "Belt tension and guard condition checked on the weekly route.",
  "MCC-022": "Quarterly visual inspection complete; circuit schedule verified.",
  "CNV-006": "Conveyor tracking and emergency stops passed the dispatch inspection.",
  "VLV-087": "Stem packing leak found during the utilities route. Valve sent for bench service.",
  "SNS-042": "Calibration verified against the workshop reference.",
  "AIR-034": "Weekly start test complete; standby availability confirmed.",
};

function createServiceRecords(
  id: string,
  owner: string,
  condition: ResourceCondition,
): AssetServiceRecord[] {
  const inspection: AssetServiceRecord = {
    id: id === "PMP-204" ? "INSP-4821" : `INSP-${id}`,
    kind: "inspection",
    title: id === "PMP-204" ? "Bearing vibration inspection" : "Equipment condition inspection",
    recordedAt: "2026-10-01T15:10:00Z",
    recordedBy: owner,
    result: condition === "ready" ? "Complete" : "Action required",
    detail: inspectionNotes[id]!,
  };
  if (id !== "PMP-204") return [inspection];
  return [
    {
      id: "WO-2641",
      kind: "service",
      title: "Drive-end bearing replacement",
      recordedAt: "2026-10-02T08:10:00Z",
      recordedBy: "Marcus Reed",
      result: "In progress",
      detail:
        "Replacement bearing issued to the maintenance shop. Alignment and acceptance test remain open.",
    },
    inspection,
  ];
}

/** Fresh objects keep every documentation scenario isolated from edits in another. */
export function createResourceRecords(domain: OperationalDomain): ManagedResource[] {
  return seeds[domain].map(
    ([id, name, category, owner, location, condition, serviceDue, note], index) => ({
      id,
      name,
      category,
      owner,
      location,
      condition,
      serviceDue,
      note,
      revision: index === 1 ? 4 : 2,
      updatedAt: `2026-10-02T08:${String(20 - index).padStart(2, "0")}:00Z`,
      ...(domain === "industrial"
        ? { serviceRecords: createServiceRecords(id, owner, condition) }
        : {}),
      activity: [
        {
          id: `${id}-check`,
          at: `2026-10-02T08:${String(20 - index).padStart(2, "0")}:00Z`,
          detail: `${owner} confirmed ${conditionLabels[condition].toLowerCase()} condition.`,
        },
        {
          id: `${id}-location`,
          at: "2026-10-01T15:10:00Z",
          detail: `Location confirmed: ${location}.`,
        },
      ],
    }),
  );
}

patterns/resource-management/resource-form.tsx

"use client";

import { useEffect, useRef, useState } from "react";
import {
  Button,
  ConfirmDialog,
  Dialog,
  Field,
  Input,
  Select,
  SelectOption,
  Textarea,
} from "@operator-ds/react";
import type { OperationalDomain } from "../operational-domain";
import {
  conditionLabels,
  resourceScenarios,
  type ManagedResource,
  type ResourceCondition,
} from "./fixtures";
import {
  validateResource,
  valuesOf,
  type ResourceErrors,
  type ResourceSaveRequest,
  type ResourceSaveResult,
  type ResourceValues,
} from "./state";

export function ResourceForm({
  domain,
  asset = false,
  record,
  onSave,
  onSaved,
  onClose,
}: {
  domain: OperationalDomain;
  asset?: boolean;
  record: ManagedResource | null;
  onSave: (request: ResourceSaveRequest) => Promise<ResourceSaveResult>;
  onSaved: (record: ManagedResource) => void;
  onClose: () => void;
}) {
  const scenario = resourceScenarios[domain];
  const subject = asset ? "asset" : "resource";
  const label = asset ? "Asset" : "Resource";
  const [baseline] = useState<ResourceValues>(() =>
    record
      ? valuesOf(record)
      : {
          name: "",
          category: scenario.categories[0],
          owner: scenario.owners[0],
          location: scenario.locations[0],
          condition: "ready",
          serviceDue: "2026-10-09",
          note: "",
        },
  );
  const [values, setValues] = useState(baseline);
  const [id, setId] = useState(record?.id ?? "");
  const [errors, setErrors] = useState<ResourceErrors>({});
  const [failure, setFailure] = useState("");
  const [saving, setSaving] = useState(false);
  const [confirmDiscard, setConfirmDiscard] = useState(false);
  const live = useRef(true);
  const busy = useRef(false);
  const form = useRef<HTMLFormElement>(null);
  const dirty = JSON.stringify(values) !== JSON.stringify(baseline) || id !== (record?.id ?? "");

  useEffect(() => {
    live.current = true;
    return () => {
      live.current = false;
    };
  }, []);
  useEffect(() => {
    if (!dirty) return;
    const guard = (event: BeforeUnloadEvent) => {
      event.preventDefault();
      event.returnValue = "";
    };
    window.addEventListener("beforeunload", guard);
    return () => window.removeEventListener("beforeunload", guard);
  }, [dirty]);

  function change<K extends keyof ResourceValues>(key: K, value: ResourceValues[K]) {
    setValues((previous) => ({ ...previous, [key]: value }));
    setErrors((previous) => {
      const next = { ...previous };
      delete next[key];
      return next;
    });
    setFailure("");
  }
  function close() {
    if (busy.current) return;
    if (dirty) setConfirmDiscard(true);
    else onClose();
  }
  async function save() {
    if (busy.current) return;
    const nextErrors = validateResource(domain, id, values);
    setErrors(nextErrors);
    setFailure("");
    if (Object.keys(nextErrors).length) {
      requestAnimationFrame(() =>
        form.current?.querySelector<HTMLElement>("[aria-invalid='true']")?.focus(),
      );
      return;
    }
    busy.current = true;
    setSaving(true);
    try {
      const result = await onSave({
        domain,
        id,
        expectedRevision: record?.revision ?? null,
        values,
      });
      if (!live.current) return;
      if (result.state !== "accepted") setFailure(result.message);
      else if (
        result.record.id !== id ||
        !Number.isSafeInteger(result.record.revision) ||
        result.record.revision <= (record?.revision ?? 0)
      )
        setFailure(
          "The save response did not confirm this revision. Your draft is still open; retry after checking the register.",
        );
      else onSaved(result.record);
    } catch {
      if (live.current)
        setFailure(`The ${subject} could not be saved. Your draft is still here; try again.`);
    } finally {
      busy.current = false;
      if (live.current) setSaving(false);
    }
  }

  return (
    <>
      <Dialog
        open
        title={record ? `Edit ${record.id}` : `Add ${subject}`}
        description={record ? record.name : `Register equipment at ${scenario.title}.`}
        size="lg"
        onOpenChange={(open) => {
          if (!open) close();
        }}
        className="max-h-[90dvh] overflow-y-auto"
      >
        <form
          ref={form}
          className="flex flex-col gap-3u"
          noValidate
          onSubmit={(event) => {
            event.preventDefault();
            void save();
          }}
          aria-busy={saving}
        >
          {!record && (
            <div className="grid grid-cols-1 gap-2u sm:grid-cols-2">
              <Field
                label={`${label} ID`}
                required
                error={errors.id ?? ""}
                help={`Example: ${scenario.idPlaceholder}`}
              >
                <Input
                  value={id}
                  maxLength={21}
                  disabled={saving}
                  autoComplete="off"
                  onChange={(event) => {
                    setId(event.target.value.toUpperCase());
                    setErrors((previous) => {
                      const next = { ...previous };
                      delete next.id;
                      return next;
                    });
                    setFailure("");
                  }}
                />
              </Field>
              <Field label={`${label} name`} required error={errors.name ?? ""}>
                <Input
                  value={values.name}
                  maxLength={80}
                  disabled={saving}
                  onChange={(event) => change("name", event.target.value)}
                />
              </Field>
              <Field label={`${label} type`} required error={errors.category ?? ""}>
                <Select
                  value={values.category}
                  disabled={saving}
                  onValueChange={(value) => change("category", value)}
                >
                  {scenario.categories.map((category) => (
                    <SelectOption key={category} value={category}>
                      {category}
                    </SelectOption>
                  ))}
                </Select>
              </Field>
            </div>
          )}
          <div className="grid grid-cols-1 gap-2u sm:grid-cols-2">
            <Field label="Owner" required error={errors.owner ?? ""}>
              <Select
                value={values.owner}
                disabled={saving}
                onValueChange={(value) => change("owner", value)}
              >
                {scenario.owners.map((owner) => (
                  <SelectOption key={owner} value={owner}>
                    {owner}
                  </SelectOption>
                ))}
              </Select>
            </Field>
            <Field label="Location" required error={errors.location ?? ""}>
              <Select
                value={values.location}
                disabled={saving}
                onValueChange={(value) => change("location", value)}
              >
                {scenario.locations.map((location) => (
                  <SelectOption key={location} value={location}>
                    {location}
                  </SelectOption>
                ))}
              </Select>
            </Field>
            <Field label="Condition" required error={errors.condition ?? ""}>
              <Select
                value={values.condition}
                disabled={saving}
                onValueChange={(value) => change("condition", value as ResourceCondition)}
              >
                {Object.entries(conditionLabels).map(([key, label]) => (
                  <SelectOption key={key} value={key}>
                    {label}
                  </SelectOption>
                ))}
              </Select>
            </Field>
            <Field label="Service due" required error={errors.serviceDue ?? ""}>
              <Input
                type="date"
                value={values.serviceDue}
                disabled={saving}
                onChange={(event) => change("serviceDue", event.target.value)}
              />
            </Field>
          </div>
          <Field
            label="Service note"
            required
            error={errors.note ?? ""}
            help="Include the next action or any limits on use."
          >
            <Textarea
              value={values.note}
              rows={3}
              maxLength={500}
              disabled={saving}
              onChange={(event) => change("note", event.target.value)}
            />
          </Field>
          {failure && (
            <p role="alert" className="m-0 border border-oprt-border p-2u text-oprt-error">
              {failure}
            </p>
          )}
          <div className="flex flex-wrap items-center justify-end gap-1u border-t border-oprt-border pt-2u">
            <Button variant="tertiary" disabled={saving} onClick={close}>
              Cancel
            </Button>
            <Button type="submit" disabled={saving || (!!record && !dirty)}>
              {saving ? "Saving…" : record ? "Save changes" : `Add ${subject}`}
            </Button>
          </div>
        </form>
      </Dialog>
      <ConfirmDialog
        open={confirmDiscard}
        onOpenChange={setConfirmDiscard}
        title="Discard unsaved changes?"
        description={`The register has not been changed. Discard this draft to return to the ${subject} details.`}
        confirmLabel="Discard changes"
        cancelLabel="Keep editing"
        onConfirm={onClose}
      />
    </>
  );
}

patterns/resource-management/state.ts

import type { OperationalDomain } from "../operational-domain";
import { conditionLabels, resourceScenarios, type ManagedResource } from "./fixtures";

export type ResourceValues = Pick<
  ManagedResource,
  "name" | "category" | "owner" | "location" | "condition" | "serviceDue" | "note"
>;
export type ResourceSaveRequest = {
  domain: OperationalDomain;
  id: string;
  expectedRevision: number | null;
  values: ResourceValues;
};
export type ResourceSaveResult =
  | { state: "accepted"; record: ManagedResource }
  | { state: "rejected" | "conflict"; message: string };
export type ResourceErrors = Partial<Record<keyof ResourceValues | "id", string>>;

export function validateResource(
  domain: OperationalDomain,
  id: string,
  values: ResourceValues,
): ResourceErrors {
  const errors: ResourceErrors = {};
  const scenario = resourceScenarios[domain];
  if (!/^[A-Z][A-Z0-9]{1,7}-[A-Z0-9]{2,12}$/.test(id))
    errors.id = `Use an identifier such as ${scenario.idPlaceholder}.`;
  if (!values.name.trim() || values.name.trim().length > 80)
    errors.name = `Enter ${domain === "industrial" ? "an asset" : "a resource"} name of 1–80 characters.`;
  if (!(scenario.categories as readonly string[]).includes(values.category))
    errors.category = `Choose ${domain === "industrial" ? "an asset" : "a resource"} type for this register.`;
  if (!(scenario.owners as readonly string[]).includes(values.owner))
    errors.owner = "Choose an owner from this team.";
  if (!(scenario.locations as readonly string[]).includes(values.location))
    errors.location = "Choose a location at this site.";
  if (!Object.hasOwn(conditionLabels, values.condition)) errors.condition = "Choose a condition.";
  const date = new Date(`${values.serviceDue}T00:00:00Z`);
  if (
    !/^\d{4}-\d{2}-\d{2}$/.test(values.serviceDue) ||
    !Number.isFinite(date.getTime()) ||
    date.toISOString().slice(0, 10) !== values.serviceDue
  )
    errors.serviceDue = "Enter a valid service date.";
  if (!values.note.trim() || values.note.trim().length > 500)
    errors.note = "Enter a service note of 1–500 characters.";
  return errors;
}

/** An application adapter may replace this local transaction with a service request. */
export function applyResourceSave(
  records: readonly ManagedResource[],
  request: ResourceSaveRequest,
  at: string,
): ResourceSaveResult & { records?: ManagedResource[] } {
  const errors = validateResource(request.domain, request.id, request.values);
  if (Object.keys(errors).length) return { state: "rejected", message: Object.values(errors)[0]! };
  const previous = records.find((record) => record.id === request.id);
  if (request.expectedRevision === null && previous)
    return {
      state: "rejected",
      message: `${request.id} already exists. Use a different identifier.`,
    };
  if (
    request.expectedRevision !== null &&
    (!previous || previous.revision !== request.expectedRevision)
  )
    return {
      state: "conflict",
      message: `This ${request.domain === "industrial" ? "asset" : "resource"} changed after you opened it. Keep your note, close the editor, and reopen the latest record before saving.`,
    };
  const record: ManagedResource = {
    ...request.values,
    name: request.values.name.trim(),
    note: request.values.note.trim(),
    id: request.id,
    revision: (previous?.revision ?? 0) + 1,
    updatedAt: at,
    ...(previous?.serviceRecords ? { serviceRecords: previous.serviceRecords } : {}),
    activity: [
      {
        id: `${request.id}-${(previous?.revision ?? 0) + 1}`,
        at,
        detail: previous
          ? "Assignment and service details updated."
          : `Added to the ${request.domain === "industrial" ? "asset" : "resource"} register.`,
      },
      ...(previous?.activity ?? []),
    ].slice(0, 4),
  };
  return {
    state: "accepted",
    record,
    records: previous
      ? records.map((item) => (item.id === record.id ? record : item))
      : [...records, record],
  };
}

export function valuesOf(record: ManagedResource): ResourceValues {
  const { name, category, owner, location, condition, serviceDue, note } = record;
  return { name, category, owner, location, condition, serviceDue, note };
}

patterns/resource-management/demo.tsx

"use client";

import { useRef, useState } from "react";
import { createResourceRecords } from "./fixtures";
import { AssetManagement } from "./resource-management";
import { applyResourceSave, type ResourceSaveRequest, type ResourceSaveResult } from "./state";

export function AssetManagementDemo() {
  const [records, setRecords] = useState(() => createResourceRecords("industrial"));
  const current = useRef(records);
  async function save(request: ResourceSaveRequest): Promise<ResourceSaveResult> {
    if (request.domain !== "industrial")
      return {
        state: "rejected",
        message: "This request belongs to a different register. Reopen the asset and try again.",
      };
    const outcome = applyResourceSave(current.current, request, new Date().toISOString());
    if (outcome.state === "accepted" && outcome.records) {
      current.current = outcome.records;
      setRecords(outcome.records);
    }
    return outcome;
  }
  return <AssetManagement records={records} onSave={save} />;
}

/** Compatibility export for applications using the original recipe name. */
export const ResourceManagementDemo = AssetManagementDemo;