diff --git a/src/pages/BuildProgress.tsx b/src/pages/BuildProgress.tsx index b94cc60..4b6e4c8 100644 --- a/src/pages/BuildProgress.tsx +++ b/src/pages/BuildProgress.tsx @@ -1,4 +1,4 @@ -import { useQuery } from 'convex/react' +import { useMutation, useQuery } from 'convex/react' import { AlertCircle, ArrowLeft, @@ -8,7 +8,7 @@ import { XCircle, } from 'lucide-react' import { useState } from 'react' -import { Link, useParams } from 'react-router-dom' +import { Link, useNavigate, useParams } from 'react-router-dom' import { toast } from 'sonner' import { BuildDownloadButton } from '@/components/BuildDownloadButton' import { Button } from '@/components/ui/button' @@ -19,10 +19,13 @@ import { TARGETS } from '../constants/targets' export default function BuildProgress() { const { buildHash } = useParams<{ buildHash: string }>() + const navigate = useNavigate() const build = useQuery( api.builds.getByHash, buildHash ? { buildHash } : 'skip' ) + const isAdmin = useQuery(api.admin.isAdmin) + const retryBuild = useMutation(api.admin.retryBuild) const [shareUrlCopied, setShareUrlCopied] = useState(false) if (!buildHash) { @@ -130,6 +133,7 @@ export default function BuildProgress() { const githubRunLink = githubActionUrl ? `[View run](${githubActionUrl})` : '(not available)' + const buildPageUrl = `${window.location.origin}/builds/${build.buildHash}` const issueTitle = `Build ${build.status === 'failure' ? 'Failed' : 'Issue'}: ${targetLabel} (${build.buildHash.substring(0, 8)})` @@ -142,6 +146,7 @@ export default function BuildProgress() { **Plugins**: ${plugins} **Build Timestamp**: ${timestamp} +**Build Page**: [View build page](${buildPageUrl}) **GitHub Run**: ${githubRunLink} ## Additional Information @@ -160,6 +165,50 @@ export default function BuildProgress() { window.open(generateIssueUrl(), '_blank', 'noopener,noreferrer') } + const handleRetry = async () => { + if (!build?._id) return + try { + await retryBuild({ buildId: build._id }) + toast.success('Build retry initiated', { + description: 'The build has been queued with the latest YAML.', + }) + } catch (error) { + toast.error('Failed to retry build', { + description: String(error), + }) + } + } + + const getStatusBadge = (status: string) => { + const statusConfig = { + success: { + bg: 'bg-green-500/20', + text: 'text-green-400', + label: 'Success', + }, + failure: { bg: 'bg-red-500/20', text: 'text-red-400', label: 'Failed' }, + queued: { + bg: 'bg-yellow-500/20', + text: 'text-yellow-400', + label: 'Queued', + }, + } + const config = statusConfig[status as keyof typeof statusConfig] || { + bg: 'bg-slate-500/20', + text: 'text-slate-400', + label: status, + } + return ( + + {config.label} + + ) + } + + const formatDate = (timestamp: number) => { + return new Date(timestamp).toLocaleString() + } + return (
@@ -223,6 +272,108 @@ export default function BuildProgress() {
+ {/* Admin Controls Section */} + {isAdmin === true && build && ( +
+
+
+

Admin Controls

+
+ + {build.buildHash.substring(0, 8)} + + {getStatusBadge(build.status)} +
+
+
+ + +
+
+ + {/* Build Configuration Details */} +
+
+
+ Target +
+ {build.config.target} +
+
+
+ Version +
+ {build.config.version} +
+
+
+
+
+ + {build.completedAt ? 'Completed' : 'Started'} + +
+ {build.completedAt + ? formatDate(build.completedAt) + : build.startedAt + ? formatDate(build.startedAt) + : 'Unknown'} +
+
+
+
+ + {/* Run History Section */} + {(build.githubRunId || + (build.githubRunIdHistory?.length ?? 0) > 0) && ( +
+ + Run History + {(build.githubRunIdHistory?.length ?? 0) > 0 && + ` (${(build.githubRunIdHistory?.length ?? 0) + (build.githubRunId ? 1 : 0)} total)`} + +
+ {build.githubRunId && ( + + {build.githubRunId} + + )} + {build.githubRunIdHistory?.map((id) => ( + + {id} + + ))} +
+
+ )} +
+ )} + {status !== 'success' && status !== 'failure' && (