fix: name validation
This commit is contained in:
+1
-1
@@ -84,4 +84,4 @@ export const modelNameReg =
|
||||
*/
|
||||
|
||||
export const validateLabelNameRegxFor63 =
|
||||
/^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$/;
|
||||
/^(?![0-9])(?!.*--)[a-z](?:[a-z0-9-]{0,61}[a-z0-9])?$/;
|
||||
|
||||
@@ -76,7 +76,9 @@ export default {
|
||||
'gpuservice.storage.persistentVolume': 'Persistent Volume',
|
||||
'gpuservice.storage.persistentVolume.required':
|
||||
'Please select a persistent volume',
|
||||
'gpuservice.storage.tempCapacity': 'Storage Capacity (GB)',
|
||||
'gpuservice.storage.tempCapacity': 'Capacity (GB)',
|
||||
'gpuservice.storage.tempCapacity.required':
|
||||
'Please enter the local temporary storage capacity'
|
||||
'Please enter the temporary storage capacity',
|
||||
'gpuservice.form.rule.name':
|
||||
"Lowercase letters, numbers, and '-'. Start and end with a letter or number, no consecutive '-', max 63 characters."
|
||||
};
|
||||
|
||||
@@ -74,7 +74,9 @@ export default {
|
||||
'gpuservice.storage.persistentVolume': '永続ボリューム',
|
||||
'gpuservice.storage.persistentVolume.required':
|
||||
'永続ボリュームを選択してください',
|
||||
'gpuservice.storage.tempCapacity': 'ストレージ容量 (GB)',
|
||||
'gpuservice.storage.tempCapacity': '容量 (GB)',
|
||||
'gpuservice.storage.tempCapacity.required':
|
||||
'ローカルの一時ストレージ容量を入力してください'
|
||||
'一時ストレージ容量を入力してください',
|
||||
'gpuservice.form.rule.name':
|
||||
"小文字、数字、'-' のみ使用可能。文字または数字で始まり、文字または数字で終わる必要があり、連続する '-' は不可、最大 63 文字。"
|
||||
};
|
||||
|
||||
@@ -75,7 +75,9 @@ export default {
|
||||
'gpuservice.storage.temporary': 'Временное',
|
||||
'gpuservice.storage.persistentVolume': 'Постоянный том',
|
||||
'gpuservice.storage.persistentVolume.required': 'Выберите постоянный том',
|
||||
'gpuservice.storage.tempCapacity': 'Объём хранилища (ГБ)',
|
||||
'gpuservice.storage.tempCapacity': 'Объём (ГБ)',
|
||||
'gpuservice.storage.tempCapacity.required':
|
||||
'Введите объём локального временного хранилища'
|
||||
'Введите объём временного хранилища',
|
||||
'gpuservice.form.rule.name':
|
||||
"Строчные буквы, цифры и '-'. Должно начинаться и заканчиваться буквой или цифрой, без подряд идущих '-', максимум 63 символа."
|
||||
};
|
||||
|
||||
@@ -75,7 +75,9 @@ export default {
|
||||
'gpuservice.storage.persistentVolume': 'Kalıcı Hacim',
|
||||
'gpuservice.storage.persistentVolume.required':
|
||||
'Lütfen bir kalıcı hacim seçin',
|
||||
'gpuservice.storage.tempCapacity': 'Depolama Kapasitesi (GB)',
|
||||
'gpuservice.storage.tempCapacity': 'Kapasite (GB)',
|
||||
'gpuservice.storage.tempCapacity.required':
|
||||
'Lütfen yerel geçici depolama kapasitesini girin'
|
||||
'Lütfen geçici depolama kapasitesini girin',
|
||||
'gpuservice.form.rule.name':
|
||||
"Küçük harfler, rakamlar ve '-'. Harf veya rakamla başlamalı ve bitmeli, ardışık '-' içermemeli, en fazla 63 karakter."
|
||||
};
|
||||
|
||||
@@ -71,6 +71,8 @@ export default {
|
||||
'gpuservice.storage.temporary': '临时',
|
||||
'gpuservice.storage.persistentVolume': '持久卷',
|
||||
'gpuservice.storage.persistentVolume.required': '请选择持久卷',
|
||||
'gpuservice.storage.tempCapacity': '存储容量 (GB)',
|
||||
'gpuservice.storage.tempCapacity.required': '请输入本地临时存储容量'
|
||||
'gpuservice.storage.tempCapacity': '容量(GB)',
|
||||
'gpuservice.storage.tempCapacity.required': '请输入临时存储容量',
|
||||
'gpuservice.form.rule.name':
|
||||
'由小写字母、数字和 "-" 组成,以字母或数字开头和结尾,不能包含连续的 "-",最多 63 个字符。'
|
||||
};
|
||||
|
||||
@@ -6,43 +6,15 @@ import { ColumnWrapper, GSDrawer, ModalFooter } from '@gpustack/core-ui';
|
||||
import { useIntl } from '@umijs/max';
|
||||
import { Empty, Input, Typography } from 'antd';
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
import styled from 'styled-components';
|
||||
import { ListItem as TemplateItem } from '../../templates/config/types';
|
||||
import useQueryTemplates from '../../templates/services/use-query-templates';
|
||||
import { FormData, InstanceTypeItem, ListItem } from '../config/types';
|
||||
import GPUServiceInstanceForm from '../forms';
|
||||
import TemplateSelector from '../forms/template-selector';
|
||||
import useQueryInstanceTypes from '../services/use-query-instance-types';
|
||||
import styles from '../styles/instances.module.less';
|
||||
import InstanceTypeList from './instance-type-list';
|
||||
|
||||
const Container = styled.div`
|
||||
display: flex;
|
||||
height: 100%;
|
||||
min-height: 0;
|
||||
`;
|
||||
|
||||
const ColWrapper = styled.div`
|
||||
display: flex;
|
||||
flex: 1;
|
||||
max-width: 33%;
|
||||
min-height: 0;
|
||||
`;
|
||||
|
||||
const PanelBody = styled.div`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
height: 100%;
|
||||
min-height: 0;
|
||||
`;
|
||||
|
||||
const FormWrapper = styled.div`
|
||||
display: flex;
|
||||
flex: 1;
|
||||
max-width: 34%;
|
||||
min-height: 0;
|
||||
`;
|
||||
|
||||
type AddModalProps = {
|
||||
title: string;
|
||||
action: PageActionType;
|
||||
@@ -280,10 +252,10 @@ const AddModal: React.FC<AddModalProps> = ({
|
||||
}}
|
||||
footer={false}
|
||||
>
|
||||
<Container>
|
||||
<ColWrapper>
|
||||
<div className={styles.container}>
|
||||
<div className={styles.colWrapper}>
|
||||
<ColumnWrapper styles={{ container: { paddingBlock: 0 } }}>
|
||||
<PanelBody>
|
||||
<div className={styles.panelBody}>
|
||||
<ColTitle style={{ paddingBottom: 0 }}>
|
||||
{intl.formatMessage({ id: 'gpuservice.instance.types' })}
|
||||
</ColTitle>
|
||||
@@ -311,13 +283,13 @@ const AddModal: React.FC<AddModalProps> = ({
|
||||
loading={instanceTypesLoading}
|
||||
onChange={handleInstanceTypeChange}
|
||||
/>
|
||||
</PanelBody>
|
||||
</div>
|
||||
</ColumnWrapper>
|
||||
<Separator></Separator>
|
||||
</ColWrapper>
|
||||
<ColWrapper>
|
||||
</div>
|
||||
<div className={styles.colWrapper}>
|
||||
<ColumnWrapper styles={{ container: { paddingBlock: 0 } }}>
|
||||
<PanelBody>
|
||||
<div className={styles.panelBody}>
|
||||
<ColTitle style={{ paddingBottom: 0 }}>
|
||||
{intl.formatMessage({ id: 'gpuservice.instance.templates' })}
|
||||
</ColTitle>
|
||||
@@ -348,11 +320,11 @@ const AddModal: React.FC<AddModalProps> = ({
|
||||
) : (
|
||||
<Empty image={Empty.PRESENTED_IMAGE_SIMPLE} />
|
||||
)}
|
||||
</PanelBody>
|
||||
</div>
|
||||
</ColumnWrapper>
|
||||
<Separator></Separator>
|
||||
</ColWrapper>
|
||||
<FormWrapper>
|
||||
</div>
|
||||
<div className={styles.formWrapper}>
|
||||
<ColumnWrapper
|
||||
styles={{ container: { paddingBlock: 0 } }}
|
||||
footer={
|
||||
@@ -381,8 +353,8 @@ const AddModal: React.FC<AddModalProps> = ({
|
||||
/>
|
||||
</>
|
||||
</ColumnWrapper>
|
||||
</FormWrapper>
|
||||
</Container>
|
||||
</div>
|
||||
</div>
|
||||
</GSDrawer>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -72,7 +72,7 @@ const InstanceTypeItem: React.FC<InstanceTypeItemProps> = ({
|
||||
<Title>
|
||||
<Flex gap={8} align="center">
|
||||
<AutoTooltip ghost minWidth={20} maxWidth={180}>
|
||||
{displayName}
|
||||
{item.spec ? displayName : '-'}
|
||||
</AutoTooltip>
|
||||
{acceleratable && manufacturer && (
|
||||
<span
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { validateLabelNameRegxFor63 } from '@/config';
|
||||
import { Input as CInput } from '@gpustack/core-ui';
|
||||
import { useIntl } from '@umijs/max';
|
||||
import { Form } from 'antd';
|
||||
@@ -16,6 +17,10 @@ const Basic = () => {
|
||||
message: intl.formatMessage({
|
||||
id: 'gpuservice.instance.name.required'
|
||||
})
|
||||
},
|
||||
{
|
||||
pattern: validateLabelNameRegxFor63,
|
||||
message: intl.formatMessage({ id: 'gpuservice.form.rule.name' })
|
||||
}
|
||||
]}
|
||||
>
|
||||
|
||||
@@ -32,11 +32,12 @@ const InstanceTypePicker: React.FC<InstanceTypePickerProps> = ({
|
||||
dataList
|
||||
}) => {
|
||||
const selected = useMemo(() => {
|
||||
return dataList.find((item) => (item.metadata?.name || '') === value);
|
||||
return (
|
||||
dataList.find((item) => (item.metadata?.name || '') === value) ||
|
||||
({} as InstanceTypeItemModel)
|
||||
);
|
||||
}, [value, dataList]);
|
||||
|
||||
if (!selected) return null;
|
||||
|
||||
return (
|
||||
<SelectedCard>
|
||||
<InstanceTypeItem item={selected} showStatus={false} />
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
import { currentClusterAtom } from '@/atoms/gpuservice';
|
||||
import { getCurrentOrganizationId } from '@/atoms/user';
|
||||
import { getCurrentOrgNamespace } from '@/atoms/user';
|
||||
import { useAtomValue } from 'jotai';
|
||||
import { useState } from 'react';
|
||||
import { GPU_SERVICE_INSTANCES_API } from '../apis';
|
||||
import { ListItem } from '../config/types';
|
||||
|
||||
const useViewLogs = () => {
|
||||
const namespace = getCurrentOrganizationId();
|
||||
const currentCluster = useAtomValue(currentClusterAtom);
|
||||
const clusterID = currentCluster?.id;
|
||||
const namespace = getCurrentOrgNamespace(currentCluster?.owner_principal_id);
|
||||
|
||||
const [openModalStatus, setOpenModalStatus] = useState<{
|
||||
open: boolean;
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
.container {
|
||||
display: flex;
|
||||
height: 100%;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
.colWrapper {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
max-width: 33%;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
.panelBody {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
height: 100%;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
.formWrapper {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
max-width: 34%;
|
||||
min-height: 0;
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
import { validateLabelNameRegxFor63 } from '@/config';
|
||||
import {
|
||||
Input as CInput,
|
||||
InputNumber,
|
||||
@@ -29,6 +30,10 @@ const Basic = ({ open }: { open: boolean }) => {
|
||||
{
|
||||
required: true,
|
||||
message: getRuleMessage('input', 'common.table.name')
|
||||
},
|
||||
{
|
||||
pattern: validateLabelNameRegxFor63,
|
||||
message: intl.formatMessage({ id: 'gpuservice.form.rule.name' })
|
||||
}
|
||||
]}
|
||||
>
|
||||
|
||||
Reference in New Issue
Block a user