Intelligence
Artifacts
Browse the repository, read documents, and manage the governance folders. Source, runtime, and infrastructure are read-only.
Repository
repositories/aaf-holdings/hq01/app/mission-control/[id]/objectives/[oid]/page.tsx
5.8 KB
import { notFound } from "next/navigation";
import { Target, User, History as HistoryIcon } from "lucide-react";
import { PageHeader } from "@/components/layout/page-header";
import { Card, CardContent } from "@/components/ui/card";
import { Separator } from "@/components/ui/separator";
import { MetaItem, FieldList } from "@/components/shared/field-list";
import { PriorityBadge } from "@/components/shared/status-badge";
import { ObjectiveStatusBadge } from "@/components/missions/objective-status-badge";
import { ObjectiveStatusSelect } from "@/components/missions/objective-status-select";
import { ObjectiveEdit } from "@/components/missions/objective-edit";
import { ReportList } from "@/components/missions/report-list";
import { getObjectiveView } from "@/lib/missions/objectives";
import { listReportsForObjective } from "@/lib/missions/reports";
import { getMission } from "@/lib/missions/manager";
import { loadRegistry } from "@/lib/executives/registry";
import type { ObjectiveEventType } from "@/lib/missions/types";
export const dynamic = "force-dynamic";
const EVENT_LABEL: Record<ObjectiveEventType, string> = {
objective_created: "Objective created",
objective_updated: "Objective updated",
state_changed: "State changed",
executive_changed: "Executive changed",
};
export default function ObjectiveDetailPage({
params,
}: {
params: { id: string; oid: string };
}) {
const view = getObjectiveView(params.id, params.oid);
if (!view) notFound();
const { objective, history } = view;
const reports = listReportsForObjective(params.id, params.oid);
const mission = getMission(params.id);
const owners = loadRegistry().map((e) => ({
id: e.id,
label: `${e.displayName} — ${e.office}`,
active: e.status === "active",
}));
return (
<div>
<PageHeader
eyebrow={`${objective.mission_id} · ${objective.id}`}
title={objective.title}
description={objective.description}
back={{
label: mission ? mission.title : "Mission",
href: `/mission-control/${objective.mission_id}`,
}}
actions={
<div className="flex flex-col items-end gap-2">
<div className="flex items-center gap-2">
<PriorityBadge priority={objective.priority} />
<ObjectiveStatusBadge status={objective.status} />
</div>
<ObjectiveEdit objective={objective} owners={owners} />
</div>
}
/>
<div className="grid grid-cols-1 gap-8 lg:grid-cols-3">
<div className="space-y-6 lg:col-span-2">
<Card>
<CardContent className="space-y-4 p-6">
<div className="flex items-center gap-2 text-[11px] font-semibold uppercase tracking-[0.1em] text-muted-foreground">
<Target className="h-3.5 w-3.5" /> Outcome
</div>
{objective.success_criteria.length > 0 ? (
<FieldList label="Success Criteria" items={objective.success_criteria} />
) : (
<p className="text-sm text-muted-foreground">No success criteria recorded.</p>
)}
</CardContent>
</Card>
<Card>
<CardContent className="p-6">
<div className="mb-3 flex items-center gap-2 text-[11px] font-semibold uppercase tracking-[0.1em] text-muted-foreground">
<Target className="h-3.5 w-3.5" /> Reports ({reports.length})
</div>
<ReportList reports={reports} emptyText="No reports for this objective yet." />
</CardContent>
</Card>
<Card>
<CardContent className="p-6">
<div className="mb-4 flex items-center gap-2 text-[11px] font-semibold uppercase tracking-[0.1em] text-muted-foreground">
<HistoryIcon className="h-3.5 w-3.5" /> History
</div>
<ol className="space-y-3">
{history.map((e, i) => (
<li key={i} className="flex gap-3">
<div className="mt-1 h-1.5 w-1.5 shrink-0 rounded-full bg-accent" />
<div>
<div className="text-[13px] font-medium text-foreground">
{EVENT_LABEL[e.type] ?? e.type}
{e.detail && (
<span className="font-normal text-muted-foreground"> — {e.detail}</span>
)}
</div>
<div className="text-[11px] text-muted-foreground">
{new Date(e.at).toLocaleString()}
</div>
</div>
</li>
))}
</ol>
</CardContent>
</Card>
</div>
<aside className="space-y-6">
<Card>
<CardContent className="space-y-5 p-6">
<MetaItem label="Status">
<ObjectiveStatusSelect
missionId={objective.mission_id}
oid={objective.id}
status={objective.status}
/>
</MetaItem>
<Separator />
<MetaItem label="Completion">
<span className="tabular-nums">{objective.completion_percentage}%</span>
</MetaItem>
<Separator />
<MetaItem label="Owner Executive">
<span className="inline-flex items-center gap-1.5 font-mono">
<User className="h-4 w-4 text-muted-foreground" />
{objective.owner_executive ?? "—"}
</span>
</MetaItem>
</CardContent>
</Card>
<div className="font-mono text-[11px] text-muted-foreground">
/srv/aaf/missions/{objective.mission_id}/objectives/{objective.id}/
</div>
</aside>
</div>
</div>
);
}
root · /srv/aaf