diff --git a/km-console/package-lock.json b/km-console/package-lock.json index e120e9eb..cb07da96 100644 --- a/km-console/package-lock.json +++ b/km-console/package-lock.json @@ -5100,9 +5100,9 @@ } }, "is-callable": { - "version": "1.2.5", - "resolved": "https://registry.npmmirror.com/is-callable/-/is-callable-1.2.5.tgz", - "integrity": "sha512-ZIWRujF6MvYGkEuHMYtFRkL2wAtFw89EHfKlXrkPkjQZZRWeh9L1q3SV13NIfHnqxugjLvAOkEHx9mb1zcMnEw==", + "version": "1.2.6", + "resolved": "https://registry.npmmirror.com/is-callable/-/is-callable-1.2.6.tgz", + "integrity": "sha512-krO72EO2NptOGAX2KYyqbP9vYMlNAXdB53rq6f8LXY6RY7JdSR/3BD6wLUlPHSAesmY9vstNrjvqGaCiRK/91Q==", "dev": true }, "is-ci": { diff --git a/km-console/packages/config-manager-fe/config/d1-webpack.base.js b/km-console/packages/config-manager-fe/config/d1-webpack.base.js deleted file mode 100644 index 95f0bc70..00000000 --- a/km-console/packages/config-manager-fe/config/d1-webpack.base.js +++ /dev/null @@ -1,205 +0,0 @@ -/* eslint-disable */ -const MiniCssExtractPlugin = require('mini-css-extract-plugin'); -const ProgressBarPlugin = require('progress-bar-webpack-plugin'); -const CaseSensitivePathsPlugin = require('case-sensitive-paths-webpack-plugin'); -const StatsPlugin = require('stats-webpack-plugin'); -const { CleanWebpackPlugin } = require('clean-webpack-plugin'); -const TerserJSPlugin = require('terser-webpack-plugin'); -const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin'); -const HappyPack = require('happypack'); -const os = require('os'); -const happyThreadPool = HappyPack.ThreadPool({ size: os.cpus().length }); -const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin'); -const theme = require('./theme'); -var cwd = process.cwd(); - -const path = require('path'); -const isProd = process.env.NODE_ENV === 'production'; -const babelOptions = { - cacheDirectory: true, - babelrc: false, - presets: [require.resolve('@babel/preset-env'), require.resolve('@babel/preset-typescript'), require.resolve('@babel/preset-react')], - plugins: [ - [require.resolve('@babel/plugin-proposal-decorators'), { legacy: true }], - [require.resolve('@babel/plugin-proposal-class-properties'), { loose: true }], - [require.resolve('@babel/plugin-proposal-private-methods'), { loose: true }], - require.resolve('@babel/plugin-proposal-export-default-from'), - require.resolve('@babel/plugin-proposal-export-namespace-from'), - require.resolve('@babel/plugin-proposal-object-rest-spread'), - require.resolve('@babel/plugin-transform-runtime'), - require.resolve('@babel/plugin-proposal-optional-chaining'), // - require.resolve('@babel/plugin-proposal-nullish-coalescing-operator'), // 解决 ?? 无法转义问题 - require.resolve('@babel/plugin-proposal-numeric-separator'), // 转义 1_000_000 - !isProd && require.resolve('react-refresh/babel'), - ] - .filter(Boolean) - .concat([ - [ - 'babel-plugin-import', - { - libraryName: 'antd', - style: true, - }, - ], - '@babel/plugin-transform-object-assign', - ]), -}; -module.exports = () => { - const manifestName = `manifest.json`; - const cssFileName = isProd ? '[name]-[chunkhash].css' : '[name].css'; - - const plugins = [ - new ProgressBarPlugin(), - new CaseSensitivePathsPlugin(), - new MiniCssExtractPlugin({ - filename: cssFileName, - }), - new StatsPlugin(manifestName, { - chunkModules: false, - source: true, - chunks: false, - modules: false, - assets: true, - children: false, - exclude: [/node_modules/], - }), - new HappyPack({ - id: 'babel', - loaders: [ - 'cache-loader', - { - loader: 'babel-loader', - options: babelOptions, - }, - ], - threadPool: happyThreadPool, - }), - !isProd && - new ReactRefreshWebpackPlugin({ - overlay: false, - }), - // new BundleAnalyzerPlugin({ - // analyzerPort: 8889 - // }), - ].filter(Boolean); - if (isProd) { - plugins.push(new CleanWebpackPlugin()); - } - return { - externals: isProd - ? [ - /^react$/, - /^react\/lib.*/, - /^react-dom$/, - /.*react-dom.*/, - /^single-spa$/, - /^single-spa-react$/, - /^moment$/, - /^antd$/, - /^lodash$/, - /^react-router$/, - /^react-router-dom$/, - ] - : [], - resolve: { - symlinks: false, - extensions: ['.web.jsx', '.web.js', '.ts', '.tsx', '.js', '.jsx', '.json'], - alias: { - // '@pkgs': path.resolve(cwd, 'src/packages'), - '@pkgs': path.resolve(cwd, './node_modules/@didi/d1-packages'), - '@cpts': path.resolve(cwd, 'src/components'), - '@interface': path.resolve(cwd, 'src/interface'), - '@apis': path.resolve(cwd, 'src/api'), - react: path.resolve('./node_modules/react'), - actions: path.resolve(cwd, 'src/actions'), - lib: path.resolve(cwd, 'src/lib'), - constants: path.resolve(cwd, 'src/constants'), - components: path.resolve(cwd, 'src/components'), - container: path.resolve(cwd, 'src/container'), - api: path.resolve(cwd, 'src/api'), - assets: path.resolve(cwd, 'src/assets'), - mobxStore: path.resolve(cwd, 'src/mobxStore'), - }, - }, - plugins, - module: { - rules: [ - { - parser: { system: false }, - }, - { - test: /\.(js|jsx|ts|tsx)$/, - exclude: /node_modules\/(?!react-intl|@didi\/dcloud-design)/, - use: [ - { - loader: 'happypack/loader?id=babel', - }, - ], - }, - { - test: /\.(png|svg|jpeg|jpg|gif|ttf|woff|woff2|eot|pdf)$/, - use: [ - { - loader: 'file-loader', - options: { - name: '[name].[ext]', - outputPath: './assets/image/', - esModule: false, - }, - }, - ], - }, - { - test: /\.(css|less)$/, - use: [ - { - loader: MiniCssExtractPlugin.loader, - }, - 'css-loader', - { - loader: 'less-loader', - options: { - javascriptEnabled: true, - modifyVars: theme, - }, - }, - ], - }, - ], - }, - optimization: Object.assign( - { - splitChunks: { - cacheGroups: { - vendor: { - test: /[\\/]node_modules[\\/]/, - chunks: 'all', - name: 'vendor', - priority: 10, - enforce: true, - minChunks: 1, - maxSize: 3500000, - }, - }, - }, - }, - isProd - ? { - minimizer: [ - new TerserJSPlugin({ - cache: true, - sourceMap: true, - }), - new OptimizeCSSAssetsPlugin({}), - ], - } - : {} - ), - devtool: isProd ? 'cheap-module-source-map' : 'source-map', - node: { - fs: 'empty', - net: 'empty', - tls: 'empty', - }, - }; -}; diff --git a/km-console/packages/config-manager-fe/config/webpack.common.js b/km-console/packages/config-manager-fe/config/webpack.common.js new file mode 100644 index 00000000..cef88e61 --- /dev/null +++ b/km-console/packages/config-manager-fe/config/webpack.common.js @@ -0,0 +1,132 @@ +const path = require('path'); +const webpack = require('webpack'); +const HtmlWebpackPlugin = require('html-webpack-plugin'); +const MiniCssExtractPlugin = require('mini-css-extract-plugin'); +const ProgressBarPlugin = require('progress-bar-webpack-plugin'); +const CaseSensitivePathsPlugin = require('case-sensitive-paths-webpack-plugin'); +const StatsPlugin = require('stats-webpack-plugin'); +const HappyPack = require('happypack'); +const os = require('os'); +const happyThreadPool = HappyPack.ThreadPool({ size: os.cpus().length }); +const theme = require('./theme'); +const pkgJson = require('../package'); + +const devMode = process.env.NODE_ENV === 'development'; +const babelOptions = { + cacheDirectory: true, + babelrc: false, + presets: [require.resolve('@babel/preset-env'), require.resolve('@babel/preset-typescript'), require.resolve('@babel/preset-react')], + plugins: [ + [require.resolve('@babel/plugin-proposal-decorators'), { legacy: true }], + [require.resolve('@babel/plugin-proposal-class-properties'), { loose: true }], + [require.resolve('@babel/plugin-proposal-private-methods'), { loose: true }], + [require.resolve('@babel/plugin-proposal-private-property-in-object'), { loose: true }], + require.resolve('@babel/plugin-proposal-export-default-from'), + require.resolve('@babel/plugin-proposal-export-namespace-from'), + require.resolve('@babel/plugin-proposal-object-rest-spread'), + require.resolve('@babel/plugin-transform-runtime'), + require.resolve('@babel/plugin-proposal-optional-chaining'), // + require.resolve('@babel/plugin-proposal-nullish-coalescing-operator'), // 解决 ?? 无法转义问题 + require.resolve('@babel/plugin-proposal-numeric-separator'), // 转义 1_000_000 + devMode && require.resolve('react-refresh/babel'), + ].filter(Boolean), +}; + +module.exports = { + entry: { + [pkgJson.ident]: ['./src/index.tsx'], + }, + resolve: { + symlinks: false, + extensions: ['.web.jsx', '.web.js', '.ts', '.tsx', '.js', '.jsx', '.json'], + alias: { + '@src': path.resolve(process.cwd(), 'src'), + }, + }, + plugins: [ + new ProgressBarPlugin(), + new CaseSensitivePathsPlugin(), + new StatsPlugin('manifest.json', { + chunkModules: false, + source: true, + chunks: false, + modules: false, + assets: true, + children: false, + exclude: [/node_modules/], + }), + new HappyPack({ + id: 'babel', + loaders: [ + 'cache-loader', + { + loader: 'babel-loader', + options: babelOptions, + }, + ], + threadPool: happyThreadPool, + }), + new webpack.DefinePlugin({ + 'process.env': { + NODE_ENV: JSON.stringify(process.env.NODE_ENV), + RUN_ENV: JSON.stringify(process.env.RUN_ENV), + }, + }), + new HtmlWebpackPlugin({ + meta: { + manifest: 'manifest.json', + }, + template: './src/index.html', + inject: 'body', + }), + ].filter(Boolean), + module: { + rules: [ + { + parser: { system: false }, + }, + { + test: /\.(js|jsx|ts|tsx)$/, + exclude: /node_modules\/(?!react-intl|@didi\/dcloud-design)/, + use: [ + { + loader: 'happypack/loader?id=babel', + }, + ], + }, + { + test: /\.(png|svg|jpeg|jpg|gif|ttf|woff|woff2|eot|pdf)$/, + use: [ + { + loader: 'file-loader', + options: { + name: '[name].[ext]', + outputPath: './assets/image/', + esModule: false, + }, + }, + ], + }, + { + test: /\.(css|less)$/, + use: [ + MiniCssExtractPlugin.loader, + 'css-loader', + { + loader: 'less-loader', + options: { + javascriptEnabled: true, + modifyVars: theme, + }, + }, + ], + }, + ], + }, + node: { + fs: 'empty', + net: 'empty', + tls: 'empty', + }, + stats: 'errors-warnings', +}; diff --git a/km-console/packages/config-manager-fe/config/webpack.dev.js b/km-console/packages/config-manager-fe/config/webpack.dev.js new file mode 100644 index 00000000..1b60f703 --- /dev/null +++ b/km-console/packages/config-manager-fe/config/webpack.dev.js @@ -0,0 +1,35 @@ +const MiniCssExtractPlugin = require('mini-css-extract-plugin'); +const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin'); +const pkgJson = require('../package'); + +module.exports = { + mode: 'development', + plugins: [ + new MiniCssExtractPlugin(), + new ReactRefreshWebpackPlugin({ + overlay: false, + }), + ], + devServer: { + host: '127.0.0.1', + port: pkgJson.port, + hot: true, + open: false, + publicPath: `http://localhost:${pkgJson.port}/${pkgJson.ident}/`, + inline: true, + disableHostCheck: true, + historyApiFallback: true, + headers: { + 'Access-Control-Allow-Origin': '*', + }, + }, + output: { + path: '/', + publicPath: `http://localhost:${pkgJson.port}/${pkgJson.ident}/`, + library: pkgJson.ident, + libraryTarget: 'amd', + filename: '[name].js', + chunkFilename: '[name].js', + }, + devtool: 'cheap-module-eval-source-map', +}; diff --git a/km-console/packages/config-manager-fe/config/webpack.prod.js b/km-console/packages/config-manager-fe/config/webpack.prod.js new file mode 100644 index 00000000..9dd9ee66 --- /dev/null +++ b/km-console/packages/config-manager-fe/config/webpack.prod.js @@ -0,0 +1,59 @@ +const path = require('path'); +const MiniCssExtractPlugin = require('mini-css-extract-plugin'); +const { CleanWebpackPlugin } = require('clean-webpack-plugin'); +const TerserJSPlugin = require('terser-webpack-plugin'); +const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin'); +const pkgJson = require('../package'); + +module.exports = { + mode: 'production', + externals: [ + /^react$/, + /^react\/lib.*/, + /^react-dom$/, + /.*react-dom.*/, + /^single-spa$/, + /^single-spa-react$/, + /^moment$/, + /^lodash$/, + /^react-router$/, + /^react-router-dom$/, + ], + plugins: [ + new CleanWebpackPlugin(), + new MiniCssExtractPlugin({ + filename: '[name]-[chunkhash].css', + }), + ], + output: { + path: path.resolve(process.cwd(), `../../../km-rest/src/main/resources/templates/${pkgJson.ident}`), + publicPath: `${process.env.PUBLIC_PATH}/${pkgJson.ident}/`, + library: pkgJson.ident, + libraryTarget: 'amd', + filename: '[name]-[chunkhash].js', + chunkFilename: '[name]-[chunkhash].js', + }, + optimization: { + splitChunks: { + cacheGroups: { + vendor: { + test: /[\\/]node_modules[\\/]/, + chunks: 'all', + name: 'vendor', + priority: 10, + enforce: true, + minChunks: 1, + maxSize: 3500000, + }, + }, + }, + minimizer: [ + new TerserJSPlugin({ + cache: true, + sourceMap: true, + }), + new OptimizeCSSAssetsPlugin({}), + ], + }, + devtool: 'none', +}; diff --git a/km-console/packages/config-manager-fe/package-lock.json b/km-console/packages/config-manager-fe/package-lock.json index 6c32859e..bf0a4f18 100644 --- a/km-console/packages/config-manager-fe/package-lock.json +++ b/km-console/packages/config-manager-fe/package-lock.json @@ -1344,6 +1344,16 @@ "@jridgewell/sourcemap-codec": "^1.4.10" } }, + "@knowdesign/icons": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/@knowdesign/icons/-/icons-1.0.0.tgz", + "integrity": "sha512-7c+h2TSbh2ihTkXIivuO+DddNC5wG7hVv9SS4ccmkvTKls2ZTLitPu+U0wpufDxPhkPMaKEQfsECsVJ+7jLMiw==", + "requires": { + "@ant-design/colors": "^6.0.0", + "@ant-design/icons": "^4.7.0", + "react": "16.12.0" + } + }, "@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmmirror.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -6815,9 +6825,9 @@ "dev": true }, "is-callable": { - "version": "1.2.5", - "resolved": "https://registry.npmmirror.com/is-callable/-/is-callable-1.2.5.tgz", - "integrity": "sha512-ZIWRujF6MvYGkEuHMYtFRkL2wAtFw89EHfKlXrkPkjQZZRWeh9L1q3SV13NIfHnqxugjLvAOkEHx9mb1zcMnEw==", + "version": "1.2.6", + "resolved": "https://registry.npmmirror.com/is-callable/-/is-callable-1.2.6.tgz", + "integrity": "sha512-krO72EO2NptOGAX2KYyqbP9vYMlNAXdB53rq6f8LXY6RY7JdSR/3BD6wLUlPHSAesmY9vstNrjvqGaCiRK/91Q==", "dev": true }, "is-color-stop": { diff --git a/km-console/packages/config-manager-fe/package.json b/km-console/packages/config-manager-fe/package.json index 2b820594..945e8b5c 100644 --- a/km-console/packages/config-manager-fe/package.json +++ b/km-console/packages/config-manager-fe/package.json @@ -21,9 +21,11 @@ "build": "cross-env NODE_ENV=production webpack --max_old_space_size=8000" }, "dependencies": { + "@knowdesign/icons": "^1.0.0", "babel-preset-react-app": "^10.0.0", "classnames": "^2.2.6", "dotenv": "^16.0.1", + "knowdesign": "1.3.7", "less": "^3.9.0", "lodash": "^4.17.11", "mobx": "4.15.7", @@ -36,8 +38,7 @@ "react-intl": "^3.2.1", "react-router-cache-route": "^1.11.1", "single-spa": "^5.8.0", - "single-spa-react": "^2.14.0", - "knowdesign": "1.3.7" + "single-spa-react": "^2.14.0" }, "devDependencies": { "@ant-design/icons": "^4.6.2", diff --git a/km-console/packages/config-manager-fe/src/components/TypicalListCard/index.less b/km-console/packages/config-manager-fe/src/components/TypicalListCard/index.less index 06516afa..9a48d134 100644 --- a/km-console/packages/config-manager-fe/src/components/TypicalListCard/index.less +++ b/km-console/packages/config-manager-fe/src/components/TypicalListCard/index.less @@ -22,6 +22,20 @@ display: flex; justify-content: space-between; margin-bottom: 12px; + .left, + .right { + display: flex; + align-items: center; + } + .left .refresh-icon { + font-size: 20px; + color: #74788d; + cursor: pointer; + } + .right .search-input { + width: 248px; + margin-right: 8px; + } } } } diff --git a/km-console/packages/config-manager-fe/src/constants/axiosConfig.ts b/km-console/packages/config-manager-fe/src/constants/axiosConfig.ts index f08ebc77..3e05e105 100644 --- a/km-console/packages/config-manager-fe/src/constants/axiosConfig.ts +++ b/km-console/packages/config-manager-fe/src/constants/axiosConfig.ts @@ -47,8 +47,8 @@ serviceInstance.interceptors.response.use( return res; }, (err: any) => { - const config = err.config; - if (!config || !config.retryTimes) return dealResponse(err, config.customNotification); + const config = err?.config; + if (!config || !config.retryTimes) return dealResponse(err); const { __retryCount = 0, retryDelay = 300, retryTimes } = config; config.__retryCount = __retryCount; if (__retryCount >= retryTimes) { diff --git a/km-console/packages/config-manager-fe/src/pages/CommonConfig.tsx b/km-console/packages/config-manager-fe/src/pages/CommonConfig.tsx index 2a9a9a74..835abf51 100644 --- a/km-console/packages/config-manager-fe/src/pages/CommonConfig.tsx +++ b/km-console/packages/config-manager-fe/src/pages/CommonConfig.tsx @@ -1,6 +1,6 @@ import React, { useLayoutEffect } from 'react'; import { Utils, AppContainer } from 'knowdesign'; -import { goLogin } from 'constants/axiosConfig'; +import { goLogin } from '@src/constants/axiosConfig'; // 权限对应表 export enum ConfigPermissionMap { diff --git a/km-console/packages/config-manager-fe/src/pages/ConfigManage/index.tsx b/km-console/packages/config-manager-fe/src/pages/ConfigManage/index.tsx index 84b5d2f6..1430fbb6 100644 --- a/km-console/packages/config-manager-fe/src/pages/ConfigManage/index.tsx +++ b/km-console/packages/config-manager-fe/src/pages/ConfigManage/index.tsx @@ -15,6 +15,7 @@ import { AppContainer, Utils, } from 'knowdesign'; +import { IconFont } from '@knowdesign/icons'; import { PlusOutlined } from '@ant-design/icons'; import moment from 'moment'; // 引入代码编辑器 @@ -26,8 +27,8 @@ import 'codemirror/addon/selection/active-line'; import 'codemirror/addon/edit/closebrackets'; require('codemirror/mode/xml/xml'); require('codemirror/mode/javascript/javascript'); -import api from 'api'; -import { defaultPagination } from 'constants/common'; +import api from '@src/api'; +import { defaultPagination } from '@src/constants/common'; import TypicalListCard from '../../components/TypicalListCard'; import { ConfigPermissionMap } from '../CommonConfig'; import { ConfigOperate, ConfigProps } from './config'; @@ -384,7 +385,7 @@ export default () => { const onDelete = (record: ConfigProps) => { confirm({ title: '确定删除配置吗?', - content: `配置⌈${record.valueName}⌋${record.status === 1 ? '为启用状态,无法删除' : ''}`, + content: `配置 [${record.valueName}] ${record.status === 1 ? '为启用状态,无法删除' : ''}`, centered: true, okText: '删除', okType: 'primary', @@ -398,9 +399,11 @@ export default () => { }, maskClosable: true, onOk() { - return request(api.editConfig, { - method: 'POST', - data: record.id, + return request(api.delConfig, { + method: 'DELETE', + params: { + id: record.id, + }, }).then((_) => { message.success('删除成功'); getConfigList(); @@ -431,22 +434,28 @@ export default () => {
-
getConfigList({ page: 1 })}> - - - - - - - - - -
+
+
getConfigList()}> + +
+ +
getConfigList({ page: 1 })}> + + + + + + + + + +
+
{global.hasPermission && global.hasPermission(ConfigPermissionMap.CONFIG_ADD) ? ( - - +
+
getData()}> + +
+ + +
getData({ page: 1 })}> + + + + + + + + + + + + +
+
{ return ( <> -
- { - setSearchKeywords(searchKeywordsInput); - }} - style={{ fontSize: '16px' }} - /> - } - placeholder="请输入角色名称" - value={searchKeywordsInput} - onPressEnter={(_) => { - setSearchKeywords(searchKeywordsInput); - }} - onChange={(e) => { - setSearchKeywordsInput(e.target.value); - }} - /> - {global.hasPermission && global.hasPermission(ConfigPermissionMap.ROLE_ADD) ? ( - - ) : ( - <> - )} +
+
+
getRoleList()}> + +
+
+
+ { + setSearchKeywords(searchKeywordsInput); + }} + style={{ fontSize: '16px' }} + /> + } + placeholder="请输入角色名称" + value={searchKeywordsInput} + onPressEnter={(_) => { + setSearchKeywords(searchKeywordsInput); + }} + onChange={(e) => { + setSearchKeywordsInput(e.target.value); + }} + /> + {global.hasPermission && global.hasPermission(ConfigPermissionMap.ROLE_ADD) ? ( + + ) : ( + <> + )} +
{ return ( <>
-
getUserList({ page: 1 })}> - - - - - - - - + + + + + + { }} onPressEnter={searchFn} /> - - { }} onPressEnter={searchFn} /> - +
{/* */}
-
+ {/*
*/}
)} {/* diff --git a/km-console/packages/layout-clusters-fe/src/pages/Jobs/RebalancePlan.tsx b/km-console/packages/layout-clusters-fe/src/pages/Jobs/RebalancePlan.tsx index 4b11b2e7..024fced3 100644 --- a/km-console/packages/layout-clusters-fe/src/pages/Jobs/RebalancePlan.tsx +++ b/km-console/packages/layout-clusters-fe/src/pages/Jobs/RebalancePlan.tsx @@ -13,8 +13,8 @@ interface PropsType { } const typeObj: any = { - 1: '周期均衡', - 2: '立即均衡', + 1: '立即均衡', + 2: '周期均衡', }; const { request, post } = Utils; diff --git a/km-console/packages/layout-clusters-fe/src/pages/Jobs/index.tsx b/km-console/packages/layout-clusters-fe/src/pages/Jobs/index.tsx index 84e70298..5432b434 100644 --- a/km-console/packages/layout-clusters-fe/src/pages/Jobs/index.tsx +++ b/km-console/packages/layout-clusters-fe/src/pages/Jobs/index.tsx @@ -1,6 +1,6 @@ import React, { useState, useEffect, memo } from 'react'; import { useParams, useHistory, useLocation } from 'react-router-dom'; -import { ProTable, Drawer, Utils, AppContainer, Form, Select, Input, Button, message, Modal } from 'knowdesign'; +import { ProTable, Drawer, Utils, AppContainer, Form, Select, Input, Button, message, Modal, IconFont, Divider } from 'knowdesign'; import API from '../../api'; import { getJobsListColumns, defaultPagination, runningStatus, jobType } from './config'; import JobsCheck from '@src/components/CardBar/JobsCheck'; @@ -10,6 +10,7 @@ import './index.less'; import ReplicaChange from '@src/components/TopicJob/ReplicaChange'; import ReplicaMove from '@src/components/TopicJob/ReplicaMove'; import BalanceDrawer from '../LoadRebalance/BalanceDrawer'; +import { tableHeaderPrefix } from '@src/constants/common'; const { request } = Utils; const JobsList: React.FC = (props: any) => { @@ -171,35 +172,44 @@ const JobsList: React.FC = (props: any) => { {/* */}
-
- - - - - - + + + + + + @@ -354,8 +365,7 @@ const LoadBalance: React.FC = (props: any) => { */} - -
+
{ const intl = useIntl(); const [form] = Form.useForm(); const [loading, setLoading] = React.useState(false); + const [confirmLoading, setConfirmLoading] = React.useState(false); const [curClusterInfo, setCurClusterInfo] = React.useState({}); - const [security, setSecurity] = React.useState(curClusterInfo?.security || 'None'); const [extra, setExtra] = React.useState({ versionExtra: '', zooKeeperExtra: '', bootstrapExtra: '', jmxExtra: '', }); - const [isLowVersion, setIsLowVersion] = React.useState(false); - const [zookeeperErrorStatus, setZookeeperErrorStatus] = React.useState(false); const lastFormItemValue = React.useRef({ - bootstrap: curClusterInfo?.bootstrapServers || '', + bootstrapServers: curClusterInfo?.bootstrapServers || '', zookeeper: curClusterInfo?.zookeeper || '', clientProperties: curClusterInfo?.clientProperties || {}, }); - const onHandleValuesChange = (value: any, allValues: any) => { - Object.keys(value).forEach((key) => { + const onHandleValuesChange = (changedValue: string[]) => { + Object.keys(changedValue).forEach((key) => { switch (key) { - case 'security': - setSecurity(value.security); - break; case 'zookeeper': - setExtra({ - ...extra, - zooKeeperExtra: '', - bootstrapExtra: '', - jmxExtra: '', - }); - break; case 'bootstrapServers': setExtra({ ...extra, @@ -78,21 +65,19 @@ const AccessClusters = (props: any): JSX.Element => { const onCancel = () => { form.resetFields(); setLoading(false); - setZookeeperErrorStatus(false); - setIsLowVersion(false); - setSecurity('None'); setExtra({ versionExtra: '', zooKeeperExtra: '', bootstrapExtra: '', jmxExtra: '', }); - lastFormItemValue.current = { bootstrap: '', zookeeper: '', clientProperties: {} }; + lastFormItemValue.current = { bootstrapServers: '', zookeeper: '', clientProperties: {} }; props.setVisible && props.setVisible(false); }; const onSubmit = () => { form.validateFields().then((res) => { + setConfirmLoading(true); let clientProperties = null; try { clientProperties = res.clientProperties && JSON.parse(res.clientProperties); @@ -107,7 +92,7 @@ const AccessClusters = (props: any): JSX.Element => { jmxProperties: { jmxPort: res.jmxPort, maxConn: res.maxConn, - openSSL: res.security === 'Password', + openSSL: res.openSSL || false, token: res.token, username: res.username, }, @@ -115,7 +100,7 @@ const AccessClusters = (props: any): JSX.Element => { name: res.name, zookeeper: res.zookeeper || '', }; - setLoading(true); + if (!isNaN(curClusterInfo?.id)) { Utils.put(api.phyCluster, { ...params, @@ -127,7 +112,7 @@ const AccessClusters = (props: any): JSX.Element => { onCancel(); }) .finally(() => { - setLoading(false); + setConfirmLoading(false); }); } else { Utils.post(api.phyCluster, params) @@ -137,7 +122,7 @@ const AccessClusters = (props: any): JSX.Element => { onCancel(); }) .finally(() => { - setLoading(false); + setConfirmLoading(false); }); } }); @@ -154,125 +139,224 @@ const AccessClusters = (props: any): JSX.Element => { } setLoading(true); - setIsLowVersion(false); - setZookeeperErrorStatus(false); return Utils.post(api.kafkaValidator, { bootstrapServers: bootstrapServers || '', zookeeper: zookeeper || '', clientProperties, }) - .then((res: any) => { - form.setFieldsValue({ - jmxPort: res.jmxPort, - }); + .then( + (res: { + errList: { code: number; message: string; data: any }[]; + jmxPort: number | null; + kafkaVersion: string | null; + zookeeper: string | null; + }) => { + const changedValue: { jmxPort?: number; kafkaVersion?: string; zookeeper: string } = { + zookeeper: zookeeper || res.zookeeper, + }; + if (res.kafkaVersion && props.kafkaVersion.includes(res.kafkaVersion)) { + changedValue.kafkaVersion = res.kafkaVersion; + } + if (res.jmxPort) { + changedValue.jmxPort = res.jmxPort; + } + form.setFieldsValue(changedValue); - if (props.kafkaVersion.indexOf(res.kafkaVersion) > -1) { - form.setFieldsValue({ - kafkaVersion: res.kafkaVersion, - }); - } else { - form.setFieldsValue({ - kafkaVersion: undefined, + const extraMsg = { + ...extra, + // 重置默认信息为连接成功 + bootstrapExtra: bootstrapServers ? '连接成功' : '', + zooKeeperExtra: zookeeper ? '连接成功' : '', + }; + + const errList = res.errList || []; + // 处理错误信息 + errList.forEach((item: any) => { + const { code, message } = item; + let modifyKey: 'bootstrapExtra' | 'zooKeeperExtra' | 'jmxExtra' | undefined; + if (bootstrapServersErrCodes.includes(code)) { + modifyKey = 'bootstrapExtra'; + } else if (zkErrCodes.includes(code)) { + modifyKey = 'zooKeeperExtra'; + } else if (jmxErrCodes.includes(code)) { + modifyKey = 'jmxExtra'; + } + + if (modifyKey) { + extraMsg[modifyKey] = message; + } }); + + setExtra(extraMsg); + return res; } - - form.setFieldsValue({ - zookeeper: zookeeper || res.zookeeper, - }); - - const errList = res.errList || []; - - const extraMsg = extra; - - // 初始化信息为连接成功 - extraMsg.bootstrapExtra = bootstrapServers ? '连接成功' : ''; - extraMsg.zooKeeperExtra = zookeeper ? '连接成功' : ''; - - // 处理错误信息 - errList.forEach((item: any) => { - const { code, message } = item; - let modifyKey: 'bootstrapExtra' | 'zooKeeperExtra' | 'jmxExtra' | undefined; - if (bootstrapServersErrCodes.includes(code)) { - modifyKey = 'bootstrapExtra'; - } else if (zkErrCodes.includes(code)) { - modifyKey = 'zooKeeperExtra'; - } else if (jmxErrCodes.includes(code)) { - modifyKey = 'jmxExtra'; - } - - if (modifyKey) { - extraMsg[modifyKey] = `连接失败。${message}`; - } - }); - - // 如果kafkaVersion小于最低版本则提示 - const showLowVersion = !( - curClusterInfo?.zookeeper || - !curClusterInfo?.kafkaVersion || - curClusterInfo?.kafkaVersion >= lowKafkaVersion - ); - setIsLowVersion(showLowVersion); - setExtra({ - ...extraMsg, - versionExtra: showLowVersion ? intl.formatMessage({ id: 'access.cluster.low.version.tip' }) : '', - }); - return res; - }) + ) .finally(() => { setLoading(false); }); }; + // 更新表单状态 React.useEffect(() => { - const showLowVersion = !(curClusterInfo?.zookeeper || !curClusterInfo?.kafkaVersion || curClusterInfo?.kafkaVersion >= lowKafkaVersion); lastFormItemValue.current = { - bootstrap: curClusterInfo?.bootstrapServers || '', + bootstrapServers: curClusterInfo?.bootstrapServers || '', zookeeper: curClusterInfo?.zookeeper || '', clientProperties: curClusterInfo?.clientProperties || {}, }; - setIsLowVersion(showLowVersion); - setExtra({ - ...extra, - versionExtra: showLowVersion ? intl.formatMessage({ id: 'access.cluster.low.version.tip' }) : '', - }); form.setFieldsValue({ ...curClusterInfo }); + if (curClusterInfo?.kafkaVersion) { + form.validateFields(['kafkaVersion']); + } }, [curClusterInfo]); + // 获取集群详情数据 React.useEffect(() => { if (visible) { if (clusterInfo?.id) { setLoading(true); + + const resolveJmxProperties = (obj: any) => { + const res = { ...obj }; + try { + const originValue = obj?.jmxProperties; + if (originValue) { + const jmxProperties = JSON.parse(originValue); + typeof jmxProperties === 'object' && jmxProperties !== null && Object.assign(res, jmxProperties); + } + } catch (err) { + console.error('jmxProperties not JSON: ', err); + } + return res; + }; + Utils.request(api.getPhyClusterBasic(clusterInfo.id)) .then((res: any) => { - let jmxProperties = null; - try { - jmxProperties = JSON.parse(res?.jmxProperties); - } catch (err) { - console.error(err); - } - - // 转化值对应成表单值 - if (jmxProperties?.openSSL) { - jmxProperties.security = 'Password'; - } - - if (jmxProperties) { - res = Object.assign({}, res || {}, jmxProperties); - } - setCurClusterInfo(res); - setLoading(false); + setCurClusterInfo(resolveJmxProperties(res)); }) .catch((err) => { - setCurClusterInfo(clusterInfo); + setCurClusterInfo(resolveJmxProperties(clusterInfo)); + }) + .finally(() => { setLoading(false); }); } else { - setCurClusterInfo(clusterInfo); + setCurClusterInfo({}); } } }, [visible, clusterInfo]); + const validators = { + name: async (_: any, value: string) => { + if (!value) { + return Promise.reject('集群名称不能为空'); + } + if (value === curClusterInfo?.name) { + return Promise.resolve(); + } + if (value?.length > 128) { + return Promise.reject('集群名称长度限制在1~128字符'); + } + if (!new RegExp(regClusterName).test(value)) { + return Promise.reject('集群名称支持中英文、数字、特殊字符 ! " # $ % & \' ( ) * + , - . / : ; < = > ? @ [ ] ^ _ ` { | } ~'); + } + return Utils.request(api.getClusterBasicExit(value)) + .then((res: any) => { + const data = res || {}; + return data?.exist ? Promise.reject('集群名称重复') : Promise.resolve(); + }) + .catch(() => Promise.reject('连接超时! 请重试或检查服务')); + }, + bootstrapServers: async (_: any, value: string) => { + if (!value) { + return Promise.reject('Bootstrap Servers不能为空'); + } + if (value.length > 2000) { + return Promise.reject('Bootstrap Servers长度限制在2000字符'); + } + if (value && value !== lastFormItemValue.current.bootstrapServers) { + lastFormItemValue.current.bootstrapServers = value; + return connectTest().catch(() => (lastFormItemValue.current.bootstrapServers = '')); + } + return Promise.resolve(''); + }, + zookeeper: async (_: any, value: string) => { + if (!value) { + return Promise.resolve(''); + } + + if (value.length > 2000) { + return Promise.reject('Zookeeper长度限制在2000字符'); + } + + if (value && value !== lastFormItemValue.current.zookeeper) { + lastFormItemValue.current.zookeeper = value; + return connectTest().catch(() => (lastFormItemValue.current.zookeeper = '')); + } + return Promise.resolve(''); + }, + securityUserName: async (_: any, value: string) => { + if (!value) { + return Promise.reject('用户名不能为空'); + } + if (!new RegExp(regUsername).test(value)) { + return Promise.reject('仅支持大小写、下划线、短划线(-)'); + } + if (value.length > 128) { + return Promise.reject('用户名长度限制在1~128字符'); + } + return Promise.resolve(); + }, + securityToken: async (_: any, value: string) => { + if (!value) { + return Promise.reject('密码不能为空'); + } + if (!new RegExp(regUsername).test(value)) { + return Promise.reject('密码只能由大小写、下划线、短划线(-)组成'); + } + if (value.length < 6 || value.length > 32) { + return Promise.reject('密码长度限制在6~32字符'); + } + return Promise.resolve(); + }, + kafkaVersion: async (_: any, value: any) => { + if (!value) { + return Promise.reject('版本号不能为空'); + } + // 检测版本号小于2.8.0,如果没有填zookeeper信息,才会提示 + const zookeeper = form.getFieldValue('zookeeper'); + let versionExtra = ''; + if (value < LOW_KAFKA_VERSION && !zookeeper) { + versionExtra = intl.formatMessage({ id: 'access.cluster.low.version.tip' }); + } + setExtra({ + ...extra, + versionExtra, + }); + return Promise.resolve(); + }, + clientProperties: async (_: any, value: string) => { + try { + if (value) { + JSON.parse(value); + } + + return Promise.resolve(); + } catch (e) { + return Promise.reject(new Error('输入内容必须为 JSON')); + } + }, + description: async (_: any, value: string) => { + if (!value) { + return Promise.resolve(''); + } + if (value && value.length > 200) { + return Promise.reject('集群描述长度限制在200字符'); + } + return Promise.resolve(); + }, + }; + return ( <> { -
} - title={intl.formatMessage({ id: props.title || 'access.cluster' })} + title={intl.formatMessage({ id: props.title || clusterInfo?.id ? 'edit.cluster' : 'access.cluster' })} visible={props.visible} placement="right" width={480} @@ -306,30 +390,7 @@ const AccessClusters = (props: any): JSX.Element => { rules={[ { required: true, - validator: async (rule: any, value: string) => { - if (!value) { - return Promise.reject('集群名称不能为空'); - } - if (value === curClusterInfo?.name) { - return Promise.resolve(); - } - if (value?.length > 128) { - return Promise.reject('集群名称长度限制在1~128字符'); - } - if (!new RegExp(regClusterName).test(value)) { - return Promise.reject( - '集群名称支持中英文、数字、特殊字符 ! " # $ % & \' ( ) * + , - . / : ; < = > ? @ [ ] ^ _ ` { | } ~' - ); - } - return Utils.request(api.getClusterBasicExit(value)).then((res: any) => { - const data = res || {}; - if (data?.exist) { - return Promise.reject('集群名称重复'); - } else { - return Promise.resolve(); - } - }); - }, + validator: validators.name, }, ]} > @@ -338,31 +399,12 @@ const AccessClusters = (props: any): JSX.Element => { {extra.bootstrapExtra}} + extra={{extra.bootstrapExtra}} validateTrigger={'onBlur'} rules={[ { required: true, - validator: async (rule: any, value: string) => { - if (!value) { - return Promise.reject('Bootstrap Servers不能为空'); - } - if (value.length > 2000) { - return Promise.reject('Bootstrap Servers长度限制在2000字符'); - } - if (value && value !== lastFormItemValue.current.bootstrap) { - return connectTest() - .then((res: any) => { - lastFormItemValue.current.bootstrap = value; - - return Promise.resolve(''); - }) - .catch((err) => { - return Promise.reject('连接失败'); - }); - } - return Promise.resolve(''); - }, + validator: validators.bootstrapServers, }, ]} > @@ -374,36 +416,11 @@ const AccessClusters = (props: any): JSX.Element => { {extra.zooKeeperExtra}} - validateStatus={zookeeperErrorStatus ? 'error' : 'success'} + extra={{extra.zooKeeperExtra}} validateTrigger={'onBlur'} rules={[ { - required: false, - validator: async (rule: any, value: string) => { - if (!value) { - setZookeeperErrorStatus(false); - return Promise.resolve(''); - } - - if (value.length > 2000) { - return Promise.reject('Zookeeper长度限制在2000字符'); - } - - if (value && value !== lastFormItemValue.current.zookeeper) { - return connectTest() - .then((res: any) => { - lastFormItemValue.current.zookeeper = value; - setZookeeperErrorStatus(false); - return Promise.resolve(''); - }) - .catch((err) => { - setZookeeperErrorStatus(true); - return Promise.reject('连接失败'); - }); - } - return Promise.resolve(''); - }, + validator: validators.zookeeper, }, ]} > @@ -412,142 +429,65 @@ const AccessClusters = (props: any): JSX.Element => { placeholder="请输入Zookeeper地址,例如:192.168.0.1:2181,192.168.0.2:2181,192.168.0.2:2181/ks-kafka" /> - - <> - - - - - - - - - - None - Password Authentication - - - {security === 'Password' ? ( - <> - { - if (!value) { - return Promise.reject('用户名不能为空'); - } - if (!new RegExp(regUsername).test(value)) { - return Promise.reject('仅支持大小写、下划线、短划线(-)'); - } - if (value.length > 128) { - return Promise.reject('用户名长度限制在1~128字符'); - } - return Promise.resolve(); - }, - }, - ]} - > - + +
+
+ + + + + + +
+ + + None + Password Authentication + - { - if (!value) { - return Promise.reject('密码不能为空'); - } - if (!new RegExp(regUsername).test(value)) { - return Promise.reject('密码只能由大小写、下划线、短划线(-)组成'); - } - if (value.length < 6 || value.length > 32) { - return Promise.reject('密码长度限制在6~32字符'); - } - return Promise.resolve(); - }, - }, - ]} - > - + + {({ getFieldValue }) => { + return getFieldValue('openSSL') ? ( +
+ +
+ + + + + + +
+
+ ) : null; + }}
- - ) : null} +
+
{extra.versionExtra}} - validateStatus={isLowVersion ? 'error' : 'success'} rules={[ { required: true, - validator: async (rule: any, value: any) => { - if (!value) { - setIsLowVersion(true); - return Promise.reject('版本号不能为空'); - } - // 检测版本号小于2.8.0,如果没有填zookeeper信息,才会提示 - const zookeeper = form.getFieldValue('zookeeper'); - if (value < lowKafkaVersion && !zookeeper) { - setIsLowVersion(true); - setExtra({ - ...extra, - versionExtra: intl.formatMessage({ id: 'access.cluster.low.version.tip' }), - }); - return Promise.resolve(); - } - setIsLowVersion(false); - return Promise.resolve(); - }, + validator: validators.kafkaVersion, }, ]} > @@ -565,29 +505,15 @@ const AccessClusters = (props: any): JSX.Element => { label="集群配置" rules={[ { - required: false, - message: '请输入集群配置', + validator: validators.clientProperties, }, - () => ({ - validator(_, value) { - try { - if (value) { - JSON.parse(value); - } - - return Promise.resolve(); - } catch (e) { - return Promise.reject(new Error('输入内容必须为 JSON')); - } - }, - }), ]} >
{ form.setFieldsValue({ clientProperties }); form.validateFields(['clientProperties']); @@ -621,20 +547,11 @@ const AccessClusters = (props: any): JSX.Element => { label="集群描述" rules={[ { - required: false, - validator: async (rule: any, value: string) => { - if (!value) { - return Promise.resolve(''); - } - if (value && value.length > 200) { - return Promise.reject('集群描述长度限制在200字符'); - } - return Promise.resolve(); - }, + validator: validators.description, }, ]} > - + diff --git a/km-console/packages/layout-clusters-fe/src/pages/MutliClusterPage/index.less b/km-console/packages/layout-clusters-fe/src/pages/MutliClusterPage/index.less index 3108c4c0..f459fd1c 100644 --- a/km-console/packages/layout-clusters-fe/src/pages/MutliClusterPage/index.less +++ b/km-console/packages/layout-clusters-fe/src/pages/MutliClusterPage/index.less @@ -656,43 +656,37 @@ color: @error-color; } } - .inline-item.dcloud-form-item { - display: -webkit-inline-box; - margin-right: 16px; - - &.adjust-height-style { - .dcloud-form-item-label { - padding: 0; - label { - height: 36px; - } - } - .dcloud-form-item-control { - &-input { - height: 36px; - } - } + .horizontal-form-container { + padding-left: 16px; + .inline-items { + display: flex; + justify-content: space-between; } - - &.max-width-66 { - .dcloud-form-item-control { - max-width: 66%; - } - } - - .dcloud-form-item-label { - margin-right: 12px; - - label { + .dcloud-form-item { + flex-direction: row; + align-items: center; + &-label { + padding: 0 12px 0 0; + font-size: 13px; font-family: @font-family; + color: #74788d; } } - } - - .no-item-control { - margin-bottom: 8px !important; - .dcloud-form-item-control { - display: none; + .metrics-form-item { + margin-top: 8px; + } + .user-info-form-items { + display: flex; + align-items: flex-start; + .user-info-label { + padding-top: 4px; + } + .inline-items { + flex: 0 0 80%; + .token-form-item { + margin-left: 16px; + } + } } } } diff --git a/km-console/packages/layout-clusters-fe/src/pages/SecurityACLs/index.less b/km-console/packages/layout-clusters-fe/src/pages/SecurityACLs/index.less index 54f77499..1d962f93 100644 --- a/km-console/packages/layout-clusters-fe/src/pages/SecurityACLs/index.less +++ b/km-console/packages/layout-clusters-fe/src/pages/SecurityACLs/index.less @@ -10,11 +10,6 @@ box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.01), 0 3px 6px 3px rgba(0, 0, 0, 0.01), 0 2px 6px 0 rgba(0, 0, 0, 0.03); // border-radius: 12px; } - .operate-bar { - display: flex; - justify-content: space-between; - margin-bottom: 12px; - } } .acls-edit-drawer { diff --git a/km-console/packages/layout-clusters-fe/src/pages/SecurityACLs/index.tsx b/km-console/packages/layout-clusters-fe/src/pages/SecurityACLs/index.tsx index 3f51bc55..7d0c9446 100644 --- a/km-console/packages/layout-clusters-fe/src/pages/SecurityACLs/index.tsx +++ b/km-console/packages/layout-clusters-fe/src/pages/SecurityACLs/index.tsx @@ -1,7 +1,8 @@ import React, { useEffect, useRef, useState } from 'react'; -import { Button, Form, Input, Select, Modal, message, ProTable, AppContainer, DKSBreadcrumb, Utils } from 'knowdesign'; +import { Button, Form, Input, Select, Modal, message, ProTable, AppContainer, DKSBreadcrumb, Utils, IconFont, Divider } from 'knowdesign'; import ACLsCardBar from '@src/components/CardBar/ACLsCardBar'; import api from '@src/api'; +import { tableHeaderPrefix } from '@src/constants/common'; import { useParams } from 'react-router-dom'; import AddACLDrawer, { ACL_OPERATION, @@ -205,37 +206,45 @@ const SecurityACLs = (): JSX.Element => {
-
-
getACLs({ page: 1 })}> - - - - - - - - - - - +
+
+
getACLs()}> + +
+ +
getACLs({ page: 1 })}> + + + + + + + + + + +
+
+ +
{ const maxPos = chars.length; @@ -426,34 +427,41 @@ const SecurityUsers = (): JSX.Element => { ]} />
-
- { - setSearchKeywords(searchKeywordsInput); - }} - style={{ fontSize: '16px' }} - /> - } - placeholder="请输入 Kafka User" - value={searchKeywordsInput} - onPressEnter={(_) => { - setSearchKeywords(searchKeywordsInput); - }} - onChange={(e) => { - setSearchKeywordsInput(e.target.value); - }} - /> - +
+
+
getKafkaUserList()}> + +
+
+
+ { + setSearchKeywords(searchKeywordsInput); + }} + style={{ fontSize: '16px' }} + /> + } + placeholder="请输入 Kafka User" + value={searchKeywordsInput} + onPressEnter={(_) => { + setSearchKeywords(searchKeywordsInput); + }} + onChange={(e) => { + setSearchKeywordsInput(e.target.value); + }} + /> + +
div { width: 100%; height: 100%; @@ -73,65 +40,64 @@ justify-content: center; align-items: center; } - - .chart-box { - position: relative; - width: 100%; - height: 244px; - background: #f8f9fa; - border-radius: 8px; - - .expand-icon-box { - position: absolute; - z-index: 1000; - top: 14px; - right: 16px; - width: 24px; - height: 24px; - cursor: pointer; - font-size: 16px; - text-align: center; - border-radius: 50%; - transition: background-color 0.3s ease; - - .expand-icon { - color: #adb5bc; - line-height: 24px; - } - - &:hover { - background: rgba(33, 37, 41, 0.06); - .expand-icon { - color: #74788d; - } - } - } - } } .config-change-records-container { width: 240px; height: 100%; margin-left: 12px; - .cluster-container-border(); + .cluster-detail-container-border(); } } } +} - .chart-box-title { - padding: 18px 0 0 20px; - font-family: @font-family-bold; - line-height: 16px; - .name { - font-size: 14px; - color: #212529; +.cluster-detail-chart-box { + position: relative; + width: 100%; + height: 244px; + background: #f8f9fa; + border-radius: 8px; + + .expand-icon-box { + position: absolute; + z-index: 1000; + top: 14px; + right: 16px; + width: 24px; + height: 24px; + cursor: pointer; + font-size: 16px; + text-align: center; + border-radius: 50%; + transition: background-color 0.3s ease; + + .expand-icon { + color: #adb5bc; + line-height: 24px; } - .unit { - font-size: 12px; - color: #495057; - } - > span { - cursor: pointer; + + &:hover { + background: rgba(33, 37, 41, 0.06); + .expand-icon { + color: #74788d; + } } } } +.cluster-detail-chart-box-title { + padding: 18px 0 0 20px; + font-family: @font-family-bold; + line-height: 16px; + .name { + font-size: 14px; + color: #212529; + } + .unit { + font-size: 12px; + color: #495057; + } + > span { + cursor: pointer; + } +} diff --git a/km-console/packages/layout-clusters-fe/src/pages/SingleClusterDetail/DetailChart/index.tsx b/km-console/packages/layout-clusters-fe/src/pages/SingleClusterDetail/DetailChart/index.tsx index 6ecb7604..db241e4e 100644 --- a/km-console/packages/layout-clusters-fe/src/pages/SingleClusterDetail/DetailChart/index.tsx +++ b/km-console/packages/layout-clusters-fe/src/pages/SingleClusterDetail/DetailChart/index.tsx @@ -15,6 +15,7 @@ import { getDataNumberUnit, getUnit } from '@src/constants/chartConfig'; import SingleChartHeader, { KsHeaderOptions } from '@src/components/SingleChartHeader'; import { MAX_TIME_RANGE_WITH_SMALL_POINT_INTERVAL } from '@src/constants/common'; import RenderEmpty from '@src/components/RenderEmpty'; +import DragGroup from '@src/components/DragGroup'; type ChartFilterOptions = Omit; interface MetricInfo { @@ -279,7 +280,7 @@ const DetailChart = (props: { children: JSX.Element }): JSX.Element => { }, []); return ( -
+
{ {messagesInMetricData.data && ( <> -
+
{ @@ -354,14 +355,25 @@ const DetailChart = (props: { children: JSX.Element }): JSX.Element => {
- - {metricDataList.length ? ( - metricDataList.map((data: any, i: number) => { - const { metricName, metricUnit, metricLines } = data; - return ( -
-
-
+ {metricDataList.length ? ( +
+ 0, + onSortEnd: () => 0, + axis: 'xy', + useDragHandle: false, + }} + gridProps={{ + span: 12, + gutter: [16, 16], + }} + > + {metricDataList.map((data: any, i: number) => { + const { metricName, metricUnit, metricLines } = data; + return ( +
+
{ @@ -379,15 +391,6 @@ const DetailChart = (props: { children: JSX.Element }): JSX.Element => {
-
{ - setChartDetail(data); - setShowChartDetailModal(true); - }} - > - -
{ })} />
- - ); - }) - ) : chartLoading ? ( - <> - ) : ( - - )} - + ); + })} +
+
+ ) : chartLoading ? ( + <> + ) : ( + + )}
@@ -421,35 +424,6 @@ const DetailChart = (props: { children: JSX.Element }): JSX.Element => {
{props.children}
- - {/* 图表详情 */} - setShowChartDetailModal(false)} - > -
-
setShowChartDetailModal(false)}> - -
- {chartDetail && ( - - )} -
-
); }; diff --git a/km-console/packages/layout-clusters-fe/src/pages/SingleClusterDetail/index.less b/km-console/packages/layout-clusters-fe/src/pages/SingleClusterDetail/index.less index 7baae7b8..3fa013de 100644 --- a/km-console/packages/layout-clusters-fe/src/pages/SingleClusterDetail/index.less +++ b/km-console/packages/layout-clusters-fe/src/pages/SingleClusterDetail/index.less @@ -231,9 +231,10 @@ } .chart-panel { - flex: 1; + flex: auto; margin-left: 12px; margin-right: 10px; + overflow: hidden; } .change-log-panel { diff --git a/km-console/packages/layout-clusters-fe/src/pages/SingleClusterDetail/index.tsx b/km-console/packages/layout-clusters-fe/src/pages/SingleClusterDetail/index.tsx index e4b4b2c6..59e679b3 100644 --- a/km-console/packages/layout-clusters-fe/src/pages/SingleClusterDetail/index.tsx +++ b/km-console/packages/layout-clusters-fe/src/pages/SingleClusterDetail/index.tsx @@ -21,11 +21,9 @@ const SingleClusterDetail = (): JSX.Element => {
-
- - - -
+ + +
diff --git a/km-console/packages/layout-clusters-fe/src/pages/TestingConsumer/config.tsx b/km-console/packages/layout-clusters-fe/src/pages/TestingConsumer/config.tsx index d27f8d4e..fc529e9d 100644 --- a/km-console/packages/layout-clusters-fe/src/pages/TestingConsumer/config.tsx +++ b/km-console/packages/layout-clusters-fe/src/pages/TestingConsumer/config.tsx @@ -268,6 +268,7 @@ export const getFormConfig = (topicMetaData: any, info = {} as any, partitionLis type: FormItemType.inputNumber, attrs: { min: 1, + max: 1000, }, invisible: !info?.needMsgNum, rules: [ diff --git a/km-console/packages/layout-clusters-fe/src/pages/TestingProduce/config.tsx b/km-console/packages/layout-clusters-fe/src/pages/TestingProduce/config.tsx index 81503271..97589f32 100644 --- a/km-console/packages/layout-clusters-fe/src/pages/TestingProduce/config.tsx +++ b/km-console/packages/layout-clusters-fe/src/pages/TestingProduce/config.tsx @@ -152,6 +152,7 @@ export const getFormConfig = (params: any) => { rules: [{ required: true, message: '请输入' }], attrs: { min: 0, + max: 1000, style: { width: 232 }, }, }, @@ -391,7 +392,7 @@ export const getTableColumns = () => { { title: 'time', dataIndex: 'costTimeUnitMs', - width: 60, + width: 100, }, ]; }; diff --git a/km-console/packages/layout-clusters-fe/src/pages/TopicDetail/Messages.tsx b/km-console/packages/layout-clusters-fe/src/pages/TopicDetail/Messages.tsx index eecf792a..1e1f6582 100644 --- a/km-console/packages/layout-clusters-fe/src/pages/TopicDetail/Messages.tsx +++ b/km-console/packages/layout-clusters-fe/src/pages/TopicDetail/Messages.tsx @@ -10,7 +10,7 @@ const defaultParams: any = { maxRecords: 100, pullTimeoutUnitMs: 5000, // filterPartitionId: 1, - filterOffsetReset: 0 + filterOffsetReset: 0, }; const defaultpaPagination = { current: 1, @@ -32,8 +32,8 @@ const TopicMessages = (props: any) => { // 获取消息开始位置 const offsetResetList = [ - { 'label': 'latest', value: 0 }, - { 'label': 'earliest', value: 1 } + { label: 'latest', value: 0 }, + { label: 'earliest', value: 1 }, ]; // 默认排序 @@ -99,10 +99,10 @@ const TopicMessages = (props: any) => { const onTableChange = (pagination: any, filters: any, sorter: any, extra: any) => { setPagination(pagination); // 只有排序事件时,触发重新请求后端数据 - if(extra.action === 'sort') { + if (extra.action === 'sort') { setSorter({ sortField: sorter.field || '', - sortType: sorter.order ? sorter.order.substring(0, sorter.order.indexOf('end')) : '' + sortType: sorter.order ? sorter.order.substring(0, sorter.order.indexOf('end')) : '', }); } // const asc = sorter?.order && sorter?.order === 'ascend' ? true : false; @@ -137,11 +137,11 @@ const TopicMessages = (props: any) => { - - - */} - {/* - - */} - {/*
*/} + +
getTopicsList()}> + +
+
{ 展示系统Topic
-
+
p), - output: { - path: outPath, - publicPath: isProd ? process.env.PUBLIC_PATH + '/layout/' : '/', - filename: jsFileName, - chunkFilename: jsFileName, - library: 'layout', - libraryTarget: 'amd', - }, - devServer: { - host: 'localhost', - port: 8000, - hot: true, - open: true, - openPage: 'http://localhost:8000/', - inline: true, - historyApiFallback: true, - publicPath: `http://localhost:8000/`, - headers: { - 'cache-control': 'no-cache', - pragma: 'no-cache', - 'Access-Control-Allow-Origin': '*', - }, - proxy: { - '/ks-km/api/v3': { - changeOrigin: true, - target: 'http://localhost:8080/', - }, - '/logi-security/api/v1': { - changeOrigin: true, - target: 'http://localhost:8080/', - }, - }, - }, +const devMode = process.env.NODE_ENV === 'development'; +const commonConfig = require('./config/webpack.common'); +const devConfig = require('./config/webpack.dev'); +const prodConfig = require('./config/webpack.prod'); - resolve: { - alias: { - '@src': path.resolve(__dirname, 'src'), - }, - }, -}); +module.exports = merge(commonConfig, devMode ? devConfig : prodConfig);