Browse Source

Merge pull request '合并dev-zw' (#138) from dev-zw into dev

dev-lc
cp3hnu 1 year ago
parent
commit
3178853faa
40 changed files with 943 additions and 236 deletions
  1. +1
    -0
      react-ui/.npmrc
  2. +2
    -2
      react-ui/package.json
  3. BIN
      react-ui/src/assets/img/code-name-icon.png
  4. BIN
      react-ui/src/assets/img/creatBy.png
  5. BIN
      react-ui/src/assets/img/robot.png
  6. BIN
      react-ui/src/assets/img/total-icon.png
  7. +0
    -5
      react-ui/src/components/BasicInfo/index.less
  8. +5
    -8
      react-ui/src/components/BasicInfo/index.tsx
  9. +1
    -5
      react-ui/src/components/BasicTableInfo/index.less
  10. +1
    -1
      react-ui/src/components/KFModal/index.less
  11. +1
    -0
      react-ui/src/enums/pagesEnums.ts
  12. +1
    -1
      react-ui/src/hooks/index.ts
  13. +1
    -1
      react-ui/src/overrides.less
  14. +37
    -38
      react-ui/src/pages/CodeConfig/List/index.less
  15. +51
    -39
      react-ui/src/pages/CodeConfig/List/index.tsx
  16. +60
    -23
      react-ui/src/pages/CodeConfig/components/CodeConfigItem/index.less
  17. +15
    -8
      react-ui/src/pages/CodeConfig/components/CodeConfigItem/index.tsx
  18. +24
    -21
      react-ui/src/pages/Dataset/components/ResourceItem/index.less
  19. +0
    -1
      react-ui/src/pages/Dataset/components/ResourceList/index.less
  20. +1
    -0
      react-ui/src/pages/Dataset/components/ResourceList/index.tsx
  21. +6
    -1
      react-ui/src/pages/DevelopmentEnvironment/List/index.tsx
  22. +27
    -0
      react-ui/src/pages/Experiment/Comparison/index.less
  23. +58
    -53
      react-ui/src/pages/Experiment/Comparison/index.tsx
  24. +1
    -1
      react-ui/src/pages/Experiment/components/AddExperimentModal/index.tsx
  25. +1
    -1
      react-ui/src/pages/Experiment/components/ExperimentInstance/index.less
  26. +2
    -1
      react-ui/src/pages/Experiment/components/ExperimentInstance/index.tsx
  27. +1
    -1
      react-ui/src/pages/Experiment/components/TensorBoardStatus/index.less
  28. +6
    -1
      react-ui/src/pages/Mirror/Info/index.tsx
  29. +6
    -1
      react-ui/src/pages/Mirror/List/index.tsx
  30. +17
    -9
      react-ui/src/pages/Model/components/ModelMetrics/index.tsx
  31. +6
    -1
      react-ui/src/pages/ModelDeployment/List/index.tsx
  32. +38
    -3
      react-ui/src/pages/ModelDeployment/ServiceInfo/index.tsx
  33. +117
    -0
      react-ui/src/pages/ModelDeployment/components/VersionCompareModal/index.less
  34. +197
    -0
      react-ui/src/pages/ModelDeployment/components/VersionCompareModal/index.tsx
  35. +0
    -4
      react-ui/src/pages/Pipeline/components/CodeSelectorModal/index.less
  36. +1
    -0
      react-ui/src/pages/Pipeline/components/CodeSelectorModal/index.tsx
  37. +4
    -6
      react-ui/src/pages/Workspace/index.less
  38. +8
    -0
      react-ui/src/services/modelDeployment/index.ts
  39. +223
    -0
      react-ui/src/services/typings.d.ts
  40. +23
    -0
      react-ui/src/utils/index.ts

+ 1
- 0
react-ui/.npmrc View File

@@ -0,0 +1 @@
save-prefix=~

+ 2
- 2
react-ui/package.json View File

@@ -60,7 +60,7 @@
"@antv/hierarchy": "^0.6.12", "@antv/hierarchy": "^0.6.12",
"@types/crypto-js": "^4.2.2", "@types/crypto-js": "^4.2.2",
"@umijs/route-utils": "^4.0.1", "@umijs/route-utils": "^4.0.1",
"antd": "^5.4.4",
"antd": "~5.21.4",
"classnames": "^2.3.2", "classnames": "^2.3.2",
"crypto-js": "^4.2.0", "crypto-js": "^4.2.0",
"echarts": "^5.5.0", "echarts": "^5.5.0",
@@ -111,7 +111,7 @@
"umi-presets-pro": "^2.0.0" "umi-presets-pro": "^2.0.0"
}, },
"engines": { "engines": {
"node": ">=12.0.0"
"node": ">=16.14.0"
}, },
"create-umi": { "create-umi": {
"ignoreScript": [ "ignoreScript": [


BIN
react-ui/src/assets/img/code-name-icon.png View File

Before After
Width: 48  |  Height: 48  |  Size: 2.2 kB

BIN
react-ui/src/assets/img/creatBy.png View File

Before After
Width: 48  |  Height: 48  |  Size: 1.6 kB Width: 48  |  Height: 48  |  Size: 1.7 kB

BIN
react-ui/src/assets/img/robot.png View File

Before After
Width: 128  |  Height: 128  |  Size: 1.8 kB Width: 222  |  Height: 222  |  Size: 15 kB

BIN
react-ui/src/assets/img/total-icon.png View File

Before After
Width: 72  |  Height: 72  |  Size: 4.1 kB

+ 0
- 5
react-ui/src/components/BasicInfo/index.less View File

@@ -38,13 +38,8 @@
margin-left: 16px; margin-left: 16px;
font-size: @font-size-content; font-size: @font-size-content;
line-height: 1.6; line-height: 1.6;
white-space: pre-line;
word-break: break-all; word-break: break-all;


&--ellipsis {
.singleLine();
}

&__text { &__text {
color: @text-color; color: @text-color;
} }


+ 5
- 8
react-ui/src/components/BasicInfo/index.tsx View File

@@ -120,13 +120,10 @@ export function BasicInfoItemValue({
} }


return ( return (
<Typography.Text
className={classNames(myClassName, {
[`${myClassName}--ellipsis`]: ellipsis,
})}
ellipsis={{ tooltip: value }}
>
{component}
</Typography.Text>
<div className={myClassName}>
<Typography.Text ellipsis={ellipsis ? { tooltip: value } : false}>
{component}
</Typography.Text>
</div>
); );
} }

+ 1
- 5
react-ui/src/components/BasicTableInfo/index.less View File

@@ -33,10 +33,10 @@


&__value { &__value {
flex: 1; flex: 1;
min-width: 0;
margin: 0 !important; margin: 0 !important;
padding: 12px 20px 4px; padding: 12px 20px 4px;
font-size: @font-size; font-size: @font-size;
white-space: pre-line;
word-break: break-all; word-break: break-all;


& + & { & + & {
@@ -47,10 +47,6 @@
padding-bottom: 12px; padding-bottom: 12px;
} }


&--ellipsis {
.singleLine();
}

&__text { &__text {
color: @text-color; color: @text-color;
} }


+ 1
- 1
react-ui/src/components/KFModal/index.less View File

@@ -20,7 +20,7 @@
height: 40px; height: 40px;
padding: 0 30px; padding: 0 30px;
font-size: @font-size-content; font-size: @font-size-content;
border-radius: 10px;
border-radius: 6px;
} }
.ant-btn-default { .ant-btn-default {
border-color: transparent; border-color: transparent;


+ 1
- 0
react-ui/src/enums/pagesEnums.ts View File

@@ -1,3 +1,4 @@
export enum PageEnum { export enum PageEnum {
LOGIN = '/user/login', LOGIN = '/user/login',
Authorize = '/authorize',
} }

+ 1
- 1
react-ui/src/hooks/index.ts View File

@@ -162,7 +162,7 @@ export const useCheck = <T>(list: T[]) => {
const [selected, setSelected] = useState<T[]>([]); const [selected, setSelected] = useState<T[]>([]);


const checked = useMemo(() => { const checked = useMemo(() => {
return selected.length === list.length;
return selected.length === list.length && selected.length > 0;
}, [selected, list]); }, [selected, list]);


const indeterminate = useMemo(() => { const indeterminate = useMemo(() => {


+ 1
- 1
react-ui/src/overrides.less View File

@@ -168,7 +168,7 @@
height: 40px; height: 40px;
padding: 0 30px; padding: 0 30px;
font-size: @font-size-content; font-size: @font-size-content;
border-radius: 10px;
border-radius: 6px;
} }
.ant-btn-default { .ant-btn-default {
border-color: transparent; border-color: transparent;


+ 37
- 38
react-ui/src/pages/CodeConfig/List/index.less View File

@@ -1,47 +1,46 @@
.code-config-list {
display: flex;
flex: 1;
flex-direction: column;
.code-config {
height: 100%; height: 100%;
height: 100%;
padding: 20px 0;
background: white;
box-shadow: 0px 3px 6px rgba(146, 146, 146, 0.09);


&__header {
&__list {
display: flex; display: flex;
align-items: center;
justify-content: space-between;
height: 32px;
margin-bottom: 30px;
padding: 0 30px;
color: @text-color;
font-size: 15px;
}
flex-direction: column;
height: calc(100% - 60px);
margin-top: 10px;
padding: 30px 30px 0;
background: white;
border-radius: 10px;
box-shadow: 0px 2px 12px rgba(180, 182, 191, 0.09);


&__content {
display: flex;
flex: 1;
flex-wrap: wrap;
gap: 20px;
align-content: flex-start;
width: 100%;
margin-bottom: 30px;
padding: 0 30px;
overflow-y: auto;
}
&__header {
display: flex;
align-items: center;
height: 32px;
color: @text-color;
font-size: 15px;
}


&__empty {
display: flex;
flex: 1;
align-items: center;
justify-content: center;
}
&__content {
display: flex;
flex: 1 1 0%;
flex-wrap: wrap;
gap: 20px;
align-content: flex-start;
width: 100%;
margin: 25px 0;
overflow-y: auto;
}

&__empty {
display: flex;
flex: 1;
align-items: center;
justify-content: center;
}


:global {
.ant-pagination {
margin-right: 30px;
text-align: right;
:global {
.ant-pagination {
margin-bottom: 25px;
}
} }
} }
} }

+ 51
- 39
react-ui/src/pages/CodeConfig/List/index.tsx View File

@@ -1,5 +1,12 @@
/*
* @Author: 赵伟
* @Date: 2024-10-10 09:55:12
* @Description: 代码配置
*/

import KFEmpty, { EmptyType } from '@/components/KFEmpty'; import KFEmpty, { EmptyType } from '@/components/KFEmpty';
import KFIcon from '@/components/KFIcon'; import KFIcon from '@/components/KFIcon';
import PageTitle from '@/components/PageTitle';
import { deleteCodeConfigReq, getCodeConfigListReq } from '@/services/codeConfig'; import { deleteCodeConfigReq, getCodeConfigListReq } from '@/services/codeConfig';
import { getGitUrl } from '@/utils'; import { getGitUrl } from '@/utils';
import { openAntdModal } from '@/utils/modal'; import { openAntdModal } from '@/utils/modal';
@@ -127,64 +134,69 @@ function CodeConfigList() {
}; };


return ( return (
<div className={styles['code-config-list']}>
<div className={styles['code-config-list__header']}>
<span>数据总数:{total} 个</span>
<div>
<div className={styles['code-config']}>
<PageTitle title="代码配置"></PageTitle>
<div className={styles['code-config__list']}>
<div className={styles['code-config__list__header']}>
<span>数据总数:{total} 个</span>
<Input.Search <Input.Search
placeholder="按代码仓库名称筛选" placeholder="按代码仓库名称筛选"
allowClear allowClear
onSearch={handleSearch} onSearch={handleSearch}
style={{ style={{
width: 300, width: 300,
marginRight: '20px',
marginLeft: 'auto',
}} }}
onChange={(e) => setInputText(e.target.value)} onChange={(e) => setInputText(e.target.value)}
value={inputText} value={inputText}
/> />
<Button <Button
type="default" type="default"
style={{ marginLeft: '20px' }}
style={{ marginRight: 0 }}
onClick={createCodeConfig} onClick={createCodeConfig}
icon={<KFIcon type="icon-xinjian2" />} icon={<KFIcon type="icon-xinjian2" />}
> >
新建代码配置 新建代码配置
</Button> </Button>
</div> </div>
</div>
{dataList && dataList.length !== 0 && (
<>
<div className={styles['code-config-list__content']}>
{dataList.map((item) => (
<CodeConfigItem
item={item}
key={item.id}
onRemove={handleRemove}
onEdit={handleEdit}
onClick={handleClick}
/>
))}
</div>
<Pagination
total={total}
showSizeChanger
defaultPageSize={20}
pageSizeOptions={[20, 40, 60, 80, 100]}
showQuickJumper
onChange={handlePageChange}
{...pagination}

{dataList && dataList.length !== 0 && (
<>
<div className={styles['code-config__list__content']}>
{dataList.map((item) => (
<CodeConfigItem
item={item}
key={item.id}
onRemove={handleRemove}
onEdit={handleEdit}
onClick={handleClick}
/>
))}
</div>
<Pagination
align="end"
total={total}
showSizeChanger
defaultPageSize={20}
pageSizeOptions={[20, 40, 60, 80, 100]}
showQuickJumper
onChange={handlePageChange}
{...pagination}
/>
</>
)}
{dataList && dataList.length === 0 && (
<KFEmpty
className={styles['code-config__list__empty']}
type={EmptyType.NoData}
title="暂无数据"
content={'很抱歉,没有搜索到您想要的内容\n建议刷新试试'}
hasFooter={true}
onRefresh={getDataList}
/> />
</>
)}
{dataList && dataList.length === 0 && (
<KFEmpty
className={styles['code-config-list__empty']}
type={EmptyType.NoData}
title="暂无数据"
content={'很抱歉,没有搜索到您想要的内容\n建议刷新试试'}
hasFooter={true}
onRefresh={getDataList}
/>
)}
)}
</div>
</div> </div>
); );
} }


+ 60
- 23
react-ui/src/pages/CodeConfig/components/CodeConfigItem/index.less View File

@@ -2,51 +2,97 @@
position: relative; position: relative;
width: calc(25% - 15px); width: calc(25% - 15px);
padding: 20px; padding: 20px;
background: white;
border: 1px solid #eaeaea;
background: linear-gradient(180deg, #f7faff 0%, #ffffff 100%);
border: 2px solid white;
border-radius: 4px; border-radius: 4px;
box-shadow: 0px 3px 10px rgba(164, 169, 181, 0.13);
cursor: pointer; cursor: pointer;


&:hover {
border-color: @primary-color;
}

@media screen and (max-width: 1860px) { @media screen and (max-width: 1860px) {
& { & {
width: calc(33.33% - 13.33px); width: calc(33.33% - 13.33px);
} }
} }


&__name {
&__icon {
flex: none;
width: 16px;
height: 16px;
margin-right: 10px; margin-right: 10px;
}

&__name {
position: relative;
margin-right: 20px;
margin-bottom: 0 !important; margin-bottom: 0 !important;
color: @text-color; color: @text-color;
font-weight: 500;
font-size: 16px; font-size: 16px;

&::after {
position: absolute;
top: 14px;
left: 0;
width: 100%;
height: 6px;
background: linear-gradient(
to right,
.addAlpha(@primary-color, 0.4) [] 0,
.addAlpha(@primary-color, 0) [] 100%
);
content: '';
}
}

&:hover &__name {
color: @primary-color;
} }


&__tag { &__tag {
padding: 2px 11px;
font-size: 12px;
border-radius: 1000px;
flex: none;
padding: 1px 10px;
font-size: 13px;
border-radius: 2px;


&--public { &--public {
color: @primary-color; color: @primary-color;
background-color: .addAlpha(@primary-color, 0.08) [];
border-color: .addAlpha(@primary-color, 0.5) [];
background-color: .addAlpha(@primary-color, 0.1) [];
border: 1px solid .addAlpha(@primary-color, 0.5) [];
} }


&--private { &--private {
color: @warning-color; color: @warning-color;
background-color: .addAlpha(@warning-color, 0.08) [];
border-color: .addAlpha(@warning-color, 0.5) [];
background-color: .addAlpha(@warning-color, 0.1) [];
border: 1px solid .addAlpha(@warning-color, 0.5) [];
} }
} }


:global {
.ant-btn {
flex: none;
color: #808080;
}
}

&__url-box {
margin-bottom: 15px;
padding: 14px;
background-color: .addAlpha(@primary-color, 0.04) [];
border-radius: 4px;
}

&__url { &__url {
margin-bottom: 10px !important;
color: @text-color-secondary;
margin-bottom: 15px !important;
color: @text-color;
font-size: 14px; font-size: 14px;
} }


&__branch { &__branch {
margin-bottom: 20px;
color: @text-color-tertiary;
color: @text-color-secondary;
font-size: 14px; font-size: 14px;
} }


@@ -59,13 +105,4 @@
color: #808080; color: #808080;
font-size: 13px; font-size: 13px;
} }

&:hover {
border-color: @primary-color;
box-shadow: 0px 0px 6px 1px rgba(0, 0, 0, 0.1);
}

&:hover &__name {
color: @primary-color;
}
} }

+ 15
- 8
react-ui/src/pages/CodeConfig/components/CodeConfigItem/index.tsx View File

@@ -19,6 +19,11 @@ function CodeConfigItem({ item, onClick, onEdit, onRemove }: CodeConfigItemProps
return ( return (
<div className={styles['code-config-item']} onClick={() => onClick?.(item)}> <div className={styles['code-config-item']} onClick={() => onClick?.(item)}>
<Flex justify="space-between" align="center" style={{ marginBottom: '20px', height: '32px' }}> <Flex justify="space-between" align="center" style={{ marginBottom: '20px', height: '32px' }}>
<img
className={styles['code-config-item__icon']}
src={require('@/assets/img/code-name-icon.png')}
alt=""
/>
<Typography.Paragraph <Typography.Paragraph
className={styles['code-config-item__name']} className={styles['code-config-item__name']}
ellipsis={{ tooltip: item.code_repo_name }} ellipsis={{ tooltip: item.code_repo_name }}
@@ -58,17 +63,19 @@ function CodeConfigItem({ item, onClick, onEdit, onRemove }: CodeConfigItemProps
<KFIcon type="icon-shanchu" font={17} /> <KFIcon type="icon-shanchu" font={17} />
</Button> </Button>
</Flex> </Flex>
<Typography.Paragraph
className={styles['code-config-item__url']}
ellipsis={{ tooltip: item.git_url }}
>
{item.git_url}
</Typography.Paragraph>
<div className={styles['code-config-item__branch']}>{item.git_branch}</div>
<div className={styles['code-config-item__url-box']}>
<Typography.Paragraph
className={styles['code-config-item__url']}
ellipsis={{ tooltip: item.git_url }}
>
{item.git_url}
</Typography.Paragraph>
<div className={styles['code-config-item__branch']}>{item.git_branch}</div>
</div>
<Flex justify="space-between"> <Flex justify="space-between">
<div className={styles['code-config-item__user']}> <div className={styles['code-config-item__user']}>
<img <img
style={{ width: '17px', marginRight: '6px' }}
style={{ width: '16px', marginRight: '6px' }}
src={creatByImg} src={creatByImg}
alt="" alt=""
draggable={false} draggable={false}


+ 24
- 21
react-ui/src/pages/Dataset/components/ResourceItem/index.less View File

@@ -13,13 +13,37 @@
} }
} }


&:hover {
border-color: @primary-color;
box-shadow: 0px 0px 6px 1px rgba(0, 0, 0, 0.1);
}

&__name { &__name {
position: relative; position: relative;
display: inline-block; display: inline-block;
height: 24px; height: 24px;
margin: 0 10px 0 0 !important; margin: 0 10px 0 0 !important;
color: @text-color; color: @text-color;
font-weight: 500;
font-size: 16px; font-size: 16px;

&::after {
position: absolute;
top: 14px;
left: 0;
width: 100%;
height: 6px;
background: linear-gradient(
to right,
.addAlpha(@primary-color, 0.3) [] 0,
.addAlpha(@primary-color, 0) [] 100%
);
content: '';
}
}

&:hover &__name {
color: @primary-color;
} }


&__description { &__description {
@@ -37,25 +61,4 @@
color: #808080; color: #808080;
font-size: 13px; font-size: 13px;
} }

&:hover {
border-color: @primary-color;
box-shadow: 0px 0px 6px 1px rgba(0, 0, 0, 0.1);

.resource-item__name {
color: @primary-color;
}
}
}

.resource-item__name {
&::after {
position: absolute;
top: 14px;
left: 0;
width: 100%;
height: 6px;
background: linear-gradient(to right, rgba(22, 100, 255, 0.3) 0, rgba(22, 100, 255, 0) 100%);
content: '';
}
} }

+ 0
- 1
react-ui/src/pages/Dataset/components/ResourceList/index.less View File

@@ -33,7 +33,6 @@
:global { :global {
.ant-pagination { .ant-pagination {
margin-right: 30px; margin-right: 30px;
text-align: right;
} }
} }




+ 1
- 0
react-ui/src/pages/Dataset/components/ResourceList/index.tsx View File

@@ -204,6 +204,7 @@ function ResourceList(
))} ))}
</div> </div>
<Pagination <Pagination
align="end"
total={total} total={total}
showSizeChanger showSizeChanger
defaultPageSize={20} defaultPageSize={20}


+ 6
- 1
react-ui/src/pages/DevelopmentEnvironment/List/index.tsx View File

@@ -152,7 +152,12 @@ function EditorList() {
}; };


// 分页切换 // 分页切换
const handleTableChange: TableProps['onChange'] = (pagination, _filters, _sorter, { action }) => {
const handleTableChange: TableProps<EditorData>['onChange'] = (
pagination,
_filters,
_sorter,
{ action },
) => {
if (action === 'paginate') { if (action === 'paginate') {
setPagination(pagination); setPagination(pagination);
} }


+ 27
- 0
react-ui/src/pages/Experiment/Comparison/index.less View File

@@ -18,6 +18,26 @@
background-color: white; background-color: white;
border-radius: 10px; border-radius: 10px;


&__footer {
display: flex;
align-items: center;
padding-top: 20px;
color: @text-color-secondary;
font-size: 12px;
background-color: white;

div {
flex: 1;
height: 1px;
background-color: @border-color-base;
}

p {
flex: none;
margin: 0 8px;
}
}

:global { :global {
.ant-table-container { .ant-table-container {
border: none !important; border: none !important;
@@ -34,6 +54,13 @@
border-left: none !important; border-left: none !important;
} }
} }
.ant-table-tbody-virtual::after {
border-bottom: none !important;
}
.ant-table-footer {
padding: 0;
border: none !important;
}
} }
} }
} }

+ 58
- 53
react-ui/src/pages/Experiment/Comparison/index.tsx View File

@@ -1,13 +1,19 @@
// import { useCacheState } from '@/hooks/pageCacheState';
/*
* @Author: 赵伟
* @Date: 2024-10-10 09:55:12
* @Description: 实验对比
*/

import { import {
getExpEvaluateInfosReq, getExpEvaluateInfosReq,
getExpMetricsReq, getExpMetricsReq,
getExpTrainInfosReq, getExpTrainInfosReq,
} from '@/services/experiment'; } from '@/services/experiment';
import { tableSorter } from '@/utils';
import { to } from '@/utils/promise'; import { to } from '@/utils/promise';
import tableCellRender, { TableCellValueType } from '@/utils/table'; import tableCellRender, { TableCellValueType } from '@/utils/table';
import { useSearchParams } from '@umijs/max'; import { useSearchParams } from '@umijs/max';
import { App, Button, Table, /* TablePaginationConfig,*/ TableProps, Tooltip } from 'antd';
import { App, Button, Table, TablePaginationConfig, TableProps, Tooltip } from 'antd';
import classNames from 'classnames'; import classNames from 'classnames';
import { useEffect, useMemo, useState } from 'react'; import { useEffect, useMemo, useState } from 'react';
import ExperimentStatusCell from '../components/ExperimentStatusCell'; import ExperimentStatusCell from '../components/ExperimentStatusCell';
@@ -20,10 +26,10 @@ type TableData = {
dataset: string[]; dataset: string[];
start_time: string; start_time: string;
status: string; status: string;
metrics_names: string[];
metrics: Record<string, number>;
params_names: string[];
params: Record<string, number>;
metrics_names?: string[];
metrics?: Record<string, number>;
params_names?: string[];
params?: Record<string, number>;
}; };


function ExperimentComparison() { function ExperimentComparison() {
@@ -31,18 +37,15 @@ function ExperimentComparison() {
const comparisonType = searchParams.get('type') as ComparisonType; const comparisonType = searchParams.get('type') as ComparisonType;
const experimentId = searchParams.get('id'); const experimentId = searchParams.get('id');
const [tableData, setTableData] = useState<TableData[]>([]); const [tableData, setTableData] = useState<TableData[]>([]);
// const [cacheState, setCacheState] = useCacheState();
// const [total, setTotal] = useState(0);
const [selectedRowKeys, setSelectedRowKeys] = useState<React.Key[]>([]); const [selectedRowKeys, setSelectedRowKeys] = useState<React.Key[]>([]);
// const [loading, setLoading] = useState(false);
const [total, setTotal] = useState(0);
const [pagination, setPagination] = useState<TablePaginationConfig>({
current: 1,
pageSize: 10,
});

const { message } = App.useApp(); const { message } = App.useApp();
const config = useMemo(() => comparisonConfig[comparisonType], [comparisonType]); const config = useMemo(() => comparisonConfig[comparisonType], [comparisonType]);
// const [pagination, setPagination] = useState<TablePaginationConfig>(
// cacheState?.pagination ?? {
// current: 1,
// pageSize: 10,
// },
// );


useEffect(() => { useEffect(() => {
getComparisonData(); getComparisonData();
@@ -50,15 +53,17 @@ function ExperimentComparison() {


// 获取对比数据列表 // 获取对比数据列表
const getComparisonData = async () => { const getComparisonData = async () => {
// setLoading(true);
const request = const request =
comparisonType === ComparisonType.Train ? getExpTrainInfosReq : getExpEvaluateInfosReq; comparisonType === ComparisonType.Train ? getExpTrainInfosReq : getExpEvaluateInfosReq;
const [res] = await to(request(experimentId, { offset: '', limit: 50 }));
// setLoading(false);
const params = {
page: pagination.current! - 1,
size: pagination.pageSize,
};
const [res] = await to(request(experimentId, params));
if (res && res.data) { if (res && res.data) {
// const { content = [], totalElements = 0 } = res.data;
setTableData(res.data);
// setTotal(totalElements);
const { content = [], totalElements = 0 } = res.data;
setTableData(content);
setTotal(totalElements);
} }
}; };


@@ -80,17 +85,10 @@ function ExperimentComparison() {
getExpMetrics(); getExpMetrics();
}; };


// 分页切换
// const handleTableChange: TableProps['onChange'] = (pagination, filters, sorter, { action }) => {
// if (action === 'paginate') {
// setPagination(pagination);
// }
// // console.log(pagination, filters, sorter, action);
// };

// 选择行 // 选择行
const rowSelection: TableProps['rowSelection'] = {
const rowSelection: TableProps<TableData>['rowSelection'] = {
type: 'checkbox', type: 'checkbox',
columnWidth: 48,
fixed: 'left', fixed: 'left',
selectedRowKeys, selectedRowKeys,
onChange: (selectedRowKeys: React.Key[]) => { onChange: (selectedRowKeys: React.Key[]) => {
@@ -98,8 +96,24 @@ function ExperimentComparison() {
}, },
}; };


// 分页切换
const handleTableChange: TableProps<TableData>['onChange'] = (
pagination,
_filters,
_sorter,
{ action },
) => {
if (action === 'paginate') {
setPagination(pagination);
}
};

const columns: TableProps<TableData>['columns'] = useMemo(() => { const columns: TableProps<TableData>['columns'] = useMemo(() => {
const first: TableData | undefined = tableData[0];
const first: TableData | undefined = tableData.find(
(item) => item.metrics_names && item.metrics_names.length > 0,
);
const metricsNames = first?.metrics_names ?? [];
const paramsNames = first?.params_names ?? [];
return [ return [
{ {
title: '基本信息', title: '基本信息',
@@ -147,7 +161,7 @@ function ExperimentComparison() {
{ {
title: `${config.title}参数`, title: `${config.title}参数`,
align: 'center', align: 'center',
children: first?.params_names.map((name) => ({
children: paramsNames.map((name) => ({
title: ( title: (
<Tooltip title={name}> <Tooltip title={name}>
<span>{name}</span> <span>{name}</span>
@@ -159,14 +173,14 @@ function ExperimentComparison() {
align: 'center', align: 'center',
render: tableCellRender(true), render: tableCellRender(true),
ellipsis: { showTitle: false }, ellipsis: { showTitle: false },
sorter: (a, b) => a.params[name] - b.params[name],
sorter: (a, b) => tableSorter(a.params?.[name], b.params?.[name]),
showSorterTooltip: false, showSorterTooltip: false,
})), })),
}, },
{ {
title: `${config.title}指标`, title: `${config.title}指标`,
align: 'center', align: 'center',
children: first?.metrics_names.map((name) => ({
children: metricsNames.map((name) => ({
title: ( title: (
<Tooltip title={name}> <Tooltip title={name}>
<span>{name}</span> <span>{name}</span>
@@ -178,7 +192,7 @@ function ExperimentComparison() {
align: 'center', align: 'center',
render: tableCellRender(true), render: tableCellRender(true),
ellipsis: { showTitle: false }, ellipsis: { showTitle: false },
sorter: (a, b) => a.metrics[name] - b.metrics[name],
sorter: (a, b) => tableSorter(a.metrics?.[name], b.metrics?.[name]),
showSorterTooltip: false, showSorterTooltip: false,
})), })),
}, },
@@ -192,30 +206,21 @@ function ExperimentComparison() {
可视化对比 可视化对比
</Button> </Button>
</div> </div>
<div
className={classNames(
'vertical-scroll-table-no-page',
styles['experiment-comparison__table'],
)}
>
<div className={classNames('vertical-scroll-table', styles['experiment-comparison__table'])}>
<Table <Table
dataSource={tableData} dataSource={tableData}
columns={columns} columns={columns}
rowSelection={rowSelection} rowSelection={rowSelection}
scroll={{ y: 'calc(100% - 110px)', x: '100%' }} scroll={{ y: 'calc(100% - 110px)', x: '100%' }}
pagination={false}
pagination={{
...pagination,
total: total,
showSizeChanger: true,
showQuickJumper: true,
}}
onChange={handleTableChange}
bordered={true} bordered={true}
virtual
// onScroll={handleTableScroll}
// loading={loading}
// pagination={{
// ...pagination,
// total: total,
// showSizeChanger: true,
// showQuickJumper: true,
// }}
// onChange={handleTableChange}
rowKey="run_id"
rowKey={(record) => record.run_id || record.experiment_ins_id}
/> />
</div> </div>
</div> </div>


+ 1
- 1
react-ui/src/pages/Experiment/components/AddExperimentModal/index.tsx View File

@@ -126,7 +126,7 @@ function AddExperimentModal({
<Button key="cancel" onClick={onCancel}> <Button key="cancel" onClick={onCancel}>
取消 取消
</Button>, </Button>,
<Button key="submit" type="primary" onClick={() => handleRun(false)}>
<Button key="submit" type={isAdd ? 'primary' : 'default'} onClick={() => handleRun(false)}>
确定 确定
</Button>, </Button>,
]; ];


+ 1
- 1
react-ui/src/pages/Experiment/components/ExperimentInstance/index.less View File

@@ -4,7 +4,7 @@
width: 100%; width: 100%;
padding: 0 0 0 33px; padding: 0 0 0 33px;
color: @text-color; color: @text-color;
font-size: 15px;
font-size: 14px;


& > div { & > div {
padding: 0 16px; padding: 0 16px;


+ 2
- 1
react-ui/src/pages/Experiment/components/ExperimentInstance/index.tsx View File

@@ -129,7 +129,8 @@ function ExperimentInstanceComponent({
{selectedIns.length > 0 && ( {selectedIns.length > 0 && (
<Button <Button
style={{ position: 'absolute', right: '0' }} style={{ position: 'absolute', right: '0' }}
type="primary"
color="primary"
variant="filled"
size="small" size="small"
onClick={handleDeleteAll} onClick={handleDeleteAll}
icon={<KFIcon type="icon-shanchu" />} icon={<KFIcon type="icon-shanchu" />}


+ 1
- 1
react-ui/src/pages/Experiment/components/TensorBoardStatus/index.less View File

@@ -5,7 +5,7 @@


&__label { &__label {
color: rgba(29, 29, 32, 0.75); color: rgba(29, 29, 32, 0.75);
font-size: 15px;
font-size: 14px;


&--running { &--running {
color: @success-color; color: @success-color;


+ 6
- 1
react-ui/src/pages/Mirror/Info/index.tsx View File

@@ -124,7 +124,12 @@ function MirrorInfo() {
}; };


// 分页切换 // 分页切换
const handleTableChange: TableProps['onChange'] = (pagination, filters, sorter, { action }) => {
const handleTableChange: TableProps<MirrorVersionData>['onChange'] = (
pagination,
_filters,
_sorter,
{ action },
) => {
if (action === 'paginate') { if (action === 'paginate') {
setPagination(pagination); setPagination(pagination);
} }


+ 6
- 1
react-ui/src/pages/Mirror/List/index.tsx View File

@@ -155,7 +155,12 @@ function MirrorList() {
}; };


// 分页切换 // 分页切换
const handleTableChange: TableProps['onChange'] = (pagination, filters, sorter, { action }) => {
const handleTableChange: TableProps<MirrorData>['onChange'] = (
pagination,
_filters,
_sorter,
{ action },
) => {
if (action === 'paginate') { if (action === 'paginate') {
setPagination(pagination); setPagination(pagination);
} }


+ 17
- 9
react-ui/src/pages/Model/components/ModelMetrics/index.tsx View File

@@ -1,6 +1,7 @@
import SubAreaTitle from '@/components/SubAreaTitle'; import SubAreaTitle from '@/components/SubAreaTitle';
import { useCheck } from '@/hooks'; import { useCheck } from '@/hooks';
import { getModelPageVersionsReq, getModelVersionsMetricsReq } from '@/services/dataset'; import { getModelPageVersionsReq, getModelVersionsMetricsReq } from '@/services/dataset';
import { tableSorter } from '@/utils';
import { to } from '@/utils/promise'; import { to } from '@/utils/promise';
import tableCellRender from '@/utils/table'; import tableCellRender from '@/utils/table';
import { Checkbox, Table, Tooltip, type TablePaginationConfig, type TableProps } from 'antd'; import { Checkbox, Table, Tooltip, type TablePaginationConfig, type TableProps } from 'antd';
@@ -18,7 +19,7 @@ type TableData = {
metrics_names?: string[]; metrics_names?: string[];
metrics?: Record<string, number>; metrics?: Record<string, number>;
params_names?: string[]; params_names?: string[];
params?: Record<string, string>;
params?: Record<string, number>;
}; };


type ModelMetricsProps = { type ModelMetricsProps = {
@@ -113,14 +114,18 @@ function ModelMetrics({ resourceId, identifier, owner, version }: ModelMetricsPr
}; };


// 分页切换 // 分页切换
const handleTableChange: TableProps['onChange'] = (pagination, _filters, _sorter, { action }) => {
const handleTableChange: TableProps<TableData>['onChange'] = (
pagination,
_filters,
_sorter,
{ action },
) => {
if (action === 'paginate') { if (action === 'paginate') {
setPagination(pagination); setPagination(pagination);
} }
// console.log(pagination, filters, sorter, action);
}; };


const rowSelection: TableProps['rowSelection'] = {
const rowSelection: TableProps<TableData>['rowSelection'] = {
type: 'checkbox', type: 'checkbox',
fixed: 'left', fixed: 'left',
selectedRowKeys, selectedRowKeys,
@@ -142,10 +147,12 @@ function ModelMetrics({ resourceId, identifier, owner, version }: ModelMetricsPr
}, [version, tableData]); }, [version, tableData]);


// 表头 // 表头
const columns: TableProps['columns'] = useMemo(() => {
const columns: TableProps<TableData>['columns'] = useMemo(() => {
const first: TableData | undefined = tableData.find( const first: TableData | undefined = tableData.find(
(item) => item.metrics_names && item.metrics_names.length > 0, (item) => item.metrics_names && item.metrics_names.length > 0,
); );
const metricsNames = first?.metrics_names ?? [];
const paramsNames = first?.params_names ?? [];
return [ return [
{ {
title: '基本信息', title: '基本信息',
@@ -165,7 +172,7 @@ function ModelMetrics({ resourceId, identifier, owner, version }: ModelMetricsPr
{ {
title: `训练参数`, title: `训练参数`,
align: 'center', align: 'center',
children: first?.params_names?.map((name) => ({
children: paramsNames.map((name) => ({
title: ( title: (
<Tooltip title={name}> <Tooltip title={name}>
<span>{name}</span> <span>{name}</span>
@@ -177,7 +184,7 @@ function ModelMetrics({ resourceId, identifier, owner, version }: ModelMetricsPr
align: 'center', align: 'center',
render: tableCellRender(true), render: tableCellRender(true),
ellipsis: { showTitle: false }, ellipsis: { showTitle: false },
sorter: (a, b) => a.params?.[name] ?? 0 - b.params?.[name] ?? 0,
sorter: (a, b) => tableSorter(a.params?.[name], b.params?.[name]),
showSorterTooltip: false, showSorterTooltip: false,
})), })),
}, },
@@ -188,12 +195,13 @@ function ModelMetrics({ resourceId, identifier, owner, version }: ModelMetricsPr
checked={metricsChecked} checked={metricsChecked}
indeterminate={metricsIndeterminate} indeterminate={metricsIndeterminate}
onChange={checkAllMetrics} onChange={checkAllMetrics}
disabled={metricsNames.length === 0}
></Checkbox>{' '} ></Checkbox>{' '}
<span>训练指标</span> <span>训练指标</span>
</div> </div>
), ),
align: 'center', align: 'center',
children: first?.metrics_names?.map((name) => ({
children: metricsNames.map((name) => ({
title: ( title: (
<div> <div>
<Checkbox <Checkbox
@@ -215,7 +223,7 @@ function ModelMetrics({ resourceId, identifier, owner, version }: ModelMetricsPr
align: 'center', align: 'center',
render: tableCellRender(true), render: tableCellRender(true),
ellipsis: { showTitle: false }, ellipsis: { showTitle: false },
sorter: (a, b) => a.metrics?.[name] ?? 0 - b.metrics?.[name] ?? 0,
sorter: (a, b) => tableSorter(a.metrics?.[name], b.metrics?.[name]),
showSorterTooltip: false, showSorterTooltip: false,
})), })),
}, },


+ 6
- 1
react-ui/src/pages/ModelDeployment/List/index.tsx View File

@@ -176,7 +176,12 @@ function ModelDeployment() {
}; };


// 分页切换 // 分页切换
const handleTableChange: TableProps['onChange'] = (pagination, _filters, _sorter, { action }) => {
const handleTableChange: TableProps<ServiceData>['onChange'] = (
pagination,
_filters,
_sorter,
{ action },
) => {
if (action === 'paginate') { if (action === 'paginate') {
setPagination(pagination); setPagination(pagination);
} }


+ 38
- 3
react-ui/src/pages/ModelDeployment/ServiceInfo/index.tsx View File

@@ -18,6 +18,7 @@ import {
} from '@/services/modelDeployment'; } from '@/services/modelDeployment';
import themes from '@/styles/theme.less'; import themes from '@/styles/theme.less';
import { formatDate } from '@/utils/date'; import { formatDate } from '@/utils/date';
import { openAntdModal } from '@/utils/modal';
import { to } from '@/utils/promise'; import { to } from '@/utils/promise';
import SessionStorage from '@/utils/sessionStorage'; import SessionStorage from '@/utils/sessionStorage';
import tableCellRender, { TableCellValueType } from '@/utils/table'; import tableCellRender, { TableCellValueType } from '@/utils/table';
@@ -37,6 +38,7 @@ import { type SearchProps } from 'antd/es/input';
import classNames from 'classnames'; import classNames from 'classnames';
import { useEffect, useState } from 'react'; import { useEffect, useState } from 'react';
import ServiceRunStatusCell from '../components/ModelDeployStatusCell'; import ServiceRunStatusCell from '../components/ModelDeployStatusCell';
import VersionCompareModal from '../components/VersionCompareModal';
import { import {
CreateServiceVersionFrom, CreateServiceVersionFrom,
ServiceData, ServiceData,
@@ -56,6 +58,7 @@ function ServiceInfo() {
const [inputText, setInputText] = useState(cacheState?.searchText); const [inputText, setInputText] = useState(cacheState?.searchText);
const [tableData, setTableData] = useState<ServiceVersionData[]>([]); const [tableData, setTableData] = useState<ServiceVersionData[]>([]);
const [total, setTotal] = useState(0); const [total, setTotal] = useState(0);
const [selectedRowKeys, setSelectedRowKeys] = useState<React.Key[]>([]);
const [pagination, setPagination] = useState<TablePaginationConfig>( const [pagination, setPagination] = useState<TablePaginationConfig>(
cacheState?.pagination ?? { cacheState?.pagination ?? {
current: 1, current: 1,
@@ -208,11 +211,39 @@ function ServiceInfo() {
}; };


// 分页切换 // 分页切换
const handleTableChange: TableProps['onChange'] = (pagination, _filters, _sorter, { action }) => {
const handleTableChange: TableProps<ServiceVersionData>['onChange'] = (
pagination,
_filters,
_sorter,
{ action },
) => {
if (action === 'paginate') { if (action === 'paginate') {
setPagination(pagination); setPagination(pagination);
} }
// console.log(pagination, filters, sorter, action);
};

// 版本对比
const handleVersionCompare = () => {
if (selectedRowKeys.length !== 2) {
message.error('请选择两个版本进行对比');
return;
}

openAntdModal(VersionCompareModal, {
version1: selectedRowKeys[0] as string,
version2: selectedRowKeys[1] as string,
});
};

// 选择行
const rowSelection: TableProps<ServiceVersionData>['rowSelection'] = {
type: 'checkbox',
columnWidth: 48,
fixed: 'left',
selectedRowKeys,
onChange: (selectedRowKeys: React.Key[]) => {
setSelectedRowKeys(selectedRowKeys);
},
}; };


const columns: TableProps<ServiceVersionData>['columns'] = [ const columns: TableProps<ServiceVersionData>['columns'] = [
@@ -379,13 +410,16 @@ function ServiceInfo() {
allowClear allowClear
></Select> ></Select>
<Button <Button
style={{ marginRight: '20px', marginLeft: 'auto' }}
style={{ marginRight: '15px', marginLeft: 'auto' }}
type="default" type="default"
onClick={() => createServiceVersion(ServiceOperationType.Create)} onClick={() => createServiceVersion(ServiceOperationType.Create)}
icon={<KFIcon type="icon-xinjian2" />} icon={<KFIcon type="icon-xinjian2" />}
> >
新增版本 新增版本
</Button> </Button>
<Button style={{ marginRight: '15px' }} type="default" onClick={handleVersionCompare}>
版本对比
</Button>
<Button <Button
style={{ marginRight: 0 }} style={{ marginRight: 0 }}
type="default" type="default"
@@ -410,6 +444,7 @@ function ServiceInfo() {
showTotal: () => `共${total}条`, showTotal: () => `共${total}条`,
}} }}
onChange={handleTableChange} onChange={handleTableChange}
rowSelection={rowSelection}
rowKey="id" rowKey="id"
/> />
</div> </div>


+ 117
- 0
react-ui/src/pages/ModelDeployment/components/VersionCompareModal/index.less View File

@@ -0,0 +1,117 @@
@purple-color: #6516ff;

.title(@color, @background) {
width: 100%;
margin-bottom: 20px;
color: @color;
font-weight: 500;
font-size: @font-size;
line-height: 42px;
text-align: center;
background: @background;
.singleLine();
}

.text() {
margin-bottom: 20px !important;
color: @text-color-secondary;
font-size: 13px;
word-break: break-all;
.singleLine();
}

.version-container(@background) {
flex: 1;
min-width: 0;
background: @background;
border-radius: 4px;
}

.version-compare {
:global {
.ant-modal-content {
padding: 40px 40px 25px !important;
}
.ant-modal-header {
margin-bottom: 20px !important;
}
.kf-modal-title {
color: @text-color;
font-weight: 500;
font-size: 20px;
}
}

&__container {
display: flex;
flex-wrap: nowrap;
gap: 0 5px;
align-items: stretch;
height: 100%;
}

&__fields {
flex: none;
width: 117px;
padding: 0 15px;
background: white;
border: 1px solid .addAlpha(@primary-color, 0.2) [];
border-radius: 4px;

&__title {
margin-bottom: 20px;
color: @text-color;
font-size: @font-size;
line-height: 42px;
}
&__text {
.text();

&--different {
color: @error-color;
}
}
}

&__left {
.version-container(.addAlpha(@primary-color, 0.04) []);

&__title {
.title(@primary-color, linear-gradient(
159.9deg,rgba(138, 177, 255, 0.5) 0%,
rgba(22, 100, 255, 0.5) 100%
));
}

&__text {
padding: 0 15px;
text-align: center;
.text();

&--different {
color: @primary-color;
}
}
}

&__right {
.version-container(rgba(100, 30, 237, 0.04));
&__title {
.title(@purple-color, linear-gradient(
159.9deg,
rgba(193, 138, 255, 0.5) 0%,
rgba(146, 22, 255, 0.5) 100%
));
}

&__text {
padding: 0 15px;
text-align: center;
.text();

&--different {
color: @purple-color;
}
}
}
}

+ 197
- 0
react-ui/src/pages/ModelDeployment/components/VersionCompareModal/index.tsx View File

@@ -0,0 +1,197 @@
import KFModal from '@/components/KFModal';
import { ServiceRunStatus } from '@/enums';
import { useComputingResource } from '@/hooks/resource';
import { type ServiceVersionData } from '@/pages/ModelDeployment/types';
import { getServiceVersionCompareReq } from '@/services/modelDeployment';
import { to } from '@/utils/promise';
import { Typography, type ModalProps } from 'antd';
import classNames from 'classnames';
import { useEffect, useMemo, useState } from 'react';
import { statusInfo } from '../ModelDeployStatusCell';
import styles from './index.less';

type CompareData = {
differences: Record<string, any>;
version1: ServiceVersionData;
version2: ServiceVersionData;
};

type ServiceVersionDataKey = keyof ServiceVersionData;

type FiledType = {
key: ServiceVersionDataKey;
text: string;
format?: (data: any) => any;
};

interface CreateMirrorModalProps extends Omit<ModalProps, 'onOk'> {
version1: string;
version2: string;
}

// 格式化环境变量
const formatEnvText = (env: Record<string, string>) => {
if (!env || Object.keys(env).length === 0) {
return '--';
}
return Object.entries(env)
.map(([key, value]) => `${key} = ${value}`)
.join(',');
};

function VersionCompareModal({ version1, version2, ...rest }: CreateMirrorModalProps) {
const [compareData, setCompareData] = useState<CompareData | undefined>(undefined);
const getResourceDescription = useComputingResource()[2];

const fields: FiledType[] = useMemo(
() => [
{
key: 'service_name',
text: '服务名称',
},
{
key: 'run_state',
text: '状态',
format: (data: any) => {
return data ? statusInfo[data as ServiceRunStatus].text : '--';
},
},
{
key: 'image',
text: '镜像',
},
{
key: 'code_config',
text: '代码配置',
format: (data: any) => {
return data?.show_value;
},
},
{
key: 'model',
text: '模型',
format: (data: any) => {
return data?.show_value;
},
},
{
key: 'resource',
text: '资源规格',
format: getResourceDescription,
},
{
key: 'replicas',
text: '副本数',
},
{
key: 'mount_path',
text: '挂载路径',
},
{
key: 'url',
text: '服务URL',
},
{
key: 'env_variables',
text: '环境变量',
format: formatEnvText,
},
{
key: 'description',
text: '描述',
},
],
[getResourceDescription],
);

useEffect(() => {
getServiceVersionCompare();
}, []);

// 获取对比数据
const getServiceVersionCompare = async () => {
const params = {
id1: version1,
id2: version2,
};
const [res] = await to(getServiceVersionCompareReq(params));
if (res && res.data) {
setCompareData(res.data);
}
};

const {
version1: v1 = {} as ServiceVersionData,
version2: v2 = {} as ServiceVersionData,
differences = {},
} = compareData || {};

const isDifferent = (key: ServiceVersionDataKey) => {
const keys = Object.keys(differences);
return keys.includes(key);
};

return (
<KFModal
{...rest}
title="服务版本对比"
width={825}
footer={null}
className={styles['version-compare']}
>
<div className={styles['version-compare__container']}>
<div className={styles['version-compare__fields']}>
<div className={styles['version-compare__fields__title']}>基础版本号</div>
{fields.map(({ key, text }) => (
<div
className={classNames(styles['version-compare__fields__text'], {
[styles['version-compare__fields__text--different']]: isDifferent(key),
})}
key={key}
>
{text}
</div>
))}
</div>
<div className={styles['version-compare__left']}>
<div className={styles['version-compare__left__title']}>{v1.version}</div>
{fields.map(({ key, format }) => {
const text = format ? format(v1[key]) : v1[key];
return (
<div
key={key}
className={classNames(styles['version-compare__left__text'], {
[styles['version-compare__left__text--different']]: isDifferent(key),
})}
>
<Typography.Text ellipsis={{ tooltip: text }} style={{ color: 'inherit' }}>
{text}
</Typography.Text>
</div>
);
})}
</div>
<div className={styles['version-compare__right']}>
<div className={styles['version-compare__right__title']}>{v2.version}</div>
{fields.map(({ key, format }) => {
const text = format ? format(v2[key]) : v2[key];
return (
<div
key={key}
className={classNames(styles['version-compare__right__text'], {
[styles['version-compare__right__text--different']]: isDifferent(key),
})}
>
<Typography.Text ellipsis={{ tooltip: text }} style={{ color: 'inherit' }}>
{text}
</Typography.Text>
</div>
);
})}
</div>
</div>
</KFModal>
);
}

export default VersionCompareModal;

+ 0
- 4
react-ui/src/pages/Pipeline/components/CodeSelectorModal/index.less View File

@@ -20,10 +20,6 @@
} }
} }


.ant-pagination {
text-align: center;
}

.ant-input-group-addon { .ant-input-group-addon {
display: none; display: none;
} }


+ 1
- 0
react-ui/src/pages/Pipeline/components/CodeSelectorModal/index.tsx View File

@@ -97,6 +97,7 @@ function CodeSelectorModal({ onOk, ...rest }: CodeSelectorModalProps) {
))} ))}
</div> </div>
<Pagination <Pagination
align="center"
total={total} total={total}
showSizeChanger showSizeChanger
defaultPageSize={20} defaultPageSize={20}


+ 4
- 6
react-ui/src/pages/Workspace/index.less View File

@@ -47,13 +47,11 @@


&__robot-img { &__robot-img {
position: fixed; position: fixed;
right: 30px;
bottom: 20px;
right: 20px;
bottom: 90px;
z-index: 99; z-index: 99;
width: 64px;
height: 64px;
background-color: white;
border-radius: 10px;
width: 56px;
height: 56px;
cursor: pointer; cursor: pointer;
} }
} }

+ 8
- 0
react-ui/src/services/modelDeployment/index.ts View File

@@ -104,3 +104,11 @@ export function getServiceVersionLogReq(params: any) {
params, params,
}); });
} }

// 获取服务版本对比
export function getServiceVersionCompareReq(params: any) {
return request(`/api/mmp/service/serviceVersionCompare`, {
method: 'GET',
params,
});
}

+ 223
- 0
react-ui/src/services/typings.d.ts View File

@@ -188,4 +188,227 @@ declare namespace API {
filter?: string; filter?: string;
sorter?: string; sorter?: string;
}; };
type CurrentUser = UserInfo & {
signature?: string;
title?: string;
group?: string;
tags?: { key?: string; label?: string }[];
notifyCount?: number;
unreadCount?: number;
country?: string;
access?: string;
geographic?: {
province?: { label?: string; key?: string };
city?: { label?: string; key?: string };
};
address?: string;
phone?: string;
roleNames?: {
roleName?: string;
}[];
};

type ErrorResponse = {
/** 业务约定的错误码 */
errorCode: string;
/** 业务上的错误信息 */
errorMessage?: string;
/** 业务上的请求是否成功 */
success?: boolean;
};

type FakeCaptcha = {
code?: number;
status?: string;
};

type getFakeCaptchaParams = {
/** 手机号 */
phone?: string;
};

type LoginParams = {
username?: string;
password?: string;
uuid?: string;
autoLogin?: boolean;
type?: string;
};

type LoginResult = {
code: number;
msg?: string;
type?: string;
data?: {
access_token?: string;
expires_in?: number;
};
};

type NoticeIconItem = {
id?: string;
extra?: string;
key?: string;
read?: boolean;
avatar?: string;
title?: string;
status?: string;
datetime?: string;
description?: string;
type?: NoticeIconItemType;
};

type NoticeIconItemType = 'notification' | 'message' | 'event';

type NoticeIconList = {
data?: NoticeIconItem[];
/** 列表的内容总数 */
total?: number;
success?: boolean;
};

type PageParams = {
current?: number;
pageSize?: number;
};

type RuleList = {
data?: RuleListItem[];
/** 列表的内容总数 */
total?: number;
success?: boolean;
};

type RuleListItem = {
key?: number;
disabled?: boolean;
href?: string;
avatar?: string;
name?: string;
owner?: string;
desc?: string;
callNo?: number;
status?: number;
updatedAt?: string;
createdAt?: string;
progress?: number;
};

type ruleParams = {
/** 当前的页码 */
current?: number;
/** 页面的容量 */
pageSize?: number;
};

type ApiResponse = {
code?: number;
type?: string;
message?: string;
};

type Category = {
id?: number;
name?: string;
};

type deleteOrderParams = {
/** ID of the order that needs to be deleted */
orderId: number;
};

type deletePetParams = {
api_key?: string;
/** Pet id to delete */
petId: number;
};

type deleteUserParams = {
/** The name that needs to be deleted */
username: string;
};

type findPetsByStatusParams = {
/** Status values that need to be considered for filter */
status: ('available' | 'pending' | 'sold')[];
};

type findPetsByTagsParams = {
/** Tags to filter by */
tags: string[];
};

type getOrderByIdParams = {
/** ID of pet that needs to be fetched */
orderId: number;
};

type getPetByIdParams = {
/** ID of pet to return */
petId: number;
};

type getUserByNameParams = {
/** The name that needs to be fetched. Use user1 for testing. */
username: string;
};

type loginUserParams = {
/** The user name for login */
username: string;
/** The password for login in clear text */
password: string;
};

type Order = {
id?: number;
petId?: number;
quantity?: number;
shipDate?: string;
/** Order Status */
status?: 'placed' | 'approved' | 'delivered';
complete?: boolean;
};

type Pet = {
id?: number;
category?: Category;
name: string;
photoUrls: string[];
tags?: Tag[];
/** pet status in the store */
status?: 'available' | 'pending' | 'sold';
};

type Tag = {
id?: number;
name?: string;
};

type updatePetWithFormParams = {
/** ID of pet that needs to be updated */
petId: number;
};

type updateUserParams = {
/** name that need to be updated */
username: string;
};

type uploadFileParams = {
/** ID of pet to update */
petId: number;
};

type User = {
id?: number;
username?: string;
firstName?: string;
lastName?: string;
email?: string;
password?: string;
phone?: string;
/** User Status */
userStatus?: number;
};
} }

+ 23
- 0
react-ui/src/utils/index.ts View File

@@ -4,6 +4,7 @@
* @Description: 工具类 * @Description: 工具类
*/ */


import { PageEnum } from '@/enums/pagesEnums';
import G6 from '@antv/g6'; import G6 from '@antv/g6';


// 生成 8 位随机数 // 生成 8 位随机数
@@ -218,3 +219,25 @@ export const getGitUrl = (url: string, branch: string): string => {
const gitUrl = url.replace(/\.git$/, ''); const gitUrl = url.replace(/\.git$/, '');
return branch ? `${gitUrl}/tree/${branch}` : gitUrl; return branch ? `${gitUrl}/tree/${branch}` : gitUrl;
}; };

// 判断是否需要登录
export const needAuth = (pathname: string) => {
return pathname !== PageEnum.LOGIN && pathname !== PageEnum.Authorize;
};

// 表格排序
export const tableSorter = (a: any, b: any) => {
if (b === null || b === undefined) {
return -1;
}
if (a === null || a === undefined) {
return 1;
}
if (typeof a === 'number' && typeof b === 'number') {
return a - b;
}
if (typeof a === 'string' && typeof b === 'string') {
return a.localeCompare(b);
}
return 0;
};

Loading…
Cancel
Save