Files
bodyshop/client/src/components/job-lifecycle/job-lifecycle.component.jsx
Dave Richer 5ea64ed805 - Progress
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-01-24 17:18:43 -05:00

175 lines
6.1 KiB
JavaScript

import React, {useCallback, useEffect, useState} from 'react';
import moment from "moment";
import axios from 'axios';
import {Card, Space, Table} from 'antd';
import {gql, useQuery} from "@apollo/client";
import {DateTimeFormatterFunction} from "../../utils/DateFormatter";
import {isEmpty} from "lodash";
import {Bar, BarChart, CartesianGrid, Legend, ResponsiveContainer, Tooltip, XAxis, YAxis} from "recharts";
const transformDataForChart = (durations) => {
const output = {};
output.total = durations.total;
return durations.summations.forEach((summation) => {
output[summation.status] = summation.value
});
};
const getColor = (key) => {
// Generate a random color
const randomColor = '#' + Math.floor(Math.random()*16777215).toString(16);
return randomColor;
};
export function JobLifecycleComponent({job, ...rest}) {
const [loading, setLoading] = useState(true);
const [lifecycleData, setLifecycleData] = useState(null);
// Used for tracking external state changes.
const {data} = useQuery(gql`
query get_job_test($id: uuid!){
jobs_by_pk(id:$id){
id
status
}
}
`, {
variables: {
id: job.id
},
fetchPolicy: 'cache-only'
});
/**
* Gets the lifecycle data for the job.
* @returns {Promise<void>}
*/
const getLifecycleData = useCallback(async () => {
if (job && job.id) {
try {
setLoading(true);
const response = await axios.post("/job/lifecycle", {jobids: job.id});
const data = response.data.transition[job.id];
setLifecycleData(data);
} catch (err) {
console.error(`Error getting Job Lifecycle Data: ${err.message}`);
} finally {
setLoading(false);
}
}
}, [job]);
useEffect(() => {
if (!data) return;
setTimeout(() => {
getLifecycleData().catch(err => console.error(`Error getting Job Lifecycle Data: ${err.message}`));
}, 1000);
}, [data, getLifecycleData]);
const columns = [
{
title: 'Value',
dataIndex: 'value',
key: 'value',
},
{
title: 'Start',
dataIndex: 'start',
key: 'start',
render: (text) => DateTimeFormatterFunction(text),
sorter: (a, b) => moment(a.start).unix() - moment(b.start).unix(),
},
{
title: 'Relative Start',
dataIndex: 'start_readable',
key: 'start_readable',
},
{
title: 'End',
dataIndex: 'end',
key: 'end',
sorter: (a, b) => {
if (isEmpty(a.end) || isEmpty(b.end)) {
if (isEmpty(a.end) && isEmpty(b.end)) {
return 0;
}
return isEmpty(a.end) ? 1 : -1;
}
return moment(a.end).unix() - moment(b.end).unix();
},
render: (text) => isEmpty(text) ? 'N/A' : DateTimeFormatterFunction(text)
},
{
title: 'Relative End',
dataIndex: 'end_readable',
key: 'end_readable',
},
{
title: 'Duration',
dataIndex: 'duration_readable',
key: 'duration_readable',
sorter: (a, b) => a.duration - b.duration,
},
];
useEffect(() => {
console.log('LifeCycle Data');
console.dir(lifecycleData, {depth: null})
}, [lifecycleData]);
return (
<Card loading={loading} title='Job Lifecycle Component'>
{!loading ? (
lifecycleData && lifecycleData.lifecycle && lifecycleData.durations ? (
<Space direction='vertical' style={{width: '100%'}}>
<Space direction='horizontal' style={{width: '100%'}} align='start'>
<Card type='inner' title='Durations'>
<ResponsiveContainer width="100%" height="100%">
<BarChart
width={500}
height={300}
data={transformDataForChart(lifecycleData.durations)}
margin={{
top: 20,
right: 30,
left: 20,
bottom: 5,
}}
>
<CartesianGrid strokeDasharray="3 3" />
<XAxis dataKey="name" />
<YAxis />
<Tooltip />
<Legend />
{lifecycleData.durations.summations.map((summation, idx) => {
return (
<Bar key={idx} dataKey={summation.status} stackId="a" fill={getColor(summation.status)} />
);
})}
</BarChart>
</ResponsiveContainer>
</Card>
</Space>
<Card type='inner' title='Transitions'>
<Table columns={columns} dataSource={lifecycleData.lifecycle}/>
</Card>
</Space>
) : (
<Card type='inner' style={{textAlign: 'center'}}>
There is currently no lifecycle data for this job.
</Card>
)
) : (
<Card type='inner' title='Loading'>
Loading Job Timelines....
</Card>
)}
</Card>
);
}
export default JobLifecycleComponent;