mirror of
https://github.com/didi/KnowStreaming.git
synced 2026-01-10 17:12:11 +08:00
前端调整
This commit is contained in:
@@ -29,5 +29,6 @@ module.exports = {
|
|||||||
'@typescript-eslint/no-var-requires': 0,
|
'@typescript-eslint/no-var-requires': 0,
|
||||||
'prettier/prettier': 2, // 这项配置 对于不符合prettier规范的写法,eslint会提示报错
|
'prettier/prettier': 2, // 这项配置 对于不符合prettier规范的写法,eslint会提示报错
|
||||||
'no-console': 1,
|
'no-console': 1,
|
||||||
|
'react/display-name': 0,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,19 +1,43 @@
|
|||||||
## 安装项目依赖
|
## 安装项目依赖
|
||||||
|
|
||||||
* 安装lerna
|
- 安装 lerna
|
||||||
|
|
||||||
```
|
```
|
||||||
npm i -g lerna
|
npm install -g lerna
|
||||||
|
```
|
||||||
|
|
||||||
|
- 安装项目依赖
|
||||||
|
|
||||||
|
```
|
||||||
|
npm run i
|
||||||
```
|
```
|
||||||
|
|
||||||
## 启动项目
|
## 启动项目
|
||||||
|
|
||||||
```
|
```
|
||||||
npm run start
|
npm run start
|
||||||
```
|
```
|
||||||
|
|
||||||
### 环境信息
|
### 环境信息
|
||||||
|
|
||||||
http://localhost:port
|
http://localhost:port
|
||||||
|
|
||||||
## 构建项目
|
## 构建项目
|
||||||
|
|
||||||
```
|
```
|
||||||
npm run build
|
npm run build
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## 目录结构
|
||||||
|
|
||||||
|
- packages
|
||||||
|
- layout-clusters-fe: 基座应用 & 多集群管理
|
||||||
|
- config-manager-fe: 子应用 - 系统管理
|
||||||
|
- tool: 启动 & 打包脚本
|
||||||
|
- ...
|
||||||
|
|
||||||
|
## 常见问题
|
||||||
|
|
||||||
|
Q: 执行 `npm run start` 时看不到应用构建和热加载过程?
|
||||||
|
A: 需要到具体的应用中执行 `npm run start`,例如 `cd packages/layout-clusters-fe` 后,执行 `npm run start`。
|
||||||
|
|||||||
@@ -1,11 +1,40 @@
|
|||||||
# `logi-fe`
|
## 使用说明
|
||||||
|
|
||||||
> TODO: description
|
### 依赖安装:
|
||||||
|
|
||||||
## Usage
|
```
|
||||||
|
npm install
|
||||||
|
```
|
||||||
|
|
||||||
### 启动
|
### 启动:
|
||||||
* npm i @didi/d1-cli -g
|
|
||||||
* d1 start
|
|
||||||
|
|
||||||
### 常见问题
|
```
|
||||||
|
npm run start
|
||||||
|
```
|
||||||
|
|
||||||
|
### 构建:
|
||||||
|
|
||||||
|
```
|
||||||
|
npm run build
|
||||||
|
```
|
||||||
|
|
||||||
|
构建后的代码默认会存放到项目根路径下 `km-rest/src/main/resources/templates/config` 文件夹里
|
||||||
|
|
||||||
|
## 目录结构
|
||||||
|
|
||||||
|
- config: 开发 & 构建配置
|
||||||
|
- theme.js: antd 主题配置
|
||||||
|
- d1-webpack.base.js: webpack 基础配置
|
||||||
|
- src:源代码所在目录
|
||||||
|
- @types: TypeScript 全局类型声明
|
||||||
|
- api: 请求定义
|
||||||
|
- assets:全局资源 img、css
|
||||||
|
- components:公共组件
|
||||||
|
- constants: 全局配置、通用方法
|
||||||
|
- locales: 国际化语言
|
||||||
|
- pages: 路由匹配的页面组件
|
||||||
|
- app.tsx: 菜单、路由配置组件
|
||||||
|
- index.html: 单页
|
||||||
|
- index.tsx: 入口文件
|
||||||
|
- tsconfig.json: TypeScript 配置
|
||||||
|
- webpack.config.js: webpack 配置入口
|
||||||
|
|||||||
@@ -1,37 +0,0 @@
|
|||||||
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');
|
|
||||||
|
|
||||||
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: [
|
|
||||||
new HtmlWebpackPlugin({
|
|
||||||
meta: {
|
|
||||||
manifest: 'manifest.json',
|
|
||||||
},
|
|
||||||
template: './src/index.html',
|
|
||||||
inject: 'body',
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
output: {
|
|
||||||
library: pkgJson.ident,
|
|
||||||
libraryTarget: 'amd',
|
|
||||||
},
|
|
||||||
entry: {
|
|
||||||
[pkgJson.ident]: ['./src/index.tsx'],
|
|
||||||
},
|
|
||||||
};
|
|
||||||
0
km-console/packages/config-manager-fe/src/@types/index.d.ts
vendored
Normal file
0
km-console/packages/config-manager-fe/src/@types/index.d.ts
vendored
Normal file
@@ -1,7 +0,0 @@
|
|||||||
export const defaultPagination = {
|
|
||||||
current: 1,
|
|
||||||
pageSize: 10,
|
|
||||||
position: 'bottomRight',
|
|
||||||
showSizeChanger: true,
|
|
||||||
pageSizeOptions: ['10', '20', '50', '100'],
|
|
||||||
};
|
|
||||||
@@ -376,7 +376,8 @@ export default (props: { curTabKey: string }): JSX.Element => {
|
|||||||
const [pagination, setPagination] = useState<any>(defaultPagination);
|
const [pagination, setPagination] = useState<any>(defaultPagination);
|
||||||
const [loading, setLoading] = useState<boolean>(true);
|
const [loading, setLoading] = useState<boolean>(true);
|
||||||
const [deleteBtnLoading, setDeleteBtnLoading] = useState<number>(-1);
|
const [deleteBtnLoading, setDeleteBtnLoading] = useState<number>(-1);
|
||||||
const [form] = Form.useForm();
|
const [searchKeywords, setSearchKeywords] = useState('');
|
||||||
|
const [searchKeywordsInput, setSearchKeywordsInput] = useState('');
|
||||||
const detailRef = useRef(null);
|
const detailRef = useRef(null);
|
||||||
const assignRolesRef = useRef(null);
|
const assignRolesRef = useRef(null);
|
||||||
|
|
||||||
@@ -472,11 +473,10 @@ export default (props: { curTabKey: string }): JSX.Element => {
|
|||||||
];
|
];
|
||||||
|
|
||||||
const getRoleList = (query = {}) => {
|
const getRoleList = (query = {}) => {
|
||||||
const formData = form.getFieldsValue();
|
|
||||||
const data = {
|
const data = {
|
||||||
page: pagination.current,
|
page: pagination.current,
|
||||||
size: pagination.pageSize,
|
size: pagination.pageSize,
|
||||||
...formData,
|
roleName: searchKeywords,
|
||||||
...query,
|
...query,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -582,19 +582,33 @@ export default (props: { curTabKey: string }): JSX.Element => {
|
|||||||
}
|
}
|
||||||
}, [curTabKey]);
|
}, [curTabKey]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
(searchKeywords || searchKeywords === '') && getRoleList({ pageNo: 1 });
|
||||||
|
}, [searchKeywords]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="operate-bar">
|
<div className="operate-bar-right">
|
||||||
<Form form={form} layout="inline" onFinish={() => getRoleList({ page: 1 })}>
|
<Input
|
||||||
<Form.Item name="roleName">
|
className="search-input"
|
||||||
<Input placeholder="请输入角色名称" />
|
suffix={
|
||||||
</Form.Item>
|
<IconFont
|
||||||
<Form.Item>
|
type="icon-fangdajing"
|
||||||
<Button type="primary" ghost htmlType="submit">
|
onClick={(_) => {
|
||||||
查询
|
setSearchKeywords(searchKeywordsInput);
|
||||||
</Button>
|
}}
|
||||||
</Form.Item>
|
style={{ fontSize: '16px' }}
|
||||||
</Form>
|
/>
|
||||||
|
}
|
||||||
|
placeholder="请输入角色名称"
|
||||||
|
value={searchKeywordsInput}
|
||||||
|
onPressEnter={(_) => {
|
||||||
|
setSearchKeywords(searchKeywordsInput);
|
||||||
|
}}
|
||||||
|
onChange={(e) => {
|
||||||
|
setSearchKeywordsInput(e.target.value);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
{global.hasPermission && global.hasPermission(ConfigPermissionMap.ROLE_ADD) ? (
|
{global.hasPermission && global.hasPermission(ConfigPermissionMap.ROLE_ADD) ? (
|
||||||
<Button
|
<Button
|
||||||
type="primary"
|
type="primary"
|
||||||
|
|||||||
@@ -44,3 +44,13 @@
|
|||||||
.role-tab-assign-user .desc-row {
|
.role-tab-assign-user .desc-row {
|
||||||
margin-bottom: 24px;
|
margin-bottom: 24px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.operate-bar-right {
|
||||||
|
display: flex;
|
||||||
|
justify-content: right;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
.search-input {
|
||||||
|
width: 248px;
|
||||||
|
margin-right: 8px;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,32 +1,45 @@
|
|||||||
## Usage
|
## 使用说明
|
||||||
|
|
||||||
|
### 依赖安装:
|
||||||
|
|
||||||
|
```
|
||||||
|
npm install
|
||||||
|
```
|
||||||
|
|
||||||
### 启动:
|
### 启动:
|
||||||
* 招行环境执行 npm start
|
|
||||||
* 内部环境执行 npm run start:inner
|
```
|
||||||
|
npm run start
|
||||||
|
```
|
||||||
|
|
||||||
### 构建:
|
### 构建:
|
||||||
* 招行环境执行 npm build
|
|
||||||
* 内部环境执行 npm run build:inner
|
|
||||||
|
|
||||||
构建后的代码默认会存放到 `../pub` 文件夹里
|
```
|
||||||
|
npm run build
|
||||||
|
```
|
||||||
|
|
||||||
### 部署
|
构建后的代码默认会存放到项目根路径下 `km-rest/src/main/resources/templates/layout` 文件夹里
|
||||||
* 内部环境:代码提交主干后会自动触发打包部署至http://10.190.14.125:8016
|
|
||||||
|
|
||||||
## 目录结构
|
## 目录结构
|
||||||
|
|
||||||
- config: 开发 & 构建配置
|
- config: 开发 & 构建配置
|
||||||
- theme.js:antd 主题配置
|
- theme.js: antd 主题配置
|
||||||
- webpack.dev.config.js:webpack 开发环境补充配置,覆盖默认配置
|
- registerApps.js: SPA 注册
|
||||||
- webpack.build.config.js:webpack 构建补充配置,覆盖默认配置
|
- systemsConfig.js: 子应用配置
|
||||||
- webpackConfigResolveAlias.js 文件路径别名配置
|
- d1-webpack.base.js: webpack 基础配置
|
||||||
|
- CoverHtmlWebpackPlugin.js: 输出 html 内容
|
||||||
|
- CountComponentWebpackPlugin.js: 计算 knowdesign 组件引用次数
|
||||||
|
- webpackConfigResolveAlias.js: 文件路径别名配置
|
||||||
- src:源代码所在目录
|
- src:源代码所在目录
|
||||||
|
- @types: TypeScript 全局类型声明
|
||||||
|
- api: 请求定义
|
||||||
- assets:全局资源 img、css
|
- assets:全局资源 img、css
|
||||||
- common: 全局配置、通用方法
|
|
||||||
- components:公共组件
|
- components:公共组件
|
||||||
- pages:路由匹配的页面组件
|
- constants: 全局配置、通用方法
|
||||||
- app.jsx 菜单、路由配置组件
|
- locales: 国际化语言
|
||||||
- index.html:单页
|
- pages: 路由匹配的页面组件
|
||||||
- index.jsx:入口文件
|
- app.tsx: 菜单、路由配置组件
|
||||||
- fetk.config.js 开发工具配置页面
|
- index.html: 单页
|
||||||
|
- index.tsx: 入口文件
|
||||||
|
- tsconfig.json: TypeScript 配置
|
||||||
|
- webpack.config.js: webpack 配置入口
|
||||||
|
|||||||
@@ -1,35 +0,0 @@
|
|||||||
function getApi(path: string) {
|
|
||||||
const prefix = '/api/uic';
|
|
||||||
return `${prefix}${path}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getOrderApi(path: string) {
|
|
||||||
const prefix = '/api/ticket';
|
|
||||||
return `${prefix}${path}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
const api = {
|
|
||||||
login: getApi('/auth/login'),
|
|
||||||
logout: getApi('/auth/logout'),
|
|
||||||
selftProfile: getApi('/self/profile'),
|
|
||||||
selftPassword: getApi('/self/password'),
|
|
||||||
selftToken: getApi('/self/token'),
|
|
||||||
user: getApi('/user'),
|
|
||||||
tenant: getApi('/tenant'),
|
|
||||||
team: getApi('/team'),
|
|
||||||
configs: getApi('/configs'),
|
|
||||||
role: getApi('/role'),
|
|
||||||
ops: getApi('/ops'),
|
|
||||||
log: getApi('/log'),
|
|
||||||
homeStatistics: getApi('/home/statistics'),
|
|
||||||
project: getApi('/project'),
|
|
||||||
projects: getApi('/projects'),
|
|
||||||
queues: getOrderApi('/queues'),
|
|
||||||
tickets: getOrderApi('/tickets'),
|
|
||||||
template: getOrderApi('/templates'),
|
|
||||||
upload: getOrderApi('/file/upload'),
|
|
||||||
|
|
||||||
task: '/api/job-ce/task',
|
|
||||||
};
|
|
||||||
|
|
||||||
export default api;
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
export const appname = 'ecmc';
|
|
||||||
export const prefixCls = appname;
|
|
||||||
export const loginPath = `/login`;
|
|
||||||
export const defaultPageSizeOptions = ['10', '30', '50', '100', '300', '500', '1000'];
|
|
||||||
@@ -3,8 +3,9 @@ import React, { useState, useEffect } from 'react';
|
|||||||
import { useParams } from 'react-router-dom';
|
import { useParams } from 'react-router-dom';
|
||||||
import CardBar from '@src/components/CardBar';
|
import CardBar from '@src/components/CardBar';
|
||||||
import { healthDataProps } from '.';
|
import { healthDataProps } from '.';
|
||||||
import { Tag, Utils } from 'knowdesign';
|
import { Tag, Tooltip, Utils } from 'knowdesign';
|
||||||
import api from '@src/api';
|
import api from '@src/api';
|
||||||
|
import { QuestionCircleOutlined } from '@ant-design/icons';
|
||||||
|
|
||||||
export default () => {
|
export default () => {
|
||||||
const routeParams = useParams<{
|
const routeParams = useParams<{
|
||||||
@@ -85,7 +86,16 @@ export default () => {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'Similar Config',
|
title() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<span style={{ display: 'inline-block', marginRight: '8px' }}>Similar Config</span>
|
||||||
|
<Tooltip overlayClassName="rebalance-tooltip" title="所有broker配置是否一致">
|
||||||
|
<QuestionCircleOutlined />
|
||||||
|
</Tooltip>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
},
|
||||||
value: () => {
|
value: () => {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ import './index.less';
|
|||||||
import Api, { MetricType } from '@src/api/index';
|
import Api, { MetricType } from '@src/api/index';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import PreviewTaskPlan from './PreviewTaskPlan';
|
import PreviewTaskPlan from './PreviewTaskPlan';
|
||||||
import { timeFormat } from '@src/lib/utils';
|
import { timeFormater } from '@src/constants/common';
|
||||||
import type { RangePickerProps } from 'knowdesign/es/basic/date-picker';
|
import type { RangePickerProps } from 'knowdesign/es/basic/date-picker';
|
||||||
|
|
||||||
const { TextArea } = Input;
|
const { TextArea } = Input;
|
||||||
@@ -135,7 +135,7 @@ export default (props: DefaultConfig) => {
|
|||||||
title: '数据保存时间',
|
title: '数据保存时间',
|
||||||
dataIndex: 'retentionMs',
|
dataIndex: 'retentionMs',
|
||||||
render: (v: any) => {
|
render: (v: any) => {
|
||||||
return timeFormat(v);
|
return timeFormater(v);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -154,7 +154,6 @@ export default (props: DefaultConfig) => {
|
|||||||
setMoveDataTimeRanges(moveDataTimeRangesCopy);
|
setMoveDataTimeRanges(moveDataTimeRangesCopy);
|
||||||
}}
|
}}
|
||||||
formatter={(value) => (value ? `${value} h` : '')}
|
formatter={(value) => (value ? `${value} h` : '')}
|
||||||
// @ts-ignore
|
|
||||||
parser={(value) => value.replace('h', '')}
|
parser={(value) => value.replace('h', '')}
|
||||||
></InputNumber>
|
></InputNumber>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,3 +1,7 @@
|
|||||||
|
interface IMap {
|
||||||
|
[key: string]: string;
|
||||||
|
}
|
||||||
|
|
||||||
export const defaultPagination = {
|
export const defaultPagination = {
|
||||||
current: 1,
|
current: 1,
|
||||||
pageSize: 10,
|
pageSize: 10,
|
||||||
@@ -122,10 +126,37 @@ export const hashDataParse = (hash: string) => {
|
|||||||
return newHashData;
|
return newHashData;
|
||||||
};
|
};
|
||||||
|
|
||||||
const BUSINESS_VERSION = process.env.BUSINESS_VERSION;
|
export const urlParser = () => {
|
||||||
|
const Url = {
|
||||||
|
hash: {} as IMap,
|
||||||
|
search: {} as IMap,
|
||||||
|
} as {
|
||||||
|
hash: IMap;
|
||||||
|
search: IMap;
|
||||||
|
[key: string]: IMap;
|
||||||
|
};
|
||||||
|
|
||||||
|
window.location.hash
|
||||||
|
.slice(1)
|
||||||
|
.split('&')
|
||||||
|
.forEach((str) => {
|
||||||
|
const kv = str.split('=');
|
||||||
|
Url.hash[kv[0]] = kv[1];
|
||||||
|
});
|
||||||
|
|
||||||
|
window.location.search
|
||||||
|
.slice(1)
|
||||||
|
.split('&')
|
||||||
|
.forEach((str) => {
|
||||||
|
const kv = str.split('=');
|
||||||
|
Url.search[kv[0]] = kv[1];
|
||||||
|
});
|
||||||
|
|
||||||
|
return Url;
|
||||||
|
};
|
||||||
|
|
||||||
export const getLicenseInfo = (cbk: (msg: string) => void) => {
|
export const getLicenseInfo = (cbk: (msg: string) => void) => {
|
||||||
if (BUSINESS_VERSION) {
|
if (process.env.BUSINESS_VERSION) {
|
||||||
const info = (window as any).code;
|
const info = (window as any).code;
|
||||||
if (!info) {
|
if (!info) {
|
||||||
setTimeout(() => getLicenseInfo(cbk), 1000);
|
setTimeout(() => getLicenseInfo(cbk), 1000);
|
||||||
@@ -137,3 +168,96 @@ export const getLicenseInfo = (cbk: (msg: string) => void) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const getRandomStr = (length?: number) => {
|
||||||
|
const NUM_list = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
|
||||||
|
const LOW_LETTERS_LIST = [
|
||||||
|
'a',
|
||||||
|
'b',
|
||||||
|
'c',
|
||||||
|
'd',
|
||||||
|
'e',
|
||||||
|
'f',
|
||||||
|
'g',
|
||||||
|
'h',
|
||||||
|
'i',
|
||||||
|
'j',
|
||||||
|
'k',
|
||||||
|
'l',
|
||||||
|
'm',
|
||||||
|
'n',
|
||||||
|
'o',
|
||||||
|
'p',
|
||||||
|
'q',
|
||||||
|
'r',
|
||||||
|
's',
|
||||||
|
't',
|
||||||
|
'u',
|
||||||
|
'v',
|
||||||
|
'w',
|
||||||
|
'x',
|
||||||
|
'y',
|
||||||
|
'z',
|
||||||
|
];
|
||||||
|
const CAP_LETTERS_LIST = LOW_LETTERS_LIST.map((v) => v.toUpperCase());
|
||||||
|
const SPECIAL_LIST = [
|
||||||
|
'!',
|
||||||
|
'"',
|
||||||
|
'#',
|
||||||
|
'$',
|
||||||
|
'%',
|
||||||
|
'&',
|
||||||
|
"'",
|
||||||
|
'(',
|
||||||
|
')',
|
||||||
|
'*',
|
||||||
|
'+',
|
||||||
|
'-',
|
||||||
|
'.',
|
||||||
|
'/',
|
||||||
|
':',
|
||||||
|
';',
|
||||||
|
'<',
|
||||||
|
'=',
|
||||||
|
'>',
|
||||||
|
'?',
|
||||||
|
'@',
|
||||||
|
'[',
|
||||||
|
'\\',
|
||||||
|
']',
|
||||||
|
'^',
|
||||||
|
'_',
|
||||||
|
'`',
|
||||||
|
'{',
|
||||||
|
'|',
|
||||||
|
'}',
|
||||||
|
'~',
|
||||||
|
];
|
||||||
|
const ALL_LIST = [...NUM_list, ...LOW_LETTERS_LIST, ...CAP_LETTERS_LIST];
|
||||||
|
const randomNum = (Math.random() * 128) | 0;
|
||||||
|
const randomKeys = new Array(length ?? randomNum).fill('');
|
||||||
|
|
||||||
|
for (let i = 0; i < randomKeys.length; i++) {
|
||||||
|
// ALL_LIST 随机字符
|
||||||
|
const index = (Math.random() * ALL_LIST.length) | 0;
|
||||||
|
randomKeys[i] = ALL_LIST[index - 1];
|
||||||
|
}
|
||||||
|
return randomKeys.join('');
|
||||||
|
};
|
||||||
|
|
||||||
|
export const timeFormater = function formatDuring(mss: number) {
|
||||||
|
const days = Math.floor(mss / (1000 * 60 * 60 * 24));
|
||||||
|
const hours = Math.floor((mss % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
|
||||||
|
const minutes = Math.floor((mss % (1000 * 60 * 60)) / (1000 * 60));
|
||||||
|
const seconds = (mss % (1000 * 60)) / 1000;
|
||||||
|
const parts = [
|
||||||
|
{ v: days, unit: '天' },
|
||||||
|
{ v: hours, unit: '小时' },
|
||||||
|
{ v: minutes, unit: '分钟' },
|
||||||
|
{ v: seconds, unit: '秒' },
|
||||||
|
];
|
||||||
|
return parts
|
||||||
|
.filter((o) => o.v > 0)
|
||||||
|
.map((o: any) => `${o.v}${o.unit}`)
|
||||||
|
.join();
|
||||||
|
};
|
||||||
|
|||||||
@@ -1,84 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
// TODO: 菜单配置接口有点乱,看是否可以归类下,以及是否可以去掉一些非必要的属性
|
|
||||||
export interface MenuConfItem {
|
|
||||||
key?: string;
|
|
||||||
name: string | React.ReactNode;
|
|
||||||
path: string;
|
|
||||||
icon?: string;
|
|
||||||
children?: MenuConfItem[];
|
|
||||||
visible?: boolean;
|
|
||||||
rootVisible?: boolean;
|
|
||||||
to?: string;
|
|
||||||
divider?: boolean;
|
|
||||||
target?: string;
|
|
||||||
getQuery?: (query: any) => any;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface TreeNode {
|
|
||||||
id: number;
|
|
||||||
pid: number;
|
|
||||||
name: string;
|
|
||||||
path: string;
|
|
||||||
type: number;
|
|
||||||
leaf: number;
|
|
||||||
children?: TreeNode[];
|
|
||||||
icon_color?: string;
|
|
||||||
icon_char?: string;
|
|
||||||
cate?: string;
|
|
||||||
note?: string;
|
|
||||||
selectable?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ResponseDat {
|
|
||||||
list: any[];
|
|
||||||
total: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Response {
|
|
||||||
err: string;
|
|
||||||
dat: any | ResponseDat;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface UserProfile {
|
|
||||||
id: number;
|
|
||||||
username: string;
|
|
||||||
dispname: string;
|
|
||||||
email: string;
|
|
||||||
phone: string;
|
|
||||||
im: string;
|
|
||||||
isroot: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Tenant {
|
|
||||||
id: number;
|
|
||||||
ident: string;
|
|
||||||
name: string;
|
|
||||||
note: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Team {
|
|
||||||
id: number;
|
|
||||||
ident: string;
|
|
||||||
name: string;
|
|
||||||
note: string;
|
|
||||||
mgmt: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Role {
|
|
||||||
id: number;
|
|
||||||
name: string;
|
|
||||||
note: string;
|
|
||||||
cate: 'global' | 'local';
|
|
||||||
operations: string[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Order {
|
|
||||||
id: number;
|
|
||||||
title: string;
|
|
||||||
levels: number;
|
|
||||||
cc: string;
|
|
||||||
content: string;
|
|
||||||
scheduleStartTime: string;
|
|
||||||
status: string;
|
|
||||||
creator: string;
|
|
||||||
}
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
interface IMap {
|
|
||||||
[key: string]: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default () => {
|
|
||||||
const Url = {
|
|
||||||
hash: {} as IMap,
|
|
||||||
search: {} as IMap,
|
|
||||||
} as {
|
|
||||||
hash: IMap;
|
|
||||||
search: IMap;
|
|
||||||
[key: string]: IMap;
|
|
||||||
};
|
|
||||||
|
|
||||||
window.location.hash
|
|
||||||
.slice(1)
|
|
||||||
.split('&')
|
|
||||||
.forEach((str) => {
|
|
||||||
const kv = str.split('=');
|
|
||||||
Url.hash[kv[0]] = kv[1];
|
|
||||||
});
|
|
||||||
|
|
||||||
window.location.search
|
|
||||||
.slice(1)
|
|
||||||
.split('&')
|
|
||||||
.forEach((str) => {
|
|
||||||
const kv = str.split('=');
|
|
||||||
Url.search[kv[0]] = kv[1];
|
|
||||||
});
|
|
||||||
|
|
||||||
return Url;
|
|
||||||
};
|
|
||||||
@@ -1,88 +0,0 @@
|
|||||||
export const getRandomStr = (length?: number) => {
|
|
||||||
const NUM_list = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
|
|
||||||
const LOW_LETTERS_LIST = [
|
|
||||||
'a',
|
|
||||||
'b',
|
|
||||||
'c',
|
|
||||||
'd',
|
|
||||||
'e',
|
|
||||||
'f',
|
|
||||||
'g',
|
|
||||||
'h',
|
|
||||||
'i',
|
|
||||||
'j',
|
|
||||||
'k',
|
|
||||||
'l',
|
|
||||||
'm',
|
|
||||||
'n',
|
|
||||||
'o',
|
|
||||||
'p',
|
|
||||||
'q',
|
|
||||||
'r',
|
|
||||||
's',
|
|
||||||
't',
|
|
||||||
'u',
|
|
||||||
'v',
|
|
||||||
'w',
|
|
||||||
'x',
|
|
||||||
'y',
|
|
||||||
'z',
|
|
||||||
];
|
|
||||||
const CAP_LETTERS_LIST = LOW_LETTERS_LIST.map((v) => v.toUpperCase());
|
|
||||||
const SPECIAL_LIST = [
|
|
||||||
'!',
|
|
||||||
'"',
|
|
||||||
'#',
|
|
||||||
'$',
|
|
||||||
'%',
|
|
||||||
'&',
|
|
||||||
"'",
|
|
||||||
'(',
|
|
||||||
')',
|
|
||||||
'*',
|
|
||||||
'+',
|
|
||||||
'-',
|
|
||||||
'.',
|
|
||||||
'/',
|
|
||||||
':',
|
|
||||||
';',
|
|
||||||
'<',
|
|
||||||
'=',
|
|
||||||
'>',
|
|
||||||
'?',
|
|
||||||
'@',
|
|
||||||
'[',
|
|
||||||
'\\',
|
|
||||||
']',
|
|
||||||
'^',
|
|
||||||
'_',
|
|
||||||
'`',
|
|
||||||
'{',
|
|
||||||
'|',
|
|
||||||
'}',
|
|
||||||
'~',
|
|
||||||
];
|
|
||||||
const ALL_LIST = [...NUM_list, ...LOW_LETTERS_LIST, ...CAP_LETTERS_LIST];
|
|
||||||
const randomNum = (Math.random() * 128) | 0;
|
|
||||||
const randomKeys = new Array(length ?? randomNum).fill('');
|
|
||||||
|
|
||||||
for (let i = 0; i < randomKeys.length; i++) {
|
|
||||||
// ALL_LIST 随机字符
|
|
||||||
const index = (Math.random() * ALL_LIST.length) | 0;
|
|
||||||
randomKeys[i] = ALL_LIST[index - 1];
|
|
||||||
}
|
|
||||||
return randomKeys.join('');
|
|
||||||
};
|
|
||||||
export const timeFormat = function formatDuring(mss: number) {
|
|
||||||
var days = Math.floor(mss / (1000 * 60 * 60 * 24));
|
|
||||||
var hours = Math.floor((mss % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
|
|
||||||
var minutes = Math.floor((mss % (1000 * 60 * 60)) / (1000 * 60));
|
|
||||||
var seconds = (mss % (1000 * 60)) / 1000;
|
|
||||||
var parts = [
|
|
||||||
{ v: days, unit: "天" },
|
|
||||||
{ v: hours, unit: "小时" },
|
|
||||||
{ v: minutes, unit: "分钟" },
|
|
||||||
{ v: seconds, unit: "秒" },
|
|
||||||
]
|
|
||||||
return parts.filter(o => o.v > 0).map((o: any) => `${o.v}${o.unit}`).join();
|
|
||||||
}
|
|
||||||
@@ -74,23 +74,23 @@ const BrokerDetail = (props: any) => {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
global?.clusterInfo?.id && hashDataParse(urlLocation.hash).brokerId
|
global?.clusterInfo?.id && hashDataParse(urlLocation.hash).brokerId
|
||||||
? Utils.request(Api.getBrokerMetadata(hashDataParse(urlLocation.hash).brokerId, global?.clusterInfo?.id), {
|
? Utils.request(Api.getBrokerMetadata(hashDataParse(urlLocation.hash).brokerId, global?.clusterInfo?.id), {
|
||||||
init: {
|
init: {
|
||||||
errorNoTips: true,
|
errorNoTips: true,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.then((brokerData: any) => {
|
.then((brokerData: any) => {
|
||||||
if (brokerData?.exist && brokerData?.alive && hashDataParse(urlLocation.hash).host === brokerData.host) {
|
if (brokerData?.exist && brokerData?.alive) {
|
||||||
setHashData(brokerData);
|
setHashData(brokerData);
|
||||||
setVisible(true);
|
setVisible(true);
|
||||||
} else {
|
} else {
|
||||||
|
history.replace(urlLocation.pathname);
|
||||||
|
setVisible(false);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
history.replace(urlLocation.pathname);
|
history.replace(urlLocation.pathname);
|
||||||
setVisible(false);
|
setVisible(false);
|
||||||
}
|
})
|
||||||
})
|
|
||||||
.catch((err) => {
|
|
||||||
history.replace(urlLocation.pathname);
|
|
||||||
setVisible(false);
|
|
||||||
})
|
|
||||||
: setVisible(false);
|
: setVisible(false);
|
||||||
}, [hashDataParse(urlLocation.hash).brokerId, global?.clusterInfo, urlLocation]);
|
}, [hashDataParse(urlLocation.hash).brokerId, global?.clusterInfo, urlLocation]);
|
||||||
|
|
||||||
|
|||||||
@@ -114,7 +114,7 @@ export default (props: any) => {
|
|||||||
key: 'memberId',
|
key: 'memberId',
|
||||||
width: 200,
|
width: 200,
|
||||||
render: (v: string) => {
|
render: (v: string) => {
|
||||||
return <ContentWithCopy content={v} />;
|
return v ? <ContentWithCopy content={v} /> : '-';
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -60,7 +60,10 @@ const AutoPage = (props: any) => {
|
|||||||
setConsumersListLoading(true);
|
setConsumersListLoading(true);
|
||||||
Utils.post(Api.getOperatingStateList(clusterPhyId), params).then((data: any) => {
|
Utils.post(Api.getOperatingStateList(clusterPhyId), params).then((data: any) => {
|
||||||
setConsumersListLoading(false);
|
setConsumersListLoading(false);
|
||||||
setConsumerGroupList(data?.bizData || []);
|
const newData = data?.bizData.map((item: any, key: number) => {
|
||||||
|
return { ...item, unique: key * pageIndex * pageSize + item?.groupName };
|
||||||
|
});
|
||||||
|
setConsumerGroupList(newData || []);
|
||||||
setPageIndex(data.pagination.pageNo);
|
setPageIndex(data.pagination.pageNo);
|
||||||
setPageTotal(data.pagination.total);
|
setPageTotal(data.pagination.total);
|
||||||
setPageSize(data.pagination.pageSize);
|
setPageSize(data.pagination.pageSize);
|
||||||
@@ -230,7 +233,7 @@ const AutoPage = (props: any) => {
|
|||||||
tableProps={{
|
tableProps={{
|
||||||
loading: consumersListLoading,
|
loading: consumersListLoading,
|
||||||
showHeader: false,
|
showHeader: false,
|
||||||
rowKey: 'groupName',
|
rowKey: 'unique',
|
||||||
columns: columns(),
|
columns: columns(),
|
||||||
dataSource: consumerGroupList,
|
dataSource: consumerGroupList,
|
||||||
paginationProps:
|
paginationProps:
|
||||||
@@ -250,7 +253,6 @@ const AutoPage = (props: any) => {
|
|||||||
// },
|
// },
|
||||||
onChange: onTableChange,
|
onChange: onTableChange,
|
||||||
scroll: { y: 'calc(100vh - 400px)' },
|
scroll: { y: 'calc(100vh - 400px)' },
|
||||||
// className: `frameless-table ${scene !== 'topicDetail' && 'clustom-table-content'}`, // 纯无边框表格类名
|
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import React, { useState, useEffect } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
import { Alert, Badge, Descriptions, Dropdown, ProTable, DTable, Table, Utils, Spin, Tag } from 'knowdesign';
|
import { Badge, Descriptions, ProTable, Utils, Spin, Tag } from 'knowdesign';
|
||||||
import { useParams } from 'react-router-dom';
|
import { useParams } from 'react-router-dom';
|
||||||
import Api from '@src/api';
|
import Api from '@src/api';
|
||||||
import { getNodeTrafficColumns } from './config';
|
|
||||||
import { getSizeAndUnit } from '@src/constants/common';
|
import { getSizeAndUnit } from '@src/constants/common';
|
||||||
|
import TagsWithHide from '@src/components/TagsWithHide';
|
||||||
interface PropsType {
|
interface PropsType {
|
||||||
jobId?: any;
|
jobId?: any;
|
||||||
balanceData?: any;
|
balanceData?: any;
|
||||||
@@ -54,7 +54,6 @@ const RebalancePlan = (props: PropsType) => {
|
|||||||
// });
|
// });
|
||||||
|
|
||||||
// setData(mockData);
|
// setData(mockData);
|
||||||
|
|
||||||
setData(res || []);
|
setData(res || []);
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
})
|
})
|
||||||
@@ -221,9 +220,10 @@ const RebalancePlan = (props: PropsType) => {
|
|||||||
<Spin spinning={loading}>
|
<Spin spinning={loading}>
|
||||||
<Descriptions
|
<Descriptions
|
||||||
style={{ fontSize: '13px' }}
|
style={{ fontSize: '13px' }}
|
||||||
column={2}
|
column={3}
|
||||||
labelStyle={{
|
labelStyle={{
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
|
textAlign: 'right',
|
||||||
justifyContent: 'end',
|
justifyContent: 'end',
|
||||||
color: '#74788D',
|
color: '#74788D',
|
||||||
fontSize: '13px',
|
fontSize: '13px',
|
||||||
@@ -231,11 +231,12 @@ const RebalancePlan = (props: PropsType) => {
|
|||||||
contentStyle={{ fontSize: '13px' }}
|
contentStyle={{ fontSize: '13px' }}
|
||||||
>
|
>
|
||||||
<Descriptions.Item label="任务类型">{typeObj[data?.type] || '-'}</Descriptions.Item>
|
<Descriptions.Item label="任务类型">{typeObj[data?.type] || '-'}</Descriptions.Item>
|
||||||
<Descriptions.Item label="总迁移大小">{Utils.getSizeAndUnit(data?.moveSize, 'B').valueWithUnit}</Descriptions.Item>
|
<Descriptions.Item labelStyle={{ width: '100px' }} label="总迁移大小">
|
||||||
<Descriptions.Item label="Topic黑名单">
|
{Utils.getSizeAndUnit(data?.moveSize, 'B').valueWithUnit}
|
||||||
{data?.blackTopics && data?.blackTopics?.length > 0 ? data?.blackTopics.join('、') : '-'}
|
</Descriptions.Item>
|
||||||
|
<Descriptions.Item labelStyle={{ width: '100px' }} label="迁移副本数">
|
||||||
|
{data?.replicas || '-'}
|
||||||
</Descriptions.Item>
|
</Descriptions.Item>
|
||||||
<Descriptions.Item label="迁移副本数">{data?.replicas || '-'}</Descriptions.Item>
|
|
||||||
<Descriptions.Item label="均衡阈值">
|
<Descriptions.Item label="均衡阈值">
|
||||||
{data?.clusterBalanceIntervalList
|
{data?.clusterBalanceIntervalList
|
||||||
? data?.clusterBalanceIntervalList?.map((item: any) => {
|
? data?.clusterBalanceIntervalList?.map((item: any) => {
|
||||||
@@ -247,6 +248,13 @@ const RebalancePlan = (props: PropsType) => {
|
|||||||
})
|
})
|
||||||
: '-'}
|
: '-'}
|
||||||
</Descriptions.Item>
|
</Descriptions.Item>
|
||||||
|
<Descriptions.Item labelStyle={{ width: '100px' }} label="Topic黑名单">
|
||||||
|
{data?.blackTopics && data?.blackTopics?.length > 0 ? (
|
||||||
|
<TagsWithHide placement="bottomLeft" list={data?.blackTopics} expandTagContent={(num: any) => `共有${num}个`} />
|
||||||
|
) : (
|
||||||
|
'-'
|
||||||
|
)}
|
||||||
|
</Descriptions.Item>
|
||||||
</Descriptions>
|
</Descriptions>
|
||||||
</Spin>
|
</Spin>
|
||||||
<h3 style={{ fontSize: '16px' }}>计划明细</h3>
|
<h3 style={{ fontSize: '16px' }}>计划明细</h3>
|
||||||
@@ -271,7 +279,7 @@ const RebalancePlan = (props: PropsType) => {
|
|||||||
</div>
|
</div>
|
||||||
{data?.reassignmentJson && (
|
{data?.reassignmentJson && (
|
||||||
<>
|
<>
|
||||||
<h3 style={{ fontSize: '16px', marginTop: '22px' }}>执行文件</h3>
|
<h3 style={{ fontSize: '16px' }}>执行文件</h3>
|
||||||
<div>
|
<div>
|
||||||
<a href={`data:,${data?.reassignmentJson}`} rel="noopener" download="reassignment.json">
|
<a href={`data:,${data?.reassignmentJson}`} rel="noopener" download="reassignment.json">
|
||||||
Reassignment json file(点击下载)
|
Reassignment json file(点击下载)
|
||||||
|
|||||||
@@ -1,18 +1,5 @@
|
|||||||
import React, { useState, useEffect, useRef } from 'react';
|
import React, { useState, useEffect, useRef } from 'react';
|
||||||
import {
|
import { Utils, Drawer, Button, Form, Space, Divider, AppContainer, Input, Transfer, message, IconFont, InputNumber } from 'knowdesign';
|
||||||
Utils,
|
|
||||||
Drawer,
|
|
||||||
Button,
|
|
||||||
Form,
|
|
||||||
Space,
|
|
||||||
Divider,
|
|
||||||
AppContainer,
|
|
||||||
Input,
|
|
||||||
Transfer,
|
|
||||||
message,
|
|
||||||
IconFont,
|
|
||||||
InputNumber,
|
|
||||||
} from 'knowdesign';
|
|
||||||
import { CloseOutlined } from '@ant-design/icons';
|
import { CloseOutlined } from '@ant-design/icons';
|
||||||
import api from '../../api';
|
import api from '../../api';
|
||||||
import './style/BalanceDrawer.less';
|
import './style/BalanceDrawer.less';
|
||||||
@@ -38,7 +25,7 @@ const ClusterNorms: React.FC<PropsType> = ({ onClose, visible, genData }) => {
|
|||||||
// 周期均衡
|
// 周期均衡
|
||||||
form.validateFields().then((values) => {
|
form.validateFields().then((values) => {
|
||||||
const params = values?.brokers?.map((item: any) => {
|
const params = values?.brokers?.map((item: any) => {
|
||||||
const brokerId = nodeData?.filter((key) => key.brokerId === item && item)[0]?.brokerId;
|
const brokerId = nodeData?.filter((key) => key.brokerId === item)[0]?.brokerId;
|
||||||
const newValue = brokerId && { brokerId, cpu: values?.cpu, disk: values?.disk, flow: values?.flow };
|
const newValue = brokerId && { brokerId, cpu: values?.cpu, disk: values?.disk, flow: values?.flow };
|
||||||
return {
|
return {
|
||||||
clusterId: global?.clusterInfo?.id + '',
|
clusterId: global?.clusterInfo?.id + '',
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { Button, Divider, Drawer, Form, Input, InputNumber, message, Radio, Sele
|
|||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import { useIntl } from 'react-intl';
|
import { useIntl } from 'react-intl';
|
||||||
import api from '../../api';
|
import api from '../../api';
|
||||||
import { regClusterName, regUsername } from '../../common/reg';
|
import { regClusterName, regUsername } from '../../constants/reg';
|
||||||
import { bootstrapServersErrCodes, jmxErrCodes, zkErrCodes } from './config';
|
import { bootstrapServersErrCodes, jmxErrCodes, zkErrCodes } from './config';
|
||||||
import CodeMirrorFormItem from '@src/components/CodeMirrorFormItem';
|
import CodeMirrorFormItem from '@src/components/CodeMirrorFormItem';
|
||||||
|
|
||||||
|
|||||||
@@ -10,8 +10,12 @@
|
|||||||
border-top-right-radius: 12px;
|
border-top-right-radius: 12px;
|
||||||
.operate-bar {
|
.operate-bar {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: right;
|
||||||
margin-bottom: 12px;
|
margin-bottom: 12px;
|
||||||
|
.search-input {
|
||||||
|
width: 248px;
|
||||||
|
margin-right: 8px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ import { CloseOutlined, EyeInvisibleOutlined, EyeOutlined, LoadingOutlined } fro
|
|||||||
import './index.less';
|
import './index.less';
|
||||||
import api from '@src/api';
|
import api from '@src/api';
|
||||||
import { useParams } from 'react-router-dom';
|
import { useParams } from 'react-router-dom';
|
||||||
import { regKafkaPassword } from '@src/common/reg';
|
import { regKafkaPassword } from '@src/constants/reg';
|
||||||
|
|
||||||
export const randomString = (len = 32, chars = 'abcdefghijklmnopqrstuvwxyz1234567890'): string => {
|
export const randomString = (len = 32, chars = 'abcdefghijklmnopqrstuvwxyz1234567890'): string => {
|
||||||
const maxPos = chars.length;
|
const maxPos = chars.length;
|
||||||
@@ -283,18 +283,17 @@ const SecurityUsers = (): JSX.Element => {
|
|||||||
const [loading, setLoading] = useState<boolean>(true);
|
const [loading, setLoading] = useState<boolean>(true);
|
||||||
const [data, setData] = useState<UsersProps[]>([]);
|
const [data, setData] = useState<UsersProps[]>([]);
|
||||||
const [pagination, setPagination] = useState<any>(defaultPagination);
|
const [pagination, setPagination] = useState<any>(defaultPagination);
|
||||||
const [form] = Form.useForm();
|
const [searchKeywords, setSearchKeywords] = useState('');
|
||||||
|
const [searchKeywordsInput, setSearchKeywordsInput] = useState('');
|
||||||
const editDrawerRef = useRef(null);
|
const editDrawerRef = useRef(null);
|
||||||
|
|
||||||
const getKafkaUserList = (query = {}) => {
|
const getKafkaUserList = (query = {}) => {
|
||||||
const formData = form.getFieldsValue();
|
|
||||||
const queryParams = {
|
const queryParams = {
|
||||||
pageNo: pagination.current,
|
pageNo: pagination.current,
|
||||||
pageSize: pagination.pageSize,
|
pageSize: pagination.pageSize,
|
||||||
...formData,
|
searchKeywords,
|
||||||
...query,
|
...query,
|
||||||
};
|
};
|
||||||
|
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
Utils.request(api.getKafkaUsers(clusterId), {
|
Utils.request(api.getKafkaUsers(clusterId), {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
@@ -413,6 +412,10 @@ const SecurityUsers = (): JSX.Element => {
|
|||||||
getKafkaUserList();
|
getKafkaUserList();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
(searchKeywords || searchKeywords === '') && getKafkaUserList({ pageNo: 1 });
|
||||||
|
}, [searchKeywords]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="security-users-page">
|
<div className="security-users-page">
|
||||||
<DKSBreadcrumb
|
<DKSBreadcrumb
|
||||||
@@ -424,16 +427,26 @@ const SecurityUsers = (): JSX.Element => {
|
|||||||
/>
|
/>
|
||||||
<div className="security-users-page-list">
|
<div className="security-users-page-list">
|
||||||
<div className="operate-bar">
|
<div className="operate-bar">
|
||||||
<Form form={form} layout="inline" onFinish={() => getKafkaUserList({ pageNo: 1 })}>
|
<Input
|
||||||
<Form.Item name="searchKeywords">
|
className="search-input"
|
||||||
<Input placeholder="请输入 Kafka User" />
|
suffix={
|
||||||
</Form.Item>
|
<IconFont
|
||||||
<Form.Item>
|
type="icon-fangdajing"
|
||||||
<Button type="primary" ghost htmlType="submit">
|
onClick={(_) => {
|
||||||
查询
|
setSearchKeywords(searchKeywordsInput);
|
||||||
</Button>
|
}}
|
||||||
</Form.Item>
|
style={{ fontSize: '16px' }}
|
||||||
</Form>
|
/>
|
||||||
|
}
|
||||||
|
placeholder="请输入 Kafka User"
|
||||||
|
value={searchKeywordsInput}
|
||||||
|
onPressEnter={(_) => {
|
||||||
|
setSearchKeywords(searchKeywordsInput);
|
||||||
|
}}
|
||||||
|
onChange={(e) => {
|
||||||
|
setSearchKeywordsInput(e.target.value);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
<Button
|
<Button
|
||||||
type="primary"
|
type="primary"
|
||||||
// icon={<PlusOutlined />}
|
// icon={<PlusOutlined />}
|
||||||
|
|||||||
@@ -107,6 +107,7 @@ const LeftSider = () => {
|
|||||||
strokeWidth={4}
|
strokeWidth={4}
|
||||||
strokeColor={getHealthProcessColor(clusterMetrics?.HealthScore, clusterMetrics?.Alive)}
|
strokeColor={getHealthProcessColor(clusterMetrics?.HealthScore, clusterMetrics?.Alive)}
|
||||||
percent={clusterMetrics?.HealthScore ?? '-'}
|
percent={clusterMetrics?.HealthScore ?? '-'}
|
||||||
|
className={+clusterMetrics.Alive <= 0 ? 'red-circle' : +clusterMetrics?.HealthScore < 90 ? 'blue-circle' : 'green-circle'}
|
||||||
format={() => (
|
format={() => (
|
||||||
<div className={`healthy-percent ${getHealthClassName(clusterMetrics?.HealthScore, clusterMetrics?.Alive)}`}>
|
<div className={`healthy-percent ${getHealthClassName(clusterMetrics?.HealthScore, clusterMetrics?.Alive)}`}>
|
||||||
{getHealthText(clusterMetrics?.HealthScore, clusterMetrics?.Alive)}
|
{getHealthText(clusterMetrics?.HealthScore, clusterMetrics?.Alive)}
|
||||||
|
|||||||
@@ -156,7 +156,20 @@
|
|||||||
.state-card {
|
.state-card {
|
||||||
display: flex;
|
display: flex;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
.green-circle {
|
||||||
|
.dcloud-progress-inner {
|
||||||
|
background: #f5fdfc;
|
||||||
|
overflow: hidden;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.red-circle {
|
||||||
|
.dcloud-progress-inner {
|
||||||
|
background: #fffafa;
|
||||||
|
overflow: hidden;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
}
|
||||||
.healthy-percent {
|
.healthy-percent {
|
||||||
font-family: DIDIFD-Regular;
|
font-family: DIDIFD-Regular;
|
||||||
font-size: 38px;
|
font-size: 38px;
|
||||||
|
|||||||
@@ -219,7 +219,7 @@ const ConsumeClientTest = () => {
|
|||||||
];
|
];
|
||||||
const _params = {
|
const _params = {
|
||||||
clusterId,
|
clusterId,
|
||||||
maxDurationUnitMs: 8000, // 前端超时时间为10s,这里接口超时设置8s
|
maxDurationUnitMs: 5000, // 前端超时时间为10s,这里接口超时设置8s
|
||||||
clientProperties: {},
|
clientProperties: {},
|
||||||
maxRecords: 10,
|
maxRecords: 10,
|
||||||
topicName: values.topic,
|
topicName: values.topic,
|
||||||
@@ -239,9 +239,9 @@ const ConsumeClientTest = () => {
|
|||||||
? offsetLists
|
? offsetLists
|
||||||
: undefined
|
: undefined
|
||||||
: lastPartitionList.current?.map((item) => ({
|
: lastPartitionList.current?.map((item) => ({
|
||||||
offset: item.consumedOffset,
|
offset: item.consumedOffset,
|
||||||
partitionId: item.partitionId,
|
partitionId: item.partitionId,
|
||||||
})),
|
})),
|
||||||
timestampUnitMs:
|
timestampUnitMs:
|
||||||
values.start[1] === 'a specific date'
|
values.start[1] === 'a specific date'
|
||||||
? startFromMap[values.start[1]].getDate(values.startDate)
|
? startFromMap[values.start[1]].getDate(values.startDate)
|
||||||
|
|||||||
@@ -3,8 +3,7 @@ import { IconFont, Switch, Tooltip } from 'knowdesign';
|
|||||||
import { FormItemType, IFormItem } from 'knowdesign/lib/extend/x-form';
|
import { FormItemType, IFormItem } from 'knowdesign/lib/extend/x-form';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { timeFormat } from '../../constants/common';
|
import { timeFormat, getRandomStr } from '@src/constants/common';
|
||||||
import { getRandomStr } from '../../lib/utils';
|
|
||||||
import { ControlStatusMap } from '../CommonRoute';
|
import { ControlStatusMap } from '../CommonRoute';
|
||||||
|
|
||||||
export const filterList = [
|
export const filterList = [
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ const { request } = Utils;
|
|||||||
const defaultParams: any = {
|
const defaultParams: any = {
|
||||||
truncate: true,
|
truncate: true,
|
||||||
maxRecords: 100,
|
maxRecords: 100,
|
||||||
pullTimeoutUnitMs: 8000,
|
pullTimeoutUnitMs: 5000,
|
||||||
// filterPartitionId: 1,
|
// filterPartitionId: 1,
|
||||||
};
|
};
|
||||||
const defaultpaPagination = {
|
const defaultpaPagination = {
|
||||||
|
|||||||
Reference in New Issue
Block a user