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/artifacts/page.tsx
5.1 KB
import { FolderTree, FileWarning } from "lucide-react";
import { PageHeader } from "@/components/layout/page-header";
import { Markdown } from "@/components/shared/markdown";
import { FileTree } from "@/components/artifacts/file-tree";
import { FolderManager } from "@/components/files/folder-manager";
import { FileDeleteButton } from "@/components/files/file-delete-button";
import { Card } from "@/components/ui/card";
import { getArtifactTree, getArtifactFile } from "@/lib/content/artifacts";
import { CONTENT_ROOT } from "@/lib/content/config";
import { ALLOWED_EXTENSIONS } from "@/lib/uploads/config";
import { isManaged, listManagedDir, type ManagedDir } from "@/lib/files/manager";
export const dynamic = "force-dynamic";
export const metadata = { title: "Artifacts" };
function formatBytes(bytes: number): string {
if (bytes < 1024) return `${bytes} B`;
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
}
export default function ArtifactsPage({
searchParams,
}: {
searchParams: { file?: string; dir?: string };
}) {
const tree = getArtifactTree();
const selectedPath = searchParams.file ?? null;
const selectedDir = searchParams.dir ?? null;
const file = selectedPath ? getArtifactFile(selectedPath) : null;
const isMarkdown = file?.ext === ".md" || file?.ext === ".mdx";
const fileManaged = selectedPath ? isManaged(selectedPath) : false;
// When a managed folder is selected, load its contents for the file-manager.
let folder: ManagedDir | null = null;
if (!selectedPath && selectedDir && isManaged(selectedDir)) {
try {
folder = listManagedDir(selectedDir);
} catch {
folder = null;
}
}
const accept = [...ALLOWED_EXTENSIONS].join(",");
return (
<div>
<PageHeader
eyebrow="Intelligence"
title="Artifacts"
description="Browse the repository, read documents, and manage the governance folders. Source, runtime, and infrastructure are read-only."
/>
<div className="grid grid-cols-1 gap-6 lg:grid-cols-[300px_1fr]">
<Card className="h-fit max-h-[72vh] overflow-y-auto p-2 lg:sticky lg:top-6">
<div className="px-2 py-1.5 text-[11px] font-semibold uppercase tracking-[0.1em] text-muted-foreground">
Repository
</div>
<FileTree tree={tree} selected={selectedPath} selectedDir={selectedDir} />
</Card>
<div className="min-w-0">
{file ? (
<Card className="overflow-hidden">
<div className="flex items-center justify-between gap-3 border-b border-border bg-secondary/40 px-5 py-3">
<span className="truncate font-mono text-[12px] font-medium text-foreground">
{file.path}
</span>
<div className="flex shrink-0 items-center gap-3">
<span className="text-[11px] tabular-nums text-muted-foreground">
{formatBytes(file.size)}
</span>
{fileManaged && <FileDeleteButton path={file.path} />}
</div>
</div>
{file.content === null ? (
<div className="px-5 py-16 text-center text-sm text-muted-foreground">
This file is binary or too large to preview.
</div>
) : isMarkdown ? (
<div className="p-8">
<Markdown>{file.content}</Markdown>
</div>
) : (
<pre className="overflow-x-auto bg-[hsl(220,18%,9%)] p-5 text-[12.5px] leading-relaxed text-[hsl(220,14%,92%)]">
<code className="font-mono">{file.content}</code>
</pre>
)}
</Card>
) : selectedPath ? (
<Card className="flex flex-col items-center justify-center px-6 py-24 text-center">
<FileWarning className="mb-4 h-8 w-8 text-muted-foreground/50" />
<h3 className="text-sm font-semibold">File not found</h3>
<p className="mt-1 max-w-sm text-sm text-muted-foreground">
<code className="font-mono text-xs">{selectedPath}</code> could
not be read.
</p>
</Card>
) : folder ? (
<FolderManager folder={folder} accept={accept} />
) : (
<Card className="flex flex-col items-center justify-center px-6 py-24 text-center">
<FolderTree className="mb-4 h-8 w-8 text-muted-foreground/50" />
<h3 className="text-sm font-semibold">Select a file or folder</h3>
<p className="mt-1 max-w-sm text-sm text-muted-foreground">
Click a file to read it, or a folder to manage it. Folders under
canonical, constitutions, doctrine, roadmaps, templates,
artifacts, and uploads can be created, filled, and deleted.
</p>
</Card>
)}
</div>
</div>
<p className="mt-6 font-mono text-[11px] text-muted-foreground">
root · {CONTENT_ROOT}
</p>
</div>
);
}
root · /srv/aaf