feat: show the worker version
This commit is contained in:
@@ -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,
|
||||
|
||||
@@ -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>
|
||||
)
|
||||
},
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user