Intelligence

Artifacts

Browse the repository, read documents, and manage the governance folders. Source, runtime, and infrastructure are read-only.

Repository
README.md
CONSTITUTION_COMPLIANCE_AUDIT_V1.mdREADME.md
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