diff --git a/react-ui/src/components/TableColTitle/index.less b/react-ui/src/components/TableColTitle/index.less new file mode 100644 index 00000000..51207953 --- /dev/null +++ b/react-ui/src/components/TableColTitle/index.less @@ -0,0 +1,3 @@ +.ant-table .ant-table-cell .kf-table-col-title { + margin-bottom: 0; +} diff --git a/react-ui/src/components/TableColTitle/index.tsx b/react-ui/src/components/TableColTitle/index.tsx new file mode 100644 index 00000000..0583f3ed --- /dev/null +++ b/react-ui/src/components/TableColTitle/index.tsx @@ -0,0 +1,32 @@ +/* + * @Author: 赵伟 + * @Date: 2025-03-11 10:52:23 + * @Description: 用于内容可变的表格类标题 + */ + +import { Typography } from 'antd'; +import classNames from 'classnames'; +import './index.less'; + +type TableColTitleProps = { + /** 标题 */ + title: string; + /** 自定义类名 */ + className?: string; + /** 自定义样式 */ + style?: React.CSSProperties; +}; + +function TableColTitle({ title, className, style }: TableColTitleProps) { + return ( + + {title} + + ); +} + +export default TableColTitle; diff --git a/react-ui/src/pages/AutoML/components/ExperimentHistory/index.tsx b/react-ui/src/pages/AutoML/components/ExperimentHistory/index.tsx index 223f768d..fa694b27 100644 --- a/react-ui/src/pages/AutoML/components/ExperimentHistory/index.tsx +++ b/react-ui/src/pages/AutoML/components/ExperimentHistory/index.tsx @@ -69,35 +69,30 @@ function ExperimentHistory({ fileUrl, isClassification }: ExperimentHistoryProps dataIndex: 'accuracy', key: 'accuracy', render: tableCellRender(true), - ellipsis: { showTitle: false }, }, { title: '耗时', dataIndex: 'duration', key: 'duration', render: tableCellRender(true), - ellipsis: { showTitle: false }, }, { title: '训练损失', dataIndex: 'train_loss', key: 'train_loss', render: tableCellRender(true), - ellipsis: { showTitle: false }, }, { title: '特征处理', dataIndex: 'feature', key: 'feature', render: tableCellRender(true), - ellipsis: { showTitle: false }, }, { title: '算法', dataIndex: 'althorithm', key: 'althorithm', render: tableCellRender(true), - ellipsis: { showTitle: false }, }, { title: '状态', diff --git a/react-ui/src/pages/AutoML/components/ExperimentInstance/index.less b/react-ui/src/pages/AutoML/components/ExperimentInstance/index.less index 3e7d2eec..6cd9ef98 100644 --- a/react-ui/src/pages/AutoML/components/ExperimentInstance/index.less +++ b/react-ui/src/pages/AutoML/components/ExperimentInstance/index.less @@ -26,7 +26,7 @@ .startTime { .singleLine(); - width: calc(20% + 10px); + width: 200px; } .status { diff --git a/react-ui/src/pages/AutoML/components/ExperimentInstance/index.tsx b/react-ui/src/pages/AutoML/components/ExperimentInstance/index.tsx index ab713f48..9c8ea687 100644 --- a/react-ui/src/pages/AutoML/components/ExperimentInstance/index.tsx +++ b/react-ui/src/pages/AutoML/components/ExperimentInstance/index.tsx @@ -8,7 +8,7 @@ import { elapsedTime, formatDate } from '@/utils/date'; import { to } from '@/utils/promise'; import { modalConfirm } from '@/utils/ui'; import { DoubleRightOutlined } from '@ant-design/icons'; -import { App, Button, Checkbox, ConfigProvider, Tooltip } from 'antd'; +import { App, Button, Checkbox, ConfigProvider, Typography } from 'antd'; import classNames from 'classnames'; import { useEffect, useMemo } from 'react'; import { ExperimentListType, experimentListConfig } from '../ExperimentList/config'; @@ -159,9 +159,9 @@ function ExperimentInstanceComponent({ {elapsedTime(item.create_time, item.finish_time)}
- - {formatDate(item.create_time)} - + + {formatDate(item.create_time)} +
- +
); } diff --git a/react-ui/src/pages/Experiment/Comparison/index.less b/react-ui/src/pages/Experiment/Comparison/index.less index b0984b91..e34f03ad 100644 --- a/react-ui/src/pages/Experiment/Comparison/index.less +++ b/react-ui/src/pages/Experiment/Comparison/index.less @@ -34,13 +34,13 @@ border-left: none !important; } } - .ant-table-tbody-virtual::after { - border-bottom: none !important; - } .ant-table-footer { padding: 0; border: none !important; } + .ant-table-column-title { + min-width: 0; + } } } } diff --git a/react-ui/src/pages/Experiment/Comparison/index.tsx b/react-ui/src/pages/Experiment/Comparison/index.tsx index 2a75467c..3ed44cd1 100644 --- a/react-ui/src/pages/Experiment/Comparison/index.tsx +++ b/react-ui/src/pages/Experiment/Comparison/index.tsx @@ -4,6 +4,7 @@ * @Description: 实验对比 */ +import TableColTitle from '@/components/TableColTitle'; import { getExpEvaluateInfosReq, getExpMetricsReq, @@ -13,7 +14,7 @@ import { tableSorter } from '@/utils'; import { to } from '@/utils/promise'; import tableCellRender, { TableCellValueType } from '@/utils/table'; import { useSearchParams } from '@umijs/max'; -import { App, Button, Table, TablePaginationConfig, TableProps, Tooltip } from 'antd'; +import { App, Button, Table, TablePaginationConfig, TableProps } from 'antd'; import classNames from 'classnames'; import { useEffect, useMemo, useState } from 'react'; import ExperimentStatusCell from '../components/ExperimentStatusCell'; @@ -154,7 +155,6 @@ function ExperimentComparison() { fixed: 'left', align: 'center', render: tableCellRender(true, TableCellValueType.Array), - ellipsis: { showTitle: false }, }, ], }, @@ -162,17 +162,12 @@ function ExperimentComparison() { title: `${config.title}参数`, align: 'center', children: paramsNames.map((name) => ({ - title: ( - - {name} - - ), + title: , dataIndex: ['params', name], key: name, - width: 120, + width: 150, align: 'center', render: tableCellRender(true), - ellipsis: { showTitle: false }, sorter: (a, b) => tableSorter(a.params?.[name], b.params?.[name]), showSorterTooltip: false, })), @@ -181,17 +176,12 @@ function ExperimentComparison() { title: `${config.title}指标`, align: 'center', children: metricsNames.map((name) => ({ - title: ( - - {name} - - ), + title: , dataIndex: ['metrics', name], key: name, - width: 120, + width: 150, align: 'center', render: tableCellRender(true), - ellipsis: { showTitle: false }, sorter: (a, b) => tableSorter(a.metrics?.[name], b.metrics?.[name]), showSorterTooltip: false, })), diff --git a/react-ui/src/pages/Experiment/components/ExperimentInstance/index.tsx b/react-ui/src/pages/Experiment/components/ExperimentInstance/index.tsx index 9b37dba8..2c80df24 100644 --- a/react-ui/src/pages/Experiment/components/ExperimentInstance/index.tsx +++ b/react-ui/src/pages/Experiment/components/ExperimentInstance/index.tsx @@ -13,7 +13,7 @@ import { elapsedTime, formatDate } from '@/utils/date'; import { to } from '@/utils/promise'; import { modalConfirm } from '@/utils/ui'; import { DoubleRightOutlined } from '@ant-design/icons'; -import { App, Button, Checkbox, ConfigProvider, Tooltip } from 'antd'; +import { App, Button, Checkbox, ConfigProvider, Typography } from 'antd'; import classNames from 'classnames'; import { useEffect, useMemo } from 'react'; import TensorBoardStatusCell from '../TensorBoardStatus'; @@ -186,9 +186,9 @@ function ExperimentInstanceComponent({
{elapsedTime(item.create_time, item.finish_time)}
- - {formatDate(item.create_time)} - + + {formatDate(item.create_time)} +
diff --git a/react-ui/src/pages/Experiment/index.jsx b/react-ui/src/pages/Experiment/index.jsx index efd18344..51c905bb 100644 --- a/react-ui/src/pages/Experiment/index.jsx +++ b/react-ui/src/pages/Experiment/index.jsx @@ -383,7 +383,7 @@ function Experiment() { title: '实验名称', dataIndex: 'name', key: 'name', - render: tableCellRender(), + render: tableCellRender(false), width: '16%', }, { @@ -400,7 +400,6 @@ function Experiment() { dataIndex: 'description', key: 'description', render: tableCellRender(true), - ellipsis: { showTitle: false }, }, { title: '最近五次运行状态', diff --git a/react-ui/src/pages/HyperParameter/components/ExperimentHistory/index.tsx b/react-ui/src/pages/HyperParameter/components/ExperimentHistory/index.tsx index 0e79687b..c4698464 100644 --- a/react-ui/src/pages/HyperParameter/components/ExperimentHistory/index.tsx +++ b/react-ui/src/pages/HyperParameter/components/ExperimentHistory/index.tsx @@ -1,14 +1,15 @@ import InfoGroup from '@/components/InfoGroup'; import KFIcon from '@/components/KFIcon'; +import TableColTitle from '@/components/TableColTitle'; import TrialStatusCell from '@/pages/HyperParameter/components/TrialStatusCell'; import { HyperParameterFile, HyperParameterTrial } from '@/pages/HyperParameter/types'; import { getExpMetricsReq } from '@/services/hyperParameter'; import { downLoadZip } from '@/utils/downloadfile'; import { to } from '@/utils/promise'; import tableCellRender, { TableCellValueType } from '@/utils/table'; -import { App, Button, Table, Tooltip, Tree, type TableProps, type TreeDataNode } from 'antd'; +import { App, Button, Table, Tree, type TableProps, type TreeDataNode } from 'antd'; import classNames from 'classnames'; -import { useState } from 'react'; +import { useEffect, useState } from 'react'; import styles from './index.less'; const { DirectoryTree } = Tree; @@ -22,13 +23,16 @@ function ExperimentHistory({ trialList = [] }: ExperimentHistoryProps) { const [selectedRowKeys, setSelectedRowKeys] = useState([]); const { message } = App.useApp(); const [tableData, setTableData] = useState([]); - const [loading, setLoading] = useState(true); + const [loading, setLoading] = useState(false); // 防止 Tabs 卡顿 - setTimeout(() => { - setTableData(trialList); - setLoading(false); - }, 100); + useEffect(() => { + setLoading(true); + setTimeout(() => { + setTableData(trialList); + setLoading(false); + }, 500); + }, []); // 计算 column const first: HyperParameterTrial | undefined = trialList[0]; @@ -43,6 +47,7 @@ function ExperimentHistory({ trialList = [] }: ExperimentHistoryProps) { dataIndex: 'index', key: 'index', width: 100, + fixed: 'left', render: (_text, record, index: number) => { return (
@@ -53,28 +58,36 @@ function ExperimentHistory({ trialList = [] }: ExperimentHistoryProps) { }, }, { - title: '运行次数', - dataIndex: 'training_iteration', - key: 'training_iteration', - width: 120, - render: tableCellRender(false), - }, - { - title: '平均时长(秒)', - dataIndex: 'time_avg', - key: 'time_avg', - width: 150, - render: tableCellRender(false, TableCellValueType.Custom, { - format: (value = 0) => Number(value).toFixed(2), - }), - ellipsis: { showTitle: false }, - }, - { - title: '状态', - dataIndex: 'status', - key: 'status', - width: 120, - render: TrialStatusCell, + title: '基本信息', + align: 'center', + children: [ + { + title: '运行次数', + dataIndex: 'training_iteration', + key: 'training_iteration', + width: 120, + fixed: 'left', + render: tableCellRender(false), + }, + { + title: '平均时长(秒)', + dataIndex: 'time_avg', + key: 'time_avg', + width: 150, + fixed: 'left', + render: tableCellRender(false, TableCellValueType.Custom, { + format: (value = 0) => Number(value).toFixed(2), + }), + }, + { + title: '状态', + dataIndex: 'status', + key: 'status', + width: 120, + fixed: 'left', + render: TrialStatusCell, + }, + ], }, ]; @@ -85,18 +98,12 @@ function ExperimentHistory({ trialList = [] }: ExperimentHistoryProps) { key: 'config', align: 'center', children: paramsNames.map((name) => ({ - title: ( - - {name} - - ), + title: , dataIndex: ['config', name], key: name, width: 120, align: 'center', render: tableCellRender(true), - ellipsis: { showTitle: false }, - showSorterTooltip: false, })), }); } @@ -108,18 +115,12 @@ function ExperimentHistory({ trialList = [] }: ExperimentHistoryProps) { key: 'metrics', align: 'center', children: metricNames.map((name) => ({ - title: ( - - {name} - - ), + title: , dataIndex: ['metric_analysis', name], key: name, width: 120, align: 'center', render: tableCellRender(true), - ellipsis: { showTitle: false }, - showSorterTooltip: false, })), }); } diff --git a/react-ui/src/pages/HyperParameter/components/ParameterInfo/index.tsx b/react-ui/src/pages/HyperParameter/components/ParameterInfo/index.tsx index 740010cc..d946a080 100644 --- a/react-ui/src/pages/HyperParameter/components/ParameterInfo/index.tsx +++ b/react-ui/src/pages/HyperParameter/components/ParameterInfo/index.tsx @@ -1,10 +1,11 @@ +import TableColTitle from '@/components/TableColTitle'; import { getReqParamName, type FormParameter, } from '@/pages/HyperParameter/components/CreateForm/utils'; import { HyperParameterData } from '@/pages/HyperParameter/types'; import tableCellRender, { TableCellValueType } from '@/utils/table'; -import { Table, Tooltip, type TableProps } from 'antd'; +import { Table, type TableProps } from 'antd'; import { useMemo } from 'react'; import styles from './index.less'; @@ -43,16 +44,14 @@ function ParameterInfo({ info }: ParameterInfoProps) { dataIndex: 'name', key: 'type', width: '40%', - render: tableCellRender(true), - ellipsis: { showTitle: false }, + render: tableCellRender('auto'), }, { title: '参数类型', dataIndex: 'type', key: 'type', width: '20%', - render: tableCellRender(true), - ellipsis: { showTitle: false }, + render: tableCellRender(false), }, { title: '取值范围', @@ -64,7 +63,6 @@ function ParameterInfo({ info }: ParameterInfoProps) { return JSON.stringify(value); }, }), - ellipsis: { showTitle: false }, }, ]; @@ -72,16 +70,11 @@ function ParameterInfo({ info }: ParameterInfoProps) { runParameters.length > 0 ? parameters.map(({ name }) => { return { - title: ( - - {name} - - ), + title: , dataIndex: name, key: name, width: 150, render: tableCellRender(true), - ellipsis: { showTitle: false }, }; }) : []; @@ -89,7 +82,14 @@ function ParameterInfo({ info }: ParameterInfoProps) { return (
超参数
-
+
手动运行超参数
); diff --git a/react-ui/src/pages/Mirror/List/index.tsx b/react-ui/src/pages/Mirror/List/index.tsx index 629563d4..cbb8d014 100644 --- a/react-ui/src/pages/Mirror/List/index.tsx +++ b/react-ui/src/pages/Mirror/List/index.tsx @@ -192,7 +192,6 @@ function MirrorList() { key: 'description', width: '35%', render: tableCellRender(true), - ellipsis: { showTitle: false }, }, { title: '创建时间', diff --git a/react-ui/src/pages/Model/components/ModelMetrics/index.less b/react-ui/src/pages/Model/components/ModelMetrics/index.less index 03123746..bca3516c 100644 --- a/react-ui/src/pages/Model/components/ModelMetrics/index.less +++ b/react-ui/src/pages/Model/components/ModelMetrics/index.less @@ -21,6 +21,9 @@ border-left: none !important; } } + .ant-table-column-title { + min-width: 0; + } } } diff --git a/react-ui/src/pages/Model/components/ModelMetrics/index.tsx b/react-ui/src/pages/Model/components/ModelMetrics/index.tsx index d01e36f8..110d28ce 100644 --- a/react-ui/src/pages/Model/components/ModelMetrics/index.tsx +++ b/react-ui/src/pages/Model/components/ModelMetrics/index.tsx @@ -1,10 +1,11 @@ import SubAreaTitle from '@/components/SubAreaTitle'; +import TableColTitle from '@/components/TableColTitle'; import { useCheck } from '@/hooks'; import { getModelPageVersionsReq, getModelVersionsMetricsReq } from '@/services/dataset'; import { tableSorter } from '@/utils'; import { to } from '@/utils/promise'; import tableCellRender from '@/utils/table'; -import { Checkbox, Table, Tooltip, type TablePaginationConfig, type TableProps } from 'antd'; +import { Checkbox, Flex, Table, type TablePaginationConfig, type TableProps } from 'antd'; import { useEffect, useMemo, useState } from 'react'; import MetricsChart, { MetricsChatData } from '../MetricsChart'; import styles from './index.less'; @@ -174,17 +175,12 @@ function ModelMetrics({ resourceId, identifier, owner, version }: ModelMetricsPr title: `训练参数`, align: 'center', children: paramsNames.map((name) => ({ - title: ( - - {name} - - ), + title: , dataIndex: ['params', name], key: name, - width: 120, + width: 150, align: 'center', render: tableCellRender(true), - ellipsis: { showTitle: false }, sorter: (a, b) => tableSorter(a.params?.[name], b.params?.[name]), showSorterTooltip: false, })), @@ -197,14 +193,14 @@ function ModelMetrics({ resourceId, identifier, owner, version }: ModelMetricsPr indeterminate={metricsIndeterminate} onChange={checkAllMetrics} disabled={metricsNames.length === 0} - >{' '} - 训练指标 + > + 训练指标 ), align: 'center', children: metricsNames.map((name) => ({ title: ( -
+ { @@ -212,18 +208,15 @@ function ModelMetrics({ resourceId, identifier, owner, version }: ModelMetricsPr checkSingleMetrics(name); }} onClick={(e) => e.stopPropagation()} - >{' '} - - {name} - -
+ > + + ), dataIndex: ['metrics', name], key: name, - width: 120, + width: 150, align: 'center', render: tableCellRender(true), - ellipsis: { showTitle: false }, sorter: (a, b) => tableSorter(a.metrics?.[name], b.metrics?.[name]), showSorterTooltip: false, })), @@ -253,6 +246,8 @@ function ModelMetrics({ resourceId, identifier, owner, version }: ModelMetricsPr }} onChange={handleTableChange} rowKey="name" + tableLayout="fixed" + scroll={{ x: '100%' }} />
diff --git a/react-ui/src/pages/ModelDeployment/ServiceInfo/index.tsx b/react-ui/src/pages/ModelDeployment/ServiceInfo/index.tsx index b4cfb84a..143315a1 100644 --- a/react-ui/src/pages/ModelDeployment/ServiceInfo/index.tsx +++ b/react-ui/src/pages/ModelDeployment/ServiceInfo/index.tsx @@ -285,7 +285,6 @@ function ServiceInfo() { key: 'model', width: '20%', render: tableCellRender(true), - ellipsis: { showTitle: false }, }, { title: '状态', @@ -300,7 +299,6 @@ function ServiceInfo() { key: 'image', width: '20%', render: tableCellRender(true), - ellipsis: { showTitle: false }, }, { title: '副本数量', @@ -317,7 +315,6 @@ function ServiceInfo() { render: tableCellRender(true, TableCellValueType.Custom, { format: getResourceDescription, }), - ellipsis: { showTitle: false }, }, { title: '操作', diff --git a/react-ui/src/pages/Pipeline/index.jsx b/react-ui/src/pages/Pipeline/index.jsx index 2ba1b963..08d1ccf6 100644 --- a/react-ui/src/pages/Pipeline/index.jsx +++ b/react-ui/src/pages/Pipeline/index.jsx @@ -152,6 +152,7 @@ const Pipeline = () => { title: '流水线名称', dataIndex: 'name', key: 'name', + width: '50%', render: tableCellRender(false, TableCellValueType.Link, { onClick: gotoDetail, }), @@ -160,19 +161,21 @@ const Pipeline = () => { title: '流水线描述', dataIndex: 'description', key: 'description', + width: '50%', render: tableCellRender(true), - ellipsis: { showTitle: false }, }, { title: '创建时间', dataIndex: 'create_time', key: 'create_time', + width: 180, render: tableCellRender(false, TableCellValueType.Date), }, { title: '修改时间', dataIndex: 'update_time', key: 'update_time', + width: 180, render: tableCellRender(false, TableCellValueType.Date), }, { diff --git a/react-ui/src/stories/BasicTableInfo.stories.tsx b/react-ui/src/stories/BasicTableInfo.stories.tsx index 3d261d03..7f9e9e84 100644 --- a/react-ui/src/stories/BasicTableInfo.stories.tsx +++ b/react-ui/src/stories/BasicTableInfo.stories.tsx @@ -4,7 +4,7 @@ import * as BasicInfoStories from './BasicInfo.stories'; // More on how to set up stories at: https://storybook.js.org/docs/writing-stories#default-export const meta = { - title: 'Components/BasicTableInfo 表格基本信息', + title: 'Components/BasicTableInfo 基本信息表格版', component: BasicTableInfo, parameters: { // Optional parameter to center the component in the Canvas. More info: https://storybook.js.org/docs/configure/story-layout diff --git a/react-ui/src/stories/example/Configure.mdx b/react-ui/src/stories/docs/Configure.mdx similarity index 99% rename from react-ui/src/stories/example/Configure.mdx rename to react-ui/src/stories/docs/Configure.mdx index 6a537304..7651e269 100644 --- a/react-ui/src/stories/example/Configure.mdx +++ b/react-ui/src/stories/docs/Configure.mdx @@ -31,7 +31,7 @@ export const RightArrow = () => - +
diff --git a/react-ui/src/stories/example/assets/accessibility.png b/react-ui/src/stories/docs/assets/accessibility.png similarity index 100% rename from react-ui/src/stories/example/assets/accessibility.png rename to react-ui/src/stories/docs/assets/accessibility.png diff --git a/react-ui/src/stories/example/assets/accessibility.svg b/react-ui/src/stories/docs/assets/accessibility.svg similarity index 100% rename from react-ui/src/stories/example/assets/accessibility.svg rename to react-ui/src/stories/docs/assets/accessibility.svg diff --git a/react-ui/src/stories/example/assets/addon-library.png b/react-ui/src/stories/docs/assets/addon-library.png similarity index 100% rename from react-ui/src/stories/example/assets/addon-library.png rename to react-ui/src/stories/docs/assets/addon-library.png diff --git a/react-ui/src/stories/example/assets/assets.png b/react-ui/src/stories/docs/assets/assets.png similarity index 100% rename from react-ui/src/stories/example/assets/assets.png rename to react-ui/src/stories/docs/assets/assets.png diff --git a/react-ui/src/stories/example/assets/avif-test-image.avif b/react-ui/src/stories/docs/assets/avif-test-image.avif similarity index 100% rename from react-ui/src/stories/example/assets/avif-test-image.avif rename to react-ui/src/stories/docs/assets/avif-test-image.avif diff --git a/react-ui/src/stories/example/assets/context.png b/react-ui/src/stories/docs/assets/context.png similarity index 100% rename from react-ui/src/stories/example/assets/context.png rename to react-ui/src/stories/docs/assets/context.png diff --git a/react-ui/src/stories/example/assets/discord.svg b/react-ui/src/stories/docs/assets/discord.svg similarity index 100% rename from react-ui/src/stories/example/assets/discord.svg rename to react-ui/src/stories/docs/assets/discord.svg diff --git a/react-ui/src/stories/example/assets/docs.png b/react-ui/src/stories/docs/assets/docs.png similarity index 100% rename from react-ui/src/stories/example/assets/docs.png rename to react-ui/src/stories/docs/assets/docs.png diff --git a/react-ui/src/stories/example/assets/figma-plugin.png b/react-ui/src/stories/docs/assets/figma-plugin.png similarity index 100% rename from react-ui/src/stories/example/assets/figma-plugin.png rename to react-ui/src/stories/docs/assets/figma-plugin.png diff --git a/react-ui/src/stories/example/assets/github.svg b/react-ui/src/stories/docs/assets/github.svg similarity index 100% rename from react-ui/src/stories/example/assets/github.svg rename to react-ui/src/stories/docs/assets/github.svg diff --git a/react-ui/src/stories/example/assets/share.png b/react-ui/src/stories/docs/assets/share.png similarity index 100% rename from react-ui/src/stories/example/assets/share.png rename to react-ui/src/stories/docs/assets/share.png diff --git a/react-ui/src/stories/example/assets/styling.png b/react-ui/src/stories/docs/assets/styling.png similarity index 100% rename from react-ui/src/stories/example/assets/styling.png rename to react-ui/src/stories/docs/assets/styling.png diff --git a/react-ui/src/stories/example/assets/testing.png b/react-ui/src/stories/docs/assets/testing.png similarity index 100% rename from react-ui/src/stories/example/assets/testing.png rename to react-ui/src/stories/docs/assets/testing.png diff --git a/react-ui/src/stories/example/assets/theming.png b/react-ui/src/stories/docs/assets/theming.png similarity index 100% rename from react-ui/src/stories/example/assets/theming.png rename to react-ui/src/stories/docs/assets/theming.png diff --git a/react-ui/src/stories/example/assets/tutorials.svg b/react-ui/src/stories/docs/assets/tutorials.svg similarity index 100% rename from react-ui/src/stories/example/assets/tutorials.svg rename to react-ui/src/stories/docs/assets/tutorials.svg diff --git a/react-ui/src/stories/example/assets/youtube.svg b/react-ui/src/stories/docs/assets/youtube.svg similarity index 100% rename from react-ui/src/stories/example/assets/youtube.svg rename to react-ui/src/stories/docs/assets/youtube.svg diff --git a/react-ui/src/stories/example/Button.stories.ts b/react-ui/src/stories/example/Button.stories.ts deleted file mode 100644 index 2a05e01b..00000000 --- a/react-ui/src/stories/example/Button.stories.ts +++ /dev/null @@ -1,53 +0,0 @@ -import type { Meta, StoryObj } from '@storybook/react'; -import { fn } from '@storybook/test'; - -import { Button } from './Button'; - -// More on how to set up stories at: https://storybook.js.org/docs/writing-stories#default-export -const meta = { - title: 'Example/Button', - component: Button, - parameters: { - // Optional parameter to center the component in the Canvas. More info: https://storybook.js.org/docs/configure/story-layout - layout: 'centered', - }, - // This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/writing-docs/autodocs - tags: ['autodocs'], - // More on argTypes: https://storybook.js.org/docs/api/argtypes - argTypes: { - backgroundColor: { control: 'color' }, - }, - // Use `fn` to spy on the onClick arg, which will appear in the actions panel once invoked: https://storybook.js.org/docs/essentials/actions#action-args - args: { onClick: fn() }, -} satisfies Meta; - -export default meta; -type Story = StoryObj; - -// More on writing stories with args: https://storybook.js.org/docs/writing-stories/args -export const Primary: Story = { - args: { - primary: true, - label: 'Button', - }, -}; - -export const Secondary: Story = { - args: { - label: 'Button', - }, -}; - -export const Large: Story = { - args: { - size: 'large', - label: 'Button', - }, -}; - -export const Small: Story = { - args: { - size: 'small', - label: 'Button', - }, -}; diff --git a/react-ui/src/stories/example/Button.tsx b/react-ui/src/stories/example/Button.tsx deleted file mode 100644 index f35dafdc..00000000 --- a/react-ui/src/stories/example/Button.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import React from 'react'; - -import './button.css'; - -export interface ButtonProps { - /** Is this the principal call to action on the page? */ - primary?: boolean; - /** What background color to use */ - backgroundColor?: string; - /** How large should the button be? */ - size?: 'small' | 'medium' | 'large'; - /** Button contents */ - label: string; - /** Optional click handler */ - onClick?: () => void; -} - -/** Primary UI component for user interaction */ -export const Button = ({ - primary = false, - size = 'medium', - backgroundColor, - label, - ...props -}: ButtonProps) => { - const mode = primary ? 'storybook-button--primary' : 'storybook-button--secondary'; - return ( - - ); -}; diff --git a/react-ui/src/stories/example/Header.stories.ts b/react-ui/src/stories/example/Header.stories.ts deleted file mode 100644 index 80c71d0f..00000000 --- a/react-ui/src/stories/example/Header.stories.ts +++ /dev/null @@ -1,33 +0,0 @@ -import type { Meta, StoryObj } from '@storybook/react'; -import { fn } from '@storybook/test'; - -import { Header } from './Header'; - -const meta = { - title: 'Example/Header', - component: Header, - // This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/writing-docs/autodocs - tags: ['autodocs'], - parameters: { - // More on how to position stories at: https://storybook.js.org/docs/configure/story-layout - layout: 'fullscreen', - }, - args: { - onLogin: fn(), - onLogout: fn(), - onCreateAccount: fn(), - }, -} satisfies Meta; - -export default meta; -type Story = StoryObj; - -export const LoggedIn: Story = { - args: { - user: { - name: 'Jane Doe', - }, - }, -}; - -export const LoggedOut: Story = {}; diff --git a/react-ui/src/stories/example/Header.tsx b/react-ui/src/stories/example/Header.tsx deleted file mode 100644 index 1bf981a4..00000000 --- a/react-ui/src/stories/example/Header.tsx +++ /dev/null @@ -1,56 +0,0 @@ -import React from 'react'; - -import { Button } from './Button'; -import './header.css'; - -type User = { - name: string; -}; - -export interface HeaderProps { - user?: User; - onLogin?: () => void; - onLogout?: () => void; - onCreateAccount?: () => void; -} - -export const Header = ({ user, onLogin, onLogout, onCreateAccount }: HeaderProps) => ( -
-
-
- - - - - - - -

Acme

-
-
- {user ? ( - <> - - Welcome, {user.name}! - -
-
-
-); diff --git a/react-ui/src/stories/example/Page.stories.ts b/react-ui/src/stories/example/Page.stories.ts deleted file mode 100644 index 5d2c688a..00000000 --- a/react-ui/src/stories/example/Page.stories.ts +++ /dev/null @@ -1,32 +0,0 @@ -import type { Meta, StoryObj } from '@storybook/react'; -import { expect, userEvent, within } from '@storybook/test'; - -import { Page } from './Page'; - -const meta = { - title: 'Example/Page', - component: Page, - parameters: { - // More on how to position stories at: https://storybook.js.org/docs/configure/story-layout - layout: 'fullscreen', - }, -} satisfies Meta; - -export default meta; -type Story = StoryObj; - -export const LoggedOut: Story = {}; - -// More on component testing: https://storybook.js.org/docs/writing-tests/component-testing -export const LoggedIn: Story = { - play: async ({ canvasElement }) => { - const canvas = within(canvasElement); - const loginButton = canvas.getByRole('button', { name: /Log in/i }); - await expect(loginButton).toBeInTheDocument(); - await userEvent.click(loginButton); - await expect(loginButton).not.toBeInTheDocument(); - - const logoutButton = canvas.getByRole('button', { name: /Log out/i }); - await expect(logoutButton).toBeInTheDocument(); - }, -}; diff --git a/react-ui/src/stories/example/Page.tsx b/react-ui/src/stories/example/Page.tsx deleted file mode 100644 index e1174830..00000000 --- a/react-ui/src/stories/example/Page.tsx +++ /dev/null @@ -1,73 +0,0 @@ -import React from 'react'; - -import { Header } from './Header'; -import './page.css'; - -type User = { - name: string; -}; - -export const Page: React.FC = () => { - const [user, setUser] = React.useState(); - - return ( -
-
setUser({ name: 'Jane Doe' })} - onLogout={() => setUser(undefined)} - onCreateAccount={() => setUser({ name: 'Jane Doe' })} - /> - -
-

Pages in Storybook

-

- We recommend building UIs with a{' '} - - component-driven - {' '} - process starting with atomic components and ending with pages. -

-

- Render pages with mock data. This makes it easy to build and review page states without - needing to navigate to them in your app. Here are some handy patterns for managing page - data in Storybook: -

-
    -
  • - Use a higher-level connected component. Storybook helps you compose such data from the - "args" of child component stories -
  • -
  • - Assemble data in the page component from your services. You can mock these services out - using Storybook. -
  • -
-

- Get a guided tutorial on component-driven development at{' '} - - Storybook tutorials - - . Read more in the{' '} - - docs - - . -

-
- Tip Adjust the width of the canvas with the{' '} - - - - - - Viewports addon in the toolbar -
-
-
- ); -}; diff --git a/react-ui/src/stories/example/button.css b/react-ui/src/stories/example/button.css deleted file mode 100644 index 4e3620b0..00000000 --- a/react-ui/src/stories/example/button.css +++ /dev/null @@ -1,30 +0,0 @@ -.storybook-button { - display: inline-block; - cursor: pointer; - border: 0; - border-radius: 3em; - font-weight: 700; - line-height: 1; - font-family: 'Nunito Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif; -} -.storybook-button--primary { - background-color: #555ab9; - color: white; -} -.storybook-button--secondary { - box-shadow: rgba(0, 0, 0, 0.15) 0px 0px 0px 1px inset; - background-color: transparent; - color: #333; -} -.storybook-button--small { - padding: 10px 16px; - font-size: 12px; -} -.storybook-button--medium { - padding: 11px 20px; - font-size: 14px; -} -.storybook-button--large { - padding: 12px 24px; - font-size: 16px; -} diff --git a/react-ui/src/stories/example/header.css b/react-ui/src/stories/example/header.css deleted file mode 100644 index 5efd46c2..00000000 --- a/react-ui/src/stories/example/header.css +++ /dev/null @@ -1,32 +0,0 @@ -.storybook-header { - display: flex; - justify-content: space-between; - align-items: center; - border-bottom: 1px solid rgba(0, 0, 0, 0.1); - padding: 15px 20px; - font-family: 'Nunito Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif; -} - -.storybook-header svg { - display: inline-block; - vertical-align: top; -} - -.storybook-header h1 { - display: inline-block; - vertical-align: top; - margin: 6px 0 6px 10px; - font-weight: 700; - font-size: 20px; - line-height: 1; -} - -.storybook-header button + button { - margin-left: 10px; -} - -.storybook-header .welcome { - margin-right: 10px; - color: #333; - font-size: 14px; -} diff --git a/react-ui/src/stories/example/page.css b/react-ui/src/stories/example/page.css deleted file mode 100644 index 77c81d2d..00000000 --- a/react-ui/src/stories/example/page.css +++ /dev/null @@ -1,68 +0,0 @@ -.storybook-page { - margin: 0 auto; - padding: 48px 20px; - max-width: 600px; - color: #333; - font-size: 14px; - line-height: 24px; - font-family: 'Nunito Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif; -} - -.storybook-page h2 { - display: inline-block; - vertical-align: top; - margin: 0 0 4px; - font-weight: 700; - font-size: 32px; - line-height: 1; -} - -.storybook-page p { - margin: 1em 0; -} - -.storybook-page a { - color: inherit; -} - -.storybook-page ul { - margin: 1em 0; - padding-left: 30px; -} - -.storybook-page li { - margin-bottom: 8px; -} - -.storybook-page .tip { - display: inline-block; - vertical-align: top; - margin-right: 10px; - border-radius: 1em; - background: #e7fdd8; - padding: 4px 12px; - color: #357a14; - font-weight: 700; - font-size: 11px; - line-height: 12px; -} - -.storybook-page .tip-wrapper { - margin-top: 40px; - margin-bottom: 40px; - font-size: 13px; - line-height: 20px; -} - -.storybook-page .tip-wrapper svg { - display: inline-block; - vertical-align: top; - margin-top: 3px; - margin-right: 4px; - width: 12px; - height: 12px; -} - -.storybook-page .tip-wrapper svg path { - fill: #1ea7fd; -} diff --git a/react-ui/src/utils/table.tsx b/react-ui/src/utils/table.tsx index d3ec10d6..30cdedc9 100644 --- a/react-ui/src/utils/table.tsx +++ b/react-ui/src/utils/table.tsx @@ -6,7 +6,7 @@ import { isEmpty } from '@/utils'; import { formatDate } from '@/utils/date'; -import { Tooltip } from 'antd'; +import { Tooltip, TooltipProps, Typography } from 'antd'; import dayjs from 'dayjs'; export enum TableCellValueType { @@ -65,7 +65,7 @@ function formatArray(property?: string): TableCellFormatter { } function tableCellRender( - ellipsis: boolean = false, + ellipsis: boolean | TooltipProps | 'auto' = false, type: TableCellValueType = TableCellValueType.Text, options?: TableCellValueOptions, ) { @@ -92,41 +92,83 @@ function tableCellRender( break; } - if (ellipsis && text) { + if (ellipsis === 'auto' && text) { + return renderCell(type, text, 'auto', record, options?.onClick); + } else if (ellipsis && text) { + const tooltipProps = typeof ellipsis === 'object' ? ellipsis : {}; + const { overlayStyle, ...rest } = tooltipProps; return ( - - {renderCell(text, type === TableCellValueType.Link, record, options?.onClick)} + + {renderCell(type, text, true, record, options?.onClick)} ); } else { - return renderCell(text, type === TableCellValueType.Link, record, options?.onClick); + return renderCell(type, text, false, record, options?.onClick); } }; } function renderCell( + type: TableCellValueType, text: any | undefined | null, - isLink: boolean, + ellipsis: boolean | 'auto', record: T, onClick?: (record: T, e: React.MouseEvent) => void, ) { - return isLink ? renderLink(text, record, onClick) : renderText(text); -} - -function renderText(text: any | undefined | null) { - return {!isEmpty(text) ? text : '--'}; + return type === TableCellValueType.Link + ? renderLink(text, ellipsis, record, onClick) + : renderText(text, ellipsis); } function renderLink( text: any | undefined | null, + ellipsis: boolean | 'auto', record: T, onClick?: (record: T, e: React.MouseEvent) => void, ) { return ( onClick?.(record, e)}> - {text} + {renderText(text, ellipsis)} ); } +function renderText(text: any | undefined | null, ellipsis: boolean | 'auto') { + if (ellipsis === 'auto') { + return ( + + {!isEmpty(text) ? text : '--'} + + ); + } + + return ( + + {!isEmpty(text) ? text : '--'} + + ); +} + export default tableCellRender;