Mirror of https://github.com/roostorg/osprey
github.com/roostorg/osprey
1import React from 'react';
2
3import type { BulkActionJob } from '../../types/BulkActionTypes';
4
5import styles from './BulkActionTable.module.css';
6import CopyLinkButton from '../common/CopyLinkButton';
7import { Spin } from 'antd';
8
9interface JobTableProps {
10 jobs?: BulkActionJob[];
11 onCancelJob: (jobId: string) => void;
12 jobPollingInProgress: boolean;
13}
14
15function isJobInProgress(job: BulkActionJob): boolean {
16 return job.status === 'processing' || job.status === 'uploaded' || job.status === 'parsing';
17}
18
19export const BulkActionJobTable: React.FC<JobTableProps> = ({ jobs = [], onCancelJob, jobPollingInProgress }) => {
20 const formatDate = (dateString: string): string => {
21 return new Date(dateString).toLocaleDateString('en-US', {
22 year: 'numeric',
23 month: 'short',
24 day: 'numeric',
25 hour: '2-digit',
26 minute: '2-digit',
27 });
28 };
29
30 const getStatusClass = (status: string): string => {
31 switch (status) {
32 case 'completed':
33 return styles.statusCompleted;
34 case 'processing':
35 case 'uploaded':
36 case 'parsing':
37 return styles.statusInProgress;
38 case 'failed':
39 case 'cancelled':
40 return styles.statusFailed;
41 default:
42 return styles.statusDefault;
43 }
44 };
45
46 const getStatusDisplay = (job: BulkActionJob) => {
47 switch (job.status) {
48 case 'completed':
49 return 'Completed';
50 case 'processing':
51 return 'Processing';
52 case 'uploaded':
53 case 'pending_upload':
54 return 'Uploaded & Pending ';
55 case 'parsing':
56 return 'Setting up job';
57 case 'failed':
58 return 'Failed';
59 case 'cancelled':
60 return 'Cancelled';
61 default:
62 return 'Unknown';
63 }
64 };
65
66 return (
67 <div className={styles.tableContainer}>
68 <table className={styles.jobTable}>
69 <thead>
70 <tr className={styles.tableHeader}>
71 <th>Job ID</th>
72 <th>Job Name</th>
73 <th>Job Description</th>
74 <th>Workflow</th>
75 <th>Status</th>
76 <th>Progress</th>
77 <th>Created By</th>
78 <th>Created At</th>
79 <th>Actions</th>
80 </tr>
81 </thead>
82 <tbody>
83 {jobs.map((job: BulkActionJob, index: number) => (
84 <tr key={job.id || index} className={`${styles.tableRow} ${isJobInProgress(job) ? styles.inProgress : ''}`}>
85 <td className={styles.tableCell}>{job.id}</td>
86 <td className={`${styles.tableCell} ${styles.descriptionCell}`}>{job.name}</td>
87 <td className={`${styles.tableCell} ${styles.descriptionCell}`}>{job.description}</td>
88 <td className={styles.tableCell}>{job.action_workflow_name}</td>
89 <td className={styles.tableCell}>
90 <span className={`${styles.statusBadge} ${getStatusClass(job.status)}`}>{getStatusDisplay(job)}</span>
91 {jobPollingInProgress && isJobInProgress(job) && <Spin size="small" />}
92 </td>
93 <td className={styles.tableCell}>
94 {job.processed_rows ?? 0}/{job.total_rows ?? 0} actions processed
95 </td>
96 <td className={styles.tableCell}>{job.user_id}</td>
97 <td className={styles.tableCell}>{formatDate(job.created_at)}</td>
98 <td className={styles.tableCell}>
99 <div className={styles.actionsContainer}>
100 <button
101 className={`${styles.actionButton} ${styles.deleteButton} ${
102 job.status === 'completed' || job.status === 'failed' || job.status === 'cancelled'
103 ? styles.disabledButton
104 : ''
105 }`}
106 onClick={() => onCancelJob(job.id)}
107 disabled={job.status === 'completed' || job.status === 'failed' || job.status === 'cancelled'}
108 >
109 Cancel
110 </button>
111 </div>
112 </td>
113 </tr>
114 ))}
115 </tbody>
116 </table>
117 </div>
118 );
119};