Spaces:
Paused
Paused
| import { useCallback, useState } from 'react' | |
| import { runJob } from './api' | |
| // Shared shape for "kick off a backend job, show progress, surface errors". | |
| export function useJob() { | |
| const [running, setRunning] = useState(false) | |
| const [progress, setProgress] = useState([]) | |
| const [error, setError] = useState('') | |
| const start = useCallback(async (path, body) => { | |
| setRunning(true) | |
| setProgress([]) | |
| setError('') | |
| try { | |
| return await runJob(path, body, setProgress) | |
| } catch (e) { | |
| setError(e.message) | |
| throw e | |
| } finally { | |
| setRunning(false) | |
| } | |
| }, []) | |
| return { running, progress, error, setError, start } | |
| } | |
| export function ProgressBox({ progress }) { | |
| if (!progress.length) return null | |
| return ( | |
| <div className="progress-box"> | |
| {progress.slice(0, -1).map((m, i) => <div key={i}>{m}</div>)} | |
| <div className="latest"><span className="spinner" />{progress[progress.length - 1]}</div> | |
| </div> | |
| ) | |
| } | |
| export function ErrorBox({ error, onRetry }) { | |
| if (!error) return null | |
| return ( | |
| <div className="error-box"> | |
| {error} | |
| {onRetry && ( | |
| <div style={{ marginTop: 8 }}> | |
| <button className="btn small secondary" onClick={onRetry}>Retry</button> | |
| </div> | |
| )} | |
| </div> | |
| ) | |
| } | |