style: cluster selector
This commit is contained in:
@@ -12,6 +12,15 @@ const Wrapper = styled.div<{ $maxHeight?: number | string }>`
|
||||
width: 100%;
|
||||
`;
|
||||
|
||||
const Title = styled.div`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
max-width: 360px;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
`;
|
||||
|
||||
const ScrollerModal = (
|
||||
props: ModalProps & { maxContentHeight?: number | string }
|
||||
) => {
|
||||
@@ -48,6 +57,7 @@ const ScrollerModal = (
|
||||
return (
|
||||
<Modal
|
||||
{...props}
|
||||
title={<Title>{props.title}</Title>}
|
||||
destroyOnHidden={true}
|
||||
styles={{
|
||||
content: {
|
||||
|
||||
@@ -68,15 +68,19 @@ Same applies to the <span class="bold-text">/opt/dtk</span> directory.`,
|
||||
'clusters.addworker.checkEnv': 'Check Environment',
|
||||
'clusters.addworker.specifyArgs': 'Specify Arguments',
|
||||
'clusters.addworker.runCommand': 'Run Command',
|
||||
'clusters.addworker.specifyWorkerIP': 'Specify Worker IP',
|
||||
'clusters.addworker.specifyWorkerIP': 'Worker IP',
|
||||
'clusters.addworker.detectWorkerIP': 'Auto-detect Worker IP',
|
||||
'clusters.addworker.specifyWorkerAddress': 'Specify Worker External Address',
|
||||
'clusters.addworker.detectWorkerAddress':
|
||||
'Specify Worker External Address (default to Worker IP)',
|
||||
'clusters.addworker.specifyWorkerAddress': 'Worker External Address',
|
||||
'clusters.addworker.detectWorkerAddress': 'Worker External Address',
|
||||
'clusters.addworker.detectWorkerAddress.tips':
|
||||
'Defaults to Worker IP if not specified.',
|
||||
'clusters.addworker.externalIP.tips':
|
||||
'If running in a VPC or private network, please specify the Worker external address reachable by the GPUStack Server.',
|
||||
'clusters.addworker.enterWorkerIP': 'Enter worker IP',
|
||||
'clusters.addworker.enterWorkerIP.error': 'Please enter the worker IP.',
|
||||
'clusters.addworker.enterWorkerAddress': 'Enter worker external address',
|
||||
'clusters.addworker.enterWorkerAddress.error':
|
||||
'Please enter the worker external address.',
|
||||
'clusters.addworker.extraVolume': 'Additional Volume Mount',
|
||||
'clusters.addworker.cacheVolume': 'Model Cache Volume Mount',
|
||||
'clusters.addworker.cacheVolume.tips':
|
||||
|
||||
@@ -68,15 +68,19 @@ Same applies to the <span class="bold-text">/opt/dtk</span> directory.`,
|
||||
'clusters.addworker.checkEnv': 'Check Environment',
|
||||
'clusters.addworker.specifyArgs': 'Specify Arguments',
|
||||
'clusters.addworker.runCommand': 'Run Command',
|
||||
'clusters.addworker.specifyWorkerIP': 'Worker IP を指定',
|
||||
'clusters.addworker.specifyWorkerIP': 'Worker IP',
|
||||
'clusters.addworker.detectWorkerIP': 'Worker IP を自動検出',
|
||||
'clusters.addworker.specifyWorkerAddress': 'Worker 外部アドレスを指定',
|
||||
'clusters.addworker.detectWorkerAddress':
|
||||
'Worker 外部アドレスを指定(デフォルトはWorker IP)',
|
||||
'clusters.addworker.specifyWorkerAddress': 'Worker 外部アドレス',
|
||||
'clusters.addworker.detectWorkerAddress': 'Worker 外部アドレス',
|
||||
'clusters.addworker.detectWorkerAddress.tips':
|
||||
'指定がない場合、デフォルトで Worker IP が使用されます。',
|
||||
'clusters.addworker.externalIP.tips':
|
||||
'VPCやプライベートネットワークで動作している場合は、サーバーから到達可能なWorkerの外部アドレスを指定してください。',
|
||||
'clusters.addworker.enterWorkerIP': 'Enter worker IP',
|
||||
'clusters.addworker.enterWorkerIP.error': 'Please enter the worker IP.',
|
||||
'clusters.addworker.enterWorkerAddress': 'Enter worker external address',
|
||||
'clusters.addworker.enterWorkerAddress.error':
|
||||
'Please enter the worker external address.',
|
||||
'clusters.addworker.extraVolume': 'Additional Volume Mount',
|
||||
'clusters.addworker.cacheVolume': 'Model Cache Volume Mount',
|
||||
'clusters.addworker.cacheVolume.tips':
|
||||
@@ -172,7 +176,7 @@ Same applies to the <span class="bold-text">/opt/dtk</span> directory.`,
|
||||
// 54. 'clusters.addworker.checkEnv': 'Check Environment',
|
||||
// 55. 'clusters.addworker.specifyArgs': 'Specify Arguments',
|
||||
// 56. 'clusters.addworker.runCommand': 'Run Command',
|
||||
// 57. 'clusters.addworker.specifyWorkerIP': 'Specify Worker IP',
|
||||
// 57. 'clusters.addworker.specifyWorkerIP': 'Worker IP',
|
||||
// 58. 'clusters.addworker.detectWorkerIP': 'Auto-detect Worker IP',
|
||||
// 59. 'clusters.addworker.enterWorkerIP': 'Enter worker IP',
|
||||
// 60. 'clusters.addworker.enterWorkerIP.error': 'Please enter the worker IP.',
|
||||
@@ -203,5 +207,7 @@ Same applies to the <span class="bold-text">/opt/dtk</span> directory.`,
|
||||
// 81. 'clusters.form.serverUrl.tips': 'Specify the server URL accessible from your cloud provider.',
|
||||
// 82. 'clusters.addworker.externalIP.tips': 'Specify an external IP if the worker is in a VPC or private network.',
|
||||
// 83. 'clusters.form.setDefault': 'Set as Default',
|
||||
// 84. 'clusters.form.setDefault.tips': 'Default for deployment'
|
||||
// 84. 'clusters.form.setDefault.tips': 'Default for deployment',
|
||||
// 85. 'clusters.addworker.enterWorkerAddress': 'Enter worker external address',
|
||||
// 86. 'clusters.addworker.enterWorkerAddress.error': 'Please enter the worker external address.',
|
||||
// ========== End of To-Do List ==========
|
||||
|
||||
@@ -71,12 +71,16 @@ export default {
|
||||
'clusters.addworker.specifyWorkerIP': 'Указать IP воркера',
|
||||
'clusters.addworker.detectWorkerIP': 'Автоматически определить IP воркера',
|
||||
'clusters.addworker.specifyWorkerAddress': 'Указать внешний адрес воркера',
|
||||
'clusters.addworker.detectWorkerAddress':
|
||||
'Указать внешний адрес воркера (по умолчанию используется IP воркера)',
|
||||
'clusters.addworker.detectWorkerAddress': 'Указать внешний адрес воркера',
|
||||
'clusters.addworker.detectWorkerAddress.tips':
|
||||
'По умолчанию используется IP воркера, если не указано иное.',
|
||||
'clusters.addworker.externalIP.tips':
|
||||
'Если работаете в VPC или частной сети, укажите внешний адрес воркера, доступный для сервера.',
|
||||
'clusters.addworker.enterWorkerIP': 'Введите IP воркера',
|
||||
'clusters.addworker.enterWorkerIP.error': 'Пожалуйста, введите IP воркера.',
|
||||
'clusters.addworker.enterWorkerAddress': 'Enter worker external address',
|
||||
'clusters.addworker.enterWorkerAddress.error':
|
||||
'Please enter the worker external address.',
|
||||
'clusters.addworker.extraVolume': 'Дополнительное монтирование тома',
|
||||
'clusters.addworker.cacheVolume': 'Model Cache Volume Mount',
|
||||
'clusters.addworker.cacheVolume.tips':
|
||||
@@ -134,4 +138,6 @@ export default {
|
||||
// 13. 'clusters.addworker.specifyWorkerIP': 'Specify Worker IP <span class="text-tertiary">{type}</span>',
|
||||
// 14. 'clusters.form.setDefault': 'Set as Default',
|
||||
// 15. 'clusters.form.setDefault.tips': 'Default for deployment',
|
||||
// 16. 'clusters.addworker.enterWorkerAddress': 'Enter worker external address',
|
||||
// 17. 'clusters.addworker.enterWorkerAddress.error': 'Please enter the worker external address.',
|
||||
// ================================================================
|
||||
|
||||
@@ -66,19 +66,22 @@ export default {
|
||||
'clusters.addworker.checkEnv': '检查环境',
|
||||
'clusters.addworker.specifyArgs': '指定参数',
|
||||
'clusters.addworker.runCommand': '运行指令',
|
||||
'clusters.addworker.specifyWorkerIP': '指定节点 IP',
|
||||
'clusters.addworker.specifyWorkerIP': '节点 IP',
|
||||
'clusters.addworker.detectWorkerIP': '自动检测节点 IP',
|
||||
'clusters.addworker.specifyWorkerAddress': '指定节点外部地址',
|
||||
'clusters.addworker.detectWorkerAddress':
|
||||
'指定节点外部地址(默认使用节点 IP)',
|
||||
'clusters.addworker.specifyWorkerAddress': '节点外部地址',
|
||||
'clusters.addworker.detectWorkerAddress': '节点外部地址',
|
||||
'clusters.addworker.detectWorkerAddress.tips':
|
||||
'如果未指定,则默认为节点 IP。',
|
||||
'clusters.addworker.externalIP.tips':
|
||||
'如运行在 VPC 或私有网络时,请指定 GPUStack Server 可达的节点外部地址。',
|
||||
'clusters.addworker.enterWorkerIP': '输入节点 IP',
|
||||
'clusters.addworker.enterWorkerIP.error': '请输入节点 IP',
|
||||
'clusters.addworker.enterWorkerAddress': '输入节点外部地址',
|
||||
'clusters.addworker.enterWorkerAddress.error': '请输入节点外部地址',
|
||||
'clusters.addworker.extraVolume': '额外卷挂载',
|
||||
'clusters.addworker.cacheVolume': '缓存卷挂载',
|
||||
'clusters.addworker.cacheVolume.tips':
|
||||
'如果你想自定义模型缓存目录,可以指定路径进行挂载。',
|
||||
'如果要自定义模型缓存目录,可以指定路径进行挂载。',
|
||||
'clusters.addworker.configSummary': '配置摘要',
|
||||
'clusters.addworker.gpuVendor': 'GPU 厂商',
|
||||
'clusters.addworker.workerIP': '节点 IP',
|
||||
|
||||
@@ -5,7 +5,7 @@ export const Title = styled.div`
|
||||
`;
|
||||
|
||||
export const ConfigWrapper = styled.div`
|
||||
padding: 16px;
|
||||
padding: 12px 16px;
|
||||
margin-bottom: 16px;
|
||||
border: 1px solid var(--ant-color-split);
|
||||
border-radius: var(--ant-border-radius);
|
||||
|
||||
@@ -238,22 +238,12 @@ const SpecifyArguments = () => {
|
||||
<span
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: workerIPConfig.enable
|
||||
? intl.formatMessage(
|
||||
{
|
||||
id: 'clusters.addworker.specifyWorkerIP'
|
||||
},
|
||||
{
|
||||
type: ` (${intl.formatMessage({ id: 'clusters.table.ip.internal' })})`
|
||||
}
|
||||
)
|
||||
: intl.formatMessage(
|
||||
{
|
||||
id: 'clusters.addworker.detectWorkerIP'
|
||||
},
|
||||
{
|
||||
type: ` (${intl.formatMessage({ id: 'clusters.table.ip.internal' })})`
|
||||
}
|
||||
)
|
||||
? intl.formatMessage({
|
||||
id: 'clusters.addworker.specifyWorkerIP'
|
||||
})
|
||||
: intl.formatMessage({
|
||||
id: 'clusters.addworker.detectWorkerIP'
|
||||
})
|
||||
}}
|
||||
></span>
|
||||
}
|
||||
@@ -325,8 +315,11 @@ const SpecifyArguments = () => {
|
||||
}}
|
||||
></span>
|
||||
}
|
||||
tips={intl.formatMessage({
|
||||
id: 'clusters.addworker.detectWorkerAddress.tips'
|
||||
})}
|
||||
placeholder={intl.formatMessage({
|
||||
id: 'clusters.addworker.enterWorkerIP'
|
||||
id: 'clusters.addworker.enterWorkerAddress'
|
||||
})}
|
||||
value={externalWorkerIPConfig.ip}
|
||||
checked={externalWorkerIPConfig.enable}
|
||||
@@ -334,7 +327,7 @@ const SpecifyArguments = () => {
|
||||
externalWorkerIPConfig.required &&
|
||||
!externalWorkerIPConfig.ip &&
|
||||
intl.formatMessage({
|
||||
id: 'clusters.addworker.enterWorkerIP.error'
|
||||
id: 'clusters.addworker.enterWorkerAddress.error'
|
||||
})
|
||||
}
|
||||
onChange={(checked) =>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import AutoTooltip from '@/components/auto-tooltip';
|
||||
import SealInput from '@/components/seal-form/seal-input';
|
||||
import SealSelect from '@/components/seal-form/seal-select';
|
||||
import { modelNameReg } from '@/config';
|
||||
@@ -10,6 +11,7 @@ import {
|
||||
import { useIntl } from '@umijs/max';
|
||||
import { Form } from 'antd';
|
||||
import { useMemo } from 'react';
|
||||
import styled from 'styled-components';
|
||||
import { sourceOptions } from '../config';
|
||||
import { FormData } from '../config/types';
|
||||
import BackendForm from './backend';
|
||||
@@ -19,11 +21,59 @@ import LocalPathSource from './local-path-source';
|
||||
import ModeField from './mode-field';
|
||||
import OnlineSource from './online-source';
|
||||
|
||||
const ClusterOption = styled.span`
|
||||
display: flex;
|
||||
padding: 8px 0;
|
||||
width: 100%;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
border-bottom: 1px solid var(--ant-color-split);
|
||||
gap: 8px;
|
||||
.label {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
flex: 1;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.dot {
|
||||
display: flex;
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
background-color: var(--ant-color-warning);
|
||||
border-radius: 50%;
|
||||
&.ready {
|
||||
background-color: var(--ant-color-success);
|
||||
}
|
||||
}
|
||||
.item {
|
||||
width: max-content;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 2px 0px;
|
||||
border-radius: 4px;
|
||||
font-weight: 400;
|
||||
gap: 12px;
|
||||
}
|
||||
`;
|
||||
|
||||
interface BasicFormProps {
|
||||
fields?: string[];
|
||||
sourceDisable?: boolean;
|
||||
sourceList?: Global.BaseOption<string>[];
|
||||
clusterList: Global.BaseOption<number, { provider: string; state: string }>[];
|
||||
clusterList: Global.BaseOption<
|
||||
number,
|
||||
{
|
||||
provider: string;
|
||||
state: string;
|
||||
is_default: boolean;
|
||||
workers: number;
|
||||
ready_workers: number;
|
||||
gpus: number;
|
||||
}
|
||||
>[];
|
||||
handleClusterChange: (value: number) => void;
|
||||
onSourceChange?: (value: string) => void;
|
||||
}
|
||||
@@ -51,11 +101,43 @@ const BasicForm: React.FC<BasicFormProps> = (props) => {
|
||||
item.state === ClusterStatusValueMap.Ready
|
||||
? item.label
|
||||
: `${item.label} [${ClusterStatusLabelMap[item.state as string]}]`,
|
||||
value: item.value
|
||||
value: item.value,
|
||||
workers: item.workers,
|
||||
ready_workers: item.ready_workers,
|
||||
gpus: item.gpus
|
||||
};
|
||||
});
|
||||
}, [clusterList]);
|
||||
|
||||
const clusterOptionRender = (option: any) => {
|
||||
const { data } = option;
|
||||
|
||||
return (
|
||||
<ClusterOption>
|
||||
<span className="label">
|
||||
<AutoTooltip ghost maxWidth={'100%'}>
|
||||
{data.label}
|
||||
</AutoTooltip>
|
||||
</span>
|
||||
<span className={`item ${data.ready_workers > 0 ? 'ready' : ''}`}>
|
||||
<span
|
||||
className={`dot ${data.ready_workers > 0 ? 'ready' : ''}`}
|
||||
></span>
|
||||
<span className="flex-center gap-4 text-tertiary">
|
||||
<span>{intl.formatMessage({ id: 'resources.nodes' })}:</span>
|
||||
<span>
|
||||
{data.ready_workers} / {data.workers}
|
||||
</span>
|
||||
</span>
|
||||
<span className="flex-center gap-4 text-tertiary">
|
||||
<span>GPUs:</span>
|
||||
<span>{data.gpus}</span>
|
||||
</span>
|
||||
</span>
|
||||
</ClusterOption>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Form.Item<FormData>
|
||||
@@ -120,6 +202,7 @@ const BasicForm: React.FC<BasicFormProps> = (props) => {
|
||||
onChange={handleClusterChange}
|
||||
label={intl.formatMessage({ id: 'clusters.title' })}
|
||||
options={clusterOptions}
|
||||
optionRender={clusterOptionRender}
|
||||
required
|
||||
></SealSelect>
|
||||
}
|
||||
|
||||
@@ -218,7 +218,10 @@ export const useGenerateWorkerOptions = () => {
|
||||
value: item.id,
|
||||
provider: item.provider as string,
|
||||
state: item.state,
|
||||
is_default: item.is_default
|
||||
is_default: item.is_default,
|
||||
workers: item.workers,
|
||||
ready_workers: item.ready_workers,
|
||||
gpus: item.gpus
|
||||
}))
|
||||
);
|
||||
};
|
||||
@@ -254,7 +257,10 @@ export default function useFormInitialValues() {
|
||||
value: item.id,
|
||||
provider: item.provider as string,
|
||||
state: item.state,
|
||||
is_default: item.is_default
|
||||
is_default: item.is_default,
|
||||
workers: item.workers,
|
||||
ready_workers: item.ready_workers,
|
||||
gpus: item.gpus
|
||||
}));
|
||||
setClusterList(list);
|
||||
setClusterListAtom(list);
|
||||
|
||||
Reference in New Issue
Block a user