style: number selection

This commit is contained in:
jialin
2026-05-25 22:42:02 +08:00
committed by jialin
parent f886422f91
commit 5195b1e5fc
20 changed files with 285 additions and 150 deletions
@@ -370,9 +370,11 @@ const AddModal: React.FC<AddModalProps> = ({
}
>
<>
<ColTitle>
{intl.formatMessage({ id: 'common.title.config' })}
</ColTitle>
{action !== PageAction.VIEW && (
<ColTitle>
{intl.formatMessage({ id: 'common.title.config' })}
</ColTitle>
)}
<GPUServiceInstanceForm
ref={form}
action={action}
@@ -66,16 +66,23 @@ const InstanceTypeItem: React.FC<InstanceTypeItemProps> = ({
const intl = useIntl();
const name = item.metadata?.name;
const acceleratable = item.spec?.acceleratable;
const product = item.spec?.product;
const displayName = product || (!acceleratable ? 'CPU' : name);
const manufacturer = item.spec?.manufacturer?.toUpperCase();
const renderName = () => {
const product = item.spec?.product;
const displayName =
product ||
(!acceleratable ? `${item.status?.cpu?.capacity} vCPUs` : name);
return displayName;
};
return (
<>
<Title>
<Flex gap={8} align="center">
<AutoTooltip ghost minWidth={20} maxWidth={180}>
{item.spec ? displayName : '-'}
{item.spec ? renderName() : '-'}
</AutoTooltip>
{acceleratable && manufacturer && (
<span
@@ -165,14 +172,18 @@ const InstanceTypeItem: React.FC<InstanceTypeItemProps> = ({
<span>{toDisplayUnit(item.status?.ram?.capacity) ?? '-'}</span>
</Flex>
</span>
<span className="dot"></span>
<span className="meta-item">
<IconFont type="icon-cpu" className="meta-icon" />
<Flex align="center" gap={4}>
<span>vCPU</span>
<span>{item.status?.cpu?.capacity ?? '-'}</span>
</Flex>
</span>
{acceleratable && (
<>
<span className="dot"></span>
<span className="meta-item">
<IconFont type="icon-cpu" className="meta-icon" />
<Flex align="center" gap={4}>
<span>vCPU</span>
<span>{item.status?.cpu?.capacity ?? '-'}</span>
</Flex>
</span>
</>
)}
</span>
</Meta>
</>
@@ -160,11 +160,6 @@ const GPUServiceInstanceForm: React.FC<InstanceFormProps> = forwardRef(
);
const ports = Form.useWatch(['spec', 'ports'], form) || [];
const hasSshPort = useMemo(
() =>
ports.some((p) => Number(p?.port) === SSH_PORT && p.protocol === 'TCP'),
[ports]
);
const selectedTypeName = Form.useWatch(['spec', 'type'], form) as
| string
@@ -242,6 +237,17 @@ const GPUServiceInstanceForm: React.FC<InstanceFormProps> = forwardRef(
});
};
const segmentedTop =
action === PageAction.VIEW
? {
top: 0,
offsetTop: 100
}
: {
top: 40,
offsetTop: 130
};
useImperativeHandle(ref, () => ({
submit: () => {
form.submit();
@@ -262,10 +268,7 @@ const GPUServiceInstanceForm: React.FC<InstanceFormProps> = forwardRef(
segmentOptions={segmentOptions}
activeKey={activeKey}
setActiveKey={handleActiveChange}
segmentedTop={{
top: 40,
offsetTop: 130
}}
segmentedTop={segmentedTop}
getScrollElementScrollableHeight={getScrollElementScrollableHeight}
>
<Form
@@ -2,7 +2,7 @@ import { PageAction } from '@/config';
import { PageActionType } from '@/config/types';
import NumberSelection from '@/pages/_components/number-selection';
import { useIntl } from '@umijs/max';
import { Form } from 'antd';
import { Alert, Form } from 'antd';
import { useEffect, useMemo } from 'react';
import styled from 'styled-components';
import InstanceTypeItem from '../components/instance-type-item';
@@ -118,17 +118,12 @@ const InstanceTypeFormItem: React.FC<InstanceTypeFormItemProps> = ({
<InstanceTypePicker dataList={dataList} value={typeName} />
</Form.Item>
</FieldBlock>
{selectedInstanceType?.spec?.acceleratable && (
{!selectedInstanceType?.spec?.acceleratable && (
<Form.Item
name={['spec', 'resources', 'accelerator']}
rules={[
{
required: true,
message: intl.formatMessage({
id: 'gpuservice.instance.gpuCount.required'
})
},
{
validator: (_, value) => {
if (value > maxGpuCount) {
return Promise.reject(
@@ -143,9 +138,14 @@ const InstanceTypeFormItem: React.FC<InstanceTypeFormItemProps> = ({
if (value < 1) {
return Promise.reject(
new Error(
intl.formatMessage({
id: 'gpuservice.instance.gpuCount.min'
})
intl.formatMessage(
{
id: 'gpuservice.instance.gpuCount.min'
},
{
count: 1
}
)
)
);
}
@@ -160,6 +160,23 @@ const InstanceTypeFormItem: React.FC<InstanceTypeFormItemProps> = ({
step={1}
required
disabled={disabled || action === PageAction.EDIT}
labelExtra={
!maxGpuCount && (
<Alert
showIcon
type="warning"
title={intl.formatMessage({
id: 'gpuservice.instance.gpuCount.noAvailable'
})}
styles={{
root: {
marginLeft: 4,
paddingBlock: 0
}
}}
></Alert>
)
}
label={intl.formatMessage({ id: 'gpuservice.instance.gpuCount' })}
/>
</Form.Item>
@@ -2,9 +2,11 @@ import { currentClusterAtom } from '@/atoms/gpuservice';
import { getCurrentOrgNamespace } from '@/atoms/user';
import { PageAction } from '@/config';
import {
Input as CInput,
InputNumber as CInputNumber,
LabelInfo,
Select
Select,
useAppUtils
} from '@gpustack/core-ui';
import { useIntl } from '@umijs/max';
import { Button, Flex, Form, Radio } from 'antd';
@@ -32,6 +34,7 @@ const StorageVolume = ({
action: PageActionType;
}) => {
const intl = useIntl();
const { getRuleMessage } = useAppUtils();
const { fetchData: createStorage } = useCreateStorage();
const { detailData: storageData, fetchData: fetchStorage } =
useQueryStorage();
@@ -84,7 +87,7 @@ const StorageVolume = ({
};
return (
<FieldBlock data-field="storage">
<FieldBlock>
<Flex
style={{
justifyContent: 'space-between',
@@ -146,6 +149,7 @@ const StorageVolume = ({
</Button>
)}
</Flex>
<div data-field="storage"></div>
{storageMode === StorageModeValueMap.Existing && (
<Form.Item
@@ -199,6 +203,26 @@ const StorageVolume = ({
/>
</Form.Item>
)}
<Form.Item<FormData>
name={['spec', 'volumeMount']}
rules={[
{
required: true,
message: getRuleMessage('input', 'gpuservice.template.mountPath')
}
]}
>
<CInput.Input
required
label={intl.formatMessage({
id: 'gpuservice.template.mountPath'
})}
placeholder={intl.formatMessage({
id: 'clusters.volume.mountPath.format'
})}
disabled={disabled}
/>
</Form.Item>
<StorageOverlay
open={overlayOpen}