import Link from 'next/link'; import { notFound, redirect } from 'next/navigation'; import { ArrowLeft, Edit, Play, Archive, Plus } from 'lucide-react'; import { Button } from '@/components/ui/button'; import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; import { Badge } from '@/components/ui/badge'; import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'; import { Separator } from '@/components/ui/separator'; import { getReleaseById, activateRelease, archiveRelease } from '@/lib/actions/releases'; import { getReleaseStepsGroupedByCluster, getStepStats } from '@/lib/actions/customer-steps'; import { listCustomers } from '@/lib/actions/customers'; import { ReleaseMatrixClient } from '@/components/releases/release-matrix-client'; interface ReleaseDetailPageProps { params: Promise<{ id: string; }>; } const typeColors: Record = { onboarding: 'bg-purple-100 text-purple-800', release: 'bg-blue-100 text-blue-800', hotfix: 'bg-red-100 text-red-800', }; const statusColors: Record = { draft: 'bg-slate-100 text-slate-800', active: 'bg-green-100 text-green-800', archived: 'bg-gray-100 text-gray-800', }; function getTypeColor(type: string) { return typeColors[type] || 'bg-slate-100 text-slate-800'; } function getStatusColor(status: string) { return statusColors[status] || 'bg-slate-100 text-slate-800'; } export const dynamic = 'force-dynamic'; export default async function ReleaseDetailPage({ params }: ReleaseDetailPageProps) { const { id } = await params; const releaseId = parseInt(id); const release = await getReleaseById(releaseId); if (!release) { notFound(); } // Get steps grouped by cluster const stepsByCluster = release.status === 'active' ? await getReleaseStepsGroupedByCluster(releaseId) : {}; const stats = release.status === 'active' ? await getStepStats(releaseId) : { total: 0, done: 0, skipped: 0, pending: 0, reverted: 0, percentage: 0 }; const customers = await listCustomers(); async function handleActivate() { 'use server'; await activateRelease(releaseId); redirect(`/releases/${releaseId}`); } async function handleArchive() { 'use server'; await archiveRelease(releaseId); redirect(`/releases/${releaseId}`); } return (
{/* Header */}

{release.name}

{release.type} {release.status}
{release.versionNumber && (

Version: {release.versionNumber}

)}
{release.status === 'draft' && (
)} {release.status === 'active' && (
)}
{/* Release Info */}

{release.releaseDate ? new Date(release.releaseDate).toLocaleDateString() : 'Not set'}

{customers.length}

{release.status === 'active' && (
{stats.percentage}%
)}
{release.description && ( <>

{release.description}

)} {/* Steps Management (for draft) */} {release.status === 'draft' && ( Template Steps

Deploy Steps ({release.templates.filter(t => t.category === 'deploy').length})

Verify Steps ({release.templates.filter(t => t.category === 'verify').length})

)} {/* Matrix View (for active) */} {release.status === 'active' && ( Deploy ({stats.done + stats.skipped}/{stats.total}) Verify )}
); }