diff --git a/src/pages/gpu-service/instances/hooks/use-view-events.ts b/src/pages/gpu-service/instances/hooks/use-view-events.ts
index c7565c01..ecee914d 100644
--- a/src/pages/gpu-service/instances/hooks/use-view-events.ts
+++ b/src/pages/gpu-service/instances/hooks/use-view-events.ts
@@ -9,19 +9,23 @@ const useViewEvents = () => {
name: string;
namespace: string;
clusterID?: number;
+ hasPersistentVolume: boolean;
}>({
open: false,
name: '',
namespace: '',
- clusterID: undefined
+ clusterID: undefined,
+ hasPersistentVolume: false
});
const openModal = (row?: ListItem) => {
+ const volume = row?.spec?.volume;
setOpenModalStatus({
open: true,
name: row?.name || '',
namespace: row?.status?.namespace || '',
- clusterID: row?.clusterId ?? undefined
+ clusterID: row?.clusterId ?? undefined,
+ hasPersistentVolume: !!volume?.persistent?.name
});
};
@@ -30,7 +34,8 @@ const useViewEvents = () => {
open: false,
name: '',
namespace: '',
- clusterID: undefined
+ clusterID: undefined,
+ hasPersistentVolume: false
});
};
diff --git a/src/pages/gpu-service/instances/index.tsx b/src/pages/gpu-service/instances/index.tsx
index e443d8cc..79a0dd6e 100644
--- a/src/pages/gpu-service/instances/index.tsx
+++ b/src/pages/gpu-service/instances/index.tsx
@@ -80,7 +80,7 @@ const GPUService: React.FC = () => {
if (openInstanceModalStatus.realAction === PageAction.CREATE) {
await deleteGPUServiceInstance(openInstanceModalStatus.currentData!.id);
await new Promise((resolve) => {
- setTimeout(resolve, 500);
+ setTimeout(resolve, 300);
});
await createInstance({ data });
} else if (openInstanceModalStatus.action === PageAction.EDIT) {
@@ -233,6 +233,7 @@ const GPUService: React.FC = () => {
name={openViewEventsModalStatus.name}
namespace={openViewEventsModalStatus.namespace}
clusterID={openViewEventsModalStatus.clusterID}
+ hasPersistentVolume={openViewEventsModalStatus.hasPersistentVolume}
onCancel={closeViewEventsModal}
/>
diff --git a/src/pages/gpu-service/storage-types/forms/basic.tsx b/src/pages/gpu-service/storage-types/forms/basic.tsx
index 2d7e4562..d07ba052 100644
--- a/src/pages/gpu-service/storage-types/forms/basic.tsx
+++ b/src/pages/gpu-service/storage-types/forms/basic.tsx
@@ -2,7 +2,6 @@ import { PageAction, validateLabelNameRegxFor63 } from '@/config';
import {
Input as CInput,
Select as SealSelect,
- Textarea,
useAppUtils
} from '@gpustack/core-ui';
import { useIntl } from '@umijs/max';
@@ -43,13 +42,6 @@ const Basic = ({ action }: { action: string }) => {
label={intl.formatMessage({ id: 'common.table.displayName' })}
/>
-
name="description">
-
-
name="type"
rules={[
diff --git a/src/pages/gpu-service/storage-types/forms/nfs.tsx b/src/pages/gpu-service/storage-types/forms/nfs.tsx
index 9371a6b3..04d80e5f 100644
--- a/src/pages/gpu-service/storage-types/forms/nfs.tsx
+++ b/src/pages/gpu-service/storage-types/forms/nfs.tsx
@@ -24,6 +24,9 @@ const NFSForm = ({ action }: { action: string }) => {
>
{
>
name={['spec', 'nfs', 'subDirectory']}>
{
console.log('action', action);
const intl = useIntl();
+ const form = Form.useFormInstance();
const { getRuleMessage } = useAppUtils();
+ const handleEndpointBlur = (e: any) => {
+ const value: string = e.target.value;
+ if (!value) return;
+
+ // Auto-fill region based on endpoint if it's an AWS S3 endpoint
+ const awsMatch = value.match(
+ /^https?:\/\/s3[.-]([a-z0-9-]+)\.amazonaws\.com/
+ );
+ if (awsMatch) {
+ const region = awsMatch[1];
+ form.setFieldValue(['spec', 's3', 'region'], region);
+ }
+ };
+
return (
<>
@@ -39,7 +54,11 @@ const S3Form = ({ action }: { action: string }) => {
label={intl.formatMessage({
id: 'gpuservice.storageType.s3.endpoint'
})}
- placeholder="http | https://..."
+ description={intl.formatMessage({
+ id: 'gpuservice.storageType.s3.endpoint.tips'
+ })}
+ onBlur={handleEndpointBlur}
+ placeholder="https://s3..amazonaws.com"
/>
@@ -53,11 +72,36 @@ const S3Form = ({ action }: { action: string }) => {
-
name={['spec', 's3', 'bucket']}>
+
+ name={['spec', 's3', 'bucket']}
+ rules={[
+ {
+ required: true,
+ message: getRuleMessage(
+ 'input',
+ 'gpuservice.storageType.s3.bucket'
+ )
+ }
+ ]}
+ >
+
+ {intl.formatMessage({
+ id: 'gpuservice.storageType.s3.bucket.tips1'
+ })}
+
+
+
+ }
label={intl.formatMessage({
id: 'gpuservice.storageType.s3.bucket'
})}
diff --git a/src/pages/gpu-service/storage-types/hooks/use-storage-type-columns.tsx b/src/pages/gpu-service/storage-types/hooks/use-storage-type-columns.tsx
index db2faad6..cdb0e207 100644
--- a/src/pages/gpu-service/storage-types/hooks/use-storage-type-columns.tsx
+++ b/src/pages/gpu-service/storage-types/hooks/use-storage-type-columns.tsx
@@ -66,18 +66,18 @@ const useStorageTypeColumns = ({
sorter: false,
render: (_text, record) => getKindLabel(record)
},
- {
- title: intl.formatMessage({ id: 'common.table.description' }),
- dataIndex: 'description',
- key: 'description',
- sorter: false,
- ellipsis: { showTitle: false },
- render: (text: string) => (
-
- {text || '-'}
-
- )
- },
+ // {
+ // title: intl.formatMessage({ id: 'common.table.description' }),
+ // dataIndex: 'description',
+ // key: 'description',
+ // sorter: false,
+ // ellipsis: { showTitle: false },
+ // render: (text: string) => (
+ //
+ // {text || '-'}
+ //
+ // )
+ // },
{
title: intl.formatMessage({ id: 'common.table.createTime' }),
dataIndex: 'created_at',
diff --git a/src/pages/gpu-service/storage/components/add-modal.tsx b/src/pages/gpu-service/storage/components/add-modal.tsx
index 91158ce6..970244b8 100644
--- a/src/pages/gpu-service/storage/components/add-modal.tsx
+++ b/src/pages/gpu-service/storage/components/add-modal.tsx
@@ -2,6 +2,7 @@ import { PageActionType } from '@/config/types';
import { ModalFooter } from '@gpustack/core-ui';
import { useRef } from 'react';
import FormDrawer from '../../../_components/form-drawer';
+import { FormContext } from '../config/form-context';
import { FormData, ListItem } from '../config/types';
import GPUServiceStorageForm from '../forms';
@@ -12,6 +13,7 @@ type AddModalProps = {
onOk: (values: FormData) => void;
data?: ListItem | null;
onCancel: () => void;
+ storageClassList: Global.BaseOption[];
};
const AddModal: React.FC = ({
@@ -20,7 +22,8 @@ const AddModal: React.FC = ({
open,
onOk,
data,
- onCancel
+ onCancel,
+ storageClassList
}) => {
const form = useRef(null);
@@ -58,13 +61,15 @@ const AddModal: React.FC = ({
/>
}
>
-
+
+
+
);
};
diff --git a/src/pages/gpu-service/storage/config/form-context.ts b/src/pages/gpu-service/storage/config/form-context.ts
new file mode 100644
index 00000000..345b667d
--- /dev/null
+++ b/src/pages/gpu-service/storage/config/form-context.ts
@@ -0,0 +1,11 @@
+import { createContext } from 'react';
+
+export interface FormContextValue {
+ storageClassList: Global.BaseOption[];
+}
+
+export const FormContext = createContext({
+ storageClassList: []
+});
+
+export default FormContext;
diff --git a/src/pages/gpu-service/storage/forms/basic.tsx b/src/pages/gpu-service/storage/forms/basic.tsx
index 786a4ac4..fcf0ab2e 100644
--- a/src/pages/gpu-service/storage/forms/basic.tsx
+++ b/src/pages/gpu-service/storage/forms/basic.tsx
@@ -3,26 +3,19 @@ import {
Input as CInput,
InputNumber,
Select as SealSelect,
- Textarea,
useAppUtils
} from '@gpustack/core-ui';
import { useIntl } from '@umijs/max';
import { Flex, Form } from 'antd';
-import { useEffect } from 'react';
+import { useContext } from 'react';
import OwnerPrincipalIdField from '../../../_components/owner-principal-id-field';
+import { FormContext } from '../config/form-context';
import { FormData } from '../config/types';
-import useQueryStorageClass from '../services/use-query-storage-class';
-const Basic = ({ open, action }: { open: boolean; action: string }) => {
+const Basic = ({ action, open }: { action: string; open: boolean }) => {
const intl = useIntl();
const { getRuleMessage } = useAppUtils();
- const { storageClassList, fetchData, loading } = useQueryStorageClass();
-
- useEffect(() => {
- if (open) {
- fetchData({ page: 1, perPage: 100 });
- }
- }, [open]);
+ const { storageClassList } = useContext(FormContext);
return (
<>
@@ -52,13 +45,6 @@ const Basic = ({ open, action }: { open: boolean; action: string }) => {
label={intl.formatMessage({ id: 'common.table.displayName' })}
/>
- name="description">
-
-
@@ -74,7 +60,6 @@ const Basic = ({ open, action }: { open: boolean; action: string }) => {
disabled={action === PageAction.EDIT}
label={intl.formatMessage({ id: 'gpuservice.storage.type' })}
required
- loading={loading}
options={storageClassList}
/>
diff --git a/src/pages/gpu-service/storage/forms/index.tsx b/src/pages/gpu-service/storage/forms/index.tsx
index d07dd22c..7fff3c8c 100644
--- a/src/pages/gpu-service/storage/forms/index.tsx
+++ b/src/pages/gpu-service/storage/forms/index.tsx
@@ -54,7 +54,7 @@ const GPUServiceStorageForm: React.FC
= forwardRef(
preserve={false}
initialValues={{}}
>
-
+
);
}
diff --git a/src/pages/gpu-service/storage/hooks/use-storage-columns.tsx b/src/pages/gpu-service/storage/hooks/use-storage-columns.tsx
index 1bab1d15..54e3190c 100644
--- a/src/pages/gpu-service/storage/hooks/use-storage-columns.tsx
+++ b/src/pages/gpu-service/storage/hooks/use-storage-columns.tsx
@@ -1,18 +1,20 @@
-import { AutoTooltip, DropdownButtons, StatusTag } from '@gpustack/core-ui';
+import { AutoTooltip, DropdownButtons } from '@gpustack/core-ui';
import { useIntl } from '@umijs/max';
import type { ColumnsType } from 'antd/lib/table';
import dayjs from 'dayjs';
import { useMemo } from 'react';
-import { rowActionList, status, StoragePhaseLabelMap } from '../config';
+import { rowActionList } from '../config';
import { ListItem } from '../config/types';
interface ColumnsHookProps {
handleSelect: (val: string, record: ListItem) => void;
+ storageClassList: Global.BaseOption[];
sortOrder: string[];
}
const useStorageColumns = ({
handleSelect,
+ storageClassList,
sortOrder
}: ColumnsHookProps): ColumnsType => {
const intl = useIntl();
@@ -37,7 +39,14 @@ const useStorageColumns = ({
dataIndex: ['spec', 'type'],
key: 'type',
sorter: false,
- render: (value: string) => value || '-'
+ render: (value: string) => {
+ return (
+
+ {storageClassList.find((item) => item.value === value)?.label ||
+ '-'}
+
+ );
+ }
},
{
title: intl.formatMessage({ id: 'gpuservice.storage.capacity' }),
@@ -46,23 +55,23 @@ const useStorageColumns = ({
sorter: false,
render: (value: string) => (value ? value.replace(/Gi$/, 'GB') : '-')
},
- {
- title: intl.formatMessage({ id: 'common.table.status' }),
- dataIndex: ['status', 'phase'],
- key: 'status',
- sorter: false,
- render: (value: string) =>
- value ? (
-
- ) : (
- '-'
- )
- },
+ // {
+ // title: intl.formatMessage({ id: 'common.table.status' }),
+ // dataIndex: ['status', 'phase'],
+ // key: 'status',
+ // sorter: false,
+ // render: (value: string) =>
+ // value ? (
+ //
+ // ) : (
+ // '-'
+ // )
+ // },
{
title: intl.formatMessage({ id: 'common.table.createTime' }),
dataIndex: 'created_at',
@@ -89,7 +98,7 @@ const useStorageColumns = ({
)
}
];
- }, [handleSelect, sortOrder, intl]);
+ }, [handleSelect, sortOrder, storageClassList, intl]);
};
export default useStorageColumns;
diff --git a/src/pages/gpu-service/storage/index.tsx b/src/pages/gpu-service/storage/index.tsx
index 1dce2ac1..c3c3f429 100644
--- a/src/pages/gpu-service/storage/index.tsx
+++ b/src/pages/gpu-service/storage/index.tsx
@@ -6,6 +6,7 @@ import { useIntl } from '@umijs/max';
import { useMemoizedFn } from 'ahooks';
import { ConfigProvider, message, Table } from 'antd';
import _ from 'lodash';
+import { useEffect } from 'react';
import PageBox from '../../_components/page-box';
import {
deleteGPUServiceStorage,
@@ -17,6 +18,7 @@ import { FormData, ListItem } from './config/types';
import useCreateStorageModal from './hooks/use-create-storage-modal';
import useStorageColumns from './hooks/use-storage-columns';
import useCreateStorage from './services/use-create-storage';
+import useQueryStorageClass from './services/use-query-storage-class';
import useUpdateStorage from './services/use-update-storage';
const GPUServiceStorage: React.FC = () => {
@@ -40,16 +42,20 @@ const GPUServiceStorage: React.FC = () => {
fetchAPI: queryGPUServiceStorage,
deleteAPI: deleteGPUServiceStorage,
watch: false,
- polling: true,
API: GPU_SERVICE_STORAGE_API,
contentForDelete: intl.formatMessage({ id: 'gpuservice.storage' })
});
-
+ const { storageClassList, fetchData: fetchStorageClass } =
+ useQueryStorageClass();
const { fetchData: createStorage } = useCreateStorage();
const { fetchData: updateStorage } = useUpdateStorage();
const { openStorageModalStatus, openStorageModal, closeStorageModal } =
useCreateStorageModal();
+ useEffect(() => {
+ fetchStorageClass({ page: -1 });
+ }, []);
+
const handleAddStorage = () => {
openStorageModal(
PageAction.CREATE,
@@ -123,6 +129,7 @@ const GPUServiceStorage: React.FC = () => {
const columns = useStorageColumns({
handleSelect,
+ storageClassList,
sortOrder
});
@@ -170,6 +177,7 @@ const GPUServiceStorage: React.FC = () => {
action={openStorageModalStatus.action}
title={openStorageModalStatus.title}
data={openStorageModalStatus.currentData}
+ storageClassList={storageClassList}
onCancel={closeStorageModal}
onOk={handleModalOk}
/>
diff --git a/src/pages/gpu-service/templates/forms/ports.tsx b/src/pages/gpu-service/templates/forms/ports.tsx
index a04a9ca2..66a7cc83 100644
--- a/src/pages/gpu-service/templates/forms/ports.tsx
+++ b/src/pages/gpu-service/templates/forms/ports.tsx
@@ -29,9 +29,9 @@ const protocolOptions = [
];
const wellKnownTcpPortNames: Record = {
- 22: 'ssh',
- 80: 'http',
- 443: 'https'
+ 22: 'SSH',
+ 80: 'WEB',
+ 443: 'HTTPS'
};
const getAutoFilledName = (