diff --git a/src/resource-group-detail.jsx b/src/resource-group-detail.jsx index b8e4b2e..2d0ca24 100644 --- a/src/resource-group-detail.jsx +++ b/src/resource-group-detail.jsx @@ -19,7 +19,7 @@ export default function ResourceGroupDetail({ baseUri, infoGroupId }) { - {/* */} + diff --git a/src/resource-group-queue-metrics.jsx b/src/resource-group-queue-metrics.jsx index 99dcc83..4587614 100644 --- a/src/resource-group-queue-metrics.jsx +++ b/src/resource-group-queue-metrics.jsx @@ -1,81 +1,83 @@ import { useState } from "preact/hooks"; -import { useJSON } from "./utils"; +import { useJSON, useResourceGroup } from "./utils"; -import Grid from "./grid"; -import InfoTip from "./info-tip"; import Section from "./section"; -const formatTime = (value) => { - const hours = Math.floor(value); - const minutes = Math.floor((value - hours) * 60); - const seconds = Math.round((value - hours) * 3600 - minutes * 60); - return [hours, minutes, seconds] - .map((value) => value.toString().padStart(2, "0")) - .join(":"); -}; +const pluralize = (count, label, places = 0) => + `${count.toFixed(places)} ${label}${count == 1 ? "" : "s"}`; -const formatHeaderTip = (content) => (value) => { - return ( - <> - {value} - - ); +const formatTime = (seconds) => { + const hours = seconds / 3600; + if (hours >= 1) return pluralize(hours, "hour", 1); + const minutes = seconds / 60; + if (minutes >= 1) return pluralize(minutes, "minute", 0); + return pluralize(seconds, "second", 0); }; -export default function ResourceGroupQueueMetrics({ baseUri, infoGroupId }) { - const [days, setDays] = useState(30); - const data = useJSON( - `${baseUri}/api/resource-groups/${infoGroupId}/queue-metrics/${days}.json` +export default function ResourceGroupQueueMetrics({ infoGroupId }) { + const [view, setView] = useState("overview"); + const resourceGroup = useResourceGroup(infoGroupId); + const resources = useJSON( + resourceGroup + ? resourceGroup.infoResourceIds.map( + (infoResourceId) => + `https://operations-api.access-ci.org/wh2/cider/v1/info_resourceid/${infoResourceId}/?format=json` + ) + : null, + { defaultValue: [] } ); - if (!data || data.error) return; + const overviewMetrics = useJSON( + resourceGroup + ? resourceGroup.infoResourceIds.map( + (infoResourceId) => + `https://rest-test.ccr.xdmod.org/rest/v0.1/custom_queries/wait_times/${infoResourceId}/` + ) + : null, + { corsProxy: true, defaultValue: [] } + ); + + if (!overviewMetrics.length || !resources.length) return; - const columns = [ - { - key: "name", - name: "Resource", - }, - { - key: "waitTime", - name: "Wait Time", - format: formatTime, - formatHeader: formatHeaderTip( - "Wait time is the average time a job spends waiting in the queue before running on a resource." - ), - }, - { - key: "wallTime", - name: "Wall Time", - format: formatTime, - formatHeader: formatHeaderTip( - "Wall time is the average time a job spends running on a resource." - ), - }, - { - key: "expansionFactor", - name: "Expansion Factor", - format: (_value, row) => - ((row.waitTime + row.wallTime) / row.wallTime).toFixed(2), - formatHeader: formatHeaderTip( - 'Expansion factor is the ratio of the total time (wait time and wall time) to the wall time. It measures how much waiting in the queue "expands" the total time taken to complete a job relative to its length.' - ), - }, - ]; + const overview = overviewMetrics + .map((om, i) => + om.error ? om : { ...om.data[0], ...resources[i].results } + ) + .filter((data) => !data.error); - const headerComponents = [ - , - ]; + if (!overview.length) return; return ( -
- +
+ {overview.map( + ({ + job_count, + median_expansion_factor, + median_wait_time, + median_wall_time, + resource_descriptive_name, + }) => { + return ( +

+ + {resource_descriptive_name.replace(/ \([^)]+\)/, "")}: + {" "} + Users ran{" "} + {parseInt(job_count).toLocaleString("en-us")}{" "} + jobs during the last 30 days. Waiting in the queue increased the + time to complete these jobs by{" "} + + {((median_expansion_factor - 1) * 100).toLocaleString("en-us", { + maximumFractionDigits: 0, + })} + % + {" "} + on average. The median job waited for{" "} + {formatTime(median_wait_time)} and ran for{" "} + {formatTime(median_wall_time)}. +

+ ); + } + )}
); }