diff --git a/client/src/components/job-lifecycle/job-lifecycle.component.jsx b/client/src/components/job-lifecycle/job-lifecycle.component.jsx
index 8122229af..62ecb920a 100644
--- a/client/src/components/job-lifecycle/job-lifecycle.component.jsx
+++ b/client/src/components/job-lifecycle/job-lifecycle.component.jsx
@@ -1,139 +1,110 @@
-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";
+import React, {useEffect, useMemo, useState} from 'react';
+import axios from 'axios';
+import {Card, Space, Table, Timeline} from 'antd';
+import {Bar, BarChart, CartesianGrid, LabelList, Legend, ResponsiveContainer, Tooltip, XAxis, YAxis} from 'recharts';
-const mapStateToProps = createStructuredSelector({
- bodyshop: selectBodyshop,
-});
-const mapDispatchToProps = (dispatch) => ({
- //setUserLanguage: language => dispatch(setUserLanguage(language))
-});
+export function JobLifecycleComponent({job, ...rest}) {
-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() {
+ const getLifecycleData = async () => {
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);
+ 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);
+ }
}
- }
+ };
- getLifecycleData().catch((err) => {
- console.log(`Something went wrong getting Job Lifecycle Data: ${err.message}`);
- setLoading(false);
- });
+ getLifecycleData();
}, [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',
+ 'start', 'end', 'value', 'prev_value', 'next_value', 'duration', 'type', 'created_at', 'updated_at', 'start_readable', 'end_readable','duration'
];
const columns = columnKeys.map(key => ({
- title: key.charAt(0).toUpperCase() + key.slice(1), // Capitalize the first letter for the title
+ title: key.charAt(0).toUpperCase() + key.slice(1),
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) => (
- |
-
-
- |
- ));
- }, [lifecycleData, job]);
+ const durationsData = useMemo(() => {
+ if (!lifecycleData) {
+ return [];
+ }
- /**
- * 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]);
+ const transformedData = Object.entries(lifecycleData.durations).map(([name, {value, humanReadable}]) => {
+ return {
+ name,
+ amt: value,
+ pv: humanReadable,
+ uv: value,
+ }
+ })
+
+ return [transformedData];
+ }, [lifecycleData]);
+
+
+ useEffect(() => {
+ console.dir(lifecycleData, {depth: null})
+ console.dir(durationsData, {depth: null})
+
+ }, [lifecycleData,durationsData]);
return (
{!loading ? (
lifecycleData ? (
-
-
-
{lifecycleData.lifecycle.map((item, index) => (
-
+
{item.value} - {item.start_readable}
))}
-
- `${name}: ${(percent * 100).toFixed(0)}%`}
- outerRadius={80}
- fill="#8884d8"
- dataKey="value"
+
+
- {renderCells()}
-
-
-
-
+
+
+
+
+
+
+
+
+
-
+
+
+
) : (
@@ -149,4 +120,4 @@ export function JobLifecycleComponent({bodyshop, job, ...rest}) {
);
}
-export default connect(mapStateToProps, mapDispatchToProps)(JobLifecycleComponent);
+export default JobLifecycleComponent;
\ No newline at end of file
diff --git a/client/src/pages/jobs-detail/jobs-detail.page.component.jsx b/client/src/pages/jobs-detail/jobs-detail.page.component.jsx
index a7d51d5e3..0f335d982 100644
--- a/client/src/pages/jobs-detail/jobs-detail.page.component.jsx
+++ b/client/src/pages/jobs-detail/jobs-detail.page.component.jsx
@@ -294,7 +294,7 @@ export function JobsDetailPage({
tab={Lifecycle}
key="lifecycle"
>
-
+
{
let statusDuration = {};
transitions.forEach((transition, index) => {
- let duration = transition.duration;
+ let duration = transition.duration_minutes;
// If there is no prev_value, it is the first transition
if (!transition.prev_value) {
- statusDuration[transition.value] = duration;
+ statusDuration[transition.value] = {
+ value: duration,
+ humanReadable: transition.duration_readable
+ };
}
// If there is no next_value, it is the last transition (the active one)
else if (!transition.next_value) {
if (statusDuration[transition.value]) {
- statusDuration[transition.value] += duration;
+ statusDuration[transition.value].value += duration;
+ statusDuration[transition.value].humanReadable = transition.duration_readable;
} else {
- statusDuration[transition.value] = duration;
+ statusDuration[transition.value] = {
+ value: duration,
+ humanReadable: transition.duration_readable
+ };
}
}
// For all other transitions
else {
if (statusDuration[transition.value]) {
- statusDuration[transition.value] += duration;
+ statusDuration[transition.value].value += duration;
+ statusDuration[transition.value].humanReadable = transition.duration_readable;
} else {
- statusDuration[transition.value] = duration;
+ statusDuration[transition.value] = {
+ value: duration,
+ humanReadable: transition.duration_readable
+ };
}
}
});
@@ -53,7 +64,6 @@ const jobLifecycle = async (req, res) => {
}
-
const transitionsByJobId = _.groupBy(resp.transitions, 'jobid');
const groupedTransitions = {};
@@ -66,6 +76,11 @@ const jobLifecycle = async (req, res) => {
if (transition.end) {
transition.end_readable = moment(transition.end).fromNow();
}
+ if(transition.duration){
+ transition.duration_seconds = Math.round(transition.duration / 1000);
+ transition.duration_minutes = Math.round(transition.duration_seconds / 60);
+ transition.duration_readable = moment.duration(transition.duration).humanize();
+ }
return transition;
});
@@ -75,7 +90,7 @@ const jobLifecycle = async (req, res) => {
};
}
- console.dir(groupedTransitions, {depth: null});
+ console.dir(groupedTransitions, {depth: null})
return res.status(200).json({
jobIDs,