const _ = require("lodash"); const queries = require("../graphql-client/queries"); const moment = require("moment"); const durationToHumanReadable = require("../utils/durationToHumanReadable"); const calculateStatusDuration = require("../utils/calculateStatusDuration"); const getLifecycleStatusColor = require("../utils/getLifecycleStatusColor"); const jobLifecycle = async (req, res) => { // Grab the jobids and statuses from the request body const { jobids, statuses } = req.body; if (!jobids) { return res.status(400).json({ error: "Missing jobids" }); } const jobIDs = _.isArray(jobids) ? jobids : [jobids]; const client = req.userGraphQLClient; const resp = await client.request(queries.QUERY_TRANSITIONS_BY_JOBID, { jobids: jobIDs }); const transitions = resp.transitions; if (!transitions) { return res.status(200).json({ jobIDs, transitions: [] }); } const transitionsByJobId = _.groupBy(resp.transitions, "jobid"); const groupedTransitions = {}; const allDurations = []; for (let jobId in transitionsByJobId) { let lifecycle = transitionsByJobId[jobId].map((transition) => { transition.start_readable = transition.start ? moment(transition.start).fromNow() : "N/A"; transition.end_readable = transition.end ? moment(transition.end).fromNow() : "N/A"; if (transition.duration) { transition.duration_seconds = Math.round(transition.duration / 1000); transition.duration_minutes = Math.round(transition.duration_seconds / 60); let duration = moment.duration(transition.duration); transition.duration_readable = durationToHumanReadable(duration); } else { transition.duration_seconds = 0; transition.duration_minutes = 0; transition.duration_readable = "N/A"; } return transition; }); const durations = calculateStatusDuration(lifecycle, statuses); groupedTransitions[jobId] = { lifecycle, durations }; if (durations?.summations) { allDurations.push(durations.summations); } } const finalSummations = []; const flatGroupedAllDurations = _.groupBy(allDurations.flat(), "status"); const finalStatusCounts = Object.keys(flatGroupedAllDurations).reduce((acc, status) => { acc[status] = flatGroupedAllDurations[status].length; return acc; }, {}); // Calculate total value of all statuses const finalTotal = Object.values(flatGroupedAllDurations).reduce((total, statusArr) => { return total + statusArr.reduce((acc, curr) => acc + curr.value, 0); }, 0); Object.keys(flatGroupedAllDurations).forEach((status) => { const value = flatGroupedAllDurations[status].reduce((acc, curr) => acc + curr.value, 0); const humanReadable = durationToHumanReadable(moment.duration(value)); const percentage = finalTotal > 0 ? (value / finalTotal) * 100 : 0; const color = getLifecycleStatusColor(status); const roundedPercentage = `${Math.round(percentage)}%`; const averageValue = _.size(jobIDs) > 0 ? value / jobIDs.length : 0; const averageHumanReadable = durationToHumanReadable(moment.duration(averageValue)); finalSummations.push({ status, value, humanReadable, percentage, color, roundedPercentage, averageValue, averageHumanReadable }); }); return res.status(200).json({ jobIDs, transition: groupedTransitions, durations: { jobs: jobIDs.length, summations: finalSummations, totalStatuses: finalSummations.length, total: finalTotal, statusCounts: finalStatusCounts, humanReadable: durationToHumanReadable(moment.duration(finalTotal)), averageValue: _.size(jobIDs) > 0 ? finalTotal / jobIDs.length : 0, averageHumanReadable: _.size(jobIDs) > 0 ? durationToHumanReadable(moment.duration(finalTotal / jobIDs.length)) : durationToHumanReadable(moment.duration(0)) } }); }; module.exports = jobLifecycle;