feat: monitor button

This commit is contained in:
jialin
2026-02-04 20:14:25 +08:00
parent 47596fdb1a
commit 4e8b5e26ae
40 changed files with 352 additions and 176 deletions
@@ -0,0 +1,50 @@
import { DeleteOutlined, PlusOutlined } from '@ant-design/icons';
import { useIntl } from '@umijs/max';
import { Button, Space } from 'antd';
import React from 'react';
export interface WorkerRightActionsProps {
handleDeleteByBatch: () => void;
handleClickPrimary?: () => void;
MonitorButton?: React.ReactNode;
rowSelection: {
selectedRowKeys: React.Key[];
};
}
const WorkerRightActions: React.FC<WorkerRightActionsProps> = ({
handleDeleteByBatch,
handleClickPrimary,
rowSelection,
MonitorButton
}) => {
const intl = useIntl();
return (
<Space size={16}>
{MonitorButton}
<Button
icon={<PlusOutlined />}
type="primary"
onClick={handleClickPrimary}
>
{intl.formatMessage({ id: 'resources.button.create' })}
</Button>
<Button
icon={<DeleteOutlined />}
danger
onClick={handleDeleteByBatch}
disabled={!rowSelection?.selectedRowKeys?.length}
>
<span>
{intl.formatMessage({ id: 'common.button.delete' })}
{rowSelection?.selectedRowKeys?.length > 0 && (
<span>({rowSelection?.selectedRowKeys?.length})</span>
)}
</span>
</Button>
</Space>
);
};
export default WorkerRightActions;
+14 -2
View File
@@ -25,6 +25,7 @@ import useWorkerColumns from '../hooks/use-worker-columns';
import useWorkerMaintenance from '../hooks/use-worker-maintenance';
import UpdateLabels from './update-labels';
import WorkerDetailModal from './worker-detail-modal';
import WorkerRightActions from './worker-right-actions';
const Workers: React.FC<{
clusterId?: string | number | null;
@@ -65,7 +66,10 @@ const Workers: React.FC<{
cluster_id: clusterId
}
});
const { goToGrafana } = useGranfanaLink({ type: 'worker' });
const { goToGrafana, ActionButton } = useGranfanaLink({
type: 'worker',
dataList: dataSource.dataList || []
});
const { MaintenanceModal, handleStopMaintenance, setOpenStatus } =
useWorkerMaintenance({ fetchData: handleSearch });
@@ -268,11 +272,19 @@ const Workers: React.FC<{
handleDeleteByBatch={handleDeleteBatch}
handleSearch={handleSearch}
handleSelectChange={handleClusterChange}
handleClickPrimary={showAddButton ? handleOnAddWorker : undefined}
handleClickPrimary={handleOnAddWorker}
handleInputChange={handleNameChange}
rowSelection={rowSelection}
selectOptions={clusterData.list}
widths={widths}
right={
<WorkerRightActions
handleDeleteByBatch={handleDeleteBatch}
handleClickPrimary={handleOnAddWorker}
rowSelection={rowSelection}
MonitorButton={ActionButton()}
></WorkerRightActions>
}
></FilterBar>
<ConfigProvider renderEmpty={renderEmpty}>
<Table
+1 -2
View File
@@ -223,8 +223,7 @@ const setWorkerIPArg = (params: any) => {
const setImageArgs = (params: any) => {
return `${params.image} \\
--server-url ${params.server} \\
${generateExtraArgs(params)}`;
--server-url ${params.server} \\`;
};
// avaliable for NVIDIA、MThreads
@@ -1,44 +0,0 @@
import { GPUSTACK_API_BASE_URL } from '@/config/settings';
// 1. /grafana/d/gpustack-model/gpustack-model
// 2. /grafana/d/gpustack-worker/gpustack-worker
const useGranfanaLink = (options: {
type: 'model' | 'worker' | 'instance';
}) => {
const goToModelGrafana = (row: { id: number }) => {
window.open(
`/${GPUSTACK_API_BASE_URL}/models/${row.id}/dashboard`,
'_blank'
);
};
const goToWorkerGrafana = (row: { id: number }) => {
window.open(
`/${GPUSTACK_API_BASE_URL}/workers/${row.id}/dashboard`,
'_blank'
);
};
const goToInstanceGrafana = (row: { id: number }) => {
window.open(
`/${GPUSTACK_API_BASE_URL}/model-instances/${row.id}/dashboard`,
'_blank'
);
};
const goToGrafana = (row: { id: number }) => {
if (options.type === 'model') {
goToModelGrafana(row);
} else if (options.type === 'worker') {
goToWorkerGrafana(row);
} else if (options.type === 'instance') {
goToInstanceGrafana(row);
}
};
return {
goToGrafana
};
};
export default useGranfanaLink;
@@ -0,0 +1,81 @@
import { systemConfigAtom } from '@/atoms/system';
import IconFont from '@/components/icon-font';
import { GPUSTACK_API_BASE_URL } from '@/config/settings';
import { useIntl } from '@umijs/max';
import { Button } from 'antd';
import { useAtomValue } from 'jotai';
const useGranfanaLink = (options: {
type: 'model' | 'worker' | 'instance' | 'cluster';
dataList: any[];
}) => {
const intl = useIntl();
const systemConfig = useAtomValue(systemConfigAtom);
const goToModelGrafana = (row: { id: number }) => {
window.open(
`/${GPUSTACK_API_BASE_URL}/models/${row.id}/dashboard`,
'_blank'
);
};
const goToWorkerGrafana = (row: { id: number }) => {
window.open(
`/${GPUSTACK_API_BASE_URL}/workers/${row.id}/dashboard`,
'_blank'
);
};
const goToInstanceGrafana = (row: { id: number }) => {
window.open(
`/${GPUSTACK_API_BASE_URL}/model-instances/${row.id}/dashboard`,
'_blank'
);
};
const goToClusterGrafana = (row: { id: number }) => {
window.open(
`/${GPUSTACK_API_BASE_URL}/clusters/${row.id}/dashboard`,
'_blank'
);
};
const goToGrafana = (row: { id: number }) => {
if (options.type === 'model') {
goToModelGrafana(row);
} else if (options.type === 'worker') {
goToWorkerGrafana(row);
} else if (options.type === 'instance') {
goToInstanceGrafana(row);
} else if (options.type === 'cluster') {
goToClusterGrafana(row);
}
};
const handleClick = () => {
if (options.dataList?.length > 0) {
goToGrafana(options.dataList?.[0]);
}
};
const ActionButton = () => {
if (systemConfig?.showMonitoring) {
return (
<Button
onClick={handleClick}
icon={<IconFont type="icon-metrics" style={{ fontSize: 16 }} />}
>
{intl.formatMessage({ id: 'resources.metrics.details' })}
</Button>
);
}
return null;
};
return {
goToGrafana,
ActionButton
};
};
export default useGranfanaLink;
@@ -1,3 +1,4 @@
import { systemConfigAtom } from '@/atoms/system';
import AutoTooltip from '@/components/auto-tooltip';
import DropdownButtons from '@/components/drop-down-buttons';
import IconFont from '@/components/icon-font';
@@ -18,6 +19,7 @@ import {
import { useIntl } from '@umijs/max';
import { Tooltip } from 'antd';
import { ColumnsType } from 'antd/lib/table';
import { useAtomValue } from 'jotai';
import _ from 'lodash';
import { useMemo } from 'react';
import styled from 'styled-components';
@@ -83,21 +85,6 @@ const ActionList = [
}
];
const setActions = (row: ListItem) => {
return ActionList.filter((action) => {
if (action.key === 'download_ssh_key') {
return !!row.ssh_key_id;
}
if (action.key === 'star_maintenance') {
return !row.maintenance?.enabled;
}
if (action.key === 'stop_maintenance') {
return row.maintenance?.enabled;
}
return true;
});
};
const fieldList = [
{
label: 'resources.table.total',
@@ -252,6 +239,7 @@ const useWorkerColumns = ({
handleSelect: (action: string, record: ListItem) => void;
}): ColumnsType<ListItem> => {
const intl = useIntl();
const systemConfig = useAtomValue(systemConfigAtom);
const renderIP = (text: string, record: ListItem) => {
if (record.advertise_address === record.ip) {
@@ -277,6 +265,25 @@ const useWorkerColumns = ({
return record.ip || record.advertise_address || '';
};
const setActions = (row: ListItem) => {
return ActionList.filter((action) => {
if (action.key === 'download_ssh_key') {
return !!row.ssh_key_id;
}
if (action.key === 'star_maintenance') {
return !row.maintenance?.enabled;
}
if (action.key === 'stop_maintenance') {
return row.maintenance?.enabled;
}
if (action.key === 'metrics') {
return systemConfig.showMonitoring;
}
return true;
});
};
return useMemo<ColumnsType<ListItem>>(
() => [
{