diff --git a/react-ui/src/assets/img/metrics-title-icon.png b/react-ui/src/assets/img/metrics-title-icon.png new file mode 100644 index 00000000..66cd461f Binary files /dev/null and b/react-ui/src/assets/img/metrics-title-icon.png differ diff --git a/react-ui/src/assets/img/model-metrics.png b/react-ui/src/assets/img/model-metrics.png new file mode 100644 index 00000000..3379db8a Binary files /dev/null and b/react-ui/src/assets/img/model-metrics.png differ diff --git a/react-ui/src/components/BasicInfo/index.less b/react-ui/src/components/BasicInfo/index.less index 53fcb46c..ffeb3d3d 100644 --- a/react-ui/src/components/BasicInfo/index.less +++ b/react-ui/src/components/BasicInfo/index.less @@ -5,48 +5,54 @@ gap: 20px 40px; align-items: flex-start; width: 80%; -} -.kf-basic-info-item { - display: flex; - align-items: flex-start; - width: calc(50% - 20px); - font-size: 16px; - line-height: 1.6; - - &__label { - position: relative; - flex: none; - color: @text-color-secondary; - text-align: justify; - text-align-last: justify; - - &::after { - position: absolute; - content: ':'; + &__item { + display: flex; + align-items: flex-start; + width: calc(50% - 20px); + + &__label { + position: relative; + flex: none; + color: @text-color-secondary; + font-size: @font-size-content; + line-height: 1.6; + text-align: justify; + text-align-last: justify; + + &::after { + position: absolute; + content: ':'; + } } - } - &__list-value { - display: flex; - flex: 1; - flex-direction: column; - gap: 5px 0; - } + &__value-container { + display: flex; + flex: 1; + flex-direction: column; + gap: 5px 0; + } - &__value { - flex: 1; - margin-left: 16px; - white-space: pre-line; - word-break: break-all; - } + &__value { + flex: 1; + margin-left: 16px; + font-size: @font-size-content; + line-height: 1.6; + white-space: pre-line; + word-break: break-all; - &__text { - color: @text-color; - } + &--ellipsis { + .singleLine(); + } + + &__text { + color: @text-color; + } - &__link:hover { - text-decoration: underline @underline-color; - text-underline-offset: 3px; + &__link:hover { + text-decoration: underline @underline-color; + text-underline-offset: 3px; + } + } } } diff --git a/react-ui/src/components/BasicInfo/index.tsx b/react-ui/src/components/BasicInfo/index.tsx index af56ded0..60cd5b57 100644 --- a/react-ui/src/components/BasicInfo/index.tsx +++ b/react-ui/src/components/BasicInfo/index.tsx @@ -1,4 +1,5 @@ import { Link } from '@umijs/max'; +import { Typography } from 'antd'; import classNames from 'classnames'; import './index.less'; @@ -11,6 +12,7 @@ export type BasicInfoLink = { export type BasicInfoData = { label: string; value?: any; + ellipsis?: boolean; format?: (_value?: any) => string | BasicInfoLink | BasicInfoLink[] | undefined; }; @@ -18,45 +20,73 @@ type BasicInfoProps = { datas: BasicInfoData[]; className?: string; style?: React.CSSProperties; - labelWidth?: number; + labelWidth: number; }; -function BasicInfo({ datas, className, style, labelWidth = 100 }: BasicInfoProps) { +type BasicInfoItemProps = { + data: BasicInfoData; + labelWidth: number; + classPrefix: string; +}; + +type BasicInfoItemValueProps = BasicInfoLink & { + ellipsis?: boolean; + classPrefix: string; +}; + +export default function BasicInfo({ datas, className, style, labelWidth }: BasicInfoProps) { return (
{datas.map((item) => ( - + ))}
); } -type BasicInfoItemProps = { - data: BasicInfoData; - labelWidth?: number; -}; -function BasicInfoItem({ data, labelWidth = 100 }: BasicInfoItemProps) { - const { label, value, format } = data; +export function BasicInfoItem({ data, labelWidth, classPrefix }: BasicInfoItemProps) { + const { label, value, format, ellipsis } = data; const formatValue = format ? format(value) : value; + const myClassName = `${classPrefix}__item`; let valueComponent = undefined; if (Array.isArray(formatValue)) { valueComponent = ( -
+
{formatValue.map((item: BasicInfoLink) => ( - + ))}
); } else if (typeof formatValue === 'object' && formatValue) { valueComponent = ( - + ); } else { - valueComponent = ; + valueComponent = ( + + ); } return ( -
-
+
+
{label}
{valueComponent} @@ -64,35 +94,39 @@ function BasicInfoItem({ data, labelWidth = 100 }: BasicInfoItemProps) { ); } -type BasicInfoItemValueProps = { - value: string; - link?: string; - url?: string; -}; - -function BasicInfoItemValue({ value, link, url }: BasicInfoItemValueProps) { +export function BasicInfoItemValue({ + value, + link, + url, + ellipsis, + classPrefix, +}: BasicInfoItemValueProps) { + const myClassName = `${classPrefix}__item__value`; + let component = undefined; if (url && value) { - return ( - + component = ( + {value} ); } else if (link && value) { - return ( - + component = ( + {value} ); } else { - return ( -
{value ?? '--'}
- ); + component = {value ?? '--'}; } -} -export default BasicInfo; + return ( + + {component} + + ); +} diff --git a/react-ui/src/components/BasicTableInfo/index.less b/react-ui/src/components/BasicTableInfo/index.less new file mode 100644 index 00000000..cc3d0984 --- /dev/null +++ b/react-ui/src/components/BasicTableInfo/index.less @@ -0,0 +1,64 @@ +.kf-basic-table-info { + display: flex; + flex-direction: row; + flex-wrap: wrap; + align-items: stretch; + width: 100%; + border: 1px solid @border-color-base; + border-bottom: none; + border-radius: 4px; + + &__item { + display: flex; + align-items: stretch; + width: 25%; + border-bottom: 1px solid @border-color-base; + + &__label { + flex: none; + padding: 12px 20px; + color: @text-color-secondary; + font-size: 14px; + text-align: left; + background-color: .addAlpha(#606b7a, 0.05) []; + } + + &__value-container { + display: flex; + flex: 1; + flex-direction: column; + align-items: flex-start; + min-width: 0; + } + + &__value { + flex: 1; + margin: 0 !important; + padding: 12px 20px 4px; + font-size: @font-size; + white-space: pre-line; + word-break: break-all; + + & + & { + padding-top: 0; + } + + &:last-child { + padding-bottom: 12px; + } + + &--ellipsis { + .singleLine(); + } + + &__text { + color: @text-color; + } + + &__link:hover { + text-decoration: underline @underline-color; + text-underline-offset: 3px; + } + } + } +} diff --git a/react-ui/src/components/BasicTableInfo/index.tsx b/react-ui/src/components/BasicTableInfo/index.tsx new file mode 100644 index 00000000..df167ae2 --- /dev/null +++ b/react-ui/src/components/BasicTableInfo/index.tsx @@ -0,0 +1,43 @@ +import classNames from 'classnames'; +import { BasicInfoItem, type BasicInfoData, type BasicInfoLink } from '../BasicInfo'; +import './index.less'; +export type { BasicInfoData, BasicInfoLink }; + +type BasicTableInfoProps = { + datas: BasicInfoData[]; + className?: string; + style?: React.CSSProperties; + labelWidth: number; +}; + +export default function BasicTableInfo({ + datas, + className, + style, + labelWidth, +}: BasicTableInfoProps) { + const remainder = datas.length % 4; + const array = []; + if (remainder > 0) { + for (let i = 0; i < 4 - remainder; i++) { + array.push({ + label: '', + value: '', + }); + } + } + const showDatas = [...datas, ...array]; + + return ( +
+ {showDatas.map((item) => ( + + ))} +
+ ); +} diff --git a/react-ui/src/pages/Dataset/components/ResourceInfo/index.less b/react-ui/src/pages/Dataset/components/ResourceInfo/index.less index 6103b602..8cbba3d6 100644 --- a/react-ui/src/pages/Dataset/components/ResourceInfo/index.less +++ b/react-ui/src/pages/Dataset/components/ResourceInfo/index.less @@ -38,10 +38,6 @@ &__bottom { position: relative; height: calc(100% - 135px); - padding: 8px 30px 20px; - background: #ffffff; - border-radius: 10px; - box-shadow: 0px 2px 12px rgba(180, 182, 191, 0.09); &__legend { position: absolute; @@ -52,6 +48,12 @@ :global { .ant-tabs { height: 100%; + .ant-tabs-nav-wrap { + padding-top: 8px; + padding-left: 30px; + background-color: white; + border-radius: 10px 10px 0 0; + } .ant-tabs-content-holder { height: 100%; .ant-tabs-content { diff --git a/react-ui/src/pages/Dataset/components/ResourceInfo/index.tsx b/react-ui/src/pages/Dataset/components/ResourceInfo/index.tsx index fe1e9a86..159ba9f1 100644 --- a/react-ui/src/pages/Dataset/components/ResourceInfo/index.tsx +++ b/react-ui/src/pages/Dataset/components/ResourceInfo/index.tsx @@ -164,7 +164,16 @@ const ResourceInfo = ({ resourceType }: ResourceInfoProps) => { key: ResourceInfoTabKeys.Introduction, label: `${typeName}简介`, icon: , - children: , + children: ( + + ), }, { key: ResourceInfoTabKeys.Version, diff --git a/react-ui/src/pages/Dataset/components/ResourceIntro/index.less b/react-ui/src/pages/Dataset/components/ResourceIntro/index.less index 57d40216..6ac9223b 100644 --- a/react-ui/src/pages/Dataset/components/ResourceIntro/index.less +++ b/react-ui/src/pages/Dataset/components/ResourceIntro/index.less @@ -1,10 +1,25 @@ .resource-intro { width: 100%; - margin-top: 24px; - &__basic { - width: 100%; - } - &__usage { - width: 100%; + + &__top { + padding: 20px 30px; + background: white; + border-radius: 0 0 10px 10px; + box-shadow: 0px 2px 12px rgba(180, 182, 191, 0.09); + + pre { + margin-bottom: 0 !important; + } + + &__title { + margin: 15px 0; + color: @text-color-secondary; + font-size: 14px; + } + + &__desc { + color: @text-color; + font-size: @font-size; + } } } diff --git a/react-ui/src/pages/Dataset/components/ResourceIntro/index.tsx b/react-ui/src/pages/Dataset/components/ResourceIntro/index.tsx index 2ee7fb24..0aa3b7e3 100644 --- a/react-ui/src/pages/Dataset/components/ResourceIntro/index.tsx +++ b/react-ui/src/pages/Dataset/components/ResourceIntro/index.tsx @@ -1,4 +1,4 @@ -import BasicInfo, { BasicInfoData } from '@/components/BasicInfo'; +import BasicTableInfo, { BasicInfoData } from '@/components/BasicTableInfo'; import SubAreaTitle from '@/components/SubAreaTitle'; import { ResourceInfoTabKeys } from '@/pages/Dataset/components/ResourceInfo'; import { @@ -8,13 +8,19 @@ import { ProjectDependency, ResourceType, TrainTask, + resourceConfig, } from '@/pages/Dataset/config'; +import ModelMetrics from '@/pages/Model/components/ModelMetrics'; import { getGitUrl } from '@/utils'; import styles from './index.less'; type ResourceIntroProps = { resourceType: ResourceType; info: DatasetData | ModelData; + resourceId: number; + identifier: string; + owner: string; + version?: string; }; const formatDataset = (datasets?: DatasetData[]) => { @@ -27,29 +33,6 @@ const formatDataset = (datasets?: DatasetData[]) => { })); }; -const formatParams = (map?: Record, space: string = '') => { - if (!map || Object.keys(map).length === 0) { - return undefined; - } - return Object.entries(map) - .map(([key, value]) => `${space}${key} : ${value}`) - .join('\n'); -}; - -const formatMetrics = (map?: Record) => { - if (!map || Object.keys(map).length === 0) { - return undefined; - } - return Object.entries(map) - .map(([key, value]) => { - if (typeof value === 'object' && value !== null) { - return `${key} : \n${formatParams(value, ' ')}`; - } - return `${key} : ${value}`; - }) - .join('\n'); -}; - const getProjectUrl = (project?: ProjectDependency) => { if (!project || !project.url || !project.branch) { return undefined; @@ -93,49 +76,50 @@ const getDatasetDatas = (data: DatasetData): BasicInfoData[] => [ { label: '数据集名称', value: data.name, + ellipsis: true, }, { label: '版本', value: data.version, + ellipsis: true, }, { label: '创建人', value: data.create_by, + ellipsis: true, }, { label: '更新时间', value: data.update_time, + ellipsis: true, }, { label: '数据来源', value: data.dataset_source, format: formatSource, + ellipsis: true, }, { label: '训练任务', value: data.train_task, format: formatTrainTask, + ellipsis: true, }, { label: '处理代码', value: data.processing_code, format: formatProject, + ellipsis: true, }, { label: '数据集分类', value: data.data_type, + ellipsis: true, }, { label: '研究方向', value: data.data_tag, - }, - { - label: '数据集描述', - value: data.description, - }, - { - label: '版本描述', - value: data.version_desc, + ellipsis: true, }, ]; @@ -143,77 +127,79 @@ const getModelDatas = (data: ModelData): BasicInfoData[] => [ { label: '模型名称', value: data.name, + ellipsis: true, }, { label: '版本', value: data.version, + ellipsis: true, }, { label: '创建人', value: data.create_by, + ellipsis: true, }, { label: '更新时间', value: data.update_time, + ellipsis: true, }, { label: '训练镜像', value: data.image, + ellipsis: true, }, { label: '训练代码', value: data.project_depency, format: formatProject, + ellipsis: true, }, { label: '训练数据集', value: data.train_datasets, format: formatDataset, + ellipsis: true, }, { label: '测试数据集', value: data.test_datasets, format: formatDataset, - }, - { - label: '参数', - value: data.params, - format: formatParams, - }, - { - label: '指标', - value: data.metrics, - format: formatMetrics, + ellipsis: true, }, { label: '模型来源', value: data.model_source, format: formatSource, + ellipsis: true, }, { label: '训练任务', value: data.train_task, format: formatTrainTask, + ellipsis: true, }, { label: '模型框架', value: data.model_type, + ellipsis: true, }, { label: '模型能力', value: data.model_tag, - }, - { - label: '模型描述', - value: data.description, - }, - { - label: '版本描述', - value: data.version_desc, + ellipsis: true, }, ]; -function ResourceIntro({ resourceType, info }: ResourceIntroProps) { +function ResourceIntro({ + resourceType, + info, + resourceId, + identifier, + owner, + version, +}: ResourceIntroProps) { + const config = resourceConfig[resourceType]; const basicDatas: BasicInfoData[] = resourceType === ResourceType.Dataset ? getDatasetDatas(info as DatasetData) @@ -221,23 +207,37 @@ function ResourceIntro({ resourceType, info }: ResourceIntroProps) { return (
- -
- +
+ +
+ +
+
{`${config.name}描述`}
+
{info.description ?? '暂无描述'}
+
版本描述
+
{info.version_desc ?? '暂无描述'}
+ +
- -
+ {resourceType === ResourceType.Model && version && ( + + )}
); } diff --git a/react-ui/src/pages/Dataset/components/ResourceVersion/index.less b/react-ui/src/pages/Dataset/components/ResourceVersion/index.less index d36c5ab6..e40591bd 100644 --- a/react-ui/src/pages/Dataset/components/ResourceVersion/index.less +++ b/react-ui/src/pages/Dataset/components/ResourceVersion/index.less @@ -1,4 +1,9 @@ .resource-version { + min-height: 100%; + padding: 20px 30px; color: @text-color; font-size: @font-size-content; + background: white; + border-radius: 0 0 10px 10px; + box-shadow: 0px 2px 12px rgba(180, 182, 191, 0.09); } diff --git a/react-ui/src/pages/Dataset/components/ResourceVersion/index.tsx b/react-ui/src/pages/Dataset/components/ResourceVersion/index.tsx index 4a6d190c..44c54320 100644 --- a/react-ui/src/pages/Dataset/components/ResourceVersion/index.tsx +++ b/react-ui/src/pages/Dataset/components/ResourceVersion/index.tsx @@ -86,7 +86,7 @@ function ResourceVersion({ resourceType, info }: ResourceVersionProps) { return (
- +