Newer
Older
CNCTools / ReferenceSurfaceGenerator / frontend / src / JobItem.js
import React from 'react';
import axios from 'axios';
import { ListGroup, Badge, Button, ProgressBar, Alert } from 'react-bootstrap';

const JobItem = ({ job, API_URL, onJobDelete, onView }) => {
  const getVariant = (status) => {
    switch (status) {
      case 'PENDING': return 'info';
      case 'PROCESSING': return 'primary';
      case 'COMPLETE': return 'success';
      case 'FAILED': return 'danger';
      default: return 'secondary';
    }
  };

  const handleDelete = async () => {
    if (window.confirm(`Are you sure you want to delete job ${job.filename} (${job.id})?`)) {
      try {
        await axios.delete(`${API_URL}/api/jobs/${job.id}`);
        onJobDelete(job.id);
      } catch (error) {
        console.error("Error deleting job:", error);
        alert("Failed to delete job.");
      }
    }
  };

  return (
    <ListGroup.Item>
      <div className="d-flex justify-content-between align-items-center">
        <div>
          <strong>{job.filename}</strong> (ID: {job.id.substring(0, 8) + '...'})
          <br />
          <small className="text-muted">Status: <Badge bg={getVariant(job.status)}>{job.status}</Badge></small>
        </div>
        <div>
          {job.status === 'COMPLETE' && job.view_url && (
            <Button variant="secondary" onClick={() => onView(job.view_url)} size="sm" className="me-2">
              View
            </Button>
          )}
          {job.status === 'COMPLETE' && job.download_url && (
            <Button variant="success" href={`${API_URL}${job.download_url}`} size="sm" className="me-2">
              Download
            </Button>
          )}
          <Button variant="outline-danger" size="sm" onClick={handleDelete}>
            Delete
          </Button>
        </div>
      </div>

      {/* Progress Bar for Processing state */}
      {job.status === 'PROCESSING' && <ProgressBar now={job.progress} label={`${job.progress}%`} animated className="mt-2" />}
      
      {/* Informational Message for non-failed states */}
      {job.status !== 'FAILED' && job.message && (
        <small className="d-block mt-1 text-muted">{job.message}</small>
      )}

      {/* Error Alert for FAILED state */}
      {job.status === 'FAILED' && job.message && (
        <Alert variant="danger" className="mt-2 mb-0" style={{ fontSize: '0.875em', padding: '0.5rem 1rem' }}>
          <strong>Error:</strong> {job.message}
        </Alert>
      )}
    </ListGroup.Item>
  );
};

export default JobItem;