diff --git a/src/renderer/components/+config-resource-quotas/resource-quota-details.tsx b/src/renderer/components/+config-resource-quotas/resource-quota-details.tsx index 6a2665e741..3da8c7112a 100644 --- a/src/renderer/components/+config-resource-quotas/resource-quota-details.tsx +++ b/src/renderer/components/+config-resource-quotas/resource-quota-details.tsx @@ -4,7 +4,7 @@ import kebabCase from "lodash/kebabCase"; import { observer } from "mobx-react"; import { Trans } from "@lingui/macro"; import { DrawerItem, DrawerTitle } from "../drawer"; -import { cpuUnitsToNumber, cssNames, unitsToBytes } from "../../utils"; +import { cpuUnitsToNumber, cssNames, unitsToBytes, metricUnitsToNumber } from "../../utils"; import { KubeObjectDetailsProps } from "../kube-object"; import { ResourceQuota, resourceQuotaApi } from "../../api/endpoints/resource-quota.api"; import { LineProgress } from "../line-progress"; @@ -15,24 +15,30 @@ import { KubeObjectMeta } from "../kube-object/kube-object-meta"; interface Props extends KubeObjectDetailsProps { } -@observer -export class ResourceQuotaDetails extends React.Component { - renderQuotas = (quota: ResourceQuota) => { - const { hard, used } = quota.status - if (!hard || !used) return null - const transformUnit = (name: string, value: string) => { - if (name.includes("memory") || name.includes("storage")) { - return unitsToBytes(value) - } - if (name.includes("cpu")) { - return cpuUnitsToNumber(value) - } - return parseInt(value) - } - return Object.entries(hard).map(([name, value]) => { - if (!used[name]) return null +const onlyNumbers = /$[0-9]*^/g; + +function transformUnit(name: string, value: string): number { + if (name.includes("memory") || name.includes("storage")) { + return unitsToBytes(value) + } + + if (name.includes("cpu")) { + return cpuUnitsToNumber(value) + } + + return metricUnitsToNumber(value); +} + +function renderQuotas(quota: ResourceQuota): JSX.Element[] { + const { hard = {}, used = {} } = quota.status + + return Object.entries(hard) + .filter(([name]) => used[name]) + .map(([name, value]) => { const current = transformUnit(name, used[name]) const max = transformUnit(name, value) + const usage = max === 0 ? 100 : Math.ceil(current / max * 100); // special case 0 max as always 100% usage + return (
{name} @@ -41,14 +47,16 @@ export class ResourceQuotaDetails extends React.Component { max={max} value={current} tooltip={ -

Set: {value}. Used: {Math.ceil(current / max * 100) + "%"}

+

Set: {value}. Usage: {usage + "%"}

} />
) }) - } +} +@observer +export class ResourceQuotaDetails extends React.Component { render() { const { object: quota } = this.props; if (!quota) return null; @@ -57,7 +65,7 @@ export class ResourceQuotaDetails extends React.Component { Quotas} className="quota-list"> - {this.renderQuotas(quota)} + {renderQuotas(quota)} {quota.getScopeSelector().length > 0 && ( diff --git a/src/renderer/utils/convertCpu.ts b/src/renderer/utils/convertCpu.ts index 2e7c6b85c3..7b81a30cc3 100644 --- a/src/renderer/utils/convertCpu.ts +++ b/src/renderer/utils/convertCpu.ts @@ -1,10 +1,13 @@ // Helper to convert CPU K8S units to numbers +const thousand = 1000; +const million = thousand * thousand; +const shortBillion = thousand * million; + export function cpuUnitsToNumber(cpu: string) { const cpuNum = parseInt(cpu) - const billion = 1000000 * 1000 - if (cpu.includes("m")) return cpuNum / 1000 - if (cpu.includes("u")) return cpuNum / 1000000 - if (cpu.includes("n")) return cpuNum / billion + if (cpu.includes("m")) return cpuNum / thousand + if (cpu.includes("u")) return cpuNum / million + if (cpu.includes("n")) return cpuNum / shortBillion return parseFloat(cpu) -} \ No newline at end of file +} diff --git a/src/renderer/utils/convertMemory.ts b/src/renderer/utils/convertMemory.ts index faa89dd990..d0d7e1fc52 100644 --- a/src/renderer/utils/convertMemory.ts +++ b/src/renderer/utils/convertMemory.ts @@ -7,9 +7,9 @@ export function unitsToBytes(value: string) { if (!suffixes.some(suffix => value.includes(suffix))) { return parseFloat(value) } - const index = suffixes.findIndex(suffix => - suffix == value.replace(/[0-9]|i|\./g, '') - ) + + const suffix = value.replace(/[0-9]|i|\./g, ''); + const index = suffixes.indexOf(suffix); return parseInt( (parseFloat(value) * Math.pow(base, index + 1)).toFixed(1) ) @@ -21,8 +21,10 @@ export function bytesToUnits(bytes: number, precision = 1) { if (!bytes) { return "N/A" } + if (index === 0) { return `${bytes}${sizes[index]}` } + return `${(bytes / (1024 ** index)).toFixed(precision)}${sizes[index]}i` -} \ No newline at end of file +} diff --git a/src/renderer/utils/index.ts b/src/renderer/utils/index.ts index 8a3a263077..578ec5c355 100755 --- a/src/renderer/utils/index.ts +++ b/src/renderer/utils/index.ts @@ -20,3 +20,4 @@ export * from './formatDuration' export * from './isReactNode' export * from './convertMemory' export * from './convertCpu' +export * from './metricUnitsToNumber' diff --git a/src/renderer/utils/metricUnitsToNumber.ts b/src/renderer/utils/metricUnitsToNumber.ts new file mode 100644 index 0000000000..9390c35b24 --- /dev/null +++ b/src/renderer/utils/metricUnitsToNumber.ts @@ -0,0 +1,10 @@ +const base = 1000; +const suffixes = ["k", "m", "g", "t", "q"]; + +export function metricUnitsToNumber(value: string): number { + const suffix = value.toLowerCase().slice(-1); + const index = suffixes.indexOf(suffix); + return parseInt( + (parseFloat(value) * Math.pow(base, index + 1)).toFixed(1) + ) +} diff --git a/src/renderer/utils/metricUnitsToNumber_test.ts b/src/renderer/utils/metricUnitsToNumber_test.ts new file mode 100644 index 0000000000..cbb0669122 --- /dev/null +++ b/src/renderer/utils/metricUnitsToNumber_test.ts @@ -0,0 +1,15 @@ +import { metricUnitsToNumber } from "./metricUnitsToNumber"; + +describe("metricUnitsToNumber tests", () => { + test("plain number", () => { + expect(metricUnitsToNumber("124")).toStrictEqual(124); + }); + + test("with k suffix", () => { + expect(metricUnitsToNumber("124k")).toStrictEqual(124000); + }); + + test("with m suffix", () => { + expect(metricUnitsToNumber("124m")).toStrictEqual(124000000); + }); +}); \ No newline at end of file