fix: parse quality data
This commit is contained in:
@@ -268,6 +268,7 @@ const AddModal: React.FC<AddModalProps> = ({
|
|||||||
await onOk({
|
await onOk({
|
||||||
...values
|
...values
|
||||||
});
|
});
|
||||||
|
console.log('submit form values', values);
|
||||||
} finally {
|
} finally {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import { ceilMilliToCore } from '@/pages/gpu-service/utils';
|
|
||||||
import { AutoTooltip, IconFont, ThemeTag } from '@gpustack/core-ui';
|
import { AutoTooltip, IconFont, ThemeTag } from '@gpustack/core-ui';
|
||||||
import { useIntl } from '@umijs/max';
|
import { useIntl } from '@umijs/max';
|
||||||
import { Flex } from 'antd';
|
import { Flex } from 'antd';
|
||||||
@@ -62,7 +61,7 @@ interface InstanceTypeItemProps {
|
|||||||
const MetaItem: React.FC<{
|
const MetaItem: React.FC<{
|
||||||
icon: string;
|
icon: string;
|
||||||
label?: string;
|
label?: string;
|
||||||
value?: string | null;
|
value?: string | null | number;
|
||||||
showDot?: boolean;
|
showDot?: boolean;
|
||||||
show?: boolean;
|
show?: boolean;
|
||||||
}> = ({ icon, label, value, showDot = true, show = true }) => {
|
}> = ({ icon, label, value, showDot = true, show = true }) => {
|
||||||
@@ -91,15 +90,13 @@ const InstanceTypeItem: React.FC<InstanceTypeItemProps> = ({ item }) => {
|
|||||||
const onceMaxRequestData = item.status?.onceMaxRequest || {};
|
const onceMaxRequestData = item.status?.onceMaxRequest || {};
|
||||||
|
|
||||||
// RAM resource
|
// RAM resource
|
||||||
const ramRaw = acceleratable
|
const ramUnit = acceleratable
|
||||||
? specData.unitResources?.ram
|
? specData.unitResourcesParsed?.ram?.value
|
||||||
: onceMaxRequestData.ram;
|
: onceMaxRequestData.ram;
|
||||||
|
|
||||||
console.log('InstanceTypeItem', item.name, 'ramRaw', ramRaw);
|
|
||||||
|
|
||||||
// CPU resource
|
// CPU resource
|
||||||
const cpuRaw = acceleratable
|
const cpuUnitCores = acceleratable
|
||||||
? specData.unitResources?.cpu
|
? specData.unitResourcesParsed?.cpu?.cores
|
||||||
: onceMaxRequestData.cpu;
|
: onceMaxRequestData.cpu;
|
||||||
|
|
||||||
const renderName = () => {
|
const renderName = () => {
|
||||||
@@ -159,7 +156,7 @@ const InstanceTypeItem: React.FC<InstanceTypeItemProps> = ({ item }) => {
|
|||||||
},
|
},
|
||||||
{ count: '' }
|
{ count: '' }
|
||||||
)}
|
)}
|
||||||
value={`${item.maxAccelerator || '-'}`}
|
value={`${item.maxAccelerator || 0}`}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
@@ -169,14 +166,14 @@ const InstanceTypeItem: React.FC<InstanceTypeItemProps> = ({ item }) => {
|
|||||||
showDot={false}
|
showDot={false}
|
||||||
icon="icon-ram-02"
|
icon="icon-ram-02"
|
||||||
label={intl.formatMessage({ id: 'gpuservice.instance.ram' })}
|
label={intl.formatMessage({ id: 'gpuservice.instance.ram' })}
|
||||||
value={toDisplayUnit(convertKiToGi(ramRaw)) ?? '-'}
|
value={ramUnit ? `${ramUnit}GB` : '-'}
|
||||||
/>
|
/>
|
||||||
<MetaItem
|
<MetaItem
|
||||||
show={!!cpuRaw}
|
show={!!cpuUnitCores}
|
||||||
showDot={true}
|
showDot={true}
|
||||||
icon="icon-cpu"
|
icon="icon-cpu"
|
||||||
label="CPU"
|
label="CPU"
|
||||||
value={ceilMilliToCore(cpuRaw) ?? '-'}
|
value={cpuUnitCores || '-'}
|
||||||
/>
|
/>
|
||||||
</span>
|
</span>
|
||||||
</Meta>
|
</Meta>
|
||||||
|
|||||||
@@ -41,10 +41,10 @@ export interface FormData {
|
|||||||
}[];
|
}[];
|
||||||
volumeMount: string;
|
volumeMount: string;
|
||||||
resources: {
|
resources: {
|
||||||
cpu?: string;
|
cpu: string | null | number;
|
||||||
ram?: string;
|
ram: string | null | number;
|
||||||
localStorage?: string;
|
localStorage: string | null | number;
|
||||||
accelerator?: number | string;
|
accelerator: number | string | null;
|
||||||
};
|
};
|
||||||
volume: {
|
volume: {
|
||||||
ephemeral?: {
|
ephemeral?: {
|
||||||
@@ -162,6 +162,18 @@ export interface InstanceTypeSpec {
|
|||||||
cpu: QuanityCPU;
|
cpu: QuanityCPU;
|
||||||
ram: QuanityMemory;
|
ram: QuanityMemory;
|
||||||
};
|
};
|
||||||
|
unitResourcesParsed?: {
|
||||||
|
cpu: {
|
||||||
|
cores?: number;
|
||||||
|
unit: string;
|
||||||
|
num: number;
|
||||||
|
} | null;
|
||||||
|
ram: {
|
||||||
|
value: number;
|
||||||
|
unit: string;
|
||||||
|
num: number;
|
||||||
|
} | null;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface InstanceTypeStatus {
|
export interface InstanceTypeStatus {
|
||||||
|
|||||||
@@ -1,10 +1,6 @@
|
|||||||
import { PageAction } from '@/config';
|
import { PageAction } from '@/config';
|
||||||
import { PageActionType } from '@/config/types';
|
import { PageActionType } from '@/config/types';
|
||||||
import {
|
import { ceilMilliToCore, parseQuantityToGi } from '@/pages/gpu-service/utils';
|
||||||
ceilMilliToCore,
|
|
||||||
parseQuantityToGi,
|
|
||||||
parseQuantityToNumber
|
|
||||||
} from '@/pages/gpu-service/utils';
|
|
||||||
import { PlusOutlined } from '@ant-design/icons';
|
import { PlusOutlined } from '@ant-design/icons';
|
||||||
import {
|
import {
|
||||||
CheckboxField,
|
CheckboxField,
|
||||||
@@ -198,10 +194,52 @@ const GPUServiceInstanceForm: React.FC<InstanceFormProps> = forwardRef(
|
|||||||
localStorage: null
|
localStorage: null
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const buildResourcesData = (
|
||||||
|
instanceType: InstanceTypeItem | undefined,
|
||||||
|
options: {
|
||||||
|
count: number;
|
||||||
|
}
|
||||||
|
) => {
|
||||||
|
const unitResourcesParsed = instanceType?.spec?.unitResourcesParsed;
|
||||||
|
const acceleratable = instanceType?.spec?.acceleratable;
|
||||||
|
const { count = 0 } = options;
|
||||||
|
|
||||||
|
if (acceleratable) {
|
||||||
|
return {
|
||||||
|
accelerator: _.toString(count),
|
||||||
|
cpu: unitResourcesParsed?.cpu?.cores
|
||||||
|
? count * unitResourcesParsed?.cpu?.cores
|
||||||
|
: undefined,
|
||||||
|
ram: unitResourcesParsed?.ram?.value
|
||||||
|
? count * unitResourcesParsed?.ram?.value
|
||||||
|
: undefined
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
};
|
||||||
|
|
||||||
|
const buildResourcesDataForSubmit = (values: FormData) => {
|
||||||
|
const unitResourcesParsed = getUnitResources();
|
||||||
|
const accelerator = _.toNumber(values.spec?.resources?.accelerator) || 0;
|
||||||
|
|
||||||
|
const cpuNum = unitResourcesParsed?.cpu?.num;
|
||||||
|
const ramNum = unitResourcesParsed?.ram?.num;
|
||||||
|
|
||||||
|
return {
|
||||||
|
cpu:
|
||||||
|
accelerator > 0 && cpuNum
|
||||||
|
? `${accelerator * cpuNum}${unitResourcesParsed?.cpu?.unit || ''}`
|
||||||
|
: `${values.spec?.resources?.cpu}`,
|
||||||
|
ram:
|
||||||
|
accelerator > 0 && ramNum
|
||||||
|
? `${accelerator * ramNum}${unitResourcesParsed?.ram?.unit || ''}`
|
||||||
|
: values.spec?.resources?.ram
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
const resolveAndApply = (
|
const resolveAndApply = (
|
||||||
instanceType: InstanceTypeItem | undefined,
|
instanceType: InstanceTypeItem | undefined,
|
||||||
count: number,
|
count: number
|
||||||
options: { writeAccelerator?: boolean } = {}
|
|
||||||
) => {
|
) => {
|
||||||
if (!instanceType) {
|
if (!instanceType) {
|
||||||
setSelectedInstanceType(undefined);
|
setSelectedInstanceType(undefined);
|
||||||
@@ -214,40 +252,22 @@ const GPUServiceInstanceForm: React.FC<InstanceFormProps> = forwardRef(
|
|||||||
);
|
);
|
||||||
|
|
||||||
setSelectedInstanceType(instanceType);
|
setSelectedInstanceType(instanceType);
|
||||||
|
|
||||||
setOnceMaxRequest({
|
setOnceMaxRequest({
|
||||||
cpu: ceilMilliToCore(candidate?.cpu?.onceMaxRequest),
|
cpu: ceilMilliToCore(candidate?.cpu?.onceMaxRequest)?.cores,
|
||||||
memory: parseQuantityToGi(candidate?.ram?.onceMaxRequest),
|
memory: parseQuantityToGi(candidate?.ram?.onceMaxRequest)?.value,
|
||||||
localStorage: parseQuantityToGi(candidate?.localStorage?.onceMaxRequest)
|
localStorage: parseQuantityToGi(candidate?.localStorage?.onceMaxRequest)
|
||||||
|
?.value
|
||||||
});
|
});
|
||||||
|
|
||||||
const unitResources = instanceType.spec?.unitResources;
|
|
||||||
const unitCpu = parseQuantityToNumber(unitResources?.cpu);
|
|
||||||
const unitRam = parseQuantityToNumber(unitResources?.ram);
|
|
||||||
const acceleratable = instanceType.spec?.acceleratable;
|
|
||||||
const cpuCores =
|
|
||||||
unitCpu != null ? ceilMilliToCore(`${count * unitCpu}m`) : null;
|
|
||||||
const ramGi =
|
|
||||||
unitRam != null ? parseQuantityToGi(`${count * unitRam}Mi`) : null;
|
|
||||||
|
|
||||||
form.setFieldsValue({
|
form.setFieldsValue({
|
||||||
clusterId: candidate?.cluster ? _.toNumber(candidate.cluster) : null,
|
clusterId: candidate?.cluster ? _.toNumber(candidate.cluster) : null,
|
||||||
spec: {
|
spec: {
|
||||||
type: candidate?.name || '',
|
type: candidate?.name || '',
|
||||||
...(options.writeAccelerator
|
resources: {
|
||||||
? { resources: { accelerator: _.toString(count) } }
|
...buildResourcesData(instanceType, {
|
||||||
: {}),
|
count
|
||||||
...(acceleratable
|
})
|
||||||
? {
|
}
|
||||||
resources: {
|
|
||||||
...(options.writeAccelerator
|
|
||||||
? { accelerator: _.toString(count) }
|
|
||||||
: {}),
|
|
||||||
...(cpuCores != null ? { cpu: cpuCores } : {}),
|
|
||||||
...(ramGi != null ? { ram: `${ramGi}Gi` } : {})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
: {})
|
|
||||||
} as any
|
} as any
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@@ -293,8 +313,22 @@ const GPUServiceInstanceForm: React.FC<InstanceFormProps> = forwardRef(
|
|||||||
action === PageAction.VIEW ||
|
action === PageAction.VIEW ||
|
||||||
realAction === PageAction.CREATE
|
realAction === PageAction.CREATE
|
||||||
) {
|
) {
|
||||||
|
console.log('currentData', currentData);
|
||||||
form.setFieldsValue({
|
form.setFieldsValue({
|
||||||
...currentData,
|
...currentData,
|
||||||
|
spec: {
|
||||||
|
...currentData?.spec,
|
||||||
|
resources: {
|
||||||
|
...currentData?.spec?.resources,
|
||||||
|
...buildResourcesData(
|
||||||
|
JSON.parse(currentData?.description || '{}'),
|
||||||
|
{
|
||||||
|
count:
|
||||||
|
_.toNumber(currentData?.spec?.resources?.accelerator) || 0
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
enable_ssh: !!currentData?.spec?.sshPublicKeys?.length,
|
enable_ssh: !!currentData?.spec?.sshPublicKeys?.length,
|
||||||
storageMode: detectMode(currentData?.spec?.volume)
|
storageMode: detectMode(currentData?.spec?.volume)
|
||||||
});
|
});
|
||||||
@@ -302,13 +336,13 @@ const GPUServiceInstanceForm: React.FC<InstanceFormProps> = forwardRef(
|
|||||||
}, [action, currentData, form, open, realAction, instanceTypeList]);
|
}, [action, currentData, form, open, realAction, instanceTypeList]);
|
||||||
|
|
||||||
const getUnitResources = () => {
|
const getUnitResources = () => {
|
||||||
if (selectedInstanceType?.spec?.unitResources) {
|
if (selectedInstanceType?.spec?.unitResourcesParsed) {
|
||||||
return selectedInstanceType.spec.unitResources;
|
return selectedInstanceType.spec.unitResourcesParsed;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
return (
|
return (
|
||||||
JSON.parse(currentData?.description || '{}')?.spec?.unitResources ??
|
JSON.parse(currentData?.description || '{}')?.spec
|
||||||
undefined
|
?.unitResourcesParsed ?? undefined
|
||||||
);
|
);
|
||||||
} catch {
|
} catch {
|
||||||
return undefined;
|
return undefined;
|
||||||
@@ -329,26 +363,15 @@ const GPUServiceInstanceForm: React.FC<InstanceFormProps> = forwardRef(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const accelerator = _.toNumber(values.spec?.resources?.accelerator);
|
|
||||||
const submittedResources = { ...(values.spec?.resources ?? {}) };
|
|
||||||
if (accelerator > 0) {
|
|
||||||
const unitResources = getUnitResources();
|
|
||||||
const unitCpu = parseQuantityToNumber(unitResources?.cpu);
|
|
||||||
const unitRam = parseQuantityToNumber(unitResources?.ram);
|
|
||||||
if (unitCpu != null) {
|
|
||||||
submittedResources.cpu = `${accelerator * unitCpu}m`;
|
|
||||||
}
|
|
||||||
if (unitRam != null) {
|
|
||||||
submittedResources.ram = `${accelerator * unitRam}Mi`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
await onFinish({
|
await onFinish({
|
||||||
..._.omit(values, ['enable_ssh']),
|
..._.omit(values, ['enable_ssh']),
|
||||||
spec: {
|
spec: {
|
||||||
...values.spec,
|
...values.spec,
|
||||||
ports: submittedPorts,
|
ports: submittedPorts,
|
||||||
resources: submittedResources
|
resources: {
|
||||||
|
...values.spec?.resources,
|
||||||
|
...buildResourcesDataForSubmit(values)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@@ -377,7 +400,7 @@ const GPUServiceInstanceForm: React.FC<InstanceFormProps> = forwardRef(
|
|||||||
getFieldsValue: () => form.getFieldsValue(),
|
getFieldsValue: () => form.getFieldsValue(),
|
||||||
applyInstanceType: (instanceType: InstanceTypeItem) => {
|
applyInstanceType: (instanceType: InstanceTypeItem) => {
|
||||||
const count = instanceType.spec?.acceleratable ? 1 : 0;
|
const count = instanceType.spec?.acceleratable ? 1 : 0;
|
||||||
resolveAndApply(instanceType, count, { writeAccelerator: true });
|
resolveAndApply(instanceType, count);
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ import _ from 'lodash';
|
|||||||
import { useMemo } from 'react';
|
import { useMemo } from 'react';
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
import { BasicResourceMax } from '../../templates/forms/basic';
|
import { BasicResourceMax } from '../../templates/forms/basic';
|
||||||
import { ceilMilliToCore, parseQuantityToGi } from '../../utils';
|
|
||||||
import InstanceTypeItem from '../components/instance-type-item';
|
import InstanceTypeItem from '../components/instance-type-item';
|
||||||
import { getAcceleratorMax } from '../config';
|
import { getAcceleratorMax } from '../config';
|
||||||
import {
|
import {
|
||||||
@@ -102,7 +101,7 @@ const InstanceTypeFormItem: React.FC<InstanceTypeFormItemProps> = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const renderMemoryLabel = (): React.ReactNode => {
|
const renderMemoryLabel = (): React.ReactNode => {
|
||||||
if (isGPU) {
|
if (isGPU || action === PageAction.EDIT || !onceMaxRequest?.memory) {
|
||||||
return intl.formatMessage({ id: 'gpuservice.template.memory' });
|
return intl.formatMessage({ id: 'gpuservice.template.memory' });
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -235,40 +234,24 @@ const InstanceTypeFormItem: React.FC<InstanceTypeFormItemProps> = ({
|
|||||||
<div style={{ flex: 1 }}>
|
<div style={{ flex: 1 }}>
|
||||||
<Form.Item<FormData>
|
<Form.Item<FormData>
|
||||||
name={['spec', 'resources', 'ram']}
|
name={['spec', 'resources', 'ram']}
|
||||||
normalize={(value) => (value ? `${value}Gi` : undefined)}
|
normalize={(value) => (value ? `${value}Gi` : null)}
|
||||||
getValueProps={(value) => {
|
getValueProps={(value) => ({
|
||||||
if (!value) return { value: '' };
|
value: _.toString(value).replace(/Gi$/, '')
|
||||||
const str = String(value);
|
})}
|
||||||
if (/Gi$/.test(str)) return { value: str.replace(/Gi$/, '') };
|
|
||||||
if (/(Ki|Mi|Ti)$/.test(str)) {
|
|
||||||
return { value: parseQuantityToGi(str) ?? '' };
|
|
||||||
}
|
|
||||||
return { value: str };
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
<InputNumber
|
<InputNumber
|
||||||
disabled={isGPU || disabled}
|
disabled={isGPU || disabled || action === PageAction.EDIT}
|
||||||
label={renderMemoryLabel()}
|
label={renderMemoryLabel()}
|
||||||
max={onceMaxRequest?.memory ?? undefined}
|
max={onceMaxRequest?.memory ?? undefined}
|
||||||
/>
|
/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</div>
|
</div>
|
||||||
<div style={{ flex: 1 }}>
|
<div style={{ flex: 1 }}>
|
||||||
<Form.Item<FormData>
|
<Form.Item<FormData> name={['spec', 'resources', 'cpu']}>
|
||||||
name={['spec', 'resources', 'cpu']}
|
|
||||||
normalize={(value) => (value ? `${value}` : '')}
|
|
||||||
getValueProps={(value) => {
|
|
||||||
if (!value) return { value: '' };
|
|
||||||
const str = String(value);
|
|
||||||
return {
|
|
||||||
value: /m$/.test(str) ? (ceilMilliToCore(str) ?? '') : str
|
|
||||||
};
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<InputNumber
|
<InputNumber
|
||||||
label={renderMaxLabel('CPU', onceMaxRequest?.cpu)}
|
label={renderMaxLabel('CPU', onceMaxRequest?.cpu)}
|
||||||
max={onceMaxRequest?.cpu ?? undefined}
|
max={onceMaxRequest?.cpu ?? undefined}
|
||||||
disabled={disabled || isGPU}
|
disabled={disabled || isGPU || action === PageAction.EDIT}
|
||||||
/>
|
/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -88,7 +88,7 @@ const GPUService: React.FC = () => {
|
|||||||
} = useViewEvents();
|
} = useViewEvents();
|
||||||
const {
|
const {
|
||||||
fetchClusterList,
|
fetchClusterList,
|
||||||
cancelRequest: cancelClusterRequest,
|
cancelRequest,
|
||||||
clusterList,
|
clusterList,
|
||||||
loading: clusterLoading
|
loading: clusterLoading
|
||||||
} = useQueryClusterList();
|
} = useQueryClusterList();
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { useQueryData } from '@gpustack/core-ui';
|
import { useQueryData } from '@gpustack/core-ui';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import { ceilMilliToCore, parseQuantityToGi } from '../../utils';
|
||||||
import { queryGPUServiceInstanceTypes } from '../apis';
|
import { queryGPUServiceInstanceTypes } from '../apis';
|
||||||
import { getAcceleratorMax } from '../config';
|
import { getAcceleratorMax } from '../config';
|
||||||
import { InstanceTypeItem } from '../config/types';
|
import { InstanceTypeItem } from '../config/types';
|
||||||
@@ -44,13 +45,33 @@ export default function useQueryInstanceTypes() {
|
|||||||
|
|
||||||
const list = (res?.items || []).map((item) => {
|
const list = (res?.items || []).map((item) => {
|
||||||
const remainingData = isAvailable(item);
|
const remainingData = isAvailable(item);
|
||||||
|
const rawMax = item.status?.onceMaxRequest;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...item,
|
...item,
|
||||||
|
spec: {
|
||||||
|
...item.spec,
|
||||||
|
unitResourcesParsed: {
|
||||||
|
cpu: ceilMilliToCore(item.spec?.unitResources?.cpu ?? null),
|
||||||
|
ram: parseQuantityToGi(item.spec?.unitResources?.ram ?? null)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
status: {
|
||||||
|
...item.status,
|
||||||
|
onceMaxRequest: {
|
||||||
|
...rawMax,
|
||||||
|
cpu: rawMax?.cpu ? `${ceilMilliToCore(rawMax.cpu)?.cores}` : '',
|
||||||
|
ram: rawMax?.ram ? `${parseQuantityToGi(rawMax.ram)?.value}` : '',
|
||||||
|
localStorage: rawMax?.localStorage
|
||||||
|
? `${parseQuantityToGi(rawMax.localStorage)?.value}`
|
||||||
|
: ''
|
||||||
|
}
|
||||||
|
},
|
||||||
maxAccelerator: remainingData.maxAccelerator,
|
maxAccelerator: remainingData.maxAccelerator,
|
||||||
disabled: !remainingData.available
|
disabled: !remainingData.available
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
console.log('queryInstanceTypes', list);
|
|
||||||
setDataList(list);
|
setDataList(list);
|
||||||
return list;
|
return list;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -20,34 +20,89 @@ export const parseQuantityToNumber = (value?: string | null): number | null => {
|
|||||||
return Number.isFinite(num) && num > 0 ? num : null;
|
return Number.isFinite(num) && num > 0 ? num : null;
|
||||||
};
|
};
|
||||||
|
|
||||||
const GI_FROM_UNIT: Record<string, number> = {
|
const UNIT_FACTOR: Record<string, number> = {
|
||||||
Ki: 1 / (1024 * 1024),
|
'': 1,
|
||||||
Mi: 1 / 1024,
|
n: 1e-9,
|
||||||
Gi: 1,
|
u: 1e-6,
|
||||||
Ti: 1024
|
m: 1e-3,
|
||||||
|
k: 1e3,
|
||||||
|
M: 1e6,
|
||||||
|
G: 1e9,
|
||||||
|
T: 1e12,
|
||||||
|
P: 1e15,
|
||||||
|
E: 1e18,
|
||||||
|
Ki: 1024,
|
||||||
|
Mi: 1024 ** 2,
|
||||||
|
Gi: 1024 ** 3,
|
||||||
|
Ti: 1024 ** 4,
|
||||||
|
Pi: 1024 ** 5,
|
||||||
|
Ei: 1024 ** 6
|
||||||
};
|
};
|
||||||
|
|
||||||
// Converts a K8s-style quantity ("24314504Ki", "2Ti", "10Gi", or a bare
|
export const parseQuantity = (
|
||||||
// number assumed to be bytes) to an integer GiB. Unit suffix is
|
value?: string | null
|
||||||
// case-insensitive.
|
): { num: number; unit: string; base: number } | null => {
|
||||||
export const parseQuantityToGi = (value?: string | null): number | null => {
|
if (value == null) return null;
|
||||||
if (!value) return null;
|
const str = String(value).trim();
|
||||||
const match = /^(-?\d+(?:\.\d+)?)(Ki|Mi|Gi|Ti)?$/i.exec(String(value));
|
const len = str.length;
|
||||||
if (!match) return null;
|
if (len === 0) return null;
|
||||||
const num = Number(match[1]);
|
|
||||||
if (!Number.isFinite(num) || num <= 0) return null;
|
|
||||||
const unit = match[2]
|
|
||||||
? match[2][0].toUpperCase() + match[2].slice(1).toLowerCase()
|
|
||||||
: null;
|
|
||||||
const factor = unit ? GI_FROM_UNIT[unit] : 1 / (1024 * 1024 * 1024);
|
|
||||||
return Math.floor(num * factor);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const ceilMilliToCore = (value?: string | null): string | null => {
|
let unit = '';
|
||||||
if (!value) return null;
|
let numEnd = len;
|
||||||
const match = /^(-?\d+(?:\.\d+)?)m?$/.exec(value);
|
if (len >= 2 && str[len - 1] === 'i') {
|
||||||
if (!match) return null;
|
unit = str.slice(len - 2);
|
||||||
const num = Number(match[1]);
|
if (UNIT_FACTOR[unit] === undefined) return null;
|
||||||
|
numEnd = len - 2;
|
||||||
|
} else {
|
||||||
|
const last = str[len - 1];
|
||||||
|
const code = last.charCodeAt(0);
|
||||||
|
const isDigit = code >= 48 && code <= 57;
|
||||||
|
if (!isDigit && UNIT_FACTOR[last] !== undefined) {
|
||||||
|
unit = last;
|
||||||
|
numEnd = len - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (numEnd === 0) return null;
|
||||||
|
const num = Number(str.slice(0, numEnd));
|
||||||
if (!Number.isFinite(num)) return null;
|
if (!Number.isFinite(num)) return null;
|
||||||
return String(Math.ceil(num / 1000));
|
const base = num * UNIT_FACTOR[unit];
|
||||||
|
if (!Number.isFinite(base)) return null;
|
||||||
|
|
||||||
|
return { num, unit, base };
|
||||||
|
};
|
||||||
|
|
||||||
|
export const parseQuantityToGi = (
|
||||||
|
value?: string | null
|
||||||
|
): { value: number; unit: string; num: number } | null => {
|
||||||
|
if (!value) return null;
|
||||||
|
const normalized = String(value).replace(
|
||||||
|
/(ki|mi|gi|ti|pi|ei)$/i,
|
||||||
|
(m) => m[0].toUpperCase() + m[1].toLowerCase()
|
||||||
|
);
|
||||||
|
const parsed = parseQuantity(normalized);
|
||||||
|
|
||||||
|
if (!parsed || parsed.base <= 0) return null;
|
||||||
|
|
||||||
|
return {
|
||||||
|
value: _.floor(parsed.base / UNIT_FACTOR.Gi, 0),
|
||||||
|
unit: parsed.unit,
|
||||||
|
num: parsed.num
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export const ceilMilliToCore = (
|
||||||
|
value?: string | null,
|
||||||
|
unit?: string
|
||||||
|
): { cores: number; unit: string; num: number } | null => {
|
||||||
|
const parsed = parseQuantity(value);
|
||||||
|
if (!parsed) return null;
|
||||||
|
const outUnit = unit ?? parsed.unit;
|
||||||
|
const outFactor = UNIT_FACTOR[outUnit];
|
||||||
|
if (outFactor === undefined) return null;
|
||||||
|
return {
|
||||||
|
cores: Math.ceil(parsed.base),
|
||||||
|
unit: outUnit,
|
||||||
|
num: parsed.base / outFactor
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user