fix: storage api alignment
This commit is contained in:
@@ -1,64 +1,60 @@
|
||||
import { request } from '@umijs/max';
|
||||
import { mockStorageData } from '../config/mock-data';
|
||||
import { FormData, ListItem } from '../config/types';
|
||||
import { ListItem } from '../config/types';
|
||||
|
||||
export const GPU_SERVICE_STORAGE_API = '/gpu-service-storage';
|
||||
export const GPU_SERVICE_STORAGE_API = (namespace: string) =>
|
||||
`/proxy/apis/worker.gpustack.ai/v1/namespaces/${namespace}/instancepersistentvolumes`;
|
||||
|
||||
export async function queryGPUServiceStorage(
|
||||
params: Global.SearchParams,
|
||||
params: Global.K8sSearchParams,
|
||||
options?: any
|
||||
) {
|
||||
// return request<Global.PageResponse<ListItem>>(GPU_SERVICE_STORAGE_API, {
|
||||
// method: 'GET',
|
||||
// params,
|
||||
// cancelToken: options?.token
|
||||
// });
|
||||
const page = params.page || 1;
|
||||
const perPage = params.perPage || 10;
|
||||
const search = params.search?.toLowerCase();
|
||||
const clusterId = params.cluster_id;
|
||||
const filteredData = mockStorageData.filter((item) => {
|
||||
const matchSearch = search
|
||||
? item.name.toLowerCase().includes(search)
|
||||
: true;
|
||||
const matchCluster = clusterId ? item.cluster_id === clusterId : true;
|
||||
return matchSearch && matchCluster;
|
||||
});
|
||||
const start = (page - 1) * perPage;
|
||||
const items = filteredData.slice(start, start + perPage);
|
||||
|
||||
return {
|
||||
items,
|
||||
pagination: {
|
||||
total: filteredData.length,
|
||||
totalPage: Math.ceil(filteredData.length / perPage),
|
||||
page,
|
||||
perPage
|
||||
return request<Global.K8sPageResponse<ListItem>>(
|
||||
GPU_SERVICE_STORAGE_API(params.namespace || ''),
|
||||
{
|
||||
method: 'GET',
|
||||
params,
|
||||
cancelToken: options?.token
|
||||
}
|
||||
} as Global.PageResponse<ListItem>;
|
||||
);
|
||||
}
|
||||
|
||||
export async function createGPUServiceStorage(params: { data: FormData }) {
|
||||
// return request<ListItem>(GPU_SERVICE_STORAGE_API, {
|
||||
// method: 'POST',
|
||||
// data: params.data
|
||||
// });
|
||||
return true;
|
||||
export async function createGPUServiceStorage(
|
||||
params: {
|
||||
namespace: string;
|
||||
data: Global.K8sCommonData;
|
||||
},
|
||||
option?: any
|
||||
) {
|
||||
return request<ListItem>(GPU_SERVICE_STORAGE_API(params.namespace), {
|
||||
method: 'POST',
|
||||
data: params.data,
|
||||
cancelToken: option?.token
|
||||
});
|
||||
}
|
||||
|
||||
export async function updateGPUServiceStorage(params: {
|
||||
export async function updateGPUServiceStorage(
|
||||
params: {
|
||||
namespace: string;
|
||||
id: number;
|
||||
data: Global.K8sCommonData;
|
||||
},
|
||||
option?: any
|
||||
) {
|
||||
return request<ListItem>(
|
||||
`${GPU_SERVICE_STORAGE_API(params.namespace)}/${params.id}`,
|
||||
{
|
||||
method: 'PUT',
|
||||
data: params.data,
|
||||
cancelToken: option?.token
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
export async function deleteGPUServiceStorage(params: {
|
||||
namespace: string;
|
||||
id: number;
|
||||
data: FormData;
|
||||
}) {
|
||||
// return request<ListItem>(`${GPU_SERVICE_STORAGE_API}/${params.id}`, {
|
||||
// method: 'PUT',
|
||||
// data: params.data
|
||||
// });
|
||||
return true;
|
||||
}
|
||||
|
||||
export async function deleteGPUServiceStorage(id: number) {
|
||||
return request(`${GPU_SERVICE_STORAGE_API}/${id}`, {
|
||||
return request(`${GPU_SERVICE_STORAGE_API(params.namespace)}/${params.id}`, {
|
||||
method: 'DELETE'
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
import { StatusMaps } from '@/config';
|
||||
import { StatusType } from '@/config/types';
|
||||
import { icons } from '@gpustack/core-ui';
|
||||
|
||||
export const StorageTypeValueMap = {
|
||||
@@ -9,52 +7,72 @@ export const StorageTypeValueMap = {
|
||||
};
|
||||
|
||||
export const StorageTypeLabelMap: Record<string, string> = {
|
||||
[StorageTypeValueMap.Local]: '默认存储',
|
||||
[StorageTypeValueMap.Shared]: '默认存储',
|
||||
[StorageTypeValueMap.Local]: '本地存储',
|
||||
[StorageTypeValueMap.Shared]: '共享存储',
|
||||
[StorageTypeValueMap.Object]: '对象存储'
|
||||
};
|
||||
|
||||
export const StorageAccessModeValueMap = {
|
||||
ReadWriteOnce: 'ReadWriteOnce',
|
||||
ReadOnlyMany: 'ReadOnlyMany',
|
||||
ReadWriteMany: 'ReadWriteMany'
|
||||
};
|
||||
|
||||
export const StorageAccessModeOptions = [
|
||||
export const StorageTypeOptions = [
|
||||
{
|
||||
label: 'ReadWriteOnce',
|
||||
value: StorageAccessModeValueMap.ReadWriteOnce
|
||||
label: StorageTypeLabelMap[StorageTypeValueMap.Local],
|
||||
value: StorageTypeValueMap.Local
|
||||
},
|
||||
{
|
||||
label: 'ReadWriteMany',
|
||||
value: StorageAccessModeValueMap.ReadWriteMany
|
||||
label: StorageTypeLabelMap[StorageTypeValueMap.Shared],
|
||||
value: StorageTypeValueMap.Shared
|
||||
},
|
||||
{
|
||||
label: 'ReadOnlyMany',
|
||||
value: StorageAccessModeValueMap.ReadOnlyMany
|
||||
label: StorageTypeLabelMap[StorageTypeValueMap.Object],
|
||||
value: StorageTypeValueMap.Object
|
||||
}
|
||||
];
|
||||
|
||||
export const StorageStatusValueMap = {
|
||||
Available: 'Available',
|
||||
Bound: 'Bound',
|
||||
Released: 'Released',
|
||||
Failed: 'Failed'
|
||||
export const AccessModeValueMap = {
|
||||
ReadWriteOnce: 'ReadWriteOnce',
|
||||
ReadOnlyMany: 'ReadOnlyMany',
|
||||
ReadWriteMany: 'ReadWriteMany',
|
||||
ReadWriteOncePod: 'ReadWriteOncePod'
|
||||
};
|
||||
|
||||
export const StorageStatusLabelMap: Record<string, string> = {
|
||||
[StorageStatusValueMap.Available]: 'Available',
|
||||
[StorageStatusValueMap.Bound]: 'Bound',
|
||||
[StorageStatusValueMap.Released]: 'Released',
|
||||
[StorageStatusValueMap.Failed]: 'Failed'
|
||||
export const AccessModeOptions = [
|
||||
{
|
||||
label: 'ReadWriteOnce',
|
||||
value: AccessModeValueMap.ReadWriteOnce
|
||||
},
|
||||
{
|
||||
label: 'ReadWriteMany',
|
||||
value: AccessModeValueMap.ReadWriteMany
|
||||
},
|
||||
{
|
||||
label: 'ReadOnlyMany',
|
||||
value: AccessModeValueMap.ReadOnlyMany
|
||||
},
|
||||
{
|
||||
label: 'ReadWriteOncePod',
|
||||
value: AccessModeValueMap.ReadWriteOncePod
|
||||
}
|
||||
];
|
||||
|
||||
export const ReClaimPolicyValueMap = {
|
||||
Retain: 'Retain',
|
||||
Delete: 'Delete',
|
||||
Recycle: 'Recycle'
|
||||
};
|
||||
|
||||
export const status: Record<string, StatusType> = {
|
||||
[StorageStatusValueMap.Available]: StatusMaps.success,
|
||||
[StorageStatusValueMap.Bound]: StatusMaps.transitioning,
|
||||
[StorageStatusValueMap.Released]: StatusMaps.inactive,
|
||||
[StorageStatusValueMap.Failed]: StatusMaps.error
|
||||
};
|
||||
export const ReClaimPolicyOptions = [
|
||||
{
|
||||
label: 'Retain',
|
||||
value: ReClaimPolicyValueMap.Retain
|
||||
},
|
||||
{
|
||||
label: 'Delete',
|
||||
value: ReClaimPolicyValueMap.Delete
|
||||
},
|
||||
{
|
||||
label: 'Recycle',
|
||||
value: ReClaimPolicyValueMap.Recycle
|
||||
}
|
||||
];
|
||||
|
||||
export const rowActionList = [
|
||||
{
|
||||
|
||||
@@ -1,68 +1,64 @@
|
||||
import { StorageStatusValueMap, StorageTypeValueMap } from '.';
|
||||
import { StorageTypeValueMap } from '.';
|
||||
import { ListItem } from './types';
|
||||
|
||||
export const mockStorageData: ListItem[] = [
|
||||
export const mockStorageData: (ListItem & { cluster_id: number })[] = [
|
||||
{
|
||||
id: 1,
|
||||
name: 'local-nvme-cache',
|
||||
type: StorageTypeValueMap.Local,
|
||||
capacity_gb: 500,
|
||||
mount_path: '/mnt/nvme',
|
||||
access_modes: ['ReadWriteOnce'],
|
||||
parameters: {
|
||||
path: '/mnt/nvme'
|
||||
},
|
||||
status: StorageStatusValueMap.Available,
|
||||
cluster_id: 1,
|
||||
description: 'Local NVMe cache for hot model files',
|
||||
metadata: {
|
||||
name: 'local-nvme-cache',
|
||||
namespace: 'default'
|
||||
},
|
||||
spec: {
|
||||
accessMode: 'ReadWriteOnce',
|
||||
capacity: '500Gi',
|
||||
type: StorageTypeValueMap.Local
|
||||
},
|
||||
created_at: '2026-04-01T10:00:00Z',
|
||||
updated_at: '2026-04-10T10:00:00Z'
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: 'shared-model-store',
|
||||
type: StorageTypeValueMap.Shared,
|
||||
capacity_gb: 2048,
|
||||
mount_path: '/models',
|
||||
access_modes: ['ReadWriteMany'],
|
||||
parameters: {
|
||||
storageClassName: 'nfs-client'
|
||||
},
|
||||
status: StorageStatusValueMap.Bound,
|
||||
cluster_id: 1,
|
||||
description: 'Shared storage for model weights',
|
||||
metadata: {
|
||||
name: 'shared-model-store',
|
||||
namespace: 'default'
|
||||
},
|
||||
spec: {
|
||||
accessMode: 'ReadWriteMany',
|
||||
capacity: '2Ti',
|
||||
type: StorageTypeValueMap.Shared
|
||||
},
|
||||
created_at: '2026-04-02T10:00:00Z',
|
||||
updated_at: '2026-04-11T10:00:00Z'
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: 'object-dataset-bucket',
|
||||
type: StorageTypeValueMap.Object,
|
||||
capacity_gb: 10240,
|
||||
mount_path: '/datasets',
|
||||
access_modes: ['ReadOnlyMany'],
|
||||
parameters: {
|
||||
bucket: 'datasets'
|
||||
},
|
||||
status: StorageStatusValueMap.Released,
|
||||
cluster_id: 2,
|
||||
description: 'Object storage mounted for datasets',
|
||||
metadata: {
|
||||
name: 'object-dataset-bucket',
|
||||
namespace: 'default'
|
||||
},
|
||||
spec: {
|
||||
accessMode: 'ReadOnlyMany',
|
||||
capacity: '10Ti',
|
||||
type: StorageTypeValueMap.Object
|
||||
},
|
||||
created_at: '2026-04-03T10:00:00Z',
|
||||
updated_at: '2026-04-12T10:00:00Z'
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: 'failed-shared-cache',
|
||||
type: StorageTypeValueMap.Shared,
|
||||
capacity_gb: 1024,
|
||||
mount_path: '/failed-cache',
|
||||
access_modes: ['ReadWriteMany'],
|
||||
parameters: {
|
||||
storageClassName: 'nfs-client'
|
||||
},
|
||||
status: StorageStatusValueMap.Failed,
|
||||
cluster_id: 2,
|
||||
description: 'Shared cache waiting for storage backend recovery',
|
||||
metadata: {
|
||||
name: 'failed-shared-cache',
|
||||
namespace: 'default'
|
||||
},
|
||||
spec: {
|
||||
accessMode: 'ReadWriteMany',
|
||||
capacity: '1Ti',
|
||||
type: StorageTypeValueMap.Shared
|
||||
},
|
||||
created_at: '2026-04-04T10:00:00Z',
|
||||
updated_at: '2026-04-13T10:00:00Z'
|
||||
}
|
||||
|
||||
@@ -1,13 +1,20 @@
|
||||
export type AccessModeType =
|
||||
| 'ReadOnlyMany'
|
||||
| 'ReadWriteMany'
|
||||
| 'ReadWriteOnce'
|
||||
| 'ReadWriteOncePod';
|
||||
|
||||
export type ReClaimPolicyType = 'Retain' | 'Delete' | 'Recycle';
|
||||
export interface FormData {
|
||||
name: string;
|
||||
description?: string;
|
||||
type?: string;
|
||||
capacity_gb?: number;
|
||||
mount_path?: string;
|
||||
access_modes?: string[];
|
||||
parameters?: Record<string, any>;
|
||||
status?: string;
|
||||
cluster_id?: number;
|
||||
metadata: {
|
||||
name: string;
|
||||
namespace: string;
|
||||
};
|
||||
spec: {
|
||||
accessMode: AccessModeType;
|
||||
capacity: string;
|
||||
type: string;
|
||||
};
|
||||
}
|
||||
|
||||
export interface ListItem extends FormData {
|
||||
|
||||
@@ -1,24 +1,13 @@
|
||||
import {
|
||||
Input as CInput,
|
||||
InputNumber as CInputNumber,
|
||||
Select as SealSelect
|
||||
} from '@gpustack/core-ui';
|
||||
import { Input as CInput, Select as SealSelect } from '@gpustack/core-ui';
|
||||
import { Form } from 'antd';
|
||||
import { StorageAccessModeOptions } from '../config';
|
||||
import { AccessModeOptions, StorageTypeOptions } from '../config';
|
||||
import { FormData } from '../config/types';
|
||||
|
||||
const Basic = () => {
|
||||
const form = Form.useFormInstance<FormData>();
|
||||
const parameters = Form.useWatch('parameters', form);
|
||||
|
||||
const handleParametersChange = (value: Record<string, any>) => {
|
||||
form.setFieldValue('parameters', value);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Form.Item<FormData>
|
||||
name="name"
|
||||
name={['metadata', 'name']}
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
@@ -31,7 +20,7 @@ const Basic = () => {
|
||||
<div style={{ display: 'flex', gap: 16 }}>
|
||||
<div style={{ flex: 1 }}>
|
||||
<Form.Item<FormData>
|
||||
name="type"
|
||||
name={['spec', 'type']}
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
@@ -39,12 +28,16 @@ const Basic = () => {
|
||||
}
|
||||
]}
|
||||
>
|
||||
<SealSelect label="存储类型" required options={[]}></SealSelect>
|
||||
<SealSelect
|
||||
label="存储类型"
|
||||
required
|
||||
options={StorageTypeOptions}
|
||||
></SealSelect>
|
||||
</Form.Item>
|
||||
</div>
|
||||
<div style={{ flex: 1 }}>
|
||||
<Form.Item<FormData>
|
||||
name="capacity_gb"
|
||||
name={['spec', 'capacity']}
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
@@ -52,28 +45,25 @@ const Basic = () => {
|
||||
}
|
||||
]}
|
||||
>
|
||||
<CInputNumber min={1} precision={0} label="容量 (GB)" required />
|
||||
<CInput.Input label="容量" required placeholder="例如:10Gi" />
|
||||
</Form.Item>
|
||||
</div>
|
||||
</div>
|
||||
<Form.Item<FormData> name="access_modes">
|
||||
<Form.Item<FormData>
|
||||
name={['spec', 'accessMode']}
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
message: '请选择访问模式'
|
||||
}
|
||||
]}
|
||||
>
|
||||
<SealSelect
|
||||
label="存储卷访问方式"
|
||||
allowClear
|
||||
options={StorageAccessModeOptions}
|
||||
required
|
||||
options={AccessModeOptions}
|
||||
></SealSelect>
|
||||
</Form.Item>
|
||||
{/* <Form.Item<FormData> name="parameters">
|
||||
<LabelSelector
|
||||
label="存储卷配置参数"
|
||||
labels={parameters || {}}
|
||||
btnText="添加参数"
|
||||
onChange={handleParametersChange}
|
||||
/>
|
||||
</Form.Item> */}
|
||||
<Form.Item<FormData> name="description">
|
||||
<CInput.TextArea label="描述" scaleSize />
|
||||
</Form.Item>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -2,7 +2,7 @@ import { PageAction } from '@/config';
|
||||
import { PageActionType } from '@/config/types';
|
||||
import { Form } from 'antd';
|
||||
import { forwardRef, useEffect, useImperativeHandle } from 'react';
|
||||
import { StorageStatusValueMap } from '../config';
|
||||
import { AccessModeValueMap, StorageTypeValueMap } from '../config';
|
||||
import { FormData, ListItem } from '../config/types';
|
||||
import Basic from './basic';
|
||||
|
||||
@@ -11,12 +11,19 @@ interface StorageFormProps {
|
||||
open: boolean;
|
||||
action: PageActionType;
|
||||
currentData?: ListItem | null;
|
||||
namespace?: string;
|
||||
onFinish: (values: FormData) => Promise<void>;
|
||||
}
|
||||
|
||||
const GPUServiceStorageForm: React.FC<StorageFormProps> = forwardRef(
|
||||
(props, ref) => {
|
||||
const { action, currentData, open, onFinish } = props;
|
||||
const {
|
||||
action,
|
||||
currentData,
|
||||
open,
|
||||
namespace = 'default',
|
||||
onFinish
|
||||
} = props;
|
||||
const [form] = Form.useForm<FormData>();
|
||||
|
||||
useEffect(() => {
|
||||
@@ -27,24 +34,30 @@ const GPUServiceStorageForm: React.FC<StorageFormProps> = forwardRef(
|
||||
|
||||
if (action === PageAction.EDIT && currentData) {
|
||||
form.setFieldsValue({
|
||||
name: currentData.name,
|
||||
description: currentData.description,
|
||||
type: currentData.type,
|
||||
capacity_gb: currentData.capacity_gb,
|
||||
mount_path: currentData.mount_path,
|
||||
access_modes: currentData.access_modes,
|
||||
parameters: currentData.parameters,
|
||||
status: currentData.status
|
||||
metadata: {
|
||||
name: currentData.metadata?.name,
|
||||
namespace: currentData.metadata?.namespace
|
||||
},
|
||||
spec: {
|
||||
accessMode: currentData.spec?.accessMode,
|
||||
capacity: currentData.spec?.capacity,
|
||||
type: currentData.spec?.type
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
form.setFieldsValue({
|
||||
type: '默认存储',
|
||||
parameters: {},
|
||||
status: StorageStatusValueMap.Available
|
||||
metadata: {
|
||||
namespace
|
||||
},
|
||||
spec: {
|
||||
accessMode:
|
||||
AccessModeValueMap.ReadWriteOnce as FormData['spec']['accessMode'],
|
||||
type: StorageTypeValueMap.Local
|
||||
}
|
||||
});
|
||||
}, [action, currentData, form, open]);
|
||||
}, [action, currentData, form, open, namespace]);
|
||||
|
||||
useImperativeHandle(ref, () => ({
|
||||
submit: () => {
|
||||
|
||||
@@ -1,15 +1,9 @@
|
||||
import { tableSorter } from '@/config/settings';
|
||||
import { AutoTooltip, DropdownButtons, StatusTag } from '@gpustack/core-ui';
|
||||
import { AutoTooltip, DropdownButtons } from '@gpustack/core-ui';
|
||||
import type { ColumnsType } from 'antd/lib/table';
|
||||
import dayjs from 'dayjs';
|
||||
import { useMemo } from 'react';
|
||||
import {
|
||||
rowActionList,
|
||||
status,
|
||||
StorageStatusLabelMap,
|
||||
StorageStatusValueMap,
|
||||
StorageTypeLabelMap
|
||||
} from '../config';
|
||||
import { rowActionList, StorageTypeLabelMap } from '../config';
|
||||
import { ListItem } from '../config/types';
|
||||
|
||||
interface ColumnsHookProps {
|
||||
@@ -25,7 +19,7 @@ const useStorageColumns = ({
|
||||
return [
|
||||
{
|
||||
title: '名称',
|
||||
dataIndex: 'name',
|
||||
dataIndex: ['metadata', 'name'],
|
||||
key: 'name',
|
||||
sorter: tableSorter(1),
|
||||
ellipsis: {
|
||||
@@ -39,48 +33,25 @@ const useStorageColumns = ({
|
||||
},
|
||||
{
|
||||
title: '类型',
|
||||
dataIndex: 'type',
|
||||
dataIndex: ['spec', 'type'],
|
||||
key: 'type',
|
||||
sorter: tableSorter(2),
|
||||
render: (value: string) => StorageTypeLabelMap[value] || value || '-'
|
||||
},
|
||||
{
|
||||
title: '状态',
|
||||
dataIndex: 'status',
|
||||
key: 'status',
|
||||
title: '容量',
|
||||
dataIndex: ['spec', 'capacity'],
|
||||
key: 'capacity',
|
||||
sorter: tableSorter(3),
|
||||
render: (statusValue: string) => {
|
||||
const value = statusValue || StorageStatusValueMap.Available;
|
||||
return (
|
||||
<StatusTag
|
||||
statusValue={{
|
||||
status: status[value],
|
||||
text: StorageStatusLabelMap[value] || value
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
render: (value: string) => value ?? '-'
|
||||
},
|
||||
{
|
||||
title: '容量 (GB)',
|
||||
dataIndex: 'capacity_gb',
|
||||
key: 'capacity_gb',
|
||||
title: '访问模式',
|
||||
dataIndex: ['spec', 'accessMode'],
|
||||
key: 'accessMode',
|
||||
sorter: tableSorter(4),
|
||||
render: (value: number) => value ?? '-'
|
||||
render: (value: string) => value || '-'
|
||||
},
|
||||
// {
|
||||
// title: '挂载路径',
|
||||
// dataIndex: 'mount_path',
|
||||
// key: 'mount_path',
|
||||
// ellipsis: {
|
||||
// showTitle: false
|
||||
// },
|
||||
// render: (text: string) => (
|
||||
// <AutoTooltip ghost minWidth={20}>
|
||||
// {text || '-'}
|
||||
// </AutoTooltip>
|
||||
// )
|
||||
// },
|
||||
{
|
||||
title: '创建时间',
|
||||
dataIndex: 'created_at',
|
||||
|
||||
@@ -3,6 +3,7 @@ import { PaginationKey, TABLE_SORT_DIRECTIONS } from '@/config/settings';
|
||||
import type { PageActionType } from '@/config/types';
|
||||
import useTableFetch from '@/hooks/use-table-fetch';
|
||||
import { useQueryClusterList } from '@/pages/cluster-management/services/use-query-cluster-list';
|
||||
import { useModel } from '@@/plugin-model';
|
||||
import {
|
||||
BaseSelect,
|
||||
DeleteModal,
|
||||
@@ -14,20 +15,53 @@ import { useIntl } from '@umijs/max';
|
||||
import { useMemoizedFn } from 'ahooks';
|
||||
import { ConfigProvider, Divider, Flex, message, Table } from 'antd';
|
||||
import _ from 'lodash';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
import { PageContainerInner } from '../../_components/page-box';
|
||||
import {
|
||||
createGPUServiceStorage,
|
||||
deleteGPUServiceStorage,
|
||||
GPU_SERVICE_STORAGE_API,
|
||||
queryGPUServiceStorage,
|
||||
updateGPUServiceStorage
|
||||
queryGPUServiceStorage
|
||||
} from './apis';
|
||||
|
||||
import AddModal from './components/add-modal';
|
||||
import { FormData, ListItem } from './config/types';
|
||||
import useStorageColumns from './hooks/use-storage-columns';
|
||||
import useCreateStorage from './services/use-create-storage';
|
||||
import useUpdateStorage from './services/use-update-storage';
|
||||
|
||||
const GPUServiceStorage: React.FC = () => {
|
||||
const { initialState } = useModel('@@initialState');
|
||||
const namespace = initialState?.currentUser?.org_name || 'default';
|
||||
|
||||
const deleteStorage = useCallback(
|
||||
(id: number) => deleteGPUServiceStorage({ namespace, id }),
|
||||
[namespace]
|
||||
);
|
||||
|
||||
const fetchStorage = useCallback(
|
||||
async (
|
||||
params: any,
|
||||
options?: any
|
||||
): Promise<Global.PageResponse<ListItem>> => {
|
||||
const res = await queryGPUServiceStorage(
|
||||
{ ...params, namespace },
|
||||
options
|
||||
);
|
||||
const total = res.items?.length ?? 0;
|
||||
const perPage = params.perPage || 10;
|
||||
return {
|
||||
items: res.items ?? [],
|
||||
pagination: {
|
||||
total,
|
||||
totalPage: Math.ceil(total / perPage),
|
||||
page: params.page || 1,
|
||||
perPage
|
||||
}
|
||||
};
|
||||
},
|
||||
[namespace]
|
||||
);
|
||||
|
||||
const {
|
||||
dataSource,
|
||||
rowSelection,
|
||||
@@ -44,12 +78,15 @@ const GPUServiceStorage: React.FC = () => {
|
||||
handleNameChange
|
||||
} = useTableFetch<ListItem>({
|
||||
key: PaginationKey.Storage,
|
||||
fetchAPI: queryGPUServiceStorage,
|
||||
deleteAPI: deleteGPUServiceStorage,
|
||||
fetchAPI: fetchStorage,
|
||||
deleteAPI: deleteStorage,
|
||||
watch: false,
|
||||
API: GPU_SERVICE_STORAGE_API,
|
||||
API: GPU_SERVICE_STORAGE_API(namespace),
|
||||
contentForDelete: '存储'
|
||||
});
|
||||
|
||||
const { fetchData: createStorage } = useCreateStorage();
|
||||
const { fetchData: updateStorage } = useUpdateStorage();
|
||||
const {
|
||||
fetchClusterList,
|
||||
cancelRequest: cancelClusterRequest,
|
||||
@@ -113,12 +150,12 @@ const GPUServiceStorage: React.FC = () => {
|
||||
const handleModalOk = async (data: FormData) => {
|
||||
try {
|
||||
if (openAddModalStatus.action === PageAction.EDIT) {
|
||||
await updateGPUServiceStorage({
|
||||
await updateStorage({
|
||||
id: openAddModalStatus.currentData!.id,
|
||||
data
|
||||
});
|
||||
} else {
|
||||
await createGPUServiceStorage({ data });
|
||||
await createStorage({ data });
|
||||
}
|
||||
|
||||
fetchData();
|
||||
@@ -133,7 +170,7 @@ const GPUServiceStorage: React.FC = () => {
|
||||
if (val === 'edit') {
|
||||
handleEditStorage(row);
|
||||
} else if (val === 'delete') {
|
||||
handleDelete({ ...row, name: row.name });
|
||||
handleDelete({ ...row, name: row.metadata?.name });
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
import { useModel } from '@@/plugin-model';
|
||||
import { useQueryData } from '@gpustack/core-ui';
|
||||
import { useCallback } from 'react';
|
||||
import { apiVersion, KindMapping } from '../../constants';
|
||||
import { createGPUServiceStorage } from '../apis';
|
||||
import { FormData, ListItem } from '../config/types';
|
||||
|
||||
interface CreateStorageParams {
|
||||
data: FormData;
|
||||
}
|
||||
|
||||
export default function useCreateStorage() {
|
||||
const { initialState } = useModel('@@initialState');
|
||||
const namespace = initialState?.currentUser?.org_name || 'default';
|
||||
|
||||
const fetchDetail = useCallback(
|
||||
(params: CreateStorageParams, option?: any) =>
|
||||
createGPUServiceStorage(
|
||||
{
|
||||
namespace,
|
||||
data: {
|
||||
apiVersion,
|
||||
kind: KindMapping.instancePersistentVolume,
|
||||
metadata: {
|
||||
name: params.data.metadata.name,
|
||||
namespace
|
||||
},
|
||||
spec: params.data.spec
|
||||
}
|
||||
},
|
||||
option
|
||||
),
|
||||
[namespace]
|
||||
);
|
||||
|
||||
const { detailData, loading, cancelRequest, fetchData } = useQueryData<
|
||||
ListItem,
|
||||
CreateStorageParams
|
||||
>({
|
||||
fetchDetail,
|
||||
key: 'createStorage'
|
||||
});
|
||||
|
||||
return {
|
||||
detailData,
|
||||
loading,
|
||||
cancelRequest,
|
||||
fetchData
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
import { useModel } from '@@/plugin-model';
|
||||
import { useQueryData } from '@gpustack/core-ui';
|
||||
import { useCallback } from 'react';
|
||||
import { apiVersion, KindMapping } from '../../constants';
|
||||
import { updateGPUServiceStorage } from '../apis';
|
||||
import { FormData, ListItem } from '../config/types';
|
||||
|
||||
interface UpdateStorageParams {
|
||||
id: number;
|
||||
data: FormData;
|
||||
}
|
||||
|
||||
export default function useUpdateStorage() {
|
||||
const { initialState } = useModel('@@initialState');
|
||||
const namespace = initialState?.currentUser?.org_name || 'default';
|
||||
|
||||
const fetchDetail = useCallback(
|
||||
(params: UpdateStorageParams, option?: any) =>
|
||||
updateGPUServiceStorage(
|
||||
{
|
||||
namespace,
|
||||
id: params.id,
|
||||
data: {
|
||||
apiVersion,
|
||||
kind: KindMapping.instancePersistentVolume,
|
||||
metadata: {
|
||||
name: params.data.metadata.name,
|
||||
namespace
|
||||
},
|
||||
spec: params.data.spec
|
||||
}
|
||||
},
|
||||
option
|
||||
),
|
||||
[namespace]
|
||||
);
|
||||
|
||||
const { detailData, loading, cancelRequest, fetchData } = useQueryData<
|
||||
ListItem,
|
||||
UpdateStorageParams
|
||||
>({
|
||||
fetchDetail,
|
||||
key: 'updateStorage'
|
||||
});
|
||||
|
||||
return {
|
||||
detailData,
|
||||
loading,
|
||||
cancelRequest,
|
||||
fetchData
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user