fix: update open playground btn

This commit is contained in:
jialin
2026-02-05 11:55:05 +08:00
parent 4e8b5e26ae
commit a1a7979fb3
18 changed files with 302 additions and 218 deletions
+5
View File
@@ -104,6 +104,11 @@
display: flex; display: flex;
} }
.flex-full {
display: flex;
flex: 1;
}
// space-between // space-between
.flex-between { .flex-between {
display: flex; display: flex;
+1 -1
View File
@@ -2,7 +2,7 @@ import { createFromIconfontCN } from '@ant-design/icons';
// import './iconfont/iconfont.js'; // import './iconfont/iconfont.js';
const IconFont = createFromIconfontCN({ const IconFont = createFromIconfontCN({
scriptUrl: '//at.alicdn.com/t/c/font_4613488_c3lajf3mdtk.js' scriptUrl: '//at.alicdn.com/t/c/font_4613488_i617h54opsm.js'
}); });
export default IconFont; export default IconFont;
File diff suppressed because one or more lines are too long
@@ -98,7 +98,11 @@ const CommunityBackends: React.FC<{
> >
<> <>
{data.enabled && ( {data.enabled && (
<ThemeTag style={{ margin: 0 }} color="geekblue" variant="filled"> <ThemeTag
style={{ margin: 0, fontWeight: 400 }}
color="geekblue"
variant="filled"
>
{intl.formatMessage({ id: 'common.status.enabled' })} {intl.formatMessage({ id: 'common.status.enabled' })}
</ThemeTag> </ThemeTag>
)} )}
@@ -88,53 +88,6 @@ export const credentialActionList = [
} }
]; ];
export const clusterActionList = [
{
key: 'edit',
label: 'common.button.edit',
icon: icons.EditOutlined
},
{
label: 'resources.metrics.details',
key: 'metrics',
icon: icons.Metrics
},
{
key: 'add_worker',
label: 'resources.button.create',
provider: ProviderValueMap.Docker,
locale: true,
icon: icons.DockerOutlined
},
{
key: 'register_cluster',
label: 'clusters.button.register',
provider: ProviderValueMap.Kubernetes,
locale: true,
icon: icons.KubernetesOutlined
},
{
key: 'addPool',
label: 'clusters.button.addNodePool',
provider: ProviderValueMap.DigitalOcean,
locale: true,
icon: icons.Catalog1
},
{
key: 'isDefault',
label: 'clusters.form.setDefault',
icon: icons.StarOutlined
},
{
key: 'delete',
label: 'common.button.delete',
icon: icons.DeleteOutlined,
props: {
danger: true
}
}
];
export const CloudOptionItems = [ export const CloudOptionItems = [
{ {
label: 'Volumes', label: 'Volumes',
@@ -2,9 +2,11 @@
import { systemConfigAtom } from '@/atoms/system'; import { systemConfigAtom } from '@/atoms/system';
import AutoTooltip from '@/components/auto-tooltip'; import AutoTooltip from '@/components/auto-tooltip';
import DropdownButtons from '@/components/drop-down-buttons'; import DropdownButtons from '@/components/drop-down-buttons';
import icons from '@/components/icon-font/icons';
import { SealColumnProps } from '@/components/seal-table/types'; import { SealColumnProps } from '@/components/seal-table/types';
import StatusTag from '@/components/status-tag'; import StatusTag from '@/components/status-tag';
import { tableSorter } from '@/config/settings'; import { tableSorter } from '@/config/settings';
import GrafanaIcon from '@/pages/_components/grafana-icon';
import { StarFilled } from '@ant-design/icons'; import { StarFilled } from '@ant-design/icons';
import { useIntl } from '@umijs/max'; import { useIntl } from '@umijs/max';
import { Tooltip } from 'antd'; import { Tooltip } from 'antd';
@@ -15,10 +17,61 @@ import {
ClusterStatus, ClusterStatus,
ClusterStatusLabelMap, ClusterStatusLabelMap,
ProviderLabelMap, ProviderLabelMap,
clusterActionList ProviderValueMap
} from '../config'; } from '../config';
import { ClusterListItem } from '../config/types'; import { ClusterListItem } from '../config/types';
const clusterActionList = [
{
key: 'edit',
label: 'common.button.edit',
icon: icons.EditOutlined
},
{
label: 'resources.metrics.details',
key: 'metrics',
icon: (
<span className="flex-center">
<GrafanaIcon style={{ width: 14, height: 14 }}></GrafanaIcon>
</span>
)
},
{
key: 'add_worker',
label: 'resources.button.create',
provider: ProviderValueMap.Docker,
locale: true,
icon: icons.DockerOutlined
},
{
key: 'register_cluster',
label: 'clusters.button.register',
provider: ProviderValueMap.Kubernetes,
locale: true,
icon: icons.KubernetesOutlined
},
{
key: 'addPool',
label: 'clusters.button.addNodePool',
provider: ProviderValueMap.DigitalOcean,
locale: true,
icon: icons.Catalog1
},
{
key: 'isDefault',
label: 'clusters.form.setDefault',
icon: icons.StarOutlined
},
{
key: 'delete',
label: 'common.button.delete',
icon: icons.DeleteOutlined,
props: {
danger: true
}
}
];
const useClusterColumns = ( const useClusterColumns = (
handleSelect: (val: string, record: ClusterListItem) => void, handleSelect: (val: string, record: ClusterListItem) => void,
onCellClick?: (record: ClusterListItem, dataIndex: string) => void onCellClick?: (record: ClusterListItem, dataIndex: string) => void
+21 -32
View File
@@ -12,7 +12,6 @@ import { HandlerOptions } from '@/hooks/use-chunk-fetch';
import useDownloadStream from '@/hooks/use-download-stream'; import useDownloadStream from '@/hooks/use-download-stream';
import { useBenchmarkTargetInstance } from '@/pages/llmodels/hooks/use-run-benchmark'; import { useBenchmarkTargetInstance } from '@/pages/llmodels/hooks/use-run-benchmark';
import { ListItem as WorkerListItem } from '@/pages/resources/config/types'; import { ListItem as WorkerListItem } from '@/pages/resources/config/types';
import useGranfanaLink from '@/pages/resources/hooks/use-grafana-link';
import { convertFileSize } from '@/utils'; import { convertFileSize } from '@/utils';
import { import {
DeleteOutlined, DeleteOutlined,
@@ -330,12 +329,6 @@ const childActionList = [
], ],
icon: <IconFont type="icon-logs" /> icon: <IconFont type="icon-logs" />
}, },
{
label: 'resources.metrics.details',
key: 'metrics',
status: [InstanceStatusMap.Running],
icon: <IconFont type="icon-metrics" />
},
{ {
label: 'common.button.downloadLog', label: 'common.button.downloadLog',
key: 'download', key: 'download',
@@ -438,7 +431,6 @@ const InstanceItem: React.FC<InstanceItemProps> = ({
handleChildSelect handleChildSelect
}) => { }) => {
const systemConfig = useAtomValue(systemConfigAtom); const systemConfig = useAtomValue(systemConfigAtom);
const { goToGrafana } = useGranfanaLink({ type: 'instance' });
const { runBenchmarkOnInstance } = useBenchmarkTargetInstance(); const { runBenchmarkOnInstance } = useBenchmarkTargetInstance();
const [api, contextHolder] = notification.useNotification({ const [api, contextHolder] = notification.useNotification({
stack: { threshold: 1 } stack: { threshold: 1 }
@@ -456,9 +448,6 @@ const InstanceItem: React.FC<InstanceItemProps> = ({
if (action.status && action.status.length > 0) { if (action.status && action.status.length > 0) {
return action.status.includes(instanceData.state); return action.status.includes(instanceData.state);
} }
if (action.key === 'metrics') {
return systemConfig.showMonitoring;
}
return true; return true;
}); });
}, [instanceData.state, modelData, systemConfig.showMonitoring]); }, [instanceData.state, modelData, systemConfig.showMonitoring]);
@@ -668,25 +657,27 @@ const InstanceItem: React.FC<InstanceItemProps> = ({
<InfoColumn fieldList={fieldList} data={offloadData}></InfoColumn> <InfoColumn fieldList={fieldList} data={offloadData}></InfoColumn>
} }
> >
<ThemeTag <span>
opacity={0.75} <ThemeTag
color="cyan" opacity={0.75}
style={{ color="cyan"
display: 'flex', style={{
alignItems: 'center', display: 'flex',
maxWidth: '100%', alignItems: 'center',
minWidth: 50, maxWidth: '100%',
textOverflow: 'ellipsis', minWidth: 50,
whiteSpace: 'nowrap', textOverflow: 'ellipsis',
overflow: 'hidden', whiteSpace: 'nowrap',
borderRadius: 12 overflow: 'hidden',
}} borderRadius: 12
> }}
<InfoCircleOutlined className="m-r-5" /> >
{intl.formatMessage({ <InfoCircleOutlined className="m-r-5" />
id: 'models.table.cpuoffload' {intl.formatMessage({
})} id: 'models.table.cpuoffload'
</ThemeTag> })}
</ThemeTag>
</span>
</Tooltip> </Tooltip>
); );
}, [ }, [
@@ -703,8 +694,6 @@ const InstanceItem: React.FC<InstanceItemProps> = ({
filename: createFileName(instanceData.name), filename: createFileName(instanceData.name),
downloadNotification downloadNotification
}); });
} else if (val === 'metrics') {
goToGrafana(instanceData);
} else { } else {
handleChildSelect(val, instanceData); handleChildSelect(val, instanceData);
} }
+4 -6
View File
@@ -13,11 +13,12 @@ import { PageActionType } from '@/config/types';
import useBodyScroll from '@/hooks/use-body-scroll'; import useBodyScroll from '@/hooks/use-body-scroll';
import useExpandedRowKeys from '@/hooks/use-expanded-row-keys'; import useExpandedRowKeys from '@/hooks/use-expanded-row-keys';
import useTableRowSelection from '@/hooks/use-table-row-selection'; import useTableRowSelection from '@/hooks/use-table-row-selection';
import useWatchList from '@/hooks/use-watch-list';
import PageBox from '@/pages/_components/page-box'; import PageBox from '@/pages/_components/page-box';
import useNoResourceResult from '@/pages/llmodels/hooks/use-no-resource-result'; import useNoResourceResult from '@/pages/llmodels/hooks/use-no-resource-result';
import { MODEL_ROUTE_TARGETS } from '@/pages/model-routes/apis';
import { TargetStatusValueMap } from '@/pages/model-routes/config'; import { TargetStatusValueMap } from '@/pages/model-routes/config';
import useOpenPlayground from '@/pages/model-routes/hooks/use-open-playground'; import useOpenPlayground from '@/pages/model-routes/hooks/use-open-playground';
import useQueryTargets from '@/pages/model-routes/services/use-query-targets';
import useGranfanaLink from '@/pages/resources/hooks/use-grafana-link'; import useGranfanaLink from '@/pages/resources/hooks/use-grafana-link';
import { handleBatchRequest } from '@/utils'; import { handleBatchRequest } from '@/utils';
import { DownOutlined, SearchOutlined, SyncOutlined } from '@ant-design/icons'; import { DownOutlined, SearchOutlined, SyncOutlined } from '@ant-design/icons';
@@ -166,11 +167,8 @@ const Models: React.FC<ModelsProps> = ({
useFilterStatus({ useFilterStatus({
onStatusChange: onStatusChange onStatusChange: onStatusChange
}); });
const { fetchData: fetchTargets, dataList: targetList } = useQueryTargets(); const { watchDataList: targetList } = useWatchList(MODEL_ROUTE_TARGETS);
useEffect(() => {
fetchTargets({});
}, []);
const { goToGrafana, ActionButton } = useGranfanaLink({ const { goToGrafana, ActionButton } = useGranfanaLink({
type: 'model', type: 'model',
dataList: dataSource || [] dataList: dataSource || []
@@ -554,7 +552,7 @@ const Models: React.FC<ModelsProps> = ({
sortOrder, sortOrder,
targetList: targetList targetList: targetList
}; };
}, [handleSelect, clusterList, sortOrder]); }, [handleSelect, clusterList, sortOrder, targetList]);
const columns = useModelsColumns(options); const columns = useModelsColumns(options);
@@ -275,6 +275,7 @@ const UpdateModal: React.FC<AddModalProps> = (props) => {
initialValues={formData} initialValues={formData}
source={formData.source || ''} source={formData.source || ''}
action={action} action={action}
realAction={realAction}
clusterList={clusterList} clusterList={clusterList}
onOk={handleOk} onOk={handleOk}
ref={formRef} ref={formRef}
@@ -33,47 +33,6 @@ interface ActionItem {
}; };
} }
export const ActionList: ActionItem[] = [
{
label: 'common.button.edit',
key: 'edit',
icon: icons.EditOutlined
},
{
label: 'models.openinplayground',
key: 'chat',
icon: icons.ExperimentOutlined
},
{
key: 'copy',
label: 'common.button.clone',
icon: icons.CopyOutlined
},
{
label: 'common.button.start',
key: 'start',
icon: icons.Play
},
{
label: 'common.button.stop',
key: 'stop',
icon: icons.Stop
},
{
label: 'resources.metrics.details',
key: 'metrics',
icon: icons.Metrics
},
{
label: 'common.button.delete',
key: 'delete',
props: {
danger: true
},
icon: icons.DeleteOutlined
}
];
export const ButtonList = [ export const ButtonList = [
{ {
label: 'common.button.start', label: 'common.button.start',
@@ -18,6 +18,7 @@ interface FormContextProps {
formKey: DeployFormKey; formKey: DeployFormKey;
source: string; source: string;
action: PageActionType; action: PageActionType;
realAction?: PageActionType;
gpuOptions: CascaderOption[]; gpuOptions: CascaderOption[];
workerLabelOptions: CascaderOption[]; workerLabelOptions: CascaderOption[];
backendOptions: { backendOptions: {
+34 -27
View File
@@ -1,6 +1,7 @@
import LabelSelector from '@/components/label-selector'; import LabelSelector from '@/components/label-selector';
import CheckboxField from '@/components/seal-form/checkbox-field'; import CheckboxField from '@/components/seal-form/checkbox-field';
import SealSelect from '@/components/seal-form/seal-select'; import SealSelect from '@/components/seal-form/seal-select';
import { PageAction } from '@/config';
import { useIntl } from '@umijs/max'; import { useIntl } from '@umijs/max';
import { Form } from 'antd'; import { Form } from 'antd';
import _ from 'lodash'; import _ from 'lodash';
@@ -19,6 +20,8 @@ const AdvanceConfig = () => {
const modelRouteEnable = Form.useWatch('enable_model_route', form); const modelRouteEnable = Form.useWatch('enable_model_route', form);
const { const {
onValuesChange, onValuesChange,
realAction,
action,
backendOptions, backendOptions,
flatBackendOptions, flatBackendOptions,
isGGUF, isGGUF,
@@ -133,33 +136,37 @@ const AdvanceConfig = () => {
})} })}
></CheckboxField> ></CheckboxField>
</Form.Item> </Form.Item>
<Form.Item<FormData> {realAction === PageAction.COPY || action === PageAction.CREATE ? (
name="enable_model_route" <>
valuePropName="checked" <Form.Item<FormData>
style={{ marginBottom: 8 }} name="enable_model_route"
> valuePropName="checked"
<CheckboxField style={{ marginBottom: 8 }}
label={intl.formatMessage({ >
id: 'models.form.enableModelRoute' <CheckboxField
})} label={intl.formatMessage({
></CheckboxField> id: 'models.form.enableModelRoute'
</Form.Item> })}
{modelRouteEnable && ( ></CheckboxField>
<Form.Item<FormData> </Form.Item>
name="generic_proxy" {modelRouteEnable && (
valuePropName="checked" <Form.Item<FormData>
style={{ marginBottom: 8 }} name="generic_proxy"
> valuePropName="checked"
<CheckboxField style={{ marginBottom: 8 }}
description={intl.formatMessage({ >
id: 'models.form.generic_proxy.tips' <CheckboxField
})} description={intl.formatMessage({
label={intl.formatMessage({ id: 'models.form.generic_proxy.tips'
id: 'models.form.generic_proxy' })}
})} label={intl.formatMessage({
></CheckboxField> id: 'models.form.generic_proxy'
</Form.Item> })}
)} ></CheckboxField>
</Form.Item>
)}
</>
) : null}
</> </>
); );
}; };
+3
View File
@@ -50,6 +50,7 @@ interface DataFormProps {
ref?: any; ref?: any;
source: SourceType; source: SourceType;
action: PageActionType; action: PageActionType;
realAction?: PageActionType;
isGGUF: boolean; isGGUF: boolean;
formKey: DeployFormKey; formKey: DeployFormKey;
sourceDisable?: boolean; sourceDisable?: boolean;
@@ -77,6 +78,7 @@ const DataForm: React.FC<DataFormProps> = forwardRef((props, ref) => {
isGGUF, isGGUF,
formKey, formKey,
source, source,
realAction,
initialValues, initialValues,
sourceDisable = true, sourceDisable = true,
sourceList, sourceList,
@@ -392,6 +394,7 @@ const DataForm: React.FC<DataFormProps> = forwardRef((props, ref) => {
formKey: formKey, formKey: formKey,
source: props.source, source: props.source,
action: action, action: action,
realAction: realAction,
gpuOptions: gpuOptions, gpuOptions: gpuOptions,
backendOptions: backendOptions, backendOptions: backendOptions,
flatBackendOptions: flatBackendOptions, flatBackendOptions: flatBackendOptions,
-6
View File
@@ -271,12 +271,6 @@ export const useCheckCompatibility = () => {
let compatibilityMessage = compatibility_messages.join(' '); let compatibilityMessage = compatibility_messages.join(' ');
compatibilityMessage = compatibilityMessage.startsWith(
'The model file path you specified does not exist on the GPUStack server'
)
? intl.formatMessage({ id: 'models.form.modelfile.notfound' })
: compatibilityMessage;
let msgData = { let msgData = {
title: scheduling_messages?.length > 0 ? compatibilityMessage : '', title: scheduling_messages?.length > 0 ? compatibilityMessage : '',
message: message:
@@ -2,8 +2,10 @@
import { systemConfigAtom } from '@/atoms/system'; import { systemConfigAtom } from '@/atoms/system';
import AutoTooltip from '@/components/auto-tooltip'; import AutoTooltip from '@/components/auto-tooltip';
import DropdownButtons from '@/components/drop-down-buttons'; import DropdownButtons from '@/components/drop-down-buttons';
import icons from '@/components/icon-font/icons';
import { SealColumnProps } from '@/components/seal-table/types'; import { SealColumnProps } from '@/components/seal-table/types';
import { OPENAI_COMPATIBLE, tableSorter } from '@/config/settings'; import { OPENAI_COMPATIBLE, tableSorter } from '@/config/settings';
import GrafanaIcon from '@/pages/_components/grafana-icon';
import { TargetStatusValueMap } from '@/pages/model-routes/config'; import { TargetStatusValueMap } from '@/pages/model-routes/config';
import { QuestionCircleOutlined } from '@ant-design/icons'; import { QuestionCircleOutlined } from '@ant-design/icons';
import { useIntl } from '@umijs/max'; import { useIntl } from '@umijs/max';
@@ -14,9 +16,63 @@ import { useAtomValue } from 'jotai';
import _ from 'lodash'; import _ from 'lodash';
import { useMemo } from 'react'; import { useMemo } from 'react';
import ModelTag from '../../_components/model-tag'; import ModelTag from '../../_components/model-tag';
import { ActionList, generateSource } from '../config/button-actions'; import { generateSource } from '../config/button-actions';
import { ListItem } from '../config/types'; import { ListItem } from '../config/types';
interface ActionItem {
label: string;
key: string;
icon: React.ReactNode;
props?: {
danger?: boolean;
};
}
const ActionList: ActionItem[] = [
{
label: 'common.button.edit',
key: 'edit',
icon: icons.EditOutlined
},
{
label: 'models.openinplayground',
key: 'chat',
icon: icons.ExperimentOutlined
},
{
label: 'common.button.start',
key: 'start',
icon: icons.Play
},
{
label: 'common.button.stop',
key: 'stop',
icon: icons.Stop
},
{
label: 'resources.metrics.details',
key: 'metrics',
icon: (
<span className="flex-center">
<GrafanaIcon style={{ width: 14, height: 14 }}></GrafanaIcon>
</span>
)
},
{
key: 'copy',
label: 'common.button.clone',
icon: icons.CopyOutlined
},
{
label: 'common.button.delete',
key: 'delete',
props: {
danger: true
},
icon: icons.DeleteOutlined
}
];
interface ModelsColumnsHookProps { interface ModelsColumnsHookProps {
handleSelect: (val: string, record: ListItem) => void; handleSelect: (val: string, record: ListItem) => void;
sortOrder: string[]; sortOrder: string[];
+21 -19
View File
@@ -102,7 +102,7 @@ const useGPUColumns = (props: {
sorter: tableSorter(6), sorter: tableSorter(6),
render: (text: number, record: GPUDeviceItem) => { render: (text: number, record: GPUDeviceItem) => {
return ( return (
<> <span className="flex-center flex-full">
{record.core ? ( {record.core ? (
<ProgressBar <ProgressBar
percent={_.round(record.core?.utilization_rate, 2)} percent={_.round(record.core?.utilization_rate, 2)}
@@ -110,7 +110,7 @@ const useGPUColumns = (props: {
) : ( ) : (
'-' '-'
)} )}
</> </span>
); );
} }
}, },
@@ -121,23 +121,25 @@ const useGPUColumns = (props: {
sorter: tableSorter(7), sorter: tableSorter(7),
render: (text: number, record: GPUDeviceItem, index: number) => { render: (text: number, record: GPUDeviceItem, index: number) => {
return ( return (
<ProgressBar <span className="flex-center flex-full">
defaultOpen={index === 0 && loadend && firstLoad} <ProgressBar
percent={ defaultOpen={index === 0 && loadend && firstLoad}
record.memory?.used percent={
? _.round(record.memory?.utilization_rate, 0) record.memory?.used
: _.round( ? _.round(record.memory?.utilization_rate, 0)
record.memory?.allocated / record.memory?.total, : _.round(
0 record.memory?.allocated / record.memory?.total,
) * 100 0
} ) * 100
label={ }
<InfoColumn label={
fieldList={fieldList} <InfoColumn
data={record.memory} fieldList={fieldList}
></InfoColumn> data={record.memory}
} ></InfoColumn>
></ProgressBar> }
></ProgressBar>
</span>
); );
} }
} }
@@ -1,13 +1,13 @@
import { systemConfigAtom } from '@/atoms/system'; import { systemConfigAtom } from '@/atoms/system';
import IconFont from '@/components/icon-font';
import { GPUSTACK_API_BASE_URL } from '@/config/settings'; import { GPUSTACK_API_BASE_URL } from '@/config/settings';
import GrafanaIcon from '@/pages/_components/grafana-icon';
import { useIntl } from '@umijs/max'; import { useIntl } from '@umijs/max';
import { Button } from 'antd'; import { Button } from 'antd';
import { useAtomValue } from 'jotai'; import { useAtomValue } from 'jotai';
const useGranfanaLink = (options: { const useGranfanaLink = (options: {
type: 'model' | 'worker' | 'instance' | 'cluster'; type: 'model' | 'worker' | 'instance' | 'cluster';
dataList: any[]; dataList?: any[];
}) => { }) => {
const intl = useIntl(); const intl = useIntl();
const systemConfig = useAtomValue(systemConfigAtom); const systemConfig = useAtomValue(systemConfigAtom);
@@ -53,7 +53,7 @@ const useGranfanaLink = (options: {
}; };
const handleClick = () => { const handleClick = () => {
if (options.dataList?.length > 0) { if (options.dataList && options.dataList.length > 0) {
goToGrafana(options.dataList?.[0]); goToGrafana(options.dataList?.[0]);
} }
}; };
@@ -63,7 +63,7 @@ const useGranfanaLink = (options: {
return ( return (
<Button <Button
onClick={handleClick} onClick={handleClick}
icon={<IconFont type="icon-metrics" style={{ fontSize: 16 }} />} icon={<GrafanaIcon style={{ width: 16, height: 16 }}></GrafanaIcon>}
> >
{intl.formatMessage({ id: 'resources.metrics.details' })} {intl.formatMessage({ id: 'resources.metrics.details' })}
</Button> </Button>
@@ -1,12 +1,12 @@
import { systemConfigAtom } from '@/atoms/system'; import { systemConfigAtom } from '@/atoms/system';
import AutoTooltip from '@/components/auto-tooltip'; import AutoTooltip from '@/components/auto-tooltip';
import DropdownButtons from '@/components/drop-down-buttons'; import DropdownButtons from '@/components/drop-down-buttons';
import IconFont from '@/components/icon-font';
import LabelsCell from '@/components/label-cell'; import LabelsCell from '@/components/label-cell';
import ProgressBar from '@/components/progress-bar'; import ProgressBar from '@/components/progress-bar';
import InfoColumn from '@/components/simple-table/info-column'; import InfoColumn from '@/components/simple-table/info-column';
import StatusTag from '@/components/status-tag'; import StatusTag from '@/components/status-tag';
import { tableSorter } from '@/config/settings'; import { tableSorter } from '@/config/settings';
import GrafanaIcon from '@/pages/_components/grafana-icon';
import { convertFileSize } from '@/utils'; import { convertFileSize } from '@/utils';
import { import {
DeleteOutlined, DeleteOutlined,
@@ -48,7 +48,11 @@ const ActionList = [
{ {
label: 'resources.metrics.details', label: 'resources.metrics.details',
key: 'metrics', key: 'metrics',
icon: <IconFont type="icon-metrics" /> icon: (
<span className="flex-center">
<GrafanaIcon style={{ width: 14, height: 14 }}></GrafanaIcon>
</span>
)
}, },
// { // {
// label: 'common.button.detail', // label: 'common.button.detail',
@@ -123,7 +127,10 @@ const GPUCell = ({ devices }: { devices: GPUDeviceItem[] }) => (
_.sortBy(devices || [], ['index']), _.sortBy(devices || [], ['index']),
(item: GPUDeviceItem, index: number) => ( (item: GPUDeviceItem, index: number) => (
<span className="flex-center" key={index}> <span className="flex-center" key={index}>
<span className="m-r-5" style={{ display: 'flex', width: 25 }}> <span
className="m-r-5"
style={{ display: 'flex', width: 25, lineHeight: 1 }}
>
[{item.index}] [{item.index}]
</span> </span>
{item.core ? ( {item.core ? (
@@ -155,7 +162,10 @@ const VRAMCell = ({
_.sortBy(devices || [], ['index']), _.sortBy(devices || [], ['index']),
(item: GPUDeviceItem, index: number) => ( (item: GPUDeviceItem, index: number) => (
<span key={index} className="flex-center"> <span key={index} className="flex-center">
<span className="m-r-5" style={{ display: 'flex', width: 25 }}> <span
className="m-r-5"
style={{ display: 'flex', width: 25, lineHeight: 1 }}
>
[{item.index}] [{item.index}]
</span> </span>
<ProgressBar <ProgressBar
@@ -343,33 +353,42 @@ const useWorkerColumns = ({
title: 'CPU', title: 'CPU',
dataIndex: 'status.cpu.utilization_rate', dataIndex: 'status.cpu.utilization_rate',
sorter: tableSorter(4), sorter: tableSorter(4),
render: (text: string, record) => render: (text: string, record) => (
statusAvailable(record) ? ( <span className="flex-center flex-full">
<ProgressBar {statusAvailable(record) ? (
percent={_.round(record?.status?.cpu?.utilization_rate, 0)} <ProgressBar
/> percent={_.round(record?.status?.cpu?.utilization_rate, 0)}
) : ( />
<HolderStatus /> ) : (
) <HolderStatus />
)}
</span>
)
}, },
{ {
title: intl.formatMessage({ id: 'resources.table.memory' }), title: intl.formatMessage({ id: 'resources.table.memory' }),
dataIndex: 'status.memory.utilization_rate', dataIndex: 'status.memory.utilization_rate',
sorter: tableSorter(5), sorter: tableSorter(5),
render: (_, record) => render: (_, record) => (
statusAvailable(record) ? ( <span className="flex-center flex-full">
<ProgressBar {statusAvailable(record) ? (
percent={formateUtilization( <ProgressBar
record?.status?.memory?.used, percent={formateUtilization(
record?.status?.memory?.total record?.status?.memory?.used,
)} record?.status?.memory?.total
label={ )}
<InfoColumn fieldList={fieldList} data={record.status.memory} /> label={
} <InfoColumn
/> fieldList={fieldList}
) : ( data={record.status.memory}
<HolderStatus /> />
) }
/>
) : (
<HolderStatus />
)}
</span>
)
}, },
{ {
title: 'GPU', title: 'GPU',
@@ -400,12 +419,15 @@ const useWorkerColumns = ({
{ {
title: intl.formatMessage({ id: 'resources.table.disk' }), title: intl.formatMessage({ id: 'resources.table.disk' }),
dataIndex: 'storage', dataIndex: 'storage',
render: (_, record) => render: (_, record) => (
statusAvailable(record) ? ( <span className="flex-center flex-full">
<StorageCell files={record.status?.filesystem} /> {statusAvailable(record) ? (
) : ( <StorageCell files={record.status?.filesystem} />
<HolderStatus /> ) : (
) <HolderStatus />
)}
</span>
)
}, },
{ {
title: intl.formatMessage({ id: 'common.table.operation' }), title: intl.formatMessage({ id: 'common.table.operation' }),