Skip to content

Commit fa1f3e5

Browse files
committed
feat: JobHistoryDialog relies on Stepper instead of Table
1 parent dc32e12 commit fa1f3e5

4 files changed

Lines changed: 123 additions & 116 deletions

File tree

packages/diracx-web-components/src/components/JobMonitor/JobDataTable.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,8 @@ interface JobDataTableProps {
6666
columnPinning: ColumnPinningState;
6767
/** Set column pinning */
6868
setColumnPinning: React.Dispatch<React.SetStateAction<ColumnPinningState>>;
69+
/** Status Colors */
70+
statusColors: Record<string, string>;
6971
}
7072

7173
/**
@@ -83,6 +85,7 @@ export function JobDataTable({
8385
setColumnVisibility,
8486
columnPinning,
8587
setColumnPinning,
88+
statusColors,
8689
}: JobDataTableProps) {
8790
// Authentication
8891
const { configuration } = useOIDCContext();
@@ -470,6 +473,7 @@ export function JobDataTable({
470473
onClose={handleHistoryClose}
471474
historyData={jobHistoryData}
472475
jobId={selectedJobId ?? 0}
476+
statusColors={statusColors}
473477
/>
474478
</Box>
475479
);

packages/diracx-web-components/src/components/JobMonitor/JobHistoryDialog.tsx

Lines changed: 110 additions & 115 deletions
Original file line numberDiff line numberDiff line change
@@ -1,162 +1,157 @@
1-
"use client";
2-
31
import {
42
Dialog,
53
DialogContent,
64
DialogTitle,
75
IconButton,
8-
Table,
9-
TableBody,
10-
TableCell,
11-
TableHead,
12-
TableRow,
13-
TableContainer,
6+
Stepper,
7+
Step,
8+
StepLabel,
9+
StepContent,
10+
Typography,
1411
useTheme,
1512
} from "@mui/material";
1613
import { Close } from "@mui/icons-material";
17-
import React, { useMemo } from "react";
18-
import {
19-
useReactTable,
20-
createColumnHelper,
21-
getCoreRowModel,
22-
flexRender,
23-
} from "@tanstack/react-table";
2414
import { JobHistory } from "../../types/JobHistory";
2515

2616
interface JobHistoryDialogProps {
27-
/** Whether the Dialog is open */
17+
/** Whether the dialog is open or not */
2818
open: boolean;
29-
/** The function to close the dialog */
19+
/** Function to close the dialog */
3020
onClose: () => void;
31-
/** The data for the job history dialog */
21+
/** Job history data */
3222
historyData: JobHistory[];
33-
/** The job ID */
23+
/** Job ID */
3424
jobId: number;
25+
/** Status colors */
26+
statusColors: Record<string, string>;
27+
}
28+
29+
// Helper to group consecutive entries by Status
30+
function groupByConsecutiveStatus(history: JobHistory[]) {
31+
const groups: { status: string; entries: JobHistory[] }[] = [];
32+
let lastStatus: string | null = null;
33+
let currentGroup: JobHistory[] = [];
34+
for (const entry of history) {
35+
if (entry.Status !== lastStatus) {
36+
if (currentGroup.length > 0) {
37+
groups.push({ status: lastStatus!, entries: currentGroup });
38+
}
39+
lastStatus = entry.Status;
40+
currentGroup = [entry];
41+
} else {
42+
currentGroup.push(entry);
43+
}
44+
}
45+
if (currentGroup.length > 0) {
46+
groups.push({ status: lastStatus!, entries: currentGroup });
47+
}
48+
return groups;
3549
}
3650

37-
/**
38-
* Renders a dialog component that displays the job history.
39-
*
40-
* @returns The rendered JobHistoryDialog component.
41-
*/
4251
export function JobHistoryDialog({
4352
open,
4453
onClose,
4554
historyData,
4655
jobId,
56+
statusColors,
4757
}: JobHistoryDialogProps) {
4858
const theme = useTheme();
4959

50-
// Create column helper
51-
const columnHelper = createColumnHelper<JobHistory>();
60+
// Reverse the history so the most recent is first
61+
const reversedHistory = [...historyData].reverse();
5262

53-
// Define columns
54-
const columns = useMemo(
55-
() => [
56-
columnHelper.accessor("Status", {
57-
header: "Status",
58-
}),
59-
columnHelper.accessor("MinorStatus", {
60-
header: "Minor Status",
61-
}),
62-
columnHelper.accessor("ApplicationStatus", {
63-
header: "Application Status",
64-
}),
65-
columnHelper.accessor("StatusTime", {
66-
header: "Status Time",
67-
}),
68-
columnHelper.accessor("Source", {
69-
header: "Source",
70-
}),
71-
],
72-
[columnHelper],
73-
);
63+
// Group consecutive entries by Status
64+
const grouped = groupByConsecutiveStatus(reversedHistory);
7465

75-
// Create table instance
76-
const table = useReactTable({
77-
data: historyData,
78-
columns,
79-
getCoreRowModel: getCoreRowModel(),
80-
state: {},
81-
enableColumnResizing: true, // Enable column resizing
82-
columnResizeMode: "onChange", // Column resize mode
83-
});
66+
// Custom StepIcon for color logic
67+
const CustomStepIcon = (props: {
68+
active?: boolean;
69+
completed?: boolean;
70+
className?: string;
71+
}) => {
72+
const { active, completed, className } = props;
73+
let color = theme.palette.grey[400];
74+
if (active) {
75+
color = statusColors[grouped[0].status] || theme.palette.primary.main;
76+
} else if (completed) {
77+
color = theme.palette.grey[400];
78+
}
79+
return (
80+
<span
81+
className={className}
82+
style={{
83+
display: "flex",
84+
alignItems: "center",
85+
justifyContent: "center",
86+
width: 24,
87+
height: 24,
88+
borderRadius: "50%",
89+
background: color,
90+
}}
91+
/>
92+
);
93+
};
8494

8595
return (
8696
<Dialog open={open} onClose={onClose} aria-labelledby="job-history-title">
8797
<DialogTitle id="job-history-title">Job History: {jobId}</DialogTitle>
88-
8998
<IconButton
9099
aria-label="close"
91100
onClick={onClose}
92101
sx={{
93102
position: "absolute",
94103
right: 8,
95104
top: 8,
96-
color: theme.palette.grey[500],
97105
}}
98106
>
99107
<Close />
100108
</IconButton>
109+
<DialogContent sx={{ padding: 2 }}>
110+
<Stepper orientation="vertical" nonLinear activeStep={0}>
111+
{grouped.map((group, idx) => {
112+
const isActive = idx === 0;
101113

102-
<DialogContent sx={{ padding: 0 }}>
103-
<TableContainer>
104-
<Table stickyHeader>
105-
<TableHead>
106-
{table.getHeaderGroups().map((headerGroup) => (
107-
<TableRow key={headerGroup.id}>
108-
{headerGroup.headers.map((header) => (
109-
<TableCell
110-
key={header.id}
111-
sx={{
112-
position: "relative",
113-
width: header.getSize(),
114-
}}
115-
>
116-
{header.isPlaceholder ? null : (
117-
<>
118-
{flexRender(
119-
header.column.columnDef.header,
120-
header.getContext(),
121-
)}
122-
{header.column.getCanResize() && (
123-
<div
124-
onMouseDown={header.getResizeHandler()}
125-
onTouchStart={header.getResizeHandler()}
126-
style={{
127-
position: "absolute",
128-
right: 0,
129-
top: 0,
130-
height: "100%",
131-
width: "5px",
132-
cursor: "col-resize",
133-
zIndex: 1,
134-
}}
135-
/>
136-
)}
137-
</>
138-
)}
139-
</TableCell>
140-
))}
141-
</TableRow>
142-
))}
143-
</TableHead>
144-
<TableBody>
145-
{table.getRowModel().rows.map((row) => (
146-
<TableRow key={row.id}>
147-
{row.getVisibleCells().map((cell) => (
148-
<TableCell key={cell.id}>
149-
{flexRender(
150-
cell.column.columnDef.cell,
151-
cell.getContext(),
152-
)}
153-
</TableCell>
114+
let labelColor: string = theme.palette.grey[400];
115+
if (isActive) {
116+
labelColor =
117+
statusColors[group.status] || theme.palette.primary.main;
118+
}
119+
120+
return (
121+
<Step key={idx} expanded completed={!isActive}>
122+
<StepLabel slots={{ stepIcon: CustomStepIcon }}>
123+
<Typography fontWeight="bold" color={labelColor}>
124+
{group.status}
125+
</Typography>
126+
</StepLabel>
127+
<StepContent>
128+
{group.entries.map((entry, i) => (
129+
<div key={i} style={{ marginBottom: 12 }}>
130+
<Typography variant="body2" fontWeight="bold">
131+
{entry.MinorStatus}
132+
</Typography>
133+
<Typography variant="body2" sx={{ fontStyle: "italic" }}>
134+
{entry.ApplicationStatus}
135+
</Typography>
136+
<Typography
137+
variant="caption"
138+
display="block"
139+
sx={{ mt: 1 }}
140+
>
141+
{new Date(entry.StatusTime).toLocaleString("en-GB", {
142+
timeZone: "UTC",
143+
})}{" "}
144+
UTC
145+
<br />
146+
{entry.Source}
147+
</Typography>
148+
</div>
154149
))}
155-
</TableRow>
156-
))}
157-
</TableBody>
158-
</Table>
159-
</TableContainer>
150+
</StepContent>
151+
</Step>
152+
);
153+
})}
154+
</Stepper>
160155
</DialogContent>
161156
</Dialog>
162157
);

packages/diracx-web-components/src/components/JobMonitor/JobMonitor.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -318,6 +318,7 @@ export default function JobMonitor() {
318318
setColumnPinning={setColumnPinning}
319319
rowSelection={rowSelection}
320320
setRowSelection={setRowSelection}
321+
statusColors={statusColors}
321322
/>
322323
</Box>
323324
);

packages/diracx-web-components/stories/JobMonitor.stories.tsx

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,10 +128,17 @@ const jobHistory = [
128128
StatusTime: "2024-07-04T13:00:03",
129129
Source: "Storybook",
130130
},
131+
{
132+
Status: "Running",
133+
MinorStatus: "Job initializing",
134+
ApplicationStatus: "Unknown",
135+
StatusTime: "2024-07-04T13:00:10",
136+
Source: "Storybook",
137+
},
131138
{
132139
Status: "Running",
133140
MinorStatus: "Job running",
134-
ApplicationStatus: "Running",
141+
ApplicationStatus: "Unknown",
135142
StatusTime: "2024-07-04T13:00:10",
136143
Source: "Storybook",
137144
},

0 commit comments

Comments
 (0)