| @@ -26,6 +26,7 @@ import { | |||||
| ConfigProvider, | ConfigProvider, | ||||
| Input, | Input, | ||||
| Table, | Table, | ||||
| Tooltip, | |||||
| type TablePaginationConfig, | type TablePaginationConfig, | ||||
| type TableProps, | type TableProps, | ||||
| } from 'antd'; | } from 'antd'; | ||||
| @@ -276,13 +277,18 @@ function AutoMLList() { | |||||
| {newText && newText.length > 0 | {newText && newText.length > 0 | ||||
| ? newText.map((item, index) => { | ? newText.map((item, index) => { | ||||
| return ( | return ( | ||||
| <img | |||||
| style={{ width: '17px', marginRight: '6px' }} | |||||
| <Tooltip | |||||
| key={index} | key={index} | ||||
| src={experimentStatusInfo[item as ExperimentStatus].icon} | |||||
| draggable={false} | |||||
| alt="" | |||||
| /> | |||||
| placement="top" | |||||
| title={experimentStatusInfo[item as ExperimentStatus].label} | |||||
| > | |||||
| <img | |||||
| style={{ width: '17px', marginRight: '6px' }} | |||||
| src={experimentStatusInfo[item as ExperimentStatus].icon} | |||||
| draggable={false} | |||||
| alt="" | |||||
| /> | |||||
| </Tooltip> | |||||
| ); | ); | ||||
| }) | }) | ||||
| : null} | : null} | ||||
| @@ -54,13 +54,9 @@ | |||||
| width: 200px; | width: 200px; | ||||
| .statusIcon { | .statusIcon { | ||||
| visibility: hidden; | |||||
| transition: all 0.2s; | |||||
| visibility: visible; | |||||
| } | } | ||||
| } | } | ||||
| .statusBox:hover .statusIcon { | |||||
| visibility: visible; | |||||
| } | |||||
| } | } | ||||
| .loadMoreBox { | .loadMoreBox { | ||||
| @@ -57,13 +57,9 @@ | |||||
| width: 200px; | width: 200px; | ||||
| .statusIcon { | .statusIcon { | ||||
| visibility: hidden; | |||||
| transition: all 0.2s; | |||||
| visibility: visible; | |||||
| } | } | ||||
| } | } | ||||
| .statusBox:hover .statusIcon { | |||||
| visibility: visible; | |||||
| } | |||||
| } | } | ||||
| .loadMoreBox { | .loadMoreBox { | ||||
| @@ -98,6 +98,17 @@ function ExperimentInstanceComponent({ | |||||
| } | } | ||||
| }; | }; | ||||
| // 终止实验实例 | |||||
| const handleTerminate = (instance: ExperimentInstance) => { | |||||
| modalConfirm({ | |||||
| title: '确定要终止这次实验运行吗?', | |||||
| isDelete: false, | |||||
| onOk: () => { | |||||
| terminateExperimentInstance(instance); | |||||
| }, | |||||
| }); | |||||
| }; | |||||
| // 终止实验实例 | // 终止实验实例 | ||||
| const terminateExperimentInstance = async (instance: ExperimentInstance) => { | const terminateExperimentInstance = async (instance: ExperimentInstance) => { | ||||
| const [res] = await to(putQueryByExperimentInsId(instance.id)); | const [res] = await to(putQueryByExperimentInsId(instance.id)); | ||||
| @@ -202,7 +213,7 @@ function ExperimentInstanceComponent({ | |||||
| item.status === ExperimentStatus.Terminated | item.status === ExperimentStatus.Terminated | ||||
| } | } | ||||
| icon={<KFIcon type="icon-zhongzhi" />} | icon={<KFIcon type="icon-zhongzhi" />} | ||||
| onClick={() => terminateExperimentInstance(item)} | |||||
| onClick={() => handleTerminate(item)} | |||||
| > | > | ||||
| 终止 | 终止 | ||||
| </Button> | </Button> | ||||
| @@ -1,12 +1,3 @@ | |||||
| .experiment-status-cell { | .experiment-status-cell { | ||||
| height: 100%; | height: 100%; | ||||
| &__label { | |||||
| display: none; | |||||
| } | |||||
| } | |||||
| .experiment-status-cell:hover { | |||||
| .experiment-status-cell__label { | |||||
| display: inline; | |||||
| } | |||||
| } | } | ||||
| @@ -1,5 +1,7 @@ | |||||
| import KFIcon from '@/components/KFIcon'; | import KFIcon from '@/components/KFIcon'; | ||||
| import PageTitle from '@/components/PageTitle'; | |||||
| import { ExperimentStatus, TensorBoardStatus } from '@/enums'; | import { ExperimentStatus, TensorBoardStatus } from '@/enums'; | ||||
| import { useCacheState } from '@/hooks/pageCacheState'; | |||||
| import { | import { | ||||
| deleteExperimentById, | deleteExperimentById, | ||||
| getExperiment, | getExperiment, | ||||
| @@ -16,14 +18,14 @@ import themes from '@/styles/theme.less'; | |||||
| import { to } from '@/utils/promise'; | import { to } from '@/utils/promise'; | ||||
| import tableCellRender, { TableCellValueType } from '@/utils/table'; | import tableCellRender, { TableCellValueType } from '@/utils/table'; | ||||
| import { modalConfirm } from '@/utils/ui'; | import { modalConfirm } from '@/utils/ui'; | ||||
| import { App, Button, ConfigProvider, Dropdown, Space, Table } from 'antd'; | |||||
| import { App, Button, ConfigProvider, Dropdown, Input, Space, Table, Tooltip } from 'antd'; | |||||
| import classNames from 'classnames'; | import classNames from 'classnames'; | ||||
| import { useEffect, useRef, useState } from 'react'; | |||||
| import { useEffect, useState } from 'react'; | |||||
| import { useNavigate } from 'react-router-dom'; | import { useNavigate } from 'react-router-dom'; | ||||
| import { ComparisonType } from './Comparison/config'; | import { ComparisonType } from './Comparison/config'; | ||||
| import AddExperimentModal from './components/AddExperimentModal'; | import AddExperimentModal from './components/AddExperimentModal'; | ||||
| import ExperimentInstance from './components/ExperimentInstance'; | import ExperimentInstance from './components/ExperimentInstance'; | ||||
| import Styles from './index.less'; | |||||
| import styles from './index.less'; | |||||
| import { experimentStatusInfo } from './status'; | import { experimentStatusInfo } from './status'; | ||||
| // 定时器 | // 定时器 | ||||
| @@ -47,32 +49,34 @@ function Experiment() { | |||||
| const [isModalOpen, setIsModalOpen] = useState(false); | const [isModalOpen, setIsModalOpen] = useState(false); | ||||
| const [addFormData, setAddFormData] = useState({}); | const [addFormData, setAddFormData] = useState({}); | ||||
| const [experimentInsTotal, setExperimentInsTotal] = useState(0); | const [experimentInsTotal, setExperimentInsTotal] = useState(0); | ||||
| const [cacheState, setCacheState] = useCacheState(); | |||||
| const [searchText, setSearchText] = useState(cacheState?.searchText); | |||||
| const [inputText, setInputText] = useState(cacheState?.searchText); | |||||
| const [pagination, setPagination] = useState( | |||||
| cacheState?.pagination ?? { | |||||
| current: 1, | |||||
| pageSize: 10, | |||||
| }, | |||||
| ); | |||||
| const { message } = App.useApp(); | const { message } = App.useApp(); | ||||
| const pageOption = useRef({ page: 1, size: 10 }); | |||||
| const paginationProps = { | |||||
| showSizeChanger: true, | |||||
| showQuickJumper: true, | |||||
| showTotal: () => `共${total}条`, | |||||
| total: total, | |||||
| page: pageOption.current.page, | |||||
| size: pageOption.current.size, | |||||
| onChange: (current, size) => paginationChange(current, size), | |||||
| }; | |||||
| useEffect(() => { | useEffect(() => { | ||||
| getExperimentList(); | |||||
| getWorkflowList(); | getWorkflowList(); | ||||
| return () => { | return () => { | ||||
| clearExperimentInTimers(); | clearExperimentInTimers(); | ||||
| }; | }; | ||||
| }, []); | }, []); | ||||
| useEffect(() => { | |||||
| getExperimentList(); | |||||
| }, [pagination, searchText]); | |||||
| // 获取实验列表 | // 获取实验列表 | ||||
| const getExperimentList = async () => { | const getExperimentList = async () => { | ||||
| const params = { | const params = { | ||||
| offset: 0, | |||||
| page: pageOption.current.page - 1, | |||||
| size: pageOption.current.size, | |||||
| page: pagination.current - 1, | |||||
| size: pagination.pageSize, | |||||
| name: searchText || undefined, | |||||
| }; | }; | ||||
| const [res] = await to(getExperiment(params)); | const [res] = await to(getExperiment(params)); | ||||
| if (res && res.data && Array.isArray(res.data.content)) { | if (res && res.data && Array.isArray(res.data.content)) { | ||||
| @@ -94,6 +98,15 @@ function Experiment() { | |||||
| } | } | ||||
| }; | }; | ||||
| // 搜索 | |||||
| const onSearch = (value) => { | |||||
| setSearchText(value); | |||||
| setPagination((prev) => ({ | |||||
| ...prev, | |||||
| current: 1, | |||||
| })); | |||||
| }; | |||||
| // 获取实验实例列表 | // 获取实验实例列表 | ||||
| const getQueryByExperiment = async (experimentId, page) => { | const getQueryByExperiment = async (experimentId, page) => { | ||||
| const params = { | const params = { | ||||
| @@ -259,11 +272,11 @@ function Experiment() { | |||||
| }; | }; | ||||
| // 当前页面切换 | // 当前页面切换 | ||||
| const paginationChange = async (current, size) => { | |||||
| pageOption.current = { | |||||
| page: current, | |||||
| size: size, | |||||
| }; | |||||
| const paginationChange = async (current, pageSize) => { | |||||
| setPagination({ | |||||
| current, | |||||
| pageSize, | |||||
| }); | |||||
| getExperimentList(); | getExperimentList(); | ||||
| }; | }; | ||||
| // 运行实验 | // 运行实验 | ||||
| @@ -278,14 +291,23 @@ function Experiment() { | |||||
| } | } | ||||
| }; | }; | ||||
| // 跳转, 缓存当前状态 | |||||
| const navigateToUrl = (url) => { | |||||
| setCacheState({ | |||||
| pagination, | |||||
| searchText, | |||||
| }); | |||||
| navigate(url); | |||||
| }; | |||||
| // 跳转到流水线 | // 跳转到流水线 | ||||
| const gotoPipeline = (record) => { | const gotoPipeline = (record) => { | ||||
| navigate({ pathname: `/pipeline/template/info/${record.workflow_id}` }); | |||||
| navigateToUrl(`/pipeline/template/info/${record.workflow_id}`); | |||||
| }; | }; | ||||
| // 跳转到实验实例详情 | // 跳转到实验实例详情 | ||||
| const gotoInstanceInfo = (item, record) => { | const gotoInstanceInfo = (item, record) => { | ||||
| navigate({ pathname: `/pipeline/experiment/instance/${record.workflow_id}/${item.id}` }); | |||||
| navigateToUrl(`/pipeline/experiment/instance/${record.workflow_id}/${item.id}`); | |||||
| }; | }; | ||||
| // 处理 TensorBoard 操作 | // 处理 TensorBoard 操作 | ||||
| @@ -340,7 +362,7 @@ function Experiment() { | |||||
| }, | }, | ||||
| ], | ], | ||||
| onClick: ({ key }) => { | onClick: ({ key }) => { | ||||
| navigate(`/pipeline/experiment/compare?type=${key}&id=${experimentId}`); | |||||
| navigateToUrl(`/pipeline/experiment/compare?type=${key}&id=${experimentId}`); | |||||
| }, | }, | ||||
| }; | }; | ||||
| }; | }; | ||||
| @@ -392,13 +414,14 @@ function Experiment() { | |||||
| {newText && newText.length > 0 | {newText && newText.length > 0 | ||||
| ? newText.map((item, index) => { | ? newText.map((item, index) => { | ||||
| return ( | return ( | ||||
| <img | |||||
| style={{ width: '17px', marginRight: '6px' }} | |||||
| key={index} | |||||
| src={experimentStatusInfo[item].icon} | |||||
| draggable={false} | |||||
| alt="" | |||||
| /> | |||||
| <Tooltip key={index} placement="top" title={experimentStatusInfo[item].label}> | |||||
| <img | |||||
| style={{ width: '17px', marginRight: '6px' }} | |||||
| src={experimentStatusInfo[item].icon} | |||||
| draggable={false} | |||||
| alt="" | |||||
| /> | |||||
| </Tooltip> | |||||
| ); | ); | ||||
| }) | }) | ||||
| : null} | : null} | ||||
| @@ -479,41 +502,61 @@ function Experiment() { | |||||
| }, | }, | ||||
| ]; | ]; | ||||
| return ( | return ( | ||||
| <div className={Styles.experimentBox}> | |||||
| <div className={Styles.experimentTopBox}> | |||||
| <Button type="default" onClick={createExperiment} icon={<KFIcon type="icon-xinjian2" />}> | |||||
| 新建实验 | |||||
| </Button> | |||||
| </div> | |||||
| <div className={classNames('vertical-scroll-table', Styles.experimentTable)}> | |||||
| <Table | |||||
| columns={columns} | |||||
| dataSource={experimentList} | |||||
| pagination={paginationProps} | |||||
| rowKey="id" | |||||
| scroll={{ y: 'calc(100% - 55px)' }} | |||||
| expandable={{ | |||||
| expandedRowRender: (record) => ( | |||||
| <ExperimentInstance | |||||
| experimentInList={experimentInList} | |||||
| experimentInsTotal={experimentInsTotal} | |||||
| onClickInstance={(item) => gotoInstanceInfo(item, record)} | |||||
| onClickTensorBoard={handleTensorboard} | |||||
| onRemove={() => { | |||||
| refreshExperimentIns(record.id); | |||||
| refreshExperimentList(); | |||||
| }} | |||||
| onTerminate={handleInstanceTerminate} | |||||
| onLoadMore={() => loadMoreExperimentIns()} | |||||
| ></ExperimentInstance> | |||||
| ), | |||||
| onExpand: (e, a) => { | |||||
| expandChange(e, a); | |||||
| }, | |||||
| expandedRowKeys: [expandedRowKeys], | |||||
| rowExpandable: (record) => true, | |||||
| }} | |||||
| /> | |||||
| <div className={styles['experiment-list']}> | |||||
| <PageTitle title="实验列表"></PageTitle> | |||||
| <div className={styles['experiment-list__content']}> | |||||
| <div className={styles['experiment-list__content__filter']}> | |||||
| <Input.Search | |||||
| placeholder="按实验名称筛选" | |||||
| onSearch={onSearch} | |||||
| onChange={(e) => setInputText(e.target.value)} | |||||
| style={{ width: 300 }} | |||||
| value={inputText} | |||||
| allowClear | |||||
| /> | |||||
| <Button type="default" onClick={createExperiment} icon={<KFIcon type="icon-xinjian2" />}> | |||||
| 新建实验 | |||||
| </Button> | |||||
| </div> | |||||
| <div | |||||
| className={classNames('vertical-scroll-table', styles['experiment-list__content__table'])} | |||||
| > | |||||
| <Table | |||||
| columns={columns} | |||||
| dataSource={experimentList} | |||||
| pagination={{ | |||||
| ...pagination, | |||||
| total: total, | |||||
| showSizeChanger: true, | |||||
| showQuickJumper: true, | |||||
| showTotal: () => `共${total}条`, | |||||
| onChange: paginationChange, | |||||
| }} | |||||
| rowKey="id" | |||||
| scroll={{ y: 'calc(100% - 55px)' }} | |||||
| expandable={{ | |||||
| expandedRowRender: (record) => ( | |||||
| <ExperimentInstance | |||||
| experimentInList={experimentInList} | |||||
| experimentInsTotal={experimentInsTotal} | |||||
| onClickInstance={(item) => gotoInstanceInfo(item, record)} | |||||
| onClickTensorBoard={handleTensorboard} | |||||
| onRemove={() => { | |||||
| refreshExperimentIns(record.id); | |||||
| refreshExperimentList(); | |||||
| }} | |||||
| onTerminate={handleInstanceTerminate} | |||||
| onLoadMore={() => loadMoreExperimentIns()} | |||||
| ></ExperimentInstance> | |||||
| ), | |||||
| onExpand: (e, a) => { | |||||
| expandChange(e, a); | |||||
| }, | |||||
| expandedRowKeys: [expandedRowKeys], | |||||
| rowExpandable: (record) => true, | |||||
| }} | |||||
| /> | |||||
| </div> | |||||
| </div> | </div> | ||||
| {isModalOpen && ( | {isModalOpen && ( | ||||
| @@ -1,28 +1,21 @@ | |||||
| .experimentBox { | |||||
| .experiment-list { | |||||
| height: 100%; | height: 100%; | ||||
| .experimentTopBox { | |||||
| display: flex; | |||||
| align-items: center; | |||||
| justify-content: flex-end; | |||||
| width: 100%; | |||||
| height: 49px; | |||||
| margin-bottom: 10px; | |||||
| padding-right: 30px; | |||||
| background-image: url(@/assets/img/page-title-bg.png); | |||||
| background-repeat: no-repeat; | |||||
| background-position: top center; | |||||
| background-size: 100% 100%; | |||||
| } | |||||
| .experimentTable { | |||||
| &__content { | |||||
| height: calc(100% - 60px); | height: calc(100% - 60px); | ||||
| :global { | |||||
| .ant-table-wrapper .ant-table { | |||||
| // overflow-y: auto; | |||||
| height: calc(100% - 48px); | |||||
| } | |||||
| .ant-table-row-expand-icon-cell { | |||||
| padding: 0 30px; | |||||
| } | |||||
| margin-top: 10px; | |||||
| padding: 20px 30px 0; | |||||
| background-color: white; | |||||
| border-radius: 10px; | |||||
| &__filter { | |||||
| display: flex; | |||||
| align-items: center; | |||||
| justify-content: space-between; | |||||
| } | |||||
| &__table { | |||||
| height: calc(100% - 32px - 28px); | |||||
| margin-top: 28px; | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| @@ -1,5 +1,7 @@ | |||||
| import KFIcon from '@/components/KFIcon'; | import KFIcon from '@/components/KFIcon'; | ||||
| import KFModal from '@/components/KFModal'; | import KFModal from '@/components/KFModal'; | ||||
| import PageTitle from '@/components/PageTitle'; | |||||
| import { useCacheState } from '@/hooks/pageCacheState'; | |||||
| import { | import { | ||||
| addWorkflow, | addWorkflow, | ||||
| cloneWorkflow, | cloneWorkflow, | ||||
| @@ -13,9 +15,9 @@ import tableCellRender, { TableCellValueType } from '@/utils/table'; | |||||
| import { modalConfirm } from '@/utils/ui'; | import { modalConfirm } from '@/utils/ui'; | ||||
| import { App, Button, ConfigProvider, Form, Input, Space, Table } from 'antd'; | import { App, Button, ConfigProvider, Form, Input, Space, Table } from 'antd'; | ||||
| import classNames from 'classnames'; | import classNames from 'classnames'; | ||||
| import { useEffect, useRef, useState } from 'react'; | |||||
| import { useEffect, useState } from 'react'; | |||||
| import { useNavigate } from 'react-router-dom'; | import { useNavigate } from 'react-router-dom'; | ||||
| import Styles from './index.less'; | |||||
| import styles from './index.less'; | |||||
| const { TextArea } = Input; | const { TextArea } = Input; | ||||
| const Pipeline = () => { | const Pipeline = () => { | ||||
| @@ -26,7 +28,46 @@ const Pipeline = () => { | |||||
| const [pipeList, setPipeList] = useState([]); | const [pipeList, setPipeList] = useState([]); | ||||
| const [total, setTotal] = useState(0); | const [total, setTotal] = useState(0); | ||||
| const [isModalOpen, setIsModalOpen] = useState(false); | const [isModalOpen, setIsModalOpen] = useState(false); | ||||
| const [cacheState, setCacheState] = useCacheState(); | |||||
| const [searchText, setSearchText] = useState(cacheState?.searchText); | |||||
| const [inputText, setInputText] = useState(cacheState?.searchText); | |||||
| const [pagination, setPagination] = useState( | |||||
| cacheState?.pagination ?? { | |||||
| current: 1, | |||||
| pageSize: 10, | |||||
| }, | |||||
| ); | |||||
| const { message } = App.useApp(); | const { message } = App.useApp(); | ||||
| useEffect(() => { | |||||
| getList(); | |||||
| }, [pagination, searchText]); | |||||
| // 获取流水线模板列表 | |||||
| const getList = () => { | |||||
| const params = { | |||||
| page: pagination.current - 1, | |||||
| size: pagination.pageSize, | |||||
| name: searchText || undefined, | |||||
| }; | |||||
| getWorkflow(params).then((res) => { | |||||
| if (res && res.data && Array.isArray(res.data.content)) { | |||||
| setPipeList(res.data.content); | |||||
| setTotal(res.data.totalElements); | |||||
| } | |||||
| }); | |||||
| }; | |||||
| // 搜索 | |||||
| const onSearch = (value) => { | |||||
| setSearchText(value); | |||||
| setPagination((prev) => ({ | |||||
| ...prev, | |||||
| current: 1, | |||||
| })); | |||||
| }; | |||||
| // 编辑 | |||||
| const editTable = (e, record) => { | const editTable = (e, record) => { | ||||
| e.stopPropagation(); | e.stopPropagation(); | ||||
| getWorkflowById(record.id).then((ret) => { | getWorkflowById(record.id).then((ret) => { | ||||
| @@ -39,18 +80,35 @@ const Pipeline = () => { | |||||
| } | } | ||||
| }); | }); | ||||
| }; | }; | ||||
| const routeToEdit = (record) => { | |||||
| navigate({ pathname: `/pipeline/template/info/${record.id}` }); | |||||
| // 跳转, 缓存当前状态 | |||||
| const navigateToUrl = (url) => { | |||||
| setCacheState({ | |||||
| pagination, | |||||
| searchText, | |||||
| }); | |||||
| navigate(url); | |||||
| }; | |||||
| // 查看详情 | |||||
| const gotoDetail = (record) => { | |||||
| navigateToUrl(`/pipeline/template/info/${record.id}`); | |||||
| }; | }; | ||||
| // 显示 modal | |||||
| const showModal = () => { | const showModal = () => { | ||||
| form.resetFields(); | form.resetFields(); | ||||
| setFormId(null); | setFormId(null); | ||||
| setDialogTitle('新建流水线'); | setDialogTitle('新建流水线'); | ||||
| setIsModalOpen(true); | setIsModalOpen(true); | ||||
| }; | }; | ||||
| // modal 取消 | |||||
| const handleCancel = () => { | const handleCancel = () => { | ||||
| setIsModalOpen(false); | setIsModalOpen(false); | ||||
| }; | }; | ||||
| // 表单提交 | |||||
| const onFinish = (values) => { | const onFinish = (values) => { | ||||
| if (formId) { | if (formId) { | ||||
| editWorkflow({ ...values, id: formId }).then((ret) => { | editWorkflow({ ...values, id: formId }).then((ret) => { | ||||
| @@ -63,47 +121,21 @@ const Pipeline = () => { | |||||
| setIsModalOpen(false); | setIsModalOpen(false); | ||||
| message.success('新建成功'); | message.success('新建成功'); | ||||
| if (ret.code === 200) { | if (ret.code === 200) { | ||||
| navigate({ pathname: `/pipeline/template/info/${ret.data.id}` }); | |||||
| navigateToUrl(`/pipeline/template/info/${ret.data.id}`); | |||||
| } | } | ||||
| }); | }); | ||||
| } | } | ||||
| }; | }; | ||||
| const pageOption = useRef({ page: 1, size: 10 }); | |||||
| const paginationProps = { | |||||
| showSizeChanger: true, | |||||
| showQuickJumper: true, | |||||
| showTotal: () => `共${total}条`, | |||||
| total: total, | |||||
| page: pageOption.current.page, | |||||
| size: pageOption.current.size, | |||||
| onChange: (current, size) => paginationChange(current, size), | |||||
| }; | |||||
| // 当前页面切换 | // 当前页面切换 | ||||
| const paginationChange = async (current, size) => { | |||||
| // console.log('page', current, size); | |||||
| pageOption.current = { | |||||
| page: current, | |||||
| size: size, | |||||
| }; | |||||
| const paginationChange = async (current, pageSize) => { | |||||
| setPagination({ | |||||
| current, | |||||
| pageSize, | |||||
| }); | |||||
| getList(); | getList(); | ||||
| }; | }; | ||||
| const getList = () => { | |||||
| let params = { | |||||
| offset: 1, | |||||
| page: pageOption.current.page - 1, | |||||
| size: pageOption.current.size, | |||||
| }; | |||||
| getWorkflow(params).then((ret) => { | |||||
| if (ret.code === 200) { | |||||
| setPipeList(ret.data.content); | |||||
| setTotal(ret.data.totalElements); | |||||
| } | |||||
| }); | |||||
| }; | |||||
| useEffect(() => { | |||||
| getList(); | |||||
| }, []); | |||||
| const columns = [ | const columns = [ | ||||
| { | { | ||||
| title: '序号', | title: '序号', | ||||
| @@ -112,8 +144,8 @@ const Pipeline = () => { | |||||
| width: 120, | width: 120, | ||||
| align: 'center', | align: 'center', | ||||
| render: tableCellRender(false, TableCellValueType.Index, { | render: tableCellRender(false, TableCellValueType.Index, { | ||||
| page: pageOption.current.page - 1, | |||||
| pageSize: pageOption.current.size, | |||||
| page: pagination.current - 1, | |||||
| pageSize: pagination.pageSize, | |||||
| }), | }), | ||||
| }, | }, | ||||
| { | { | ||||
| @@ -121,7 +153,7 @@ const Pipeline = () => { | |||||
| dataIndex: 'name', | dataIndex: 'name', | ||||
| key: 'name', | key: 'name', | ||||
| render: tableCellRender(false, TableCellValueType.Link, { | render: tableCellRender(false, TableCellValueType.Link, { | ||||
| onClick: routeToEdit, | |||||
| onClick: gotoDetail, | |||||
| }), | }), | ||||
| }, | }, | ||||
| { | { | ||||
| @@ -167,10 +199,10 @@ const Pipeline = () => { | |||||
| icon={<KFIcon type="icon-fuzhi" />} | icon={<KFIcon type="icon-fuzhi" />} | ||||
| onClick={async () => { | onClick={async () => { | ||||
| modalConfirm({ | modalConfirm({ | ||||
| title: '复制', | |||||
| content: '确定复制该条流水线吗?', | content: '确定复制该条流水线吗?', | ||||
| okText: '确认', | okText: '确认', | ||||
| cancelText: '取消', | cancelText: '取消', | ||||
| isDelete: false, | |||||
| onOk: () => { | onOk: () => { | ||||
| cloneWorkflow(record.id).then((ret) => { | cloneWorkflow(record.id).then((ret) => { | ||||
| if (ret.code === 200) { | if (ret.code === 200) { | ||||
| @@ -235,27 +267,47 @@ const Pipeline = () => { | |||||
| }, | }, | ||||
| ]; | ]; | ||||
| return ( | return ( | ||||
| <div className={Styles.PipelineBox}> | |||||
| <div className={Styles.pipelineTopBox}> | |||||
| <Button type="default" onClick={showModal} icon={<KFIcon type="icon-xinjian2" />}> | |||||
| 新建流水线 | |||||
| </Button> | |||||
| </div> | |||||
| <div className={classNames('vertical-scroll-table', Styles.PipelineTable)}> | |||||
| <Table | |||||
| columns={columns} | |||||
| dataSource={pipeList} | |||||
| pagination={paginationProps} | |||||
| rowKey="id" | |||||
| scroll={{ y: 'calc(100% - 55px)' }} | |||||
| /> | |||||
| <div className={styles['pipeline-list']}> | |||||
| <PageTitle title="流水线模板列表"></PageTitle> | |||||
| <div className={styles['pipeline-list__content']}> | |||||
| <div className={styles['pipeline-list__content__filter']}> | |||||
| <Input.Search | |||||
| placeholder="按流水线名称筛选" | |||||
| onSearch={onSearch} | |||||
| onChange={(e) => setInputText(e.target.value)} | |||||
| style={{ width: 300 }} | |||||
| value={inputText} | |||||
| allowClear | |||||
| /> | |||||
| <Button type="default" onClick={showModal} icon={<KFIcon type="icon-xinjian2" />}> | |||||
| 新建流水线 | |||||
| </Button> | |||||
| </div> | |||||
| <div | |||||
| className={classNames('vertical-scroll-table', styles['pipeline-list__content__table'])} | |||||
| > | |||||
| <Table | |||||
| columns={columns} | |||||
| dataSource={pipeList} | |||||
| pagination={{ | |||||
| ...pagination, | |||||
| total: total, | |||||
| showSizeChanger: true, | |||||
| showQuickJumper: true, | |||||
| showTotal: () => `共${total}条`, | |||||
| onChange: paginationChange, | |||||
| }} | |||||
| rowKey="id" | |||||
| scroll={{ y: 'calc(100% - 55px)' }} | |||||
| /> | |||||
| </div> | |||||
| </div> | </div> | ||||
| <KFModal | <KFModal | ||||
| title={dialogTitle} | title={dialogTitle} | ||||
| image={require('@/assets/img/create-experiment.png')} | image={require('@/assets/img/create-experiment.png')} | ||||
| width={825} | width={825} | ||||
| open={isModalOpen} | open={isModalOpen} | ||||
| className={Styles.modal} | |||||
| className={styles.modal} | |||||
| okButtonProps={{ | okButtonProps={{ | ||||
| htmlType: 'submit', | htmlType: 'submit', | ||||
| form: 'form', | form: 'form', | ||||
| @@ -1,26 +1,21 @@ | |||||
| .pipelineTopBox { | |||||
| display: flex; | |||||
| align-items: center; | |||||
| justify-content: flex-end; | |||||
| width: 100%; | |||||
| height: 49px; | |||||
| margin-bottom: 10px; | |||||
| padding-right: 30px; | |||||
| background-image: url(@/assets/img/page-title-bg.png); | |||||
| background-repeat: no-repeat; | |||||
| background-position: top left; | |||||
| background-size: 100% 100%; | |||||
| } | |||||
| .PipelineBox { | |||||
| .pipeline-list { | |||||
| height: 100%; | height: 100%; | ||||
| .PipelineTable { | |||||
| &__content { | |||||
| height: calc(100% - 60px); | height: calc(100% - 60px); | ||||
| :global { | |||||
| .ant-table-wrapper .ant-table { | |||||
| // overflow-y: auto; | |||||
| height: calc(100% - 48px); | |||||
| } | |||||
| margin-top: 10px; | |||||
| padding: 20px 30px 0; | |||||
| background-color: white; | |||||
| border-radius: 10px; | |||||
| &__filter { | |||||
| display: flex; | |||||
| align-items: center; | |||||
| justify-content: space-between; | |||||
| } | |||||
| &__table { | |||||
| height: calc(100% - 32px - 28px); | |||||
| margin-top: 28px; | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||