diff --git a/src/components/CalculateQuota.js b/src/components/CalculateQuota.js new file mode 100644 index 0000000..79ece65 --- /dev/null +++ b/src/components/CalculateQuota.js @@ -0,0 +1,408 @@ +function getComputationTimes(data, calcstartTimeInput, calcEndTimeInput, quotaUnit) { + const calcstartTime = calcstartTimeInput + const calcEndTime = calcEndTimeInput + + // extract the three different job types + const dataJobUsage = data['job_usage']==null?[]:data['job_usage']; + const dataPoolUsage = data['pool_usage']==null?[]:data['pool_usage']; + const dataHypercube = data['hypercube_job_usage']==null?[]:data['hypercube_job_usage']; + + // first extract all the pool infos, to later check if an individual job was part of a pool + let PoolLabels = dataPoolUsage.map(pool => pool['label']); + let poolInstances = dataPoolUsage.map(pool => pool['instance']['label']); + let poolOwners = dataPoolUsage.map(pool => pool['owner']['username']); + + // only need the idle multiplier from the pools + // for the jobs use the multiplier from the jop instance + let PoolMultipliersIdle = dataPoolUsage.map(pool => pool['instance']['multiplier_idle']); + + // contains for every pool a list of the times of every worker + // each element of the individual lists is a dictionary + let PoolTimes = dataPoolUsage.map(pool => pool['times']); + + let CommentPool = Array(PoolLabels.length).fill('This is the idle pool time. '); + let FailsPool = Array(PoolLabels.length).fill(0); + let isIdlePool = Array(PoolLabels.length).fill(true); + let tokenPool = Array(PoolLabels.length).fill(''); + + // check if workers failed, for this collect all worker_id's for each pool + // if there are multiple entries for the same id, only keep the last one + // the number of fails is saved as a comment and as an actual number, + // to later easily compute the total number of fails + PoolTimes.forEach(function (pool, i) { + // extract the worker_id for each timeframe + let workers = pool.map(time => time['worker_id']); + const workersWithoutDuplicates = [...new Set(workers)]; + workersWithoutDuplicates.forEach(function(worker) { + // need to save count for the comment, because it changes after the duplicates are deleted + const count = workers.filter(el => el === worker).length; + // if a worker failed set the start time of the last occurence of this worker to the first start time + if (count > 1) { + // get indices of the same worker + let indices = []; + for (let idx = 0; idx < workers.length; idx++) { + if (workers[idx] === worker) { + indices.push(idx); + } + } + // change the start time of the current worker to the start of it's first occurence + PoolTimes[i][indices[indices.length - 1]].start = PoolTimes[i][indices[0]].start; + // Now remove all other occurences from PoolTimes + indices = indices.slice(0, -1); + // remove all elements in PoolTimes and pool_workers + PoolTimes[i] = PoolTimes[i].filter(function(time, idx) { + return !indices.includes(idx); + }); + workers = workers.filter(function(worker_id, idx) { + return !indices.includes(idx); + }); + + CommentPool[i] = CommentPool[i].concat(`${worker} failed ${count - 1} times. `); + FailsPool[i] = count - 1 + } + }); + }); + + // compute the whole time workers existed on the pool (and didn't fail because those workers are already removed) + PoolTimes.forEach(function (pool, i) { + let totalWorkerTime = 0; + pool.forEach(function(times) { + let startTime = new Date(times['start']); + let finishTime = calcEndTime; + // check if the worker is still running + if (times['finish'] != null) { + finishTime = new Date(times['finish']); + } + else if (dataPoolUsage[i]['deleted_at'] != null){ + finishTime = new Date( dataPoolUsage[i]['deleted_at']); + CommentPool[i] = CommentPool[i].concat('There is no finish time, but the job was finished!!'); + } + else { + finishTime = calcEndTime; + CommentPool[i] = CommentPool[i].concat(`A worker on ${PoolLabels[i]} is still running. `); + } + // only include the parts of the worker times that are in the given timeframe + if (startTime >= calcstartTime && finishTime <= calcEndTime) { + totalWorkerTime += finishTime - startTime; + } else if (calcstartTime <= finishTime && finishTime <= calcEndTime) { + totalWorkerTime += finishTime - calcstartTime; + } else if (calcstartTime <= startTime && startTime <= calcEndTime) { + totalWorkerTime += calcEndTime - startTime; + } else if (startTime <= calcstartTime && calcEndTime <= finishTime) { + totalWorkerTime += calcEndTime - calcstartTime; + } + }); + + // if no worker of the pool was in the timeframe the timedelta is zero! + PoolTimes[i] = totalWorkerTime + }); + + // only needed to later exclude pools, that didn't had a worker in the timeframe + // if timedelta = 0 this will return False, else set to True + let includedPools = PoolTimes.map(item => Boolean(item)); + + // collect the instances and the corresponding multipliers + let instances = dataJobUsage.map(row => row['labels']['instance']); + + let multipliers = dataJobUsage.map(row => row['labels']['multiplier']); + let times = dataJobUsage.map(row => row['times']); + + let users = dataJobUsage.map(row => row['username']); + + let token = dataJobUsage.map(row => row['token']); + + // used to later only take the instances for jobs that are in the timeframe + let includedItems = Array(dataJobUsage.length).fill(false); + + let comments = Array(dataJobUsage.length).fill(''); + let fails = Array(dataJobUsage.length).fill(0); + let isIdle = Array(dataJobUsage.length).fill(false); + + // extract the hypercube informations an add them to the job list + let hypercubeInstances = []; + let hypercubeMultipliers = []; + let hypercubeTimes = []; + let hypercubeUsers = []; + let hypercubeToken = []; + let isHypercube = Array(dataJobUsage.length).fill(false); + + // go over every hypercube in the data + dataHypercube.forEach(function(hypercube) { + // save the label and mutliplier of the current hypercupe to add them to the job list + let currentInstance = hypercube['labels']['instance']; + let currentMultiplier = hypercube['labels']['multiplier']; + let currentUser = hypercube['username']; + let currentToken = hypercube['token'] + // go over every job of each hypercube to collect the times + // and append the instances/multipliers/time list, + // to later just concatenate this with the other job list + // this way also the check if its a pool job will be performed + hypercube['jobs'].forEach(function(job) { + hypercubeInstances.push(currentInstance); + hypercubeMultipliers.push(currentMultiplier); + hypercubeTimes.push(job['times']); + hypercubeUsers.push(currentUser); + hypercubeToken.push(currentToken); + isHypercube.push(true); + }); + }); + + const hypercubeIncludedItems = Array(hypercubeInstances.length).fill(false); + const hypercubeComments = Array(hypercubeInstances.length).fill('This job was part of a hypercube. '); + const hypercubeFails = Array(hypercubeInstances.length).fill(0); + const hypercubeIsIdle = Array(hypercubeInstances.length).fill(false); + + instances = instances.concat(hypercubeInstances); + multipliers = multipliers.concat(hypercubeMultipliers); + times = times.concat(hypercubeTimes); + includedItems = includedItems.concat(hypercubeIncludedItems); + comments = comments.concat(hypercubeComments); + fails = fails.concat(hypercubeFails); + users = users.concat(hypercubeUsers); + isIdle = isIdle.concat(hypercubeIsIdle); + token = token.concat(hypercubeToken); + + // will also report the corresponding given pool_label + // is None for jobs not run on a pool + const jobPoolLabels = Array(instances.length).fill(null); + + // needed to later check to which pool a pool_job corresponds + let jobStartTimes = dataJobUsage.map(job => new Date(job['submitted'])); + const jobHypercubeStartTimes = dataHypercube.map(job => new Date(job['submitted'])); + jobStartTimes = jobStartTimes.concat(jobHypercubeStartTimes); + + // check which jobs are in the timeframe and compute their run time + times.forEach(function(time, i) { + if (time.length !== 0){ + // always take the last element, so it also works if the job crashed before + let startTime = new Date(time[time.length - 1]['start']); + // check if the job is still running + let finishTime = calcEndTime; + if (time[time.length - 1]['finish']) { + finishTime = new Date(time[time.length - 1]['finish']); + } + else if(dataJobUsage[i]['finished'] != null){ + finishTime = new Date(dataJobUsage[i]['finished']) + comments[i] = comments[i].concat('There is no finish time, but the job was finished!!') + } + else{ + finishTime = calcEndTime; + comments[i] = comments[i].concat('The job is still running. '); + } + // check if the whole job was run in the timeframe + if (startTime >= calcstartTime && finishTime <= calcEndTime) { + times[i] = finishTime - startTime; + includedItems[i] = true; + } + // or if it finished during the timeframe + else if (calcstartTime <= finishTime && finishTime <= calcEndTime) { + times[i] = finishTime - calcstartTime; + includedItems[i] = true; + comments[i] += 'Finished in the given timeframe, but started earlier. '; + } + // or finally if it started during the timeframe + else if (calcstartTime <= startTime && startTime <= calcEndTime) { + times[i] = calcEndTime - startTime; + includedItems[i] = true; + comments[i] += 'Started in the given timeframe, but is not finished yet. '; + } + // or if it ran over the whole timeframe + else if (startTime <= calcstartTime && calcEndTime <= finishTime) { + times[i] = calcEndTime - calcstartTime; + includedItems[i] = true; + comments[i] += 'Job ran longer than the timeframe. '; + } + // no else case needed! All other times get discarded + // add debugg option: + // if debug=True this case should not happen, because no job outside of the timeframe + // should be in the json object + else { + console.error('Found job outside of the timeframe, even though this should not happen!'); + } + + fails[i] = time.length - 1; + if (time.length > 1){ + comments[i] = comments[i].concat(`The job failed ${time.length - 1} times. `); + } + } + }); + + // get existing times for the pools + const poolCreated = dataPoolUsage.map(pool => new Date(pool['created_at'])); + const poolDeleted = dataPoolUsage.map(pool => pool['deleted_at']); + + poolDeleted.forEach(function(time, i){ + if (time == null){ + poolDeleted[i] = calcEndTime; + } + else{ + poolDeleted[i] = new Date(poolDeleted[i]); + } + }); + + // substract the jobs corresponding to a pool from the PoolTimes to get the idle time + times.forEach(function(time, i) { + if (includedItems[i]) { + if (PoolLabels.includes(instances[i])){ + // get indices of the pool_label + let indices = []; + for (let idx = 0; idx < PoolLabels.length; idx++) { + if (instances[i] === PoolLabels[idx]) { + indices.push(idx); + } + } + indices.forEach(function(index) { + // find the corresponding pool, if no pool fits the job is processed as a normal job + if (poolCreated[index] <= jobStartTimes[i] && jobStartTimes[i] <= poolDeleted[index]) { + PoolTimes[index] -= times[i]; + comments[i] += 'This job ran on a pool. '; + jobPoolLabels[i] = instances[i]; + instances[i] = poolInstances[index]; + } + }); + } + } + }); + + // add the pool times at the end of the data + instances = instances.concat(poolInstances); + poolInstances = jobPoolLabels.concat(PoolLabels); + multipliers = multipliers.concat(PoolMultipliersIdle); + times = times.concat(PoolTimes); + comments = comments.concat(CommentPool); + fails = fails.concat(FailsPool); + includedItems = includedItems.concat(includedPools); + users = users.concat(poolOwners); + isIdle = isIdle.concat(isIdlePool); + isHypercube = isHypercube.concat(Array(PoolLabels.length).fill(false)) + token = token.concat(tokenPool); + + // only take the elements corresponding to jobs/pools in the timeframe + instances = instances.filter((_, i) => includedItems[i]); + poolInstances = poolInstances.filter((_, i) => includedItems[i]); + multipliers = multipliers.filter((_, i) => includedItems[i]); + times = times.filter((_, i) => includedItems[i]); + comments = comments.filter((_, i) => includedItems[i]); + fails = fails.filter((_, i) => includedItems[i]); + users = users.filter((_, i) => includedItems[i]); + isIdle = isIdle.filter((_, i) => includedItems[i]); + isHypercube = isHypercube.filter((_, i) => includedItems[i]); + token = token.filter((_, i) => includedItems[i]); + + const calcTimes = { + 'users': users, + 'instances': instances, + 'pool_labels': poolInstances, + 'multipliers': multipliers, + 'times': times, + 'comments': comments, + 'fails': fails, + 'is_idle': isIdle, + 'is_hypercube': isHypercube, + 'token': token + } + + // split into jobs and idle pool time + let calcTimesJobs = { + 'users': [], + 'instances': [], + 'pool_labels': [], + 'multipliers': [], + 'times': [], + 'comments': [], + 'fails': [], + 'is_hypercube': [], + 'token': [] + } + + let calcTimesPools = { + 'users': [], + 'instances': [], + 'pool_labels': [], + 'multipliers': [], + 'times': [], + 'comments': [], + 'fails': [], + 'is_hypercube': [], + 'token': [] + } + + calcTimes.is_idle.forEach(function (elem, i) { + if (!elem) { + calcTimesJobs.users.push(calcTimes.users[i]) + calcTimesJobs.instances.push(calcTimes.instances[i]) + calcTimesJobs.pool_labels.push(calcTimes.pool_labels[i]) + calcTimesJobs.multipliers.push(calcTimes.multipliers[i]) + calcTimesJobs.times.push(calcTimes.times[i]) + calcTimesJobs.comments.push(calcTimes.comments[i]) + calcTimesJobs.fails.push(calcTimes.fails[i]) + calcTimesJobs.is_hypercube.push(calcTimes.is_hypercube[i]) + calcTimesJobs.token.push(calcTimes.token[i]) + } + else { + calcTimesPools.users.push(calcTimes.users[i]) + calcTimesPools.instances.push(calcTimes.instances[i]) + calcTimesPools.pool_labels.push(calcTimes.pool_labels[i]) + calcTimesPools.multipliers.push(calcTimes.multipliers[i]) + calcTimesPools.times.push(calcTimes.times[i]) + calcTimesPools.comments.push(calcTimes.comments[i]) + calcTimesPools.fails.push(calcTimes.fails[i]) + calcTimesPools.is_hypercube.push(calcTimes.is_hypercube[i]) + calcTimesPools.token.push(calcTimes.token[i]) + } + }) + + const uniqueId = Array.from(Array(calcTimes.instances.length).keys()).map(el => `el_${el}`); + + let ungroupedDataJobs = [] + let ungroupedDataPools = [] + + calcTimesJobs['instances'].forEach(function (elem, i) { + let cost = calcTimesJobs.times[i] * calcTimesJobs.multipliers[i] + if (quotaUnit === 'multh') { + cost = cost / 3600 + } + ungroupedDataJobs.push({ uniqueId: uniqueId[i], user: calcTimesJobs.users[i], instances: elem, + pool_labels: calcTimesJobs.pool_labels[i], multipliers: calcTimesJobs.multipliers[i], + times: calcTimesJobs.times[i], comments: calcTimesJobs.comments[i], fails: calcTimesJobs.fails[i], + jobs: '1', is_hypercube: calcTimesJobs.is_hypercube[i], token: calcTimesJobs.token[i], + cost: cost}) + }); + + + + calcTimesPools['instances'].forEach(function (elem, i) { + let cost = calcTimesPools.times[i] * calcTimesPools.multipliers[i] + if (quotaUnit === 'multh') { + cost = cost / 3600 + } + ungroupedDataPools.push({ unique_id: uniqueId[i], user: calcTimesPools.users[i], instances: elem, + pool_labels: calcTimesPools.pool_labels[i], multipliers: calcTimesPools.multipliers[i], + times: calcTimesPools.times[i], comments: calcTimesPools.comments[i], fails: calcTimesPools.fails[i], + jobs: '1', is_hypercube: calcTimesPools.is_hypercube[i], token: calcTimesPools.token[i], + cost: cost}) + }); + + let numberUsers = [...new Set(calcTimesPools.users.concat(calcTimesJobs.users))].length; + let numberInstances = [...new Set(calcTimesPools.instances.concat(calcTimesJobs.instances))].length; + + let allPools = [...new Set(calcTimesPools.pool_labels.concat(calcTimesJobs.pool_labels))] + allPools = allPools.filter(elem => elem !== null) + + let numberPools = allPools.length; + + + const result = { + 'data_jobs': ungroupedDataJobs, + 'data_pools': ungroupedDataPools, + 'num_users': numberUsers, + 'num_instances': numberInstances, + 'num_pools': numberPools + } + + return ( + result + ) +} + +export default getComputationTimes diff --git a/src/components/Quotas.jsx b/src/components/Quotas.jsx new file mode 100644 index 0000000..585fd1f --- /dev/null +++ b/src/components/Quotas.jsx @@ -0,0 +1,460 @@ +// not here, no default set +import { testData } from './data.jsx'; +import { useEffect, useRef, useState } from 'react'; +import { Chart as ChartJS, ArcElement, Legend, Tooltip } from 'chart.js'; +import { Pie } from 'react-chartjs-2'; +import 'chartjs-adapter-date-fns'; +// can rename, because it takes the default export +import computeTimes from './CalculateQuota.js' +import Table from './Table.jsx' +import Select from 'react-select'; +import { Link } from "react-router-dom"; + + + +ChartJS.register(ArcElement, Tooltip, Legend); + + +const Quotas = ({ testData, calcStartDate, calcEndTime, quotaUnit}) => { + /* + const data = test_data['test_hypercube_with_pool_and_job']; + const calcStartDate = "2021-08-03T17:10:15.000000+00:00"; + const calcEndTime = "2021-08-05T17:10:15.000000+00:00"; + + let test_tableData = [{ unique_id: 'test', instances: 'bla', pool_labels: 'jaja', multipliers: 1, times: 17263716, comments: 'test123', fails: 0 }]; + */ + + // const data = test_data['real_test_data']; + // const data = testData + // const calcStartDate = new Date("2021-01-04T17:10:15.000000+00:00"); + // const calcEndTime = new Date("2023-03-31T17:10:15.000000+00:00"); + + const dataTmp = computeTimes(testData, calcStartDate, calcEndTime, quotaUnit) + const [ungroupedDataJobs, setUngroupedDataJobs] = useState(dataTmp.data_jobs); + const [ungroupedDataPools, setUngroupedDataPools] = useState(dataTmp.data_pools); + const [numUser, setNumUser] = useState(dataTmp.num_users); + const [numInstances, setNumInstances] = useState(dataTmp.num_instances); + const [numPools, setNumPools] = useState(dataTmp.num_pools); + const [numCharts, setNumCharts] = useState(dataTmp.num_pools); + + useEffect(() => { + const dataTmp = computeTimes(testData, calcStartDate, calcEndTime, quotaUnit) + setUngroupedDataJobs(dataTmp.data_jobs) + setUngroupedDataPools(dataTmp.data_pools) + setNumUser(dataTmp.num_users) + setNumInstances(dataTmp.num_instances) + setNumPools(dataTmp.num_pools) + + let tmp = 0; + tmp = (dataTmp.num_users > 1) ? tmp +=1: tmp; + tmp = (dataTmp.num_instances > 1) ? tmp +=1: tmp; + tmp = (dataTmp.num_pools > 1) ? tmp +=1: tmp; + + setNumCharts(tmp) + }, [testData, calcStartDate, calcEndTime, quotaUnit]) + + + function getChartData(label, ungroupedData) { + let groupedData = [] + let labels = [] + let cost = [] + if (label === 'usernames') { + groupedData = GroupByUser(ungroupedData); + labels = groupedData.map(elem => elem.user); + cost = groupedData.map(elem => elem.cost); + } else if (label === 'instances') { + groupedData = GroupByInstance(ungroupedData); + labels = groupedData.map(elem => elem.instances); + cost = groupedData.map(elem => elem.cost); + } else if (label === 'pool_labels') { + groupedData = GroupByPoolLabel(ungroupedData); + labels = groupedData.map(elem => elem.pool_labels); + cost = groupedData.map(elem => elem.cost); + } + + const labelTimePairs = labels.map((label, index) => ({ label, cost: cost[index] })); + + // Sort the array of objects based on decreasing time + labelTimePairs.sort((a, b) => b.cost - a.cost); + + // Extract the sorted labels and times separately + labels = labelTimePairs.map(pair => pair.label); + cost = labelTimePairs.map(pair => pair.cost); + + const cutOff = 20; + if (labels.length > cutOff) { + setTruncateWarning(current => `${current} Only the ${cutOff} most used ${label} displayed. `) + labels = labels.slice(0,cutOff); + cost = cost.slice(0,cutOff) + } + + return { + labels: labels, + datasets: [ + { + label: '# of Votes', + data: cost, + backgroundColor: ["rgba(31,120,180,0.2)", "rgba(51,160,44,0.2)", + "rgba(227,26,28,0.2)", "rgba(255,127,0,0.2)", + "rgba(106,61,154,0.2)", "rgba(177,89,40,0.2)", + "rgba(249,185,183,0.2)", "rgba(173,169,183,0.2)", + "rgba(102,16,31,0.2)", "rgba(196,90,179,0.2)", + "rgba(27,231,255,0.2)", "rgba(76,159,112,0.2)", + "rgba(240,247,87,0.2)", "rgba(158,109,66,0.2)", + "rgba(8,103,136,0.2)", "rgba(224,202,60,0.2)", + "rgba(186,151,144,0.2)", "rgba(235,69,17,0.2)", + "rgba(155,93,229,0.2)", "rgba(71,250,26,0.2)"], + }, + ], + } + } + + const displayFieldUngrouped = useRef([ + // { + // field: "unique_id", + // column: "id", + // sorter: "alphabetical", + // displayer: String + // }, + { + field: "user, unique_id", + column: "User", + sorter: "alphabetical", + displayer: (user, _) => user + }, + { + field: "token,is_hypercube", + column: "Job token", + displayer: (name, job_count) => <> + {job_count === true ? {name} + + HC + : + {name}} + > + }, + { + field: "instances", + column: "Instance", + sorter: "alphabetical", + displayer: String + }, + { + field: "pool_labels", + column: "Pool Label", + sorter: "alphabetical", + displayer: (pool_label) => pool_label == null ? '-' : pool_label + }, + { + field: "fails", + column: "Number Crashes", + sorter: "numerical", + displayer: Number + }, + { + field: "jobs", + column: "Number Jobs", + sorter: "alphabetical", + displayer: String + }, + { + field: "times", + column: "Solve Time", + sorter: "numerical", + displayer: formatTime + }, + { + field: "multipliers", + column: "Multiplier", + sorter: "numerical", + displayer: (mult) => Intl.NumberFormat('en-US', { style: 'decimal' }).format(mult) + }, + { + field: "cost", + column: quotaUnit, + sorter: "numerical", + displayer: (cost) => Intl.NumberFormat('en-US', { style: 'decimal' }).format(cost) + } + ]) + + function swaptDisplayFieldPool(field) { + let fieldTmp = [...field]; + + const idx1 = fieldTmp.findIndex(item => item.field === 'pool_labels'); + const idx2 = fieldTmp.findIndex(item => item.field === 'instances'); + + + const tmp = fieldTmp[idx1]; + fieldTmp[idx1] = fieldTmp[idx2]; + fieldTmp[idx2] = tmp; + + return fieldTmp + } + + + const [displayFieldsJobs, setDisplayFieldsJobs] = useState(displayFieldUngrouped.current); + const [displayFieldsPools, setDisplayFieldsPools] = useState(displayFieldUngrouped.current); + + const availableAggregateTypes = [{ value: '_', label: '_' }, { value: "username", label: 'User' }, { value: "instance", label: 'Instance' }, { value: "pool_label", label: 'Pool_label' }] + + const [selectedAggregateType, setSelectedAggregateType] = useState('_') + const [totalUsage, setTotalUsage] = useState(0); + const [tableDataJobs, setTableDataJobs] = useState([]) + const [tableDataPools, setTableDataPools] = useState([]) + const [userChartData, setUserChartData] = useState({ labels: ['-'], datasets: [{label: '# of Votes', data: [1], backgroundColor: ["rgba(31,120,180,0.2)"]}]}) + const [instanceChartData, setInstanceChartData] = useState({ labels: ['-'], datasets: [{label: '# of Votes', data: [1], backgroundColor: ["rgba(31,120,180,0.2)"]}]}) + const [poolLabelChartData, setPoolLabelChartData] = useState({ labels: ['-'], datasets: [{label: '# of Votes', data: [1], backgroundColor: ["rgba(31,120,180,0.2)"]}]}) + + const [truncateWarning, setTruncateWarning] = useState([]) + + useEffect(() => { + if (selectedAggregateType === '_') { + const displayFieldsTmpJob = displayFieldUngrouped.current.filter(el => !['jobs'].includes(el.field)) + let displayFieldsTmpPool = displayFieldUngrouped.current.filter(el => !['jobs', 'token,is_hypercube'].includes(el.field)) + displayFieldsTmpPool = swaptDisplayFieldPool(displayFieldsTmpPool) + setTableDataJobs(ungroupedDataJobs) + setTableDataPools(ungroupedDataPools) + let sumTmp = ungroupedDataJobs.reduce((accumulator, currentValue) => accumulator + currentValue.times * currentValue.multipliers, 0) + sumTmp += ungroupedDataPools.reduce((accumulator, currentValue) => accumulator + currentValue.times * currentValue.multipliers, 0) + setTotalUsage(sumTmp) + setDisplayFieldsJobs(displayFieldsTmpJob) + setDisplayFieldsPools(displayFieldsTmpPool) + } else if (selectedAggregateType === 'username') { + const displayFieldsTmpJob = displayFieldUngrouped.current.filter(el => !['instances', 'pool_labels', 'multipliers', 'token,is_hypercube'].includes(el.field)) + const displayFieldsTmpPool = displayFieldUngrouped.current.filter(el => !['instances', 'pool_labels', 'multipliers', 'token,is_hypercube'].includes(el.field)) + setTableDataJobs(GroupByUser(ungroupedDataJobs)) + setTableDataPools(GroupByUser(ungroupedDataPools)) + let sumTmp = ungroupedDataJobs.reduce((accumulator, currentValue) => accumulator + currentValue.times * currentValue.multipliers, 0) + sumTmp += ungroupedDataPools.reduce((accumulator, currentValue) => accumulator + currentValue.times * currentValue.multipliers, 0) + setTotalUsage(sumTmp) + setDisplayFieldsJobs(displayFieldsTmpJob) + setDisplayFieldsPools(displayFieldsTmpPool) + } else if (selectedAggregateType === 'instance') { + const displayFieldsTmpJob = displayFieldUngrouped.current.filter(el => !['user, unique_id', 'pool_labels', 'multipliers', 'token,is_hypercube'].includes(el.field)) + const displayFieldsTmpPool = displayFieldUngrouped.current.filter(el => !['user, unique_id', 'pool_labels', 'multipliers', 'token,is_hypercube'].includes(el.field)) + setTableDataJobs(GroupByInstance(ungroupedDataJobs)) + setTableDataPools(GroupByInstance(ungroupedDataPools)) + let sumTmp = ungroupedDataJobs.reduce((accumulator, currentValue) => accumulator + currentValue.times * currentValue.multipliers, 0) + sumTmp += ungroupedDataPools.reduce((accumulator, currentValue) => accumulator + currentValue.times * currentValue.multipliers, 0) + setTotalUsage(sumTmp) + setDisplayFieldsJobs(displayFieldsTmpJob) + setDisplayFieldsPools(displayFieldsTmpPool) + } else if (selectedAggregateType === 'pool_label') { + const displayFieldsTmpJob = displayFieldUngrouped.current.filter(el => !['instances', 'user, unique_id', 'multipliers', 'token,is_hypercube'].includes(el.field)) + const displayFieldsTmpPool = displayFieldUngrouped.current.filter(el => !['instances', 'user, unique_id', 'multipliers', 'token,is_hypercube'].includes(el.field)) + setTableDataJobs(GroupByPoolLabel(ungroupedDataJobs)) + setTableDataPools(GroupByPoolLabel(ungroupedDataPools)) + let sumTmp2 = ungroupedDataJobs.filter(el => el.pool_label != null).reduce((accumulator, currentValue) => accumulator + currentValue.times * currentValue.multipliers, 0) + sumTmp2 += ungroupedDataPools.reduce((accumulator, currentValue) => accumulator + currentValue.times * currentValue.multipliers, 0) + setTotalUsage(sumTmp2) + setDisplayFieldsJobs(displayFieldsTmpJob) + setDisplayFieldsPools(displayFieldsTmpPool) + } + + + }, [quotaUnit, selectedAggregateType, ungroupedDataJobs, ungroupedDataPools, displayFieldUngrouped]) + + useEffect(() => { + setTruncateWarning('') + let chartDataTmp = {}; + if (numUser > 1) { + chartDataTmp = getChartData('usernames', ungroupedDataJobs.concat(ungroupedDataPools)) + setUserChartData(chartDataTmp) + } + + if (numInstances > 1) { + chartDataTmp = getChartData('instances', ungroupedDataJobs.concat(ungroupedDataPools)) + setInstanceChartData(chartDataTmp) + } + + if (numPools > 1) { + chartDataTmp = getChartData('pool_labels', ungroupedDataJobs.concat(ungroupedDataPools)) + setPoolLabelChartData(chartDataTmp) + } + + }, [ungroupedDataJobs, ungroupedDataPools, numUser, numInstances, numPools]) + + console.log(numCharts) + return ( +