diff --git a/react-ui/config/config.ts b/react-ui/config/config.ts index 4ecf3ebd..d0830923 100644 --- a/react-ui/config/config.ts +++ b/react-ui/config/config.ts @@ -1,12 +1,14 @@ // https://umijs.org/config/ import { defineConfig } from '@umijs/max'; -import { join } from 'path'; +import { join, resolve } from 'path'; import defaultSettings from './defaultSettings'; import proxy from './proxy'; import routes from './routes'; const { REACT_APP_ENV = 'dev' } = process.env; +console.log('zzz', resolve(__dirname, '../src/styles/theme.less')); + export default defineConfig({ /** * @name 开启 hash 模式 @@ -39,7 +41,8 @@ export default defineConfig({ theme: { // 如果不想要 configProvide 动态设置主题需要把这个设置为 default // 只有设置为 variable, 才能使用 configProvide 动态设置主色调 - 'root-entry-name': 'variable', + // 'root-entry-name': 'variable', + 'kf-success-color': '#ff0000', }, /** * @name moment 的国际化配置 @@ -157,4 +160,10 @@ export default defineConfig({ }, requestRecord: {}, icons: {}, + lessLoader: { + modifyVars: { + hack: 'true; @import "@/styles/theme.less";', + }, + javascriptEnabled: true, + }, }); diff --git a/react-ui/config/proxy.ts b/react-ui/config/proxy.ts index 527bff75..0fdf89e3 100644 --- a/react-ui/config/proxy.ts +++ b/react-ui/config/proxy.ts @@ -1,3 +1,8 @@ +/* + * @Author: 赵伟 + * @Date: 2024-04-17 08:48:09 + * @Description: + */ /** * @name 代理的配置 * @see 在生产环境 代理是无法生效的,所以这里没有生产环境的配置 diff --git a/react-ui/jsconfig.json b/react-ui/jsconfig.json deleted file mode 100644 index 197bee5d..00000000 --- a/react-ui/jsconfig.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "compilerOptions": { - "jsx": "react-jsx", - "emitDecoratorMetadata": true, - "experimentalDecorators": true, - "baseUrl": ".", - "paths": { - "@/*": ["./src/*"] - } - } -} diff --git a/react-ui/public/assets/images/backup/component-icon-7-Failed.png b/react-ui/public/assets/images/backup/component-icon-7-Failed.png new file mode 100644 index 00000000..2427996b Binary files /dev/null and b/react-ui/public/assets/images/backup/component-icon-7-Failed.png differ diff --git a/react-ui/public/assets/images/backup/component-icon-7-Omitted.png b/react-ui/public/assets/images/backup/component-icon-7-Omitted.png new file mode 100644 index 00000000..33a4445e Binary files /dev/null and b/react-ui/public/assets/images/backup/component-icon-7-Omitted.png differ diff --git a/react-ui/public/assets/images/backup/component-icon-7-Pending.png b/react-ui/public/assets/images/backup/component-icon-7-Pending.png new file mode 100644 index 00000000..12a5aa4e Binary files /dev/null and b/react-ui/public/assets/images/backup/component-icon-7-Pending.png differ diff --git a/react-ui/public/assets/images/backup/component-icon-7-Running.png b/react-ui/public/assets/images/backup/component-icon-7-Running.png new file mode 100644 index 00000000..0328188f Binary files /dev/null and b/react-ui/public/assets/images/backup/component-icon-7-Running.png differ diff --git a/react-ui/public/assets/images/backup/component-icon-7-Skipped.png b/react-ui/public/assets/images/backup/component-icon-7-Skipped.png new file mode 100644 index 00000000..33a4445e Binary files /dev/null and b/react-ui/public/assets/images/backup/component-icon-7-Skipped.png differ diff --git a/react-ui/public/assets/images/backup/component-icon-7-Succeeded.png b/react-ui/public/assets/images/backup/component-icon-7-Succeeded.png new file mode 100644 index 00000000..30676934 Binary files /dev/null and b/react-ui/public/assets/images/backup/component-icon-7-Succeeded.png differ diff --git a/react-ui/public/assets/images/backup/component-icon-7.png b/react-ui/public/assets/images/backup/component-icon-7.png new file mode 100644 index 00000000..c0c1087c Binary files /dev/null and b/react-ui/public/assets/images/backup/component-icon-7.png differ diff --git a/react-ui/public/assets/images/component-icon-7-Failed.png b/react-ui/public/assets/images/component-icon-7-Failed.png index 2427996b..9854dc38 100644 Binary files a/react-ui/public/assets/images/component-icon-7-Failed.png and b/react-ui/public/assets/images/component-icon-7-Failed.png differ diff --git a/react-ui/public/assets/images/component-icon-7-Omitted.png b/react-ui/public/assets/images/component-icon-7-Omitted.png index 33a4445e..59b81026 100644 Binary files a/react-ui/public/assets/images/component-icon-7-Omitted.png and b/react-ui/public/assets/images/component-icon-7-Omitted.png differ diff --git a/react-ui/public/assets/images/component-icon-7-Pending.png b/react-ui/public/assets/images/component-icon-7-Pending.png index 12a5aa4e..bf06cf26 100644 Binary files a/react-ui/public/assets/images/component-icon-7-Pending.png and b/react-ui/public/assets/images/component-icon-7-Pending.png differ diff --git a/react-ui/public/assets/images/component-icon-7-Running.png b/react-ui/public/assets/images/component-icon-7-Running.png index 0328188f..6dcc20d6 100644 Binary files a/react-ui/public/assets/images/component-icon-7-Running.png and b/react-ui/public/assets/images/component-icon-7-Running.png differ diff --git a/react-ui/public/assets/images/component-icon-7-Skipped.png b/react-ui/public/assets/images/component-icon-7-Skipped.png index 33a4445e..59b81026 100644 Binary files a/react-ui/public/assets/images/component-icon-7-Skipped.png and b/react-ui/public/assets/images/component-icon-7-Skipped.png differ diff --git a/react-ui/public/assets/images/component-icon-7-Succeeded.png b/react-ui/public/assets/images/component-icon-7-Succeeded.png index 30676934..f12a5a82 100644 Binary files a/react-ui/public/assets/images/component-icon-7-Succeeded.png and b/react-ui/public/assets/images/component-icon-7-Succeeded.png differ diff --git a/react-ui/public/assets/images/component-icon-7.png b/react-ui/public/assets/images/component-icon-7.png index c0c1087c..d550d28c 100644 Binary files a/react-ui/public/assets/images/component-icon-7.png and b/react-ui/public/assets/images/component-icon-7.png differ diff --git a/react-ui/public/assets/images/component-icon-8-Failed.png b/react-ui/public/assets/images/component-icon-8-Failed.png new file mode 100644 index 00000000..a5d20128 Binary files /dev/null and b/react-ui/public/assets/images/component-icon-8-Failed.png differ diff --git a/react-ui/public/assets/images/component-icon-8-Omitted.png b/react-ui/public/assets/images/component-icon-8-Omitted.png new file mode 100644 index 00000000..ab0015cc Binary files /dev/null and b/react-ui/public/assets/images/component-icon-8-Omitted.png differ diff --git a/react-ui/public/assets/images/component-icon-8-Pending.png b/react-ui/public/assets/images/component-icon-8-Pending.png new file mode 100644 index 00000000..3dfc540e Binary files /dev/null and b/react-ui/public/assets/images/component-icon-8-Pending.png differ diff --git a/react-ui/public/assets/images/component-icon-8-Running.png b/react-ui/public/assets/images/component-icon-8-Running.png new file mode 100644 index 00000000..4713143e Binary files /dev/null and b/react-ui/public/assets/images/component-icon-8-Running.png differ diff --git a/react-ui/public/assets/images/component-icon-8-Skipped.png b/react-ui/public/assets/images/component-icon-8-Skipped.png new file mode 100644 index 00000000..ab0015cc Binary files /dev/null and b/react-ui/public/assets/images/component-icon-8-Skipped.png differ diff --git a/react-ui/public/assets/images/component-icon-8-Succeeded.png b/react-ui/public/assets/images/component-icon-8-Succeeded.png new file mode 100644 index 00000000..c890e8a1 Binary files /dev/null and b/react-ui/public/assets/images/component-icon-8-Succeeded.png differ diff --git a/react-ui/public/assets/images/component-icon-8.png b/react-ui/public/assets/images/component-icon-8.png new file mode 100644 index 00000000..81dfbe9e Binary files /dev/null and b/react-ui/public/assets/images/component-icon-8.png differ diff --git a/react-ui/src/app.tsx b/react-ui/src/app.tsx index 5c255b73..cd88f984 100644 --- a/react-ui/src/app.tsx +++ b/react-ui/src/app.tsx @@ -156,7 +156,7 @@ export const layout: RunTimeLayoutConfig = ({ initialState }) => { export async function onRouteChange({ clientRoutes, location }: any) { const menus = getRemoteMenu(); - console.log('onRouteChange', clientRoutes, location, menus); + // console.log('onRouteChange', clientRoutes, location, menus); if (menus === null && location.pathname !== PageEnum.LOGIN) { console.log('refresh'); history.go(0); @@ -164,16 +164,16 @@ export async function onRouteChange({ clientRoutes, location }: any) { } export function patchRoutes({ routes, routeComponents }: any) { - console.log('patchRoutes', routes, routeComponents); + //console.log('patchRoutes', routes, routeComponents); } export async function patchClientRoutes({ routes }: any) { - console.log('patchClientRoutes', routes); + // console.log('patchClientRoutes', routes); patchRouteWithRemoteMenus(routes); } export function render(oldRender: () => void) { - console.log('render get routers', oldRender); + // console.log('render get routers', oldRender); const token = getAccessToken(); if (!token || token?.length === 0) { oldRender(); @@ -190,10 +190,38 @@ export const antd: RuntimeAntdConfig = (memo) => { memo.theme ??= {}; memo.theme.token = { colorPrimary: themes['primaryColor'], + colorSuccess: themes['successColor'], + colorError: themes['errorColor'], + colorWarning: themes['warningColor'], + // fontSize: themes['fontSize'], }; memo.theme.components ??= {}; memo.theme.components.Tabs = {}; - // memo.theme.cssVar = true; + memo.theme.components.Button = { + defaultBg: 'rgba(22, 100, 255, 0.06)', + defaultBorderColor: 'rgba(22, 100, 255, 0.11)', + defaultColor: themes['textColor'], + defaultHoverBg: 'rgba(22, 100, 255, 0.06)', + defaultHoverBorderColor: 'rgba(22, 100, 255, 0.5)', + defaultHoverColor: '#3F7FFF ', + defaultActiveBg: 'rgba(22, 100, 255, 0.12)', + defaultActiveBorderColor: 'rgba(22, 100, 255, 0.75)', + defaultActiveColor: themes['primaryColor'], + contentFontSize: themes['fontSize'], + paddingBlock: 4, + paddingInline: 15, + controlHeight: 34, + }; + memo.theme.components.Input = { + inputFontSize: themes['fontSize'], + paddingBlock: 4, + paddingInline: 15, + }; + memo.theme.components.Table = { + headerBg: 'rgba(242, 244, 247, 0.36)', + headerBorderRadius: 4, + }; + memo.theme.cssVar = true; // memo.theme.hashed = false; // memo.appConfig = { diff --git a/react-ui/src/assets/img/modal-select-mirror.png b/react-ui/src/assets/img/modal-select-mirror.png new file mode 100644 index 00000000..93e12760 Binary files /dev/null and b/react-ui/src/assets/img/modal-select-mirror.png differ diff --git a/react-ui/src/assets/svg/modal-close.svg b/react-ui/src/assets/svg/modal-close.svg deleted file mode 100644 index 1345011e..00000000 --- a/react-ui/src/assets/svg/modal-close.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/react-ui/src/assets/svg/parameter.svg b/react-ui/src/assets/svg/parameter.svg deleted file mode 100644 index 58803521..00000000 --- a/react-ui/src/assets/svg/parameter.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/react-ui/src/assets/svg/save--return.svg b/react-ui/src/assets/svg/save--return.svg deleted file mode 100644 index 73fd196d..00000000 --- a/react-ui/src/assets/svg/save--return.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/react-ui/src/assets/svg/view-param.svg b/react-ui/src/assets/svg/view-param.svg deleted file mode 100644 index 3eb2efce..00000000 --- a/react-ui/src/assets/svg/view-param.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/react-ui/src/components/KFRadio/index.less b/react-ui/src/components/KFRadio/index.less index f9a277b1..7a941188 100644 --- a/react-ui/src/components/KFRadio/index.less +++ b/react-ui/src/components/KFRadio/index.less @@ -1,4 +1,4 @@ -@import '@/styles/theme.less'; +// @import '@/styles/theme.less'; .kf-radio { display: flex; @@ -8,7 +8,7 @@ display: flex; align-items: center; padding: 12px 20px; - color: @text-color-second; + color: @text-color-secondary; border: 1px solid #e0e0e0; border-radius: 8px; @@ -18,8 +18,8 @@ } &--active { - color: @kf-primary-color; - border: 1px solid @kf-primary-color; + color: @primary-color; + border: 1px solid @primary-color; } & + & { diff --git a/react-ui/src/components/ModalTitle/index.less b/react-ui/src/components/ModalTitle/index.less index 1ff70e81..24e10386 100644 --- a/react-ui/src/components/ModalTitle/index.less +++ b/react-ui/src/components/ModalTitle/index.less @@ -2,7 +2,7 @@ .modal_title { display: flex; align-items: center; - color: @kf-primary-color; + color: @primary-color; font-weight: 400; font-size: 20px; diff --git a/react-ui/src/enums/index.ts b/react-ui/src/enums/index.ts index c610ecf3..0c0c7b81 100644 --- a/react-ui/src/enums/index.ts +++ b/react-ui/src/enums/index.ts @@ -3,3 +3,10 @@ export enum CommonTabKeys { Private = 'Private', // 私有 Public = 'Public', // 公开 } + +// 镜像状态 +export enum MirrorVersionStatus { + Available = 'available', // 可用 + Building = 'building', // 构建中 + Failed = 'failed', // 构建中 +} diff --git a/react-ui/src/global.less b/react-ui/src/global.less index a8736138..126d627c 100644 --- a/react-ui/src/global.less +++ b/react-ui/src/global.less @@ -31,54 +31,46 @@ body { -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } -a { - color: #1664ff; -} -.ant-btn-link { - color: #1664ff; -} .ant-pro-layout .ant-pro-layout-content { padding: 10px; } .ant-pro-layout .ant-pro-layout-bg-list { background: #f9fafb; } -.ant-table-wrapper .ant-table-thead > tr > th { - background-color: #fff; -} -.ant-table-wrapper .ant-table-thead > tr > td { - background-color: #fff; -} + .ant-menu-light .ant-menu-item-selected { background: rgba(197, 232, 255, 0.8) !important; - } -.ant-menu-light .ant-menu-item-selected .ant-pro-base-menu-inline-item-text{ - color:#1664ff; +.ant-menu-light .ant-menu-item-selected .ant-pro-base-menu-inline-item-text { + // color: #1664ff; } .ant-pro-layout .ant-pro-sider .ant-layout-sider-children { background: #f2f5f7; } -.ant-pro-base-menu-inline-item-title .ant-pro-base-menu-inline-item-text{ - color:#1d1d20; -font-size:16px; +.ant-pro-base-menu-inline-item-title .ant-pro-base-menu-inline-item-text { + // color: #1d1d20; + font-size: 16px; } // .ant-menu-light .ant-menu-item-selected{ // color:#1664ff; // } -.ant-pro-layout .ant-pro-sider-menu{ +.ant-pro-layout .ant-pro-sider-menu { padding-top: 40px; } -.ant-pro-global-header-logo-mix{ +.ant-table-wrapper .ant-table-container table>thead>tr:first-child >*:first-child,.ant-table-wrapper .ant-table-container table>tbody>tr:first-child{ + padding: 0 30px; +} + +.ant-pro-global-header-logo-mix { + width: 257px; height: 75px; - border-bottom: 1px solid rgba(233, 237, 240, 1); margin-left: -16px; - width: 257px; - background:#f2f5f7; - border-top-right-radius: 20px; padding-left: 28px; + background: #f2f5f7; + border-bottom: 1px solid rgba(233, 237, 240, 1); + border-top-right-radius: 20px; } -.ant-pro-layout .ant-pro-sider .ant-layout-sider-children{ +.ant-pro-layout .ant-pro-sider .ant-layout-sider-children { border-right: unset; border-bottom-right-radius: 20px; } @@ -90,13 +82,13 @@ font-size:16px; .ant-pro-layout .ant-pro-layout-content { background-color: transparent; } -.ant-drawer .ant-drawer-body{ +.ant-drawer .ant-drawer-body { padding: 0; } -.ant-drawer .ant-drawer-body .ant-row{ +.ant-drawer .ant-drawer-body .ant-row { padding: 0 24px; } -.ant-drawer .ant-drawer-body .ant-form-item{ +.ant-drawer .ant-drawer-body .ant-form-item { margin-bottom: 20px; } .ant-menu .ant-menu-submenu-title .anticon { @@ -109,6 +101,7 @@ font-size:16px; } .ant-table-wrapper .ant-table { height: 81vh; + overflow-y: auto; } .ant-pro-global-header-logo img { height: 21px; @@ -119,7 +112,7 @@ font-size:16px; .ant-pro-layout .ant-pro-layout-container { height: 98vh; } -.ant-modal-confirm .ant-modal-confirm-paragraph{ +.ant-modal-confirm .ant-modal-confirm-paragraph { margin: 54px 0 auto; text-align: center; } @@ -130,38 +123,39 @@ font-size:16px; margin-top: 30px; text-align: center; } -.ant-modal-confirm-btns .ant-btn-default{ - width:110px; -height:40px; -background:rgba(22, 100, 255, 0.06); -border-radius:10px; -color:#1d1d20; -font-size:18px; -margin-right: 10px; -border-color: transparent; +.ant-modal-confirm-btns .ant-btn-default { + width: 110px; + height: 40px; + margin-right: 10px; + // color: #1d1d20; + font-size: 18px; + background: rgba(22, 100, 255, 0.06); + border-color: transparent; + border-radius: 10px; } .ant-modal-confirm-btns .ant-btn-default:hover { background: rgba(22, 100, 255, 0.06); border-color: transparent; } -.ant-modal-confirm-btns .ant-btn-primary{ - width:110px; - height:40px; - background:#1664ff; - border-radius:10px; +.ant-modal-confirm-btns .ant-btn-primary { + width: 110px; + height: 40px; font-size: 18px; + border-radius: 10px; + border-radius: 10px; } -.ant-modal .ant-input-affix-wrapper{ +.ant-modal .ant-input-affix-wrapper { height: 46px; padding: 1px 11px; } -.ant-modal .ant-select-single{ + +.ant-modal .ant-select-single { height: 46px; - } -.ant-modal .ant-select-single .ant-select-selector .ant-select-selection-placeholder{ +.ant-modal .ant-select-single .ant-select-selector .ant-select-selection-placeholder { line-height: 46px; } + .ant-modal .ant-modal-close-x { width: 26px; height: 26px; @@ -176,13 +170,13 @@ border-color: transparent; .ant-modal .ant-modal-content { padding: 0; } -.ant-modal-confirm-body-wrapper{ -height:303px; -background-image: url(/assets/images/modal-back.png); -background-repeat:no-repeat; -background-size:100%; -background-position: top center; -border-radius: 0; +.ant-modal-confirm-body-wrapper { + height: 303px; + background-image: url(/assets/images/modal-back.png); + background-repeat: no-repeat; + background-position: top center; + background-size: 100%; + border-radius: 0; } .ant-modal .ant-modal-content { border-radius: 20px; @@ -195,8 +189,7 @@ border-radius: 0; } .ant-pagination .ant-pagination-item-active a { color: #fff; - background: #1664ff; - border-color: #1664ff; + background: rgba(22, 100, 255, 0.8); border-radius: 6px; } .ant-pagination .ant-pagination-item-active:hover { @@ -259,7 +252,3 @@ ol { } } } - -.umi-local-svg { - vertical-align: -1px; -} diff --git a/react-ui/src/hooks/index.ts b/react-ui/src/hooks/index.ts index 32f162ad..24a80d81 100644 --- a/react-ui/src/hooks/index.ts +++ b/react-ui/src/hooks/index.ts @@ -3,14 +3,14 @@ * @Date: 2024-04-15 10:01:29 * @Description: */ +import { FormInstance } from 'antd'; import { debounce } from 'lodash'; import { useCallback, useEffect, useRef, useState } from 'react'; - /** - * Generates a state reference with the initial value. + * 生成具有初始值的状态引用 * - * @param initialValue - The initial value for the state - * @return An array containing the state value, state setter function, and a mutable reference object + * @param initialValue - 状态的初始值 + * @return 包含状态值、状态设置函数和可变引用对象的数组 */ export function useStateRef(initialValue: T) { const [value, setValue] = useState(initialValue); @@ -25,10 +25,10 @@ export function useStateRef(initialValue: T) { } /** - * Generates a custom hook for managing the visibility state of a modal. + * 生成一个自定义钩子,用于管理模态框的可见性状态。 * - * @param initialValue - The initial visibility state of the modal. - * @return An array containing the visibility state and functions to open and close the modal. + * @param initialValue - 模态框的初始可见性状态。 + * @return 一个数组,包含可见性状态和打开和关闭模态框的函数。 */ export function useVisible(initialValue: boolean) { const [visible, setVisible] = useState(initialValue); @@ -47,34 +47,34 @@ export function useVisible(initialValue: boolean) { type Callback = (state: T) => void; /** - * Generates a stateful value and a function to update it that triggers callbacks. + * 生成一个具有回调机制的可变状态值和更新它的函数。 * - * @param initialValue - The initial value of the state. - * @return A tuple containing the current state value and a function to update the state. + * @param initialValue - 初始状态值。 + * @return 一个元组,包含当前状态值和用于更新状态的函数。 */ export function useCallbackState(initialValue: T) { - const [state, _setState] = useState(initialValue); + const [state, _setState] = useState(initialValue); const callbackQueue = useRef[]>([]); useEffect(() => { callbackQueue.current.forEach((cb) => cb(state)); callbackQueue.current = []; }, [state]); - const setState = (newValue: T, callback: Callback) => { + const setState = (newValue: T | ((prevState: T) => T), callback?: Callback) => { _setState(newValue); if (callback && typeof callback === 'function') { callbackQueue.current.push(callback); } }; - return [state, setState]; + return [state, setState] as const; } /** - * A hook that tracks the size of a DOM element. + * 用于追踪 DOM 元素尺寸的 hook。 * - * @param initialWidth - The initial width of the element. - * @param initialHeight - The initial height of the element. - * @param deps - dependency list. - * @return - A tuple containing the ref to the DOM element, the current width, and the current height. + * @param initialWidth - 初始宽度。 + * @param initialHeight - 初始高度。 + * @param deps - 依赖列表。 + * @return 一个元组,包含 DOM 元素的 ref、当前宽度和当前高度。 */ export function useDomSize( initialWidth: number, @@ -86,8 +86,6 @@ export function useDomSize( const [height, setHeight] = useState(initialHeight); useEffect(() => { - console.log('dddddd'); - const setDomHeight = () => { if (domRef.current) { setHeight(domRef.current.offsetHeight); @@ -106,3 +104,25 @@ export function useDomSize( return [domRef, { width, height }] as const; } + +/** + * 用于在 modal 关闭时重置 Form 表单的 hook。 + * + * @param form - Ant Design Form 表单实例 + * @param open - modal 是否打开 + */ +export const useResetFormOnCloseModal = (form: FormInstance, open: boolean) => { + const prevOpenRef = useRef(); + + useEffect(() => { + prevOpenRef.current = open; + }, [open]); + + const prevOpen = prevOpenRef.current; + + useEffect(() => { + if (!open && prevOpen) { + form.resetFields(); + } + }, [form, prevOpen, open]); +}; diff --git a/react-ui/src/iconfont/iconfont.js b/react-ui/src/iconfont/iconfont.js index 3695c17e..a7ee3e08 100644 --- a/react-ui/src/iconfont/iconfont.js +++ b/react-ui/src/iconfont/iconfont.js @@ -1 +1 @@ -window._iconfont_svg_string_4511447='',function(l){var a=(a=document.getElementsByTagName("script"))[a.length-1],t=a.getAttribute("data-injectcss"),a=a.getAttribute("data-disable-injectsvg");if(!a){var h,i,e,o,d,z=function(a,t){t.parentNode.insertBefore(a,t)};if(t&&!l.__iconfont__svg__cssinject__){l.__iconfont__svg__cssinject__=!0;try{document.write("")}catch(a){console&&console.log(a)}}h=function(){var a,t=document.createElement("div");t.innerHTML=l._iconfont_svg_string_4511447,(t=t.getElementsByTagName("svg")[0])&&(t.setAttribute("aria-hidden","true"),t.style.position="absolute",t.style.width=0,t.style.height=0,t.style.overflow="hidden",t=t,(a=document.body).firstChild?z(t,a.firstChild):a.appendChild(t))},document.addEventListener?~["complete","loaded","interactive"].indexOf(document.readyState)?setTimeout(h,0):(i=function(){document.removeEventListener("DOMContentLoaded",i,!1),h()},document.addEventListener("DOMContentLoaded",i,!1)):document.attachEvent&&(e=h,o=l.document,d=!1,n(),o.onreadystatechange=function(){"complete"==o.readyState&&(o.onreadystatechange=null,p())})}function p(){d||(d=!0,e())}function n(){try{o.documentElement.doScroll("left")}catch(a){return void setTimeout(n,50)}p()}}(window); \ No newline at end of file +window._iconfont_svg_string_4511447='',function(t){var a=(a=document.getElementsByTagName("script"))[a.length-1],h=a.getAttribute("data-injectcss"),a=a.getAttribute("data-disable-injectsvg");if(!a){var v,i,o,l,z,m=function(a,h){h.parentNode.insertBefore(a,h)};if(h&&!t.__iconfont__svg__cssinject__){t.__iconfont__svg__cssinject__=!0;try{document.write("")}catch(a){console&&console.log(a)}}v=function(){var a,h=document.createElement("div");h.innerHTML=t._iconfont_svg_string_4511447,(h=h.getElementsByTagName("svg")[0])&&(h.setAttribute("aria-hidden","true"),h.style.position="absolute",h.style.width=0,h.style.height=0,h.style.overflow="hidden",h=h,(a=document.body).firstChild?m(h,a.firstChild):a.appendChild(h))},document.addEventListener?~["complete","loaded","interactive"].indexOf(document.readyState)?setTimeout(v,0):(i=function(){document.removeEventListener("DOMContentLoaded",i,!1),v()},document.addEventListener("DOMContentLoaded",i,!1)):document.attachEvent&&(o=v,l=t.document,z=!1,d(),l.onreadystatechange=function(){"complete"==l.readyState&&(l.onreadystatechange=null,n())})}function n(){z||(z=!0,o())}function d(){try{l.documentElement.doScroll("left")}catch(a){return void setTimeout(d,50)}n()}}(window); \ No newline at end of file diff --git a/react-ui/src/icons/add.svg b/react-ui/src/icons/add.svg deleted file mode 100644 index 272dd5ac..00000000 --- a/react-ui/src/icons/add.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/react-ui/src/icons/dataset-select-button.svg b/react-ui/src/icons/dataset-select-button.svg deleted file mode 100644 index 2a376d71..00000000 --- a/react-ui/src/icons/dataset-select-button.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/react-ui/src/icons/doc-not-inventory.svg b/react-ui/src/icons/doc-not-inventory.svg deleted file mode 100644 index bfd7d4b4..00000000 --- a/react-ui/src/icons/doc-not-inventory.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/react-ui/src/icons/mirror-select-button.svg b/react-ui/src/icons/mirror-select-button.svg deleted file mode 100644 index 59e5a215..00000000 --- a/react-ui/src/icons/mirror-select-button.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/react-ui/src/icons/modal-close.svg b/react-ui/src/icons/modal-close.svg deleted file mode 100644 index 1345011e..00000000 --- a/react-ui/src/icons/modal-close.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/react-ui/src/icons/model-select-button.svg b/react-ui/src/icons/model-select-button.svg deleted file mode 100644 index 525e061b..00000000 --- a/react-ui/src/icons/model-select-button.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/react-ui/src/icons/parameter.svg b/react-ui/src/icons/parameter.svg deleted file mode 100644 index 58803521..00000000 --- a/react-ui/src/icons/parameter.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/react-ui/src/icons/private-mirror-tab.svg b/react-ui/src/icons/private-mirror-tab.svg deleted file mode 100644 index 0898ad86..00000000 --- a/react-ui/src/icons/private-mirror-tab.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/react-ui/src/icons/public-mirror-tab.svg b/react-ui/src/icons/public-mirror-tab.svg deleted file mode 100644 index 0019be13..00000000 --- a/react-ui/src/icons/public-mirror-tab.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/react-ui/src/icons/refresh.svg b/react-ui/src/icons/refresh.svg deleted file mode 100644 index 00f51915..00000000 --- a/react-ui/src/icons/refresh.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/react-ui/src/icons/remove.svg b/react-ui/src/icons/remove.svg deleted file mode 100644 index b3519764..00000000 --- a/react-ui/src/icons/remove.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/react-ui/src/icons/view-detail.svg b/react-ui/src/icons/view-detail.svg deleted file mode 100644 index c74fe45a..00000000 --- a/react-ui/src/icons/view-detail.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/react-ui/src/icons/view-param.svg b/react-ui/src/icons/view-param.svg deleted file mode 100644 index 3eb2efce..00000000 --- a/react-ui/src/icons/view-param.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/react-ui/src/icons/下载.svg b/react-ui/src/icons/下载.svg deleted file mode 100644 index bf00e67e..00000000 --- a/react-ui/src/icons/下载.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/react-ui/src/icons/查看详情.svg b/react-ui/src/icons/查看详情.svg deleted file mode 100644 index ebdfa4b0..00000000 --- a/react-ui/src/icons/查看详情.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/react-ui/src/overrides.less b/react-ui/src/overrides.less index 00735646..1b766517 100644 --- a/react-ui/src/overrides.less +++ b/react-ui/src/overrides.less @@ -36,3 +36,13 @@ margin-bottom: 0; } } + +// 表格样式 +.ant-table-header { + border: 1px solid rgba(167, 178, 194, 0.17); + border-bottom: none; +} + +.ant-table-wrapper .ant-table-thead > tr > td { + background-color: #fff; +} diff --git a/react-ui/src/pages/Dataset/index.less b/react-ui/src/pages/Dataset/index.less index 2ff0b580..13974e52 100644 --- a/react-ui/src/pages/Dataset/index.less +++ b/react-ui/src/pages/Dataset/index.less @@ -211,6 +211,7 @@ flex: 1; flex-direction: column; height: 100%; + overflow-y: auto; padding: 22px 30px 26px 30px; background: #ffffff; box-shadow: 0px 3px 6px rgba(146, 146, 146, 0.09); @@ -229,10 +230,10 @@ flex-wrap: wrap; align-content: flex-start; - width: 102%; + width: 100%; .dataItem { position: relative; - width: 23.5%; + width: 23.8%; height:164px; background:#ffffff; border:1px solid; diff --git a/react-ui/src/pages/Experiment/experimentText/index.jsx b/react-ui/src/pages/Experiment/experimentText/index.jsx index 7911ec53..baa5bd04 100644 --- a/react-ui/src/pages/Experiment/experimentText/index.jsx +++ b/react-ui/src/pages/Experiment/experimentText/index.jsx @@ -1,4 +1,3 @@ -import { ReactComponent as ViewParam } from '@/assets/svg/view-param.svg'; import { useVisible } from '@/hooks'; import { getExperimentIns } from '@/services/experiment/index.js'; import { getWorkflowById } from '@/services/pipeline/index.js'; @@ -425,11 +424,7 @@ function ExperimentText() { {experimentStatusInfo[message.status]?.label} - diff --git a/react-ui/src/pages/Experiment/index.jsx b/react-ui/src/pages/Experiment/index.jsx index dccc18d8..0a862769 100644 --- a/react-ui/src/pages/Experiment/index.jsx +++ b/react-ui/src/pages/Experiment/index.jsx @@ -1,3 +1,4 @@ +import KFIcon from '@/components/KFIcon'; import { deleteExperimentById, deleteQueryByExperimentInsId, @@ -12,16 +13,11 @@ import { runTensorBoardReq, } from '@/services/experiment/index.js'; import { getWorkflow } from '@/services/pipeline/index.js'; +import themes from '@/styles/theme.less'; import { elapsedTime } from '@/utils/date'; import { to } from '@/utils/promise'; -import { - DeleteOutlined, - EditOutlined, - FieldTimeOutlined, - PlayCircleOutlined, - PlusCircleOutlined, -} from '@ant-design/icons'; -import { Button, Modal, Space, Table, message } from 'antd'; +import { modalConfirm } from '@/utils/ui'; +import { Button, ConfigProvider, Space, Table, message } from 'antd'; import momnet from 'moment'; import { useEffect, useRef, useState } from 'react'; import { useNavigate } from 'react-router-dom'; @@ -227,6 +223,7 @@ function Experiment() { }; const pageOption = useRef({ page: 1, size: 10 }); const paginationProps = { + showSizeChanger: true, showQuickJumper: true, showTotal: () => `共${total}条`, total: total, @@ -323,7 +320,7 @@ function Experiment() { type="link" size="small" key="run" - icon={} + icon={} onClick={() => { runExperiment(record.id); }} @@ -334,61 +331,45 @@ function Experiment() { type="link" size="small" key="edit" - icon={} + icon={} onClick={() => { editExperiment(record.id); }} > 编辑 - + + ), }, @@ -405,7 +386,7 @@ function Experiment() { type="primary" className={Styles.plusButton} onClick={createExperiment} - icon={} + icon={} > 新建实验 @@ -485,7 +466,7 @@ function Experiment() { item.status === 'Failed' || item.status === 'Terminated' } - icon={} + icon={} onClick={async () => { putQueryByExperimentInsId(item.id).then((ret) => { if (ret.code === 200) { @@ -499,35 +480,38 @@ function Experiment() { > 终止 - + + )) diff --git a/react-ui/src/pages/Experiment/status.ts b/react-ui/src/pages/Experiment/status.ts index 0a7b6652..2a075951 100644 --- a/react-ui/src/pages/Experiment/status.ts +++ b/react-ui/src/pages/Experiment/status.ts @@ -15,7 +15,10 @@ export enum ExperimentStatus { Omitted = 'Omitted', } -export const experimentStatusInfo: Record = { +type ExperimentStatusKeys = keyof typeof ExperimentStatus; +type ExperimentStatusValues = (typeof ExperimentStatus)[ExperimentStatusKeys]; + +export const experimentStatusInfo: Record = { Running: { label: '运行中', color: '#165bff', diff --git a/react-ui/src/pages/Mirror/components/MirrorStatusCell/index.less b/react-ui/src/pages/Mirror/components/MirrorStatusCell/index.less new file mode 100644 index 00000000..23c518c7 --- /dev/null +++ b/react-ui/src/pages/Mirror/components/MirrorStatusCell/index.less @@ -0,0 +1,13 @@ +//@import '@/styles/theme.less'; + +.mirror-status-cell { + color: @text-color; + + &--success { + color: @success-color; + } + + &--error { + color: @error-color; + } +} diff --git a/react-ui/src/pages/Mirror/components/MirrorStatusCell/index.tsx b/react-ui/src/pages/Mirror/components/MirrorStatusCell/index.tsx new file mode 100644 index 00000000..bf0522ed --- /dev/null +++ b/react-ui/src/pages/Mirror/components/MirrorStatusCell/index.tsx @@ -0,0 +1,40 @@ +/* + * @Author: 赵伟 + * @Date: 2024-04-18 18:35:41 + * @Description: + */ +import { MirrorVersionStatus } from '@/enums'; +import styles from './index.less'; + +type MirrorStatusCellProps = { + status: MirrorVersionStatus; +}; + +type MirrorVersionStatusKeys = keyof typeof MirrorVersionStatus; +type MirrorVersionStatusValues = (typeof MirrorVersionStatus)[MirrorVersionStatusKeys]; + +export type MirrorVersionStatusInfo = { + text: string; + classname: string; +}; + +const statusInfo: Record = { + [MirrorVersionStatus.Building]: { + text: '构建中', + classname: styles['mirror-status-cell'], + }, + [MirrorVersionStatus.Available]: { + classname: styles['mirror-status-cell--success'], + text: '可用', + }, + [MirrorVersionStatus.Failed]: { + classname: styles['mirror-status-cell--error'], + text: '构建失败', + }, +}; + +function MirrorStatusCell({ status }: MirrorStatusCellProps) { + return {statusInfo[status].text}; +} + +export default MirrorStatusCell; diff --git a/react-ui/src/pages/Mirror/create.tsx b/react-ui/src/pages/Mirror/create.tsx index e61cd665..4a87edbb 100644 --- a/react-ui/src/pages/Mirror/create.tsx +++ b/react-ui/src/pages/Mirror/create.tsx @@ -1,8 +1,9 @@ /* * @Author: 赵伟 * @Date: 2024-04-16 13:58:08 - * @Description: 镜像详情 + * @Description: 创建镜像 */ +import KFIcon from '@/components/KFIcon'; import KFRadio, { type KFRadioItem } from '@/components/KFRadio'; import PageTitle from '@/components/PageTitle'; import SubAreaTitle from '@/components/SubAreaTitle'; @@ -25,10 +26,12 @@ const mirrorRadioItems: KFRadioItem[] = [ { key: CommonTabKeys.Public, title: '基于公网镜像', + icon: , }, { key: CommonTabKeys.Private, title: '本地上传', + icon: , }, ]; diff --git a/react-ui/src/pages/Mirror/info.less b/react-ui/src/pages/Mirror/info.less index b96c0d7a..61d034d8 100644 --- a/react-ui/src/pages/Mirror/info.less +++ b/react-ui/src/pages/Mirror/info.less @@ -12,7 +12,7 @@ .label { width: 80px; - color: @text-color-second; + color: @text-color-secondary; } .value { diff --git a/react-ui/src/pages/Mirror/info.tsx b/react-ui/src/pages/Mirror/info.tsx index 5841fe26..8785f586 100644 --- a/react-ui/src/pages/Mirror/info.tsx +++ b/react-ui/src/pages/Mirror/info.tsx @@ -3,16 +3,20 @@ * @Date: 2024-04-16 13:58:08 * @Description: 镜像详情 */ +import KFIcon from '@/components/KFIcon'; import PageTitle from '@/components/PageTitle'; import SubAreaTitle from '@/components/SubAreaTitle'; +import { MirrorVersionStatus } from '@/enums'; import { useDomSize } from '@/hooks'; import { getMirrorInfoReq, getMirrorVersionListReq } from '@/services/mirror'; +import themes from '@/styles/theme.less'; import { to } from '@/utils/promise'; import { useParams, useSearchParams } from '@umijs/max'; -import { Button, Col, Row, Table, TablePaginationConfig, TableProps } from 'antd'; +import { Button, Col, ConfigProvider, Row, Table, TablePaginationConfig, TableProps } from 'antd'; import classNames from 'classnames'; import dayjs from 'dayjs'; import { useEffect, useState } from 'react'; +import MirrorStatusCell from './components/MirrorStatusCell'; import styles from './info.less'; type MirrorInfoData = { @@ -36,18 +40,20 @@ function MirrorInfo() { const [mirrorInfo, setMirrorInfo] = useState({}); const [tableData, setTableData] = useState([]); const [topRef, { height: topHeight }] = useDomSize(0, 0, [mirrorInfo]); + const [total, setTotal] = useState(0); const [pagination, setPagination] = useState({ showSizeChanger: true, showQuickJumper: true, current: 1, pageSize: 10, - total: 0, }); const isPublic = seachParams.get('isPublic') === 'true'; useEffect(() => { getMirrorInfo(); - getMirrorVersionList(); }, []); + useEffect(() => { + getMirrorVersionList(); + }, [pagination]); // 获取镜像详情 const getMirrorInfo = async () => { @@ -77,10 +83,7 @@ function MirrorInfo() { if (res && res.data) { const { content = [], totalElements = 0 } = res.data; setTableData(content); - setPagination((prev) => ({ - ...prev, - total: totalElements, - })); + setTotal(totalElements); } }; @@ -88,9 +91,7 @@ function MirrorInfo() { const handleTableChange: TableProps['onChange'] = (pagination, filters, sorter, { action }) => { if (action === 'paginate') { setPagination(pagination); - getMirrorVersionList(); } - console.log(pagination, filters, sorter, action); }; const downloadVersion = (record: MirrorVersionData) => {}; @@ -99,64 +100,61 @@ function MirrorInfo() { const columns: TableProps['columns'] = [ { title: '镜像版本', - dataIndex: 'version', - key: 'version', - width: '20%', + dataIndex: 'tag_name', + key: 'tag_name', + width: '25%', }, { title: '镜像地址', dataIndex: 'url', key: 'url', - width: '26%', }, { title: '状态', dataIndex: 'status', key: 'status', - width: '7%', + width: 150, + render: (text: string) => , }, { title: '镜像大小', dataIndex: 'file_size', key: 'file_size', - width: '7%', + width: 150, }, { title: '创建时间', dataIndex: 'create_time', key: 'create_time', - width: '20%', + width: 200, render: (text: string) => {dayjs(text).format('YYYY-MM-DD HH:mm:ss')}, }, { title: '操作', dataIndex: 'operation', - width: '20%', + width: 150, key: 'operation', + hidden: isPublic, render: (_: any, record: any) => (
- {!isPublic && ( - + + )}
), @@ -184,7 +182,7 @@ function MirrorInfo() {
版本数:
-
{mirrorInfo.version_count}
+
{mirrorInfo.version_count || '--'}
@@ -218,7 +216,7 @@ function MirrorInfo() { dataSource={tableData} columns={columns} scroll={{ y: 'calc(100% - 55px)' }} - pagination={pagination} + pagination={{ ...pagination, total }} onChange={handleTableChange} rowKey="id" /> diff --git a/react-ui/src/pages/Mirror/list.less b/react-ui/src/pages/Mirror/list.less index edd9183d..4f838b76 100644 --- a/react-ui/src/pages/Mirror/list.less +++ b/react-ui/src/pages/Mirror/list.less @@ -1,5 +1,3 @@ -@import '@/styles/theme.less'; - .mirror-list { height: 100%; &__tabs-container { diff --git a/react-ui/src/pages/Mirror/list.tsx b/react-ui/src/pages/Mirror/list.tsx index 53136147..c6881779 100644 --- a/react-ui/src/pages/Mirror/list.tsx +++ b/react-ui/src/pages/Mirror/list.tsx @@ -6,9 +6,18 @@ import KFIcon from '@/components/KFIcon'; import { CommonTabKeys } from '@/enums'; import { getMirrorListReq } from '@/services/mirror'; +import themes from '@/styles/theme.less'; import { to } from '@/utils/promise'; -import { Icon, useNavigate } from '@umijs/max'; -import { Button, Input, Table, TablePaginationConfig, TableProps, Tabs } from 'antd'; +import { useNavigate } from '@umijs/max'; +import { + Button, + ConfigProvider, + Input, + Table, + TablePaginationConfig, + TableProps, + Tabs, +} from 'antd'; import classNames from 'classnames'; import dayjs from 'dayjs'; import { useEffect, useState } from 'react'; @@ -18,12 +27,12 @@ const mirrorTabItems = [ { key: CommonTabKeys.Public, label: '公共镜像', - icon: , + icon: , }, { key: CommonTabKeys.Private, label: '个人镜像', - icon: , + icon: , }, ]; @@ -39,16 +48,16 @@ function MirrorList() { const [activeTab, setActiveTab] = useState('Public'); const [searchText, setSearchText] = useState(''); const [tableData, setTableData] = useState([]); + const [total, setTotal] = useState(0); const [pagination, setPagination] = useState({ showSizeChanger: true, showQuickJumper: true, current: 1, pageSize: 10, - total: 0, }); useEffect(() => { getMirrorList(); - }, [activeTab]); + }, [activeTab, pagination]); // 获取镜像列表 const getMirrorList = async () => { @@ -62,10 +71,7 @@ function MirrorList() { if (res && res.data) { const { content = [], totalElements = 0 } = res.data; setTableData(content); - setPagination((prev) => ({ - ...prev, - total: totalElements, - })); + setTotal(totalElements); } }; @@ -82,6 +88,9 @@ function MirrorList() { }); }; + // 删除镜像 + const deleteMirror = (record: MirrorData) => {}; + // 创建镜像 const createMirror = () => { navgite({ pathname: `/dataset/mirror/create?isPublic=${activeTab === CommonTabKeys.Public}` }); @@ -91,7 +100,6 @@ function MirrorList() { const handleTableChange: TableProps['onChange'] = (pagination, filters, sorter, { action }) => { if (action === 'paginate') { setPagination(pagination); - getMirrorList(); } console.log(pagination, filters, sorter, action); }; @@ -101,32 +109,31 @@ function MirrorList() { title: '镜像名称', dataIndex: 'name', key: 'name', - width: '10%', + width: '30%', }, { title: '版本数据', dataIndex: 'version_count', key: 'version_count', - width: '10%', + width: 100, }, { title: '镜像描述', dataIndex: 'description', key: 'description', - width: '50%', //ellipsis: true, }, { title: '创建时间', dataIndex: 'create_time', key: 'create_time', - width: '20%', + width: 200, render: (text: string) => {dayjs(text).format('YYYY-MM-DD HH:mm:ss')}, }, { title: '操作', dataIndex: 'operation', - width: '15%', + width: activeTab === CommonTabKeys.Private ? 200 : 150, key: 'operation', render: (_: any, record: any) => (
@@ -134,24 +141,29 @@ function MirrorList() { type="link" size="small" key="info" - // icon={} icon={} onClick={() => toDetail(record)} > 查看详情 {activeTab === CommonTabKeys.Private && ( - + + )}
), @@ -183,7 +195,7 @@ function MirrorList() { style={{ marginLeft: '20px' }} type="default" onClick={createMirror} - icon={} + icon={} > 制作镜像 @@ -192,7 +204,7 @@ function MirrorList() { style={{ marginRight: 0, marginLeft: 'auto' }} type="default" onClick={getMirrorList} - icon={} + icon={} > 刷新 @@ -202,7 +214,7 @@ function MirrorList() { dataSource={tableData} columns={columns} scroll={{ y: 'calc(100% - 55px)' }} - pagination={pagination} + pagination={{ ...pagination, total: total }} onChange={handleTableChange} rowKey="id" /> diff --git a/react-ui/src/pages/Model/index.less b/react-ui/src/pages/Model/index.less index 7bee2701..4f3d00df 100644 --- a/react-ui/src/pages/Model/index.less +++ b/react-ui/src/pages/Model/index.less @@ -202,6 +202,7 @@ flex: 1; flex-direction: column; height: 100%; + overflow-y: auto; padding: 22px 30px 26px 30px; background: #ffffff; box-shadow: 0px 3px 6px rgba(146, 146, 146, 0.09); @@ -219,10 +220,10 @@ flex: 1; flex-wrap: wrap; align-content: flex-start; - width: 102%; + width: 100%; .dataItem { position: relative; - width: 23.5%; + width: 23.8%; height:164px; background:#ffffff; border:1px solid; diff --git a/react-ui/src/pages/Pipeline/components/ResourceSelectorModal/index.less b/react-ui/src/pages/Pipeline/components/ResourceSelectorModal/index.less index 69e8c445..947a2bcf 100644 --- a/react-ui/src/pages/Pipeline/components/ResourceSelectorModal/index.less +++ b/react-ui/src/pages/Pipeline/components/ResourceSelectorModal/index.less @@ -58,15 +58,11 @@ overflow-y: auto; &__file { - height: 24px; margin-bottom: 10px; - padding-left: 10px; - overflow: hidden; - color: #575757; + padding: 3px 10px; + color: @text-color-secondary; font-size: 13px; - line-height: 24px; - white-space: nowrap; - text-overflow: ellipsis; + word-break: break-all; background: @background-color-gray; border-radius: 4px; } diff --git a/react-ui/src/pages/Pipeline/components/ResourceSelectorModal/index.tsx b/react-ui/src/pages/Pipeline/components/ResourceSelectorModal/index.tsx index 6ebe4621..e073a449 100644 --- a/react-ui/src/pages/Pipeline/components/ResourceSelectorModal/index.tsx +++ b/react-ui/src/pages/Pipeline/components/ResourceSelectorModal/index.tsx @@ -5,9 +5,10 @@ */ import datasetImg from '@/assets/img/modal-select-dataset.png'; +import mirrorImg from '@/assets/img/modal-select-mirror.png'; import modelImg from '@/assets/img/modal-select-model.png'; import KFModal from '@/components/KFModal'; -import { CommonTabKeys } from '@/enums'; +import { CommonTabKeys, MirrorVersionStatus } from '@/enums'; import { getDatasetList, getDatasetVersionIdList, @@ -16,6 +17,7 @@ import { getModelVersionIdList, getModelVersionsById, } from '@/services/dataset/index.js'; +import { getMirrorListReq, getMirrorVersionListReq } from '@/services/mirror'; import { to } from '@/utils/promise'; import { Icon } from '@umijs/max'; import type { GetRef, ModalProps, TabsProps, TreeDataNode, TreeProps } from 'antd'; @@ -26,42 +28,51 @@ import styles from './index.less'; export enum ResourceSelectorType { Model = 'Model', // 模型 Dataset = 'Dataset', // 数据集 + Mirror = 'Mirror', //镜像 } type ResourceSelectorTypeKeys = keyof typeof ResourceSelectorType; type ResourceSelectorTypeValues = (typeof ResourceSelectorType)[ResourceSelectorTypeKeys]; -type GetModelFilesReqParam = { - models_id: number; - version: string; -}; - -type GetDatasetFilesReqParam = { - dataset_id: number; - version: string; -}; - -type GetFilesReqParam = GetModelFilesReqParam | GetDatasetFilesReqParam; - export type SelectorTypeInfo = { - getList: (params: { page: number; size: number; available_range: string }) => Promise; - getVersions: (params: number) => Promise; - getFiles: (params: GetFilesReqParam) => Promise; + getList: (params: any) => Promise; + getVersions: (params: any) => Promise; + getFiles: (params: any) => Promise; + handleVersionResponse: (res: any) => any[]; modalIcon: string; buttonIcon: string; name: string; + litReqParamKey: 'available_range' | 'image_type'; fileReqParamKey: 'models_id' | 'dataset_id'; tabItems: TabsProps['items']; }; +// 获取镜像列表,为了兼容之前的结构 +const getMirrorFilesReq = ({ id, version }: { id: number; version: string }): Promise => { + const index = version.indexOf('-'); + const url = version.slice(index + 1); + return Promise.resolve({ + data: { + content: [ + { + id: `${id}-${version}`, + file_name: `${url}`, + }, + ], + }, + }); +}; + export const selectorTypeData: Record = { - Model: { + [ResourceSelectorType.Model]: { getList: getModelList, getVersions: getModelVersionsById, getFiles: getModelVersionIdList, + handleVersionResponse: (res) => res.data || [], name: '模型', modalIcon: modelImg, buttonIcon: 'local:model-select-button', + litReqParamKey: 'available_range', fileReqParamKey: 'models_id', tabItems: [ { @@ -74,13 +85,15 @@ export const selectorTypeData: Record res.data || [], name: '数据集', modalIcon: datasetImg, buttonIcon: 'local:dataset-select-button', + litReqParamKey: 'available_range', fileReqParamKey: 'dataset_id', tabItems: [ { @@ -93,6 +106,29 @@ export const selectorTypeData: Record getMirrorVersionListReq({ image_id: id, page: 0, size: 200 }), + getFiles: getMirrorFilesReq, + handleVersionResponse: (res) => + res.data?.content?.filter((v: MirrorVersion) => v.status === MirrorVersionStatus.Available) || + [], + name: '镜像', + modalIcon: mirrorImg, + buttonIcon: 'local:mirror-select-button', + litReqParamKey: 'image_type', + fileReqParamKey: 'dataset_id', + tabItems: [ + { + key: CommonTabKeys.Private, + label: '我的镜像', + }, + { + key: CommonTabKeys.Public, + label: '公开镜像', + }, + ], + }, }; type ResourceSelectorResponse = { @@ -108,7 +144,7 @@ interface ResourceSelectorModalProps extends Omit { defaultExpandedKeys: React.Key[]; defaultCheckedKeys: React.Key[]; defaultActiveTab: CommonTabKeys; - onOk?: (params: ResourceSelectorResponse | null) => void; + onOk?: (params: ResourceSelectorResponse | string | null) => void; } type ResourceGroup = { @@ -116,6 +152,13 @@ type ResourceGroup = { name: string; // 数据集或者模型 id }; +type MirrorVersion = { + id: number; // 镜像版本id + status: MirrorVersionStatus; // 镜像版本状态 + tag_name: string; // 镜像版本 + url: string; // 镜像版本路径 +}; + type ResourceFile = { id: number; // 文件 id file_name: string; // 文件 name @@ -133,6 +176,27 @@ const convertToTreeData = (list: ResourceGroup[]): TreeDataNode[] => { })); }; +// 版本转成 treeData +const convertVersionToTreeData = (parentId: number) => { + return (item: string | MirrorVersion): TreeDataNode => { + if (typeof item === 'string') { + return { + title: item, + key: `${parentId}-${item}`, + isLeaf: true, + checkable: true, + }; + } else { + return { + title: item.tag_name, + key: `${parentId}-${item.id}-${item.url}`, + isLeaf: true, + checkable: true, + }; + } + }; +}; + // 更新树形结构的 children const updateChildren = (parentId: number, children: TreeDataNode[]) => { return (node: TreeDataNode) => { @@ -197,11 +261,11 @@ function ResourceSelectorModal({ // 获取数据集或模型列表 const getTreeData = async () => { - const available_range = activeTab === CommonTabKeys.Private ? '0' : '1'; + const available_range = activeTab === CommonTabKeys.Private ? 0 : 1; const params = { page: 0, size: 200, - available_range: available_range, + [selectorTypeData[type].litReqParamKey]: available_range, }; const getListReq = selectorTypeData[type].getList; const [res] = await to(getListReq(params)); @@ -222,13 +286,8 @@ function ResourceSelectorModal({ const getVersionsReq = selectorTypeData[type].getVersions; const [res, error] = await to(getVersionsReq(parentId)); if (res) { - const list = res.data || []; - const children = list.map((v: string) => ({ - title: v, - key: `${parentId}-${v}`, - isLeaf: true, - checkable: true, - })); + const list = selectorTypeData[type].handleVersionResponse(res); + const children = list.map(convertVersionToTreeData(parentId)); // 更新 treeData children setOriginTreeData((prev) => prev.map(updateChildren(parentId, children))); // 缓存 loadedKeys @@ -248,7 +307,7 @@ function ResourceSelectorModal({ const getFiles = async (id: number, version: string) => { const getFilesReq = selectorTypeData[type].getFiles; const paramsKey = selectorTypeData[type].fileReqParamKey; - const params = { version: version, [paramsKey]: id } as GetFilesReqParam; + const params = { version: version, [paramsKey]: id }; const [res] = await to(getFilesReq(params)); if (res) { setVersionPath(res.data?.path || ''); @@ -329,17 +388,21 @@ function ResourceSelectorModal({ // 提交 const handleOk = () => { if (checkedKeys.length > 0) { - const last = checkedKeys[0] as string; - const { id, version } = getIdAndVersion(last); - const name = (treeData.find((v) => Number(v.key) === id)?.title ?? '') as string; - const res = { - id, - name, - path: versionPath, - version, - activeTab: activeTab as CommonTabKeys, - }; - onOk?.(res); + if (type === ResourceSelectorType.Mirror) { + onOk?.(files[0].file_name); + } else { + const last = checkedKeys[0] as string; + const { id, version } = getIdAndVersion(last); + const name = (treeData.find((v) => Number(v.key) === id)?.title ?? '') as string; + const res = { + id, + name, + path: versionPath, + version, + activeTab: activeTab as CommonTabKeys, + }; + onOk?.(res); + } } else { onOk?.(null); } @@ -347,7 +410,10 @@ function ResourceSelectorModal({ const title = `选择${selectorTypeData[type].name}`; const palceholder = `请输入${selectorTypeData[type].name}名称`; - const fileTitle = `已选${selectorTypeData[type].name}文件(${files.length})`; + const fileTitle = + type === ResourceSelectorType.Mirror + ? '已选镜像' + : `已选${selectorTypeData[type].name}文件(${files.length})`; const tabItems = selectorTypeData[type].tabItems; const titleImg = selectorTypeData[type].modalIcon; diff --git a/react-ui/src/pages/Pipeline/editPipeline/globalParamsDrawer.tsx b/react-ui/src/pages/Pipeline/editPipeline/globalParamsDrawer.tsx index fad63da3..82532a06 100644 --- a/react-ui/src/pages/Pipeline/editPipeline/globalParamsDrawer.tsx +++ b/react-ui/src/pages/Pipeline/editPipeline/globalParamsDrawer.tsx @@ -4,8 +4,9 @@ import { } from '@/pages/Experiment/experimentText/addExperimentModal'; import { type PipelineGlobalParam } from '@/types'; import { to } from '@/utils/promise'; +import { modalConfirm } from '@/utils/ui'; import { DeleteOutlined, PlusOutlined } from '@ant-design/icons'; -import { Button, Drawer, Form, Input, Radio } from 'antd'; +import { Button, Drawer, Form, Input, Radio, Tooltip } from 'antd'; import { NamePath } from 'antd/es/form/interface'; import { forwardRef, useImperativeHandle } from 'react'; import styles from './globalParamsDrawer.less'; @@ -22,9 +23,8 @@ const GlobalParamsDrawer = forwardRef( useImperativeHandle(ref, () => ({ getFieldsValue: async () => { - const [res, error] = await to(form.validateFields()); - if (res && !error) { - const values = form.getFieldsValue(); + const [values, error] = await to(form.validateFields()); + if (!error && values) { return values; } else { return Promise.reject(error); @@ -32,10 +32,20 @@ const GlobalParamsDrawer = forwardRef( }, })); + // 处理参数类型变化 const handleTypeChange = (name: NamePath) => { form.setFieldValue(name, null); }; + const removeParameter = (name: number, remove: (param: number) => void) => { + modalConfirm({ + title: '确认删除该参数吗?', + onOk: () => { + remove(name); + }, + }); + }; + return ( 否 - + + + ))} @@ -150,6 +162,7 @@ const GlobalParamsDrawer = forwardRef( )} + {/* //{contextHolder} */} ); }, diff --git a/react-ui/src/pages/Pipeline/editPipeline/index.jsx b/react-ui/src/pages/Pipeline/editPipeline/index.jsx index 94989ae5..948cd364 100644 --- a/react-ui/src/pages/Pipeline/editPipeline/index.jsx +++ b/react-ui/src/pages/Pipeline/editPipeline/index.jsx @@ -1,9 +1,7 @@ -import { ReactComponent as ParameterIcon } from '@/assets/svg/parameter.svg'; -import { ReactComponent as SaveAndReturn } from '@/assets/svg/save--return.svg'; +import KFIcon from '@/components/KFIcon'; import { useVisible } from '@/hooks'; import { getWorkflowById, saveWorkflow } from '@/services/pipeline/index.js'; import { to } from '@/utils/promise'; -import { SaveOutlined } from '@ant-design/icons'; import { useEmotionCss } from '@ant-design/use-emotion-css'; import G6 from '@antv/g6'; import { Button, message } from 'antd'; @@ -716,7 +714,7 @@ const EditPipeline = () => {
- - + +
+ + + + + + +
@@ -262,11 +306,20 @@ const Props = forwardRef(({ onParentChange }, ref) => { rules={[ { required: true, - message: '请输入资源规格', + message: '请选择资源规格', }, ]} > - + diff --git a/react-ui/src/pages/Pipeline/index.jsx b/react-ui/src/pages/Pipeline/index.jsx index a08aed4e..1dd095b2 100644 --- a/react-ui/src/pages/Pipeline/index.jsx +++ b/react-ui/src/pages/Pipeline/index.jsx @@ -1,3 +1,4 @@ +import KFIcon from '@/components/KFIcon'; import { addWorkflow, cloneWorkflow, @@ -6,8 +7,9 @@ import { getWorkflowById, removeWorkflow, } from '@/services/pipeline/index.js'; -import { CopyOutlined, DeleteOutlined, EditOutlined, PlusCircleOutlined } from '@ant-design/icons'; -import { Button, Form, Input, Modal, Space, Table, message } from 'antd'; +import themes from '@/styles/theme.less'; +import { modalConfirm } from '@/utils/ui'; +import { Button, ConfigProvider, Form, Input, Modal, Space, Table, message } from 'antd'; import momnet from 'moment'; import { useEffect, useRef, useState } from 'react'; import { useNavigate } from 'react-router-dom'; @@ -26,7 +28,7 @@ const Pipeline = () => { const editTable = (e, record) => { e.stopPropagation(); getWorkflowById(record.id).then((ret) => { - if (ret.code == 200) { + if (ret.code === 200) { form.resetFields(); form.setFieldsValue({ ...ret.data }); setFormId(ret.data.id); @@ -72,6 +74,7 @@ const Pipeline = () => { }; const pageOption = useRef({ page: 1, size: 10 }); const paginationProps = { + showSizeChanger: true, showQuickJumper: true, showTotal: () => `共${total}条`, total: total, @@ -111,7 +114,7 @@ const Pipeline = () => { title: '序号', dataIndex: 'index', key: 'index', - width: 140, + width: 120, align: 'center', render(text, record, index) { return {(pageOption.current.page - 1) * 10 + index + 1}; @@ -152,7 +155,7 @@ const Pipeline = () => { type="link" size="small" key="edit" - icon={} + icon={} onClick={(e) => { editTable(e, record); }} @@ -163,7 +166,7 @@ const Pipeline = () => { type="link" size="small" key="clone" - icon={} + icon={} onClick={async () => { Modal.confirm({ title: '复制', @@ -173,7 +176,7 @@ const Pipeline = () => { onOk: () => { console.log(record); cloneWorkflow(record.id).then((ret) => { - if (ret.code == 200) { + if (ret.code === 200) { message.success('复制成功'); getList(); } else { @@ -192,54 +195,45 @@ const Pipeline = () => { > 复制 - + + ), }, @@ -251,7 +245,7 @@ const Pipeline = () => { type="primary" className={Styles.plusButton} onClick={showModal} - icon={} + icon={} > 新建流水线 @@ -309,7 +303,12 @@ const Pipeline = () => { }, ]} > - +