ai-toolkit / ui /src /components /HFJobStatus.tsx
apolinario's picture
track the org jobs
231dcea
'use client';
import { useHFJobStatus } from '@/hooks/useHFJobStatus';
import { ExternalLink, RefreshCw } from 'lucide-react';
import { Button } from '@headlessui/react';
interface HFJobStatusProps {
hfJobId: string;
hfJobUrl?: string;
hfJobNamespace?: string;
}
const extractNamespaceFromUrl = (url?: string) => {
if (!url) {
return undefined;
}
try {
const match = url.match(/\/jobs\/([^\/]+)\//);
return match?.[1];
} catch (error) {
console.warn('Failed to derive HF job namespace from URL:', error);
return undefined;
}
};
export default function HFJobStatus({ hfJobId, hfJobUrl, hfJobNamespace }: HFJobStatusProps) {
const derivedNamespace = hfJobNamespace || extractNamespaceFromUrl(hfJobUrl);
const { status, loading, error } = useHFJobStatus(hfJobId, derivedNamespace);
if (error) {
return (
<div className="flex items-center gap-2">
<span className="text-xs text-red-400">Status Error</span>
{hfJobUrl && (
<a
href={hfJobUrl}
target="_blank"
rel="noopener noreferrer"
className="text-blue-400 hover:text-blue-300"
title="Check logs on HF Jobs"
>
<ExternalLink size={14} />
</a>
)}
</div>
);
}
if (loading && !status) {
return (
<div className="flex items-center gap-2">
<RefreshCw size={14} className="animate-spin" />
<span className="text-xs text-gray-400">Checking...</span>
</div>
);
}
if (!status) {
return (
<div className="flex items-center gap-2">
<span className="text-xs text-gray-400">Unknown</span>
{hfJobUrl && (
<a
href={hfJobUrl}
target="_blank"
rel="noopener noreferrer"
className="text-blue-400 hover:text-blue-300"
title="Check logs on HF Jobs"
>
<ExternalLink size={14} />
</a>
)}
</div>
);
}
const getStatusColor = (statusStage: string) => {
switch (statusStage.toUpperCase()) {
case 'RUNNING':
return 'text-blue-400';
case 'COMPLETED':
case 'SUCCESS':
return 'text-green-400';
case 'FAILED':
case 'ERROR':
return 'text-red-400';
case 'PENDING':
case 'QUEUED':
return 'text-yellow-400';
case 'CANCELLED':
case 'STOPPED':
return 'text-gray-400';
default:
return 'text-gray-400';
}
};
const getStatusLabel = (statusStage: string) => {
switch (statusStage.toUpperCase()) {
case 'RUNNING':
return 'Running';
case 'COMPLETED':
return 'Completed';
case 'FAILED':
return 'Failed';
case 'PENDING':
return 'Pending';
case 'QUEUED':
return 'Queued';
case 'CANCELLED':
return 'Cancelled';
case 'STOPPED':
return 'Stopped';
default:
return statusStage;
}
};
return (
<div className="flex items-center gap-2">
<div className="flex items-center gap-1">
{loading && <RefreshCw size={12} className="animate-spin" />}
<span className={`text-xs font-medium ${getStatusColor(status.status)}`}>
{getStatusLabel(status.status)}
</span>
</div>
{hfJobUrl && (
<a
href={hfJobUrl}
target="_blank"
rel="noopener noreferrer"
className="text-blue-400 hover:text-blue-300"
title={`Check logs on HF Jobs (${status.flavor})`}
>
<ExternalLink size={14} />
</a>
)}
</div>
);
}