fix(style): textarea label background
This commit is contained in:
@@ -45,6 +45,24 @@ export const GPU_SERVICE_INSTANCE_PV_EVENTS_API = (params: {
|
|||||||
return `/clusters/${params.clusterID}/proxy/apis/worker.gpustack.ai/v1/namespaces/${params.namespace}/instancepersistentvolumes/${params.name}/events`;
|
return `/clusters/${params.clusterID}/proxy/apis/worker.gpustack.ai/v1/namespaces/${params.namespace}/instancepersistentvolumes/${params.name}/events`;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// TODO: replace placeholder once start/stop endpoints are finalized
|
||||||
|
export const GPU_SERVICE_INSTANCE_START_API = (params: {
|
||||||
|
namespace: string;
|
||||||
|
name: string;
|
||||||
|
clusterID?: number;
|
||||||
|
}) => {
|
||||||
|
return `/clusters/${params.clusterID}/proxy/apis/worker.gpustack.ai/v1/namespaces/${params.namespace}/instances/${params.name}/start`;
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO: replace placeholder once start/stop endpoints are finalized
|
||||||
|
export const GPU_SERVICE_INSTANCE_STOP_API = (params: {
|
||||||
|
namespace: string;
|
||||||
|
name: string;
|
||||||
|
clusterID?: number;
|
||||||
|
}) => {
|
||||||
|
return `/clusters/${params.clusterID}/proxy/apis/worker.gpustack.ai/v1/namespaces/${params.namespace}/instances/${params.name}/stop`;
|
||||||
|
};
|
||||||
|
|
||||||
// =========== Instances ===========
|
// =========== Instances ===========
|
||||||
|
|
||||||
export async function queryGPUServiceInstances(
|
export async function queryGPUServiceInstances(
|
||||||
@@ -212,6 +230,56 @@ export async function queryGPUServiceInstancePVEvents(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: replace placeholder once start/stop endpoints are finalized
|
||||||
|
export async function startGPUServiceInstance(
|
||||||
|
params: {
|
||||||
|
namespace: string;
|
||||||
|
name: string;
|
||||||
|
clusterID?: number;
|
||||||
|
},
|
||||||
|
option?: any
|
||||||
|
) {
|
||||||
|
if (!params.clusterID) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
return request(
|
||||||
|
GPU_SERVICE_INSTANCE_START_API({
|
||||||
|
namespace: params.namespace,
|
||||||
|
clusterID: params.clusterID,
|
||||||
|
name: params.name
|
||||||
|
}),
|
||||||
|
{
|
||||||
|
method: 'POST',
|
||||||
|
cancelToken: option?.token
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: replace placeholder once start/stop endpoints are finalized
|
||||||
|
export async function stopGPUServiceInstance(
|
||||||
|
params: {
|
||||||
|
namespace: string;
|
||||||
|
name: string;
|
||||||
|
clusterID?: number;
|
||||||
|
},
|
||||||
|
option?: any
|
||||||
|
) {
|
||||||
|
if (!params.clusterID) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
return request(
|
||||||
|
GPU_SERVICE_INSTANCE_STOP_API({
|
||||||
|
namespace: params.namespace,
|
||||||
|
clusterID: params.clusterID,
|
||||||
|
name: params.name
|
||||||
|
}),
|
||||||
|
{
|
||||||
|
method: 'POST',
|
||||||
|
cancelToken: option?.token
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
export async function queryGPUServiceInstanceLog(
|
export async function queryGPUServiceInstanceLog(
|
||||||
params: InstanceLogQueryParams & {
|
params: InstanceLogQueryParams & {
|
||||||
namespace: string;
|
namespace: string;
|
||||||
|
|||||||
@@ -64,6 +64,18 @@ export const rowActionList = [
|
|||||||
locale: true,
|
locale: true,
|
||||||
icon: icons.ProfileOutlined
|
icon: icons.ProfileOutlined
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
label: 'common.button.start',
|
||||||
|
key: 'start',
|
||||||
|
locale: true,
|
||||||
|
icon: icons.Play
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'common.button.stop',
|
||||||
|
key: 'stop',
|
||||||
|
locale: true,
|
||||||
|
icon: icons.Stop
|
||||||
|
},
|
||||||
// {
|
// {
|
||||||
// label: 'common.button.edit',
|
// label: 'common.button.edit',
|
||||||
// key: 'edit',
|
// key: 'edit',
|
||||||
@@ -87,6 +99,27 @@ export const rowActionList = [
|
|||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
|
export const batchActionList = [
|
||||||
|
{
|
||||||
|
label: 'common.button.start',
|
||||||
|
key: 'start',
|
||||||
|
icon: icons.Play
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'common.button.stop',
|
||||||
|
key: 'stop',
|
||||||
|
icon: icons.Stop
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'common.button.delete',
|
||||||
|
key: 'delete',
|
||||||
|
icon: icons.DeleteOutlined,
|
||||||
|
props: {
|
||||||
|
danger: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
export const InstanceTypePhaseValueMap = {
|
export const InstanceTypePhaseValueMap = {
|
||||||
// Available: 'Available',
|
// Available: 'Available',
|
||||||
// Unavailable: 'Unavailable'
|
// Unavailable: 'Unavailable'
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { Input as CInput } from '@gpustack/core-ui';
|
|||||||
import { useIntl } from '@umijs/max';
|
import { useIntl } from '@umijs/max';
|
||||||
import { Form } from 'antd';
|
import { Form } from 'antd';
|
||||||
import { FormData } from '../config/types';
|
import { FormData } from '../config/types';
|
||||||
|
import formStyles from '../styles/instances.module.less';
|
||||||
|
|
||||||
const Basic = ({
|
const Basic = ({
|
||||||
action,
|
action,
|
||||||
@@ -37,13 +38,15 @@ const Basic = ({
|
|||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item<FormData> name={['spec', 'description']}>
|
<div className={formStyles.command}>
|
||||||
<CInput.TextArea
|
<Form.Item<FormData> name={['spec', 'description']}>
|
||||||
disabled={disabled}
|
<CInput.TextArea
|
||||||
label={intl.formatMessage({ id: 'common.table.description' })}
|
disabled={disabled}
|
||||||
scaleSize
|
label={intl.formatMessage({ id: 'common.table.description' })}
|
||||||
/>
|
scaleSize
|
||||||
</Form.Item>
|
/>
|
||||||
|
</Form.Item>
|
||||||
|
</div>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -5,16 +5,28 @@ import { PaginationKey, TABLE_SORT_DIRECTIONS } from '@/config/settings';
|
|||||||
import useTableFetch from '@/hooks/use-table-fetch';
|
import useTableFetch from '@/hooks/use-table-fetch';
|
||||||
import { ProviderValueMap } from '@/pages/cluster-management/config';
|
import { ProviderValueMap } from '@/pages/cluster-management/config';
|
||||||
import { useQueryClusterList } from '@/pages/cluster-management/services/use-query-cluster-list';
|
import { useQueryClusterList } from '@/pages/cluster-management/services/use-query-cluster-list';
|
||||||
|
import { handleBatchRequest } from '@/utils';
|
||||||
|
import { PlusOutlined } from '@ant-design/icons';
|
||||||
import {
|
import {
|
||||||
BaseSelect,
|
BaseSelect,
|
||||||
DeleteModal,
|
DeleteModal,
|
||||||
|
DropdownButtons,
|
||||||
FilterBar,
|
FilterBar,
|
||||||
IconFont,
|
IconFont,
|
||||||
NoResult
|
NoResult
|
||||||
} from '@gpustack/core-ui';
|
} from '@gpustack/core-ui';
|
||||||
import { useIntl } from '@umijs/max';
|
import { useIntl } from '@umijs/max';
|
||||||
import { useMemoizedFn } from 'ahooks';
|
import { useMemoizedFn } from 'ahooks';
|
||||||
import { ConfigProvider, Divider, Flex, message, Modal, Table } from 'antd';
|
import {
|
||||||
|
Button,
|
||||||
|
ConfigProvider,
|
||||||
|
Divider,
|
||||||
|
Flex,
|
||||||
|
message,
|
||||||
|
Modal,
|
||||||
|
Space,
|
||||||
|
Table
|
||||||
|
} from 'antd';
|
||||||
import { useAtom } from 'jotai';
|
import { useAtom } from 'jotai';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import { useCallback, useEffect, useMemo } from 'react';
|
import { useCallback, useEffect, useMemo } from 'react';
|
||||||
@@ -22,11 +34,14 @@ import { PageContainerInner } from '../../_components/page-box';
|
|||||||
import {
|
import {
|
||||||
deleteGPUServiceInstance,
|
deleteGPUServiceInstance,
|
||||||
GPU_SERVICE_INSTANCES_API,
|
GPU_SERVICE_INSTANCES_API,
|
||||||
queryGPUServiceInstances
|
queryGPUServiceInstances,
|
||||||
|
startGPUServiceInstance,
|
||||||
|
stopGPUServiceInstance
|
||||||
} from './apis';
|
} from './apis';
|
||||||
import AddModal from './components/add-modal';
|
import AddModal from './components/add-modal';
|
||||||
import ViewEventsModal from './components/view-events-modal';
|
import ViewEventsModal from './components/view-events-modal';
|
||||||
import ViewLogsModal from './components/view-logs-modal';
|
import ViewLogsModal from './components/view-logs-modal';
|
||||||
|
import { batchActionList } from './config';
|
||||||
import { FormData, ListItem } from './config/types';
|
import { FormData, ListItem } from './config/types';
|
||||||
import useCreateInstance from './hooks/use-create-instance';
|
import useCreateInstance from './hooks/use-create-instance';
|
||||||
import useInstancesColumns from './hooks/use-instances-columns';
|
import useInstancesColumns from './hooks/use-instances-columns';
|
||||||
@@ -49,6 +64,26 @@ const GPUService: React.FC = () => {
|
|||||||
[namespace, clusterID]
|
[namespace, clusterID]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const startInstance = useCallback(
|
||||||
|
(row: ListItem) =>
|
||||||
|
startGPUServiceInstance({
|
||||||
|
namespace: row.metadata?.namespace || namespace,
|
||||||
|
clusterID,
|
||||||
|
name: row.metadata?.name as string
|
||||||
|
}),
|
||||||
|
[namespace, clusterID]
|
||||||
|
);
|
||||||
|
|
||||||
|
const stopInstance = useCallback(
|
||||||
|
(row: ListItem) =>
|
||||||
|
stopGPUServiceInstance({
|
||||||
|
namespace: row.metadata?.namespace || namespace,
|
||||||
|
clusterID,
|
||||||
|
name: row.metadata?.name as string
|
||||||
|
}),
|
||||||
|
[namespace, clusterID]
|
||||||
|
);
|
||||||
|
|
||||||
const fetchInstances = useMemoizedFn(
|
const fetchInstances = useMemoizedFn(
|
||||||
async (
|
async (
|
||||||
params: any,
|
params: any,
|
||||||
@@ -225,6 +260,80 @@ const GPUService: React.FC = () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const handleStart = useMemoizedFn(async (row: ListItem) => {
|
||||||
|
modalRef.current?.show({
|
||||||
|
title: intl.formatMessage({ id: 'common.title.start.confirm' }),
|
||||||
|
content: 'gpuservice.instance',
|
||||||
|
okText: 'common.button.start',
|
||||||
|
operation: 'common.start.single.confirm',
|
||||||
|
name: row.metadata?.name,
|
||||||
|
async onOk() {
|
||||||
|
try {
|
||||||
|
await startInstance(row);
|
||||||
|
message.success(intl.formatMessage({ id: 'common.message.success' }));
|
||||||
|
fetchData();
|
||||||
|
} catch (error) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
const handleStop = useMemoizedFn(async (row: ListItem) => {
|
||||||
|
modalRef.current?.show({
|
||||||
|
title: intl.formatMessage({ id: 'common.title.stop.confirm' }),
|
||||||
|
content: 'gpuservice.instance',
|
||||||
|
okText: 'common.button.stop',
|
||||||
|
operation: 'common.stop.single.confirm',
|
||||||
|
name: row.metadata?.name,
|
||||||
|
async onOk() {
|
||||||
|
try {
|
||||||
|
await stopInstance(row);
|
||||||
|
message.success(intl.formatMessage({ id: 'common.message.success' }));
|
||||||
|
fetchData();
|
||||||
|
} catch (error) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
const handleStartBatch = useMemoizedFn(() => {
|
||||||
|
modalRef.current?.show({
|
||||||
|
title: intl.formatMessage({ id: 'common.title.start.confirm' }),
|
||||||
|
content: 'gpuservice.instance',
|
||||||
|
okText: 'common.button.start',
|
||||||
|
operation: 'common.start.confirm',
|
||||||
|
selection: true,
|
||||||
|
async onOk() {
|
||||||
|
const res = await handleBatchRequest(
|
||||||
|
rowSelection.selectedRows as ListItem[],
|
||||||
|
startInstance
|
||||||
|
);
|
||||||
|
fetchData();
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
const handleStopBatch = useMemoizedFn(() => {
|
||||||
|
modalRef.current?.show({
|
||||||
|
title: intl.formatMessage({ id: 'common.title.stop.confirm' }),
|
||||||
|
content: 'gpuservice.instance',
|
||||||
|
okText: 'common.button.stop',
|
||||||
|
operation: 'common.stop.confirm',
|
||||||
|
selection: true,
|
||||||
|
async onOk() {
|
||||||
|
const res = await handleBatchRequest(
|
||||||
|
rowSelection.selectedRows as ListItem[],
|
||||||
|
stopInstance
|
||||||
|
);
|
||||||
|
fetchData();
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
const handleSelect = useMemoizedFn((val: string, row: ListItem) => {
|
const handleSelect = useMemoizedFn((val: string, row: ListItem) => {
|
||||||
if (val === 'view') {
|
if (val === 'view') {
|
||||||
openViewInstanceModal(row);
|
openViewInstanceModal(row);
|
||||||
@@ -244,6 +353,20 @@ const GPUService: React.FC = () => {
|
|||||||
openViewLogsModal(row);
|
openViewLogsModal(row);
|
||||||
} else if (val === 'viewevent') {
|
} else if (val === 'viewevent') {
|
||||||
openViewEventsModal(row);
|
openViewEventsModal(row);
|
||||||
|
} else if (val === 'start') {
|
||||||
|
handleStart(row);
|
||||||
|
} else if (val === 'stop') {
|
||||||
|
handleStop(row);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const handleBatchActionSelect = useMemoizedFn((val: string) => {
|
||||||
|
if (val === 'start') {
|
||||||
|
handleStartBatch();
|
||||||
|
} else if (val === 'stop') {
|
||||||
|
handleStopBatch();
|
||||||
|
} else if (val === 'delete') {
|
||||||
|
handleDeleteBatch();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -317,14 +440,34 @@ const GPUService: React.FC = () => {
|
|||||||
selectHolder={intl.formatMessage({
|
selectHolder={intl.formatMessage({
|
||||||
id: 'gpuservice.instance.filter.cluster'
|
id: 'gpuservice.instance.filter.cluster'
|
||||||
})}
|
})}
|
||||||
buttonText={intl.formatMessage({ id: 'gpuservice.instance.add' })}
|
|
||||||
handleSearch={handleSearch}
|
handleSearch={handleSearch}
|
||||||
handleSelectChange={handleClusterChange}
|
handleSelectChange={handleClusterChange}
|
||||||
handleDeleteByBatch={handleDeleteBatch}
|
|
||||||
handleClickPrimary={openCreateInstanceModal}
|
|
||||||
handleInputChange={handleNameChange}
|
handleInputChange={handleNameChange}
|
||||||
rowSelection={rowSelection}
|
rowSelection={rowSelection}
|
||||||
widths={{ input: 300 }}
|
widths={{ input: 300 }}
|
||||||
|
right={
|
||||||
|
<Space size={16}>
|
||||||
|
<Button
|
||||||
|
icon={<PlusOutlined />}
|
||||||
|
type="primary"
|
||||||
|
onClick={openCreateInstanceModal}
|
||||||
|
>
|
||||||
|
{intl.formatMessage({ id: 'gpuservice.instance.add' })}
|
||||||
|
</Button>
|
||||||
|
<DropdownButtons
|
||||||
|
items={batchActionList}
|
||||||
|
extra={
|
||||||
|
rowSelection.selectedRowKeys.length > 0 && (
|
||||||
|
<span>({rowSelection.selectedRowKeys.length})</span>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
size="large"
|
||||||
|
showText={true}
|
||||||
|
disabled={!rowSelection.selectedRowKeys.length}
|
||||||
|
onSelect={handleBatchActionSelect}
|
||||||
|
/>
|
||||||
|
</Space>
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
<ConfigProvider renderEmpty={renderEmpty}>
|
<ConfigProvider renderEmpty={renderEmpty}>
|
||||||
<Table
|
<Table
|
||||||
|
|||||||
@@ -24,3 +24,11 @@
|
|||||||
flex: 1;
|
flex: 1;
|
||||||
min-height: 0;
|
min-height: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.command {
|
||||||
|
:global {
|
||||||
|
.seal-textarea-label {
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import { useIntl } from '@umijs/max';
|
|||||||
import { Flex, Form } from 'antd';
|
import { Flex, Form } from 'antd';
|
||||||
import { useMemo } from 'react';
|
import { useMemo } from 'react';
|
||||||
import { GPUsConfigs } from '../../../resources/config/gpu-driver';
|
import { GPUsConfigs } from '../../../resources/config/gpu-driver';
|
||||||
|
import formStyles from '../../instances/styles/instances.module.less';
|
||||||
import {
|
import {
|
||||||
ImagePullPolicyOptions,
|
ImagePullPolicyOptions,
|
||||||
normalizeCommand,
|
normalizeCommand,
|
||||||
@@ -154,22 +155,24 @@ const Basic: React.FC<BasicProps> = ({
|
|||||||
}))}
|
}))}
|
||||||
/>
|
/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item<FormData>
|
<div className={formStyles.command}>
|
||||||
name={['spec', 'command']}
|
<Form.Item<FormData>
|
||||||
normalize={normalizeCommand}
|
name={['spec', 'command']}
|
||||||
getValueProps={(value) => ({ value: stringifyCommand(value) })}
|
normalize={normalizeCommand}
|
||||||
>
|
getValueProps={(value) => ({ value: stringifyCommand(value) })}
|
||||||
<Textarea
|
>
|
||||||
disabled={disabled}
|
<Textarea
|
||||||
label={intl.formatMessage({ id: 'gpuservice.template.command' })}
|
disabled={disabled}
|
||||||
placeholder={intl.formatMessage({
|
label={intl.formatMessage({ id: 'gpuservice.template.command' })}
|
||||||
id: 'gpuservice.template.command.placeholder'
|
placeholder={intl.formatMessage({
|
||||||
})}
|
id: 'gpuservice.template.command.placeholder'
|
||||||
trim={false}
|
})}
|
||||||
alwaysFocus
|
trim={false}
|
||||||
scaleSize
|
alwaysFocus
|
||||||
/>
|
scaleSize
|
||||||
</Form.Item>
|
/>
|
||||||
|
</Form.Item>
|
||||||
|
</div>
|
||||||
|
|
||||||
<Flex gap={16}>
|
<Flex gap={16}>
|
||||||
<div style={{ flex: 1 }}>
|
<div style={{ flex: 1 }}>
|
||||||
|
|||||||
Reference in New Issue
Block a user