Intelligence
Artifacts
Browse the repository, read documents, and manage the governance folders. Source, runtime, and infrastructure are read-only.
Repository
assignment-dispatch-button.tsxassignment-status-badge.tsxassignments-panel.tsxcreate-mission-form.tsxgovernance-panels.tsxmission-dispatch.tsxmission-edit.tsxmission-state-actions.tsxmission-status-badge.tsxobjective-edit.tsxobjective-status-badge.tsxobjective-status-select.tsxobjectives-panel.tsxreport-list.tsxwork-orders-panel.tsx
README.md
CONSTITUTION_COMPLIANCE_AUDIT_V1.mdREADME.md
repositories/aaf-holdings/hq01/components/assets/asset-filters.tsx
2.8 KB
"use client";
import { useRouter } from "next/navigation";
interface Facets {
types: string[];
repositories: string[];
executives: string[];
statuses: string[];
tags: string[];
}
/**
* Asset Ledger filters. Search by mission, type, repository, executive, tag,
* and status — driven through the URL so the server filters the ledger.
*/
export function AssetFilters({
facets,
current,
}: {
facets: Facets;
current: Record<string, string | undefined>;
}) {
const router = useRouter();
function setParam(key: string, value: string) {
const params = new URLSearchParams();
for (const [k, v] of Object.entries(current)) {
if (v && k !== key) params.set(k, v);
}
if (value) params.set(key, value);
const qs = params.toString();
router.push(qs ? `/assets?${qs}` : "/assets");
}
const Select = ({
label,
name,
options,
}: {
label: string;
name: string;
options: string[];
}) => (
<label className="flex flex-col gap-1">
<span className="text-[10px] font-semibold uppercase tracking-[0.08em] text-muted-foreground">
{label}
</span>
<select
value={current[name] ?? ""}
onChange={(e) => setParam(name, e.target.value)}
className="h-9 rounded-md border border-input bg-background px-2 text-sm"
>
<option value="">All</option>
{options.map((o) => (
<option key={o} value={o}>
{o}
</option>
))}
</select>
</label>
);
const hasFilter = Object.values(current).some(Boolean);
return (
<div className="flex flex-wrap items-end gap-3">
<Select label="Type" name="type" options={facets.types} />
<Select label="Repository" name="repository" options={facets.repositories} />
<Select label="Executive" name="executive" options={facets.executives} />
<Select label="Status" name="status" options={facets.statuses} />
<Select label="Tag" name="tag" options={facets.tags} />
<label className="flex flex-col gap-1">
<span className="text-[10px] font-semibold uppercase tracking-[0.08em] text-muted-foreground">
Mission
</span>
<input
defaultValue={current.mission ?? ""}
onKeyDown={(e) => {
if (e.key === "Enter") setParam("mission", (e.target as HTMLInputElement).value.trim());
}}
onBlur={(e) => setParam("mission", e.target.value.trim())}
placeholder="MISSION-000001"
className="h-9 rounded-md border border-input bg-background px-2 font-mono text-xs"
/>
</label>
{hasFilter && (
<button
type="button"
onClick={() => router.push("/assets")}
className="h-9 rounded-md px-3 text-[13px] text-muted-foreground hover:text-foreground"
>
Clear
</button>
)}
</div>
);
}
root · /srv/aaf