Files
asf/frontend/asf-web/app/deployments/page.tsx
T
2026-09-08 07:21:34 -04:00

90 lines
4.8 KiB
TypeScript

"use client";
import React from "react";
import { Rocket, Cloud, CheckCircle2, AlertTriangle, Clock } from "lucide-react";
import { Card, CardBody, CardHeader, CardTitle } from "@/components/ui/Card";
import { Badge, ArtifactTypeBadge } from "@/components/ui/Badge";
import { EmptyState } from "@/components/ui/EmptyState";
import { MetricCard } from "@/components/ui/MetricCard";
import { fmtDate } from "@/lib/utils";
const DEPLOYS = [
{ id: "DEP-44", env: "prod-west-1", service: "asf-core", version: "v0.4.0", status: "done", at: "2025-11-14T14:12:00Z", by: "ci-bot" },
{ id: "DEP-43", env: "staging", service: "asf-core", version: "v0.4.0-rc3", status: "done", at: "2025-11-13T17:00:00Z", by: "ci-bot" },
{ id: "DEP-42", env: "prod-west-1", service: "asf-web", version: "v0.3.2", status: "done", at: "2025-11-11T09:30:00Z", by: "m.rossi" },
{ id: "DEP-41", env: "prod-west-1", service: "asf-worker", version: "v0.3.1", status: "failed", at: "2025-11-09T20:45:00Z", by: "ci-bot" },
{ id: "DEP-40", env: "staging", service: "asf-ai", version: "v0.3.0", status: "running", at: new Date().toISOString(), by: "ci-bot" },
];
export default function DeploymentsPage() {
return (
<div className="p-6 lg:p-8 max-w-[1400px] mx-auto">
<header className="mb-6 flex flex-wrap items-start justify-between gap-3">
<div>
<h1 className="text-2xl font-semibold tracking-tight text-slate-900 flex items-center gap-2">
<Rocket className="w-6 h-6 text-emerald-600" />
Deployments
</h1>
<p className="mt-1 text-sm text-slate-500">
Release history per environment, linked back to Build, Pull Request and Requirement artifacts.
</p>
</div>
<Badge tone="neutral">Argo CD · readiness probe</Badge>
</header>
<section className="grid grid-cols-2 md:grid-cols-4 gap-4 mb-6">
<MetricCard label="Deployed (7d)" value={14} tone="green" icon={<Rocket className="w-5 h-5" />} delta={2.0} />
<MetricCard label="Success rate" value={92.6} isPercentage tone="brand" icon={<CheckCircle2 className="w-5 h-5" />} />
<MetricCard label="In progress" value={1} tone="blue" icon={<Clock className="w-5 h-5" />} />
<MetricCard label="Failed (7d)" value={1} tone="red" icon={<AlertTriangle className="w-5 h-5" />} />
</section>
<Card>
<CardHeader>
<CardTitle>Recent deployments</CardTitle>
<div className="flex items-center gap-2 text-xs">
<Badge tone="green"><Cloud className="w-3 h-3" /> prod-west-1</Badge>
<Badge tone="blue"><Cloud className="w-3 h-3" /> staging</Badge>
</div>
</CardHeader>
<CardBody className="p-0">
{DEPLOYS.length === 0 ? (
<div className="p-6"><EmptyState title="No deployments" description="Connect a CI/CD integration or create a Deployment artifact." /></div>
) : (
<table className="w-full text-sm">
<thead className="bg-slate-50 text-xs uppercase tracking-wide text-slate-500 border-b border-slate-200">
<tr>
<th className="text-left px-4 py-2">ID</th>
<th className="text-left px-4 py-2">Env</th>
<th className="text-left px-4 py-2">Service</th>
<th className="text-left px-4 py-2">Version</th>
<th className="text-left px-4 py-2">Status</th>
<th className="text-left px-4 py-2">At</th>
<th className="text-left px-4 py-2">By</th>
</tr>
</thead>
<tbody className="divide-y divide-slate-100">
{DEPLOYS.map((d) => (
<tr key={d.id} className="hover:bg-slate-50">
<td className="px-4 py-2.5 asf-monospace text-xs text-slate-500">{d.id}</td>
<td className="px-4 py-2.5">
<Badge tone={d.env.startsWith("prod") ? "green" : "blue"}>{d.env}</Badge>
</td>
<td className="px-4 py-2.5"><ArtifactTypeBadge type="deployment" /> <span className="ml-2 font-medium text-slate-800">{d.service}</span></td>
<td className="px-4 py-2.5 asf-monospace text-xs">{d.version}</td>
<td className="px-4 py-2.5">
<Badge tone={d.status === "done" ? "green" : d.status === "running" ? "blue" : "red"}>{d.status}</Badge>
</td>
<td className="px-4 py-2.5 text-xs text-slate-500 whitespace-nowrap">{fmtDate(d.at)}</td>
<td className="px-4 py-2.5 text-xs text-slate-600">{d.by}</td>
</tr>
))}
</tbody>
</table>
)}
</CardBody>
</Card>
</div>
);
}