153 lines
5.6 KiB
JavaScript
153 lines
5.6 KiB
JavaScript
import {createStructuredSelector} from "reselect";
|
|
import {selectBodyshop} from "../../redux/user/user.selectors";
|
|
import {connect} from "react-redux";
|
|
import {useCallback, useEffect, useState} from "react";
|
|
import axios from "axios";
|
|
import {Card, Space, Table, Timeline} from "antd";
|
|
import {Cell, LabelList, Legend, Pie, PieChart, Tooltip} from "recharts";
|
|
|
|
const mapStateToProps = createStructuredSelector({
|
|
bodyshop: selectBodyshop,
|
|
});
|
|
const mapDispatchToProps = (dispatch) => ({
|
|
//setUserLanguage: language => dispatch(setUserLanguage(language))
|
|
});
|
|
|
|
const COLORS = ['#0088FE', '#00C49F', '#FFBB28', '#FF8042', '#8884d8'];
|
|
|
|
export function JobLifecycleComponent({bodyshop, job, ...rest}) {
|
|
const [loading, setLoading] = useState(true);
|
|
const [lifecycleData, setLifecycleData] = useState(null);
|
|
|
|
|
|
useEffect(() => {
|
|
async function getLifecycleData() {
|
|
if (job && job.id) {
|
|
setLoading(true);
|
|
const response = await axios.post("/job/lifecycle", {
|
|
jobids: job.id,
|
|
});
|
|
const data = response.data.transition[job.id];
|
|
setLifecycleData(data);
|
|
setLoading(false);
|
|
}
|
|
}
|
|
|
|
getLifecycleData().catch((err) => {
|
|
console.log(`Something went wrong getting Job Lifecycle Data: ${err.message}`);
|
|
setLoading(false);
|
|
});
|
|
}, [job]);
|
|
|
|
// // TODO - Delete this useEffect, it is for testing
|
|
// useEffect(() => {
|
|
// console.dir(lifecycleData)
|
|
// }, [lifecycleData]);
|
|
|
|
const columnKeys = [
|
|
'start',
|
|
'end',
|
|
'value',
|
|
'prev_value',
|
|
'next_value',
|
|
'duration',
|
|
'type',
|
|
'created_at',
|
|
'updated_at',
|
|
'start_readable',
|
|
'end_readable',
|
|
];
|
|
|
|
const columns = columnKeys.map(key => ({
|
|
title: key.charAt(0).toUpperCase() + key.slice(1), // Capitalize the first letter for the title
|
|
dataIndex: key,
|
|
key: key,
|
|
}));
|
|
|
|
/**
|
|
* Returns an array of cells for the Pie Chart
|
|
* @type {function(): *[]}
|
|
*/
|
|
const renderCells = useCallback(() => {
|
|
const entires = Object
|
|
.entries(lifecycleData.durations)
|
|
.filter(([name, value]) => {
|
|
return value > 0;
|
|
})
|
|
|
|
return entires.map(([name, value], index) => (
|
|
<Cell key={`cell-${index}`} fill={COLORS[index % COLORS.length]}>
|
|
<LabelList dataKey="name" position="insideTop" />
|
|
<LabelList dataKey="value" position="insideBottom" />
|
|
</Cell>
|
|
));
|
|
}, [lifecycleData, job]);
|
|
|
|
/**
|
|
* Returns an array of objects with the name and value of the duration
|
|
* @type {function(): {name: *, value}[]}
|
|
*/
|
|
const durationsData = useCallback(() => {
|
|
return Object.entries(lifecycleData.durations) .filter(([name, value]) => {
|
|
return value > 0;
|
|
}).map(([name, value]) => ({
|
|
name,
|
|
value: value / 1000
|
|
}))
|
|
}, [lifecycleData, job]);
|
|
|
|
return (
|
|
<Card loading={loading} title='Job Lifecycle Component'>
|
|
{!loading ? (
|
|
lifecycleData ? (
|
|
<Space direction='vertical' style={{width: '100%'}}>
|
|
<Card type='inner' title='Table Format'>
|
|
<Table columns={columns} dataSource={lifecycleData.lifecycle}/>
|
|
</Card>
|
|
<Space direction='horizontal' style={{width: '100%'}} align='start'>
|
|
<Card type='inner' title='Timeline Format'>
|
|
<Timeline>
|
|
{lifecycleData.lifecycle.map((item, index) => (
|
|
<Timeline.Item key={index} color={item.value === 'Open' ? 'green' : item.value === 'Scheduled' ? 'yellow' : 'red'}>
|
|
{item.value} - {item.start_readable}
|
|
</Timeline.Item>
|
|
))}
|
|
</Timeline>
|
|
</Card>
|
|
<Card type='inner' title='Durations'>
|
|
<PieChart width={400} height={400}>
|
|
<Pie
|
|
data={durationsData()}
|
|
cx={200}
|
|
cy={200}
|
|
labelLine={false}
|
|
label={({name, percent}) => `${name}: ${(percent * 100).toFixed(0)}%`}
|
|
outerRadius={80}
|
|
fill="#8884d8"
|
|
dataKey="value"
|
|
>
|
|
{renderCells()}
|
|
</Pie>
|
|
<Tooltip/>
|
|
<Legend/>
|
|
</PieChart>
|
|
</Card>
|
|
|
|
</Space>
|
|
</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 connect(mapStateToProps, mapDispatchToProps)(JobLifecycleComponent);
|