feat: show the worker version

This commit is contained in:
jialin
2026-03-31 15:05:38 +08:00
committed by jialin
parent 0b292829fa
commit 06160546a6
17 changed files with 221 additions and 106 deletions
+5 -34
View File
@@ -4,38 +4,9 @@ import InfiniteScroller from '@/pages/_components/infinite-scroller';
import { useScrollerContext } from '@/pages/_components/infinite-scroller/use-scroller-context';
import { Spin } from 'antd';
import React from 'react';
import styled from 'styled-components';
import backendListCss from '../styles/backend-list.less';
import BackendCard from './backend-card';
const SpinWrapper = styled.div`
width: 100%;
position: absolute;
display: flex;
align-items: center;
justify-content: center;
top: 0;
left: 0;
max-height: 400px;
right: 0;
.skelton-wrapper {
width: 100%;
}
`;
const SkeletonWrapper = styled.div`
.ant-skeleton-content {
.ant-skeleton-paragraph {
display: flex;
flex-direction: column;
gap: 16px;
margin-bottom: 0;
li {
margin-top: 0 !important;
}
}
}
`;
interface BackendListProps {
defaultSpan?: number;
resizable?: boolean;
@@ -54,7 +25,7 @@ const ListSkeleton: React.FC<{
return (
<div>
{loading && (
<SpinWrapper>
<div className={backendListCss.SpinWrapper}>
<Spin
spinning={loading}
size="middle"
@@ -66,7 +37,7 @@ const ListSkeleton: React.FC<{
}}
>
{isFirst && (
<SkeletonWrapper>
<div className={backendListCss.SkeletonWrapper}>
<CardSkeleton
skeletonProps={{
title: false
@@ -77,10 +48,10 @@ const ListSkeleton: React.FC<{
gap: 24
}}
></CardSkeleton>
</SkeletonWrapper>
</div>
)}
</Spin>
</SpinWrapper>
</div>
)}
</div>
);
@@ -0,0 +1,34 @@
.SpinWrapper {
width: 100%;
position: absolute;
display: flex;
align-items: center;
justify-content: center;
top: 0;
left: 0;
max-height: 400px;
right: 0;
:global {
.skelton-wrapper {
width: 100%;
}
}
}
.SkeletonWrapper {
:global {
.ant-skeleton-content {
.ant-skeleton-paragraph {
display: flex;
flex-direction: column;
gap: 16px;
margin-bottom: 0;
li {
margin-top: 0 !important;
}
}
}
}
}
@@ -37,10 +37,10 @@ const WorkerInfoContent: React.FC<NameCellProps> = ({ record, modelData }) => {
<div className="flex-center">
<IconFont
type="icon-filled-gpu"
className="m-r-5 text-tertiary"
className="m-r-5 text-quaternary"
style={{ fontSize: 12 }}
/>
<span className="text-tertiary">
<span className="text-quaternary">
GPU:[
{_.join(
record.gpu_indexes?.sort?.((a, b) => a - b),
@@ -115,10 +115,10 @@ const useProviderColumns = (options: {
></NameCell>
<div className="flex-center">
<ThunderboltFilled
className="m-r-5 text-tertiary"
style={{ fontSize: 12 }}
className="m-r-5 text-quaternary"
style={{ fontSize: 12, position: 'relative', top: 2 }}
/>
<span className="text-tertiary">
<span className="text-quaternary">
{record?.backend || record?.backend || ''}
{record.backend_version || record?.backend_version
? `(${record.backend_version || record?.backend_version})`
@@ -279,6 +279,7 @@ const Workers = () => {
sortDirections={TABLE_SORT_DIRECTIONS}
showSorterTooltip={false}
tableLayout={'auto'}
className={'scroll-table'}
dataSource={dataSource.dataList}
loading={{
spinning: dataSource.loading,
+1
View File
@@ -69,6 +69,7 @@ export interface ListItem {
ssh_key_id: string;
advertise_address: string;
provision_progress: string;
worker_version: string;
maintenance: {
enabled: boolean;
message: string;
@@ -1,6 +1,8 @@
import { systemConfigAtom } from '@/atoms/system';
import { GPUStackVersionAtom } from '@/atoms/user';
import AutoTooltip from '@/components/auto-tooltip';
import DropdownButtons from '@/components/drop-down-buttons';
import IconFont from '@/components/icon-font';
import LabelsCell from '@/components/label-cell';
import ProgressBar from '@/components/progress-bar';
import InfoColumn from '@/components/simple-table/info-column';
@@ -17,31 +19,16 @@ import {
ToolOutlined
} from '@ant-design/icons';
import { useIntl } from '@umijs/max';
import { Tooltip } from 'antd';
import { Tag, Tooltip } from 'antd';
import { ColumnsType } from 'antd/lib/table';
import { useAtomValue } from 'jotai';
import { useAtom, useAtomValue } from 'jotai';
import _ from 'lodash';
import { useMemo } from 'react';
import styled from 'styled-components';
import semverCoerce from 'semver/functions/coerce';
import semverGt from 'semver/functions/gt';
import { status, WorkerStatusMap, WorkerStatusMapValue } from '../config';
import { Filesystem, GPUDeviceItem, ListItem } from '../config/types';
const IPWrapper = styled.span`
display: flex;
flex-direction: column;
.item {
display: grid;
grid-template-columns: auto 1fr;
gap: 4px 8px;
.label {
text-align: right;
font-size: 13px;
display: flex;
align-items: center;
color: var(--ant-color-text-tertiary);
}
}
`;
import workerCss from '../styles/worker.less';
const ActionList = [
{ label: 'common.button.edit', key: 'edit', icon: <EditOutlined /> },
@@ -110,6 +97,16 @@ const fieldList = [
}
];
const showUpgrade = (
workerVersion: string,
currentVersion: string
): boolean => {
const w_ver = semverCoerce(workerVersion);
const c_ver = semverCoerce(currentVersion);
return !!w_ver && !!c_ver && semverGt(c_ver, w_ver);
};
const formateUtilization = (val1: number, val2: number): number =>
val1 && val2 ? _.round((val1 / val2) * 100, 0) : 0;
@@ -248,6 +245,9 @@ const useWorkerColumns = ({
}): ColumnsType<ListItem> => {
const intl = useIntl();
const systemConfig = useAtomValue(systemConfigAtom);
const [version] = useAtom(GPUStackVersionAtom);
console.log('version in useWorkerColumns', version);
const renderIP = (text: string, record: ListItem) => {
if (record.advertise_address === record.ip) {
@@ -260,14 +260,14 @@ const useWorkerColumns = ({
record.ip
) {
return (
<IPWrapper>
<span className={workerCss.ipWrapper}>
<span className="item">
<span>{record.ip}</span>
<span className="label">{`(${intl.formatMessage({ id: 'clusters.table.ip.internal' })})`}</span>
<span> {record.advertise_address}</span>
<span className="label">{`(${intl.formatMessage({ id: 'clusters.table.ip.external' })})`}</span>
</span>
</IPWrapper>
</span>
);
}
return record.ip || record.advertise_address || '';
@@ -297,12 +297,30 @@ const useWorkerColumns = ({
{
title: intl.formatMessage({ id: 'common.table.name' }),
dataIndex: 'name',
width: 100,
width: 140,
sorter: tableSorter(1),
render: (text: string) => (
<AutoTooltip ghost maxWidth={200}>
{text}
</AutoTooltip>
render: (text: string, record: ListItem) => (
<div className={workerCss.name}>
<AutoTooltip ghost maxWidth={200}>
<span className="name-text">{text}</span>
</AutoTooltip>
<div className={workerCss['worker-version']}>
<AutoTooltip
ghost
showTitle={showUpgrade(record.worker_version, version.version)}
title={intl.formatMessage({
id: 'resoureces.worker.upgrade.tips'
})}
>
<Tag className="version-tag" variant="outlined">
{version.version}
{showUpgrade(record.worker_version, version.version) && (
<IconFont type="icon-upgrade"></IconFont>
)}
</Tag>
</AutoTooltip>
</div>
</div>
)
},
{
+52
View File
@@ -0,0 +1,52 @@
.name {
display: flex;
flex-direction: column;
gap: 4px;
.worker-version {
color: var(--ant-color-text-tertiary);
display: flex;
align-items: center;
font-size: 12px;
gap: 4px;
:global(.anticon) {
color: var(--ant-color-warning);
font-size: 14px;
}
:global {
.version-tag {
display: flex;
align-items: center;
gap: 4px;
font-size: 12px;
height: auto;
border-radius: 4px;
line-height: unset;
background-color: unset;
color: var(--ant-color-text-quaternary);
border: 1px solid var(--ant-color-split);
}
}
}
}
.ipWrapper {
display: flex;
flex-direction: column;
.item {
display: grid;
grid-template-columns: auto 1fr;
gap: 4px 8px;
.label {
text-align: right;
font-size: 13px;
display: flex;
align-items: center;
color: var(--ant-color-text-tertiary);
}
}
}