You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@doris.apache.org by ji...@apache.org on 2022/04/02 09:31:42 UTC
[incubator-doris-manager] branch master updated: [refactor] upgrade to react-router v6 (#31)
This is an automated email from the ASF dual-hosted git repository.
jiafengzheng pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-doris-manager.git
The following commit(s) were added to refs/heads/master by this push:
new 8e71f37 [refactor] upgrade to react-router v6 (#31)
8e71f37 is described below
commit 8e71f37d3d727fc856cb1ebb1f9628fe0ac8d19c
Author: color_cat <co...@gmail.com>
AuthorDate: Sat Apr 2 17:31:38 2022 +0800
[refactor] upgrade to react-router v6 (#31)
upgrade to react-router v6
---
frontend/.babelrc | 4 +-
frontend/.eslintrc.js | 10 +-
frontend/babel.config.js | 24 -
frontend/config/webpack.base.config.js | 10 +-
frontend/config/webpack.dev.config.js | 54 +--
frontend/config/webpack.prod.config.js | 9 +-
frontend/package.json | 71 ++-
frontend/src/app.tsx | 4 +-
frontend/src/assets/space/u288.png | Bin 17706 -> 0 bytes
frontend/src/assets/space/u296.png | Bin 2387 -> 0 bytes
frontend/src/assets/space/u919.png | Bin 5850 -> 0 bytes
frontend/src/common/common.data.ts | 10 +-
.../auths/auth-route.tsx} | 22 +-
.../auths/auth.interface.ts} | 10 +-
.../auths/doris-auth-provider.ts} | 47 +-
.../auths/require-auth.tsx} | 48 +-
.../auths/require-initialized.tsx} | 46 +-
frontend/src/components/common-header/header.tsx | 11 +-
frontend/src/components/header/header.tsx | 85 ++--
frontend/src/components/helper/helper.less | 2 +-
frontend/src/components/helper/helper.tsx | 2 +-
.../initialized-route/initialized-route.tsx | 31 +-
frontend/src/components/metadata/index.tsx | 128 -----
frontend/src/components/not-found/index.tsx | 19 +-
frontend/src/components/sidebar/sidebar.less | 1 -
frontend/src/components/sidebar/sidebar.tsx | 54 +--
.../src/components/studio-header/header.api.ts | 37 --
frontend/src/components/studio-header/header.tsx | 148 ------
.../src/components/studio-header/index.module.less | 85 ----
frontend/src/components/tabs-header/index.tsx | 7 +-
frontend/src/config.ts | 6 +-
frontend/src/hooks/use-auth.ts | 13 +-
frontend/src/index.css | 16 +
frontend/src/index.tsx | 3 +-
frontend/src/routes.tsx | 77 ++-
frontend/src/routes/admin/admin.tsx | 20 +-
frontend/src/routes/admin/people/people.tsx | 17 +-
.../src/routes/admin/people/role/list/list.tsx | 40 +-
.../src/routes/admin/people/role/member/member.tsx | 19 +-
frontend/src/routes/admin/people/role/role.tsx | 16 +-
frontend/src/routes/cluster/cluster.tsx | 20 +-
frontend/src/routes/cluster/list/list.tsx | 65 ---
frontend/src/routes/container.tsx | 61 +--
.../dashboard/components/dashboard-item/index.tsx | 37 --
.../dashboard-item/message-item.interface.ts | 23 -
.../dashboard/connect-info/connect-info.less | 23 -
.../routes/dashboard/connect-info/connect-info.tsx | 68 ---
frontend/src/routes/dashboard/dashboard.api.ts | 31 --
frontend/src/routes/dashboard/dashboard.data.ts | 21 -
.../src/routes/dashboard/dashboard.interface.ts | 33 --
frontend/src/routes/dashboard/dashboard.less | 27 --
frontend/src/routes/dashboard/dashboard.tsx | 75 ---
.../src/routes/dashboard/overview/overview.less | 23 -
.../src/routes/dashboard/overview/overview.tsx | 69 ---
frontend/src/routes/database/index.tsx | 16 +-
frontend/src/routes/initialize/auths/auth.tsx | 22 +-
.../auths/components/admin-user/admin-user.tsx | 23 +-
.../initialize/auths/components/finish/finish.tsx | 17 +-
.../auths/ldap/ldap-admin-user/ldap-admin-user.tsx | 75 ---
.../auths/ldap/ldap-config/ldap-config.tsx | 152 ------
frontend/src/routes/initialize/auths/ldap/ldap.tsx | 55 ---
.../src/routes/initialize/auths/local/local.tsx | 53 ++
.../src/routes/initialize/auths/studio/studio.tsx | 55 ---
.../{initialize.tsx => initialize-set-type.tsx} | 27 +-
frontend/src/routes/initialize/initialize.data.ts | 8 +-
.../src/routes/initialize/initialize.route.tsx | 73 ---
frontend/src/routes/initialize/initialize.tsx | 69 +--
frontend/src/routes/meta/meta.tsx | 16 +-
.../src/routes/node/dashboard/index.module.less | 20 -
frontend/src/routes/node/dashboard/index.tsx | 336 -------------
frontend/src/routes/node/dashboard/monitor.api.ts | 61 ---
frontend/src/routes/node/dashboard/monitor.data.ts | 96 ----
.../node/list/be-configuration/be-config.api.ts | 37 --
.../routes/node/list/be-configuration/index.tsx | 534 --------------------
frontend/src/routes/node/list/config.data.ts | 26 -
.../src/routes/node/list/configuration/index.tsx | 106 ----
.../node/list/fe-configuration/fe-config.api.ts | 37 --
.../routes/node/list/fe-configuration/index.tsx | 535 ---------------------
frontend/src/routes/node/list/index.tsx | 190 --------
frontend/src/routes/node/list/node.api.ts | 33 --
frontend/src/routes/passport/forgot.login.tsx | 37 --
frontend/src/routes/passport/login.tsx | 51 +-
frontend/src/routes/query/index.tsx | 147 ------
frontend/src/routes/query/query-details/code.css | 134 ------
frontend/src/routes/query/query-details/index.tsx | 122 -----
.../src/routes/query/query-details/profile.tsx | 93 ----
frontend/src/routes/query/query.api.ts | 49 --
frontend/src/routes/query/query.data.ts | 28 --
.../settings-header/settings-header.less | 53 --
.../components/settings-header/settings-header.tsx | 72 ---
.../settings/components/tabs-header/index.tsx | 9 +-
frontend/src/routes/settings/settings.tsx | 19 +-
frontend/src/routes/settings/user/user.tsx | 14 +-
.../routes/space/access-cluster/access-cluster.tsx | 64 ++-
.../steps/cluster-verify/cluster-verify.tsx | 9 +-
.../src/routes/space/components/finish/finish.tsx | 6 +-
.../src/routes/space/components/result-modal.tsx | 172 ++++---
frontend/src/routes/space/detail/space-detail.tsx | 69 +--
frontend/src/routes/space/list/list.tsx | 17 +-
.../src/routes/space/new-cluster/logs/logs.tsx | 32 +-
.../src/routes/space/new-cluster/new-cluster.tsx | 65 ++-
.../steps/cluster-deploy/cluster-deploy.tsx | 19 +-
.../new-cluster/steps/node-config/node-config.tsx | 15 +-
.../new-cluster/steps/run-cluster/run-cluster.tsx | 158 ------
frontend/src/routes/space/space.tsx | 29 +-
frontend/src/routes/super-admin-container.tsx | 14 +-
frontend/src/routes/table-content/index.tsx | 75 +--
.../src/routes/table-content/schema/schema.tsx | 14 +-
.../src/routes/table-content/tabs/data-import.tsx | 250 ----------
.../table-content/tabs/dataImport-menu/index.tsx | 79 ---
.../src/routes/tree/create-menu/databaseModal.tsx | 107 -----
frontend/src/routes/tree/create-menu/index.tsx | 79 ---
frontend/src/routes/tree/index.tsx | 35 +-
frontend/src/routes/user-setting/index.tsx | 10 +-
.../components/visual-content/visual-editor.tsx | 2 +-
frontend/src/utils/http.ts | 7 +-
frontend/theme.js | 4 +-
frontend/tsconfig.json | 6 +-
118 files changed, 845 insertions(+), 5774 deletions(-)
diff --git a/frontend/.babelrc b/frontend/.babelrc
index e5b1e1f..d12ffac 100644
--- a/frontend/.babelrc
+++ b/frontend/.babelrc
@@ -25,7 +25,9 @@
}
}
],
- "@babel/preset-react",
+ ["@babel/preset-react", {
+ "runtime": "automatic"
+ }],
"@babel/preset-typescript"
],
diff --git a/frontend/.eslintrc.js b/frontend/.eslintrc.js
index 0b0af8c..9a1d1cd 100644
--- a/frontend/.eslintrc.js
+++ b/frontend/.eslintrc.js
@@ -19,7 +19,12 @@
module.exports = {
parser: '@typescript-eslint/parser',
- extends: ['plugin:prettier/recommended', 'plugin:@typescript-eslint/recommended', "plugin:react/recommended", "plugin:react/jsx-runtime"],
+ extends: [
+ 'plugin:prettier/recommended',
+ 'plugin:@typescript-eslint/recommended',
+ 'plugin:react/recommended',
+ 'plugin:react/jsx-runtime',
+ ],
parserOptions: {
ecmaVersion: 2019,
sourceType: 'module',
@@ -28,6 +33,9 @@ module.exports = {
browser: true,
node: true,
},
+ ignorePatterns: ['./config/*.js'],
rules: {
+ 'react/jsx-uses-react': 'off',
+ 'react/react-in-jsx-scope': 'off',
},
};
diff --git a/frontend/babel.config.js b/frontend/babel.config.js
deleted file mode 100644
index 419fe02..0000000
--- a/frontend/babel.config.js
+++ /dev/null
@@ -1,24 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements. See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership. The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License. You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing,
-// software distributed under the License is distributed on an
-// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-// KIND, either express or implied. See the License for the
-// specific language governing permissions and limitations
-// under the License.
-
-"@babel/preset-react";
-module.exports = function (api) {
- api.cache(true);
- return {
- presets: ["@babel/preset-react"],
- };
-};
diff --git a/frontend/config/webpack.base.config.js b/frontend/config/webpack.base.config.js
index 312ae5a..4ac3159 100644
--- a/frontend/config/webpack.base.config.js
+++ b/frontend/config/webpack.base.config.js
@@ -15,6 +15,7 @@
// specific language governing permissions and limitations
// under the License.
+/* eslint-disable @typescript-eslint/no-var-requires */
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
@@ -35,7 +36,7 @@ const postCssLoader = () => {
module.exports = {
entry: {
- index: ['react-hot-loader/patch'].concat([path.resolve(__dirname, '../src/index.tsx')]),
+ index: path.resolve(__dirname, '../src/index.tsx'),
},
output: {
path: path.join(__dirname, '../dist/'),
@@ -54,7 +55,7 @@ module.exports = {
'@pages': path.resolve(__dirname, '../src/pages'),
'@utils': path.resolve(__dirname, '../src/utils'),
'@tools': path.resolve(__dirname, '../src/tools'),
- 'bn.js': path.resolve(process.cwd(), 'node_modules', 'bn.js')
+ 'bn.js': path.resolve(process.cwd(), 'node_modules', 'bn.js'),
},
extensions: ['.ts', '.tsx', '.js', '.jsx'],
fallback: {
@@ -107,7 +108,7 @@ module.exports = {
loader: 'less-loader',
options: {
lessOptions: {
- modifyVars: {...themes},
+ modifyVars: { ...themes },
javascriptEnabled: true,
},
implementation: require('less'),
@@ -132,7 +133,7 @@ module.exports = {
loader: 'less-loader',
options: {
lessOptions: {
- modifyVars: {...themes},
+ modifyVars: { ...themes },
javascriptEnabled: true,
},
implementation: require('less'),
@@ -159,6 +160,5 @@ module.exports = {
}),
new ESLintPlugin(),
-
],
};
diff --git a/frontend/config/webpack.dev.config.js b/frontend/config/webpack.dev.config.js
index f158d52..4c6988a 100644
--- a/frontend/config/webpack.dev.config.js
+++ b/frontend/config/webpack.dev.config.js
@@ -15,40 +15,28 @@
// specific language governing permissions and limitations
// under the License.
-const webpackBaseConfig = require("./webpack.base.config");
-const { merge } = require("webpack-merge");
-const SERVER_RD = 'http://127.0.0.1:8880';
+/* eslint-disable @typescript-eslint/no-var-requires */
+const webpackBaseConfig = require('./webpack.base.config');
+const { merge } = require('webpack-merge');
+const SERVER_RD = 'http://127.0.0.1:8080/';
module.exports = merge(webpackBaseConfig, {
- mode: "development",
- devtool: "eval-source-map",
- // 开发服务配置
- devServer: {
- host: "localhost",
- port: 8084,
- publicPath: "/",
- disableHostCheck: true,
- useLocalIp: false,
- open: true,
- overlay: true,
- hot: true,
- stats: {
- assets: false,
- colors: true,
- modules: false,
- children: false,
- chunks: false,
- chunkModules: false,
- entrypoints: false,
+ mode: 'development',
+ devtool: 'eval-source-map',
+ // 开发服务配置
+ devServer: {
+ host: 'localhost',
+ port: 8084,
+ open: true,
+ hot: true,
+ proxy: {
+ '/api': {
+ target: SERVER_RD,
+ changeOrigin: true,
+ secure: false,
+ // pathRewrite: {'^/api': '/api'}
+ },
+ },
+ historyApiFallback: true,
},
- proxy: {
- '/api': {
- target: SERVER_RD,
- changeOrigin: true,
- secure: false,
- // pathRewrite: {'^/api': '/api'}
- },
- },
- historyApiFallback: true,
- },
});
diff --git a/frontend/config/webpack.prod.config.js b/frontend/config/webpack.prod.config.js
index a992579..f96dbec 100644
--- a/frontend/config/webpack.prod.config.js
+++ b/frontend/config/webpack.prod.config.js
@@ -15,9 +15,10 @@
// specific language governing permissions and limitations
// under the License.
-const webpackBaseConfig = require("./webpack.base.config");
-const { merge } = require("webpack-merge");
-const path = require("path");
+/* eslint-disable @typescript-eslint/no-var-requires */
+const webpackBaseConfig = require('./webpack.base.config');
+const { merge } = require('webpack-merge');
+const path = require('path');
const TerserWebpackPlugin = require('terser-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
@@ -85,7 +86,7 @@ module.exports = merge(webpackBaseConfig, {
new CopyPlugin({
patterns: [
{ from: path.join(__dirname, '../src/assets/'), to: path.join(__dirname, '../dist/src/assets/') },
- { from: path.join(__dirname, '../favicon.ico'), to: path.join(__dirname, '../dist/') }
+ { from: path.join(__dirname, '../favicon.ico'), to: path.join(__dirname, '../dist/') },
],
}),
// new BundleAnalyzerPlugin()
diff --git a/frontend/package.json b/frontend/package.json
index fdd84df..fde399f 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -1,8 +1,8 @@
{
- "name": "webpack5",
+ "name": "doris-manager",
"version": "1.0.0-beta",
"description": "",
- "main": "index.js",
+ "main": "index.tsx",
"scripts": {
"start": "npm run dev",
"dev": "cross-env NODE_ENV=development webpack serve",
@@ -18,11 +18,12 @@
"@ant-design/pro-layout": "^7.0.1-alpha.5",
"@ant-design/pro-list": "^1.17.7",
"@ant-design/pro-table": "^2.56.7",
- "@babel/core": "^7.12.10",
+ "@babel/core": "^7.17.8",
+ "@babel/plugin-transform-react-jsx": "^7.17.3",
"@monaco-editor/react": "^4.4.1",
- "ahooks": "^3.1.10",
- "antd": "^4.16.11",
- "axios": "^0.24.0",
+ "ahooks": "^3.3.0",
+ "antd": "^4.19.3",
+ "axios": "^0.26.1",
"babel-loader": "^8.2.2",
"bignumber.js": "^9.0.2",
"buffer": "^6.0.3",
@@ -32,10 +33,9 @@
"echarts-for-react": "^3.0.0",
"echarts-liquidfill": "^3.1.0",
"highlight.js": "^11.0.1",
- "i18next": "^20.4.0",
- "i18next-browser-languagedetector": "^6.1.2",
+ "i18next": "^21.6.4",
+ "i18next-browser-languagedetector": "^6.1.4",
"immer": "^9.0.12",
- "js-cookie": "^3.0.1",
"lodash-es": "^4.17.21",
"password-generator": "^2.3.2",
"path-to-regexp": "^6.2.0",
@@ -44,18 +44,15 @@
"react": "^17.0.1",
"react-css-modules": "^4.7.11",
"react-dom": "^17.0.1",
- "react-hot-loader": "^4.13.0",
- "react-i18next": "^11.11.4",
- "react-router-cache-route": "^1.12.1",
- "react-router-dom": "^5.2.0",
+ "react-i18next": "^11.16.2",
+ "react-router": "^6.3.0",
+ "react-router-dom": "^6.3.0",
"react-spring": "^9.4.4",
- "recoil": "^0.5.0",
+ "recoil": "^0.6.1",
"stream-browserify": "^3.0.0",
- "sweetalert2": "^11.1.9",
- "sweetalert2-react-content": "^4.1.1",
- "swr": "^0.5.6",
- "ttag": "1.7.15",
- "typescript": "^4.3.5",
+ "sweetalert2": "^11.4.8",
+ "sweetalert2-react-content": "^4.2.0",
+ "typescript": "^4.6.3",
"use-immer": "^0.6.0",
"webpack": "^5.11.0",
"webpack-merge": "^5.7.3"
@@ -66,47 +63,41 @@
"@babel/preset-react": "^7.12.10",
"@babel/preset-typescript": "^7.12.7",
"@types/jest": "^26.0.20",
- "@types/js-cookie": "^2.2.7",
"@types/lodash-es": "^4.17.6",
"@types/node": "^16.7.1",
- "@types/react": "^17.0.17",
+ "@types/react": "^17.0.43",
"@types/react-css-modules": "^4.6.4",
- "@types/react-dom": "^17.0.9",
- "@types/react-router": "^5.1.16",
- "@types/react-router-config": "^5.0.1",
- "@types/react-router-dom": "^5.1.8",
- "@typescript-eslint/eslint-plugin": "^4.9.1",
- "@typescript-eslint/parser": "^4.1.1",
- "autoprefixer": "^10.3.2",
+ "@types/react-dom": "^17.0.14",
+ "@typescript-eslint/eslint-plugin": "^5.17.0",
+ "@typescript-eslint/parser": "^5.17.0",
+ "autoprefixer": "^10.4.4",
"babel-plugin-import": "^1.13.3",
- "babel-plugin-ttag": "^1.7.26",
- "clean-webpack-plugin": "^3.0.0",
- "copy-webpack-plugin": "^9.0.1",
+ "clean-webpack-plugin": "^4.0.0",
+ "copy-webpack-plugin": "^10.2.4",
"css-loader": "^5.0.1",
"cssnano": "^5.0.8",
- "eslint": "^8.11.0",
+ "eslint": "^8.12.0",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-prettier": "^4.0.0",
"eslint-plugin-react": "^7.29.4",
"eslint-webpack-plugin": "^3.1.1",
"file-loader": "^6.2.0",
- "html-webpack-plugin": "^4.5.0",
+ "html-webpack-plugin": "^5.5.0",
"less": "^4.1.1",
"less-loader": "^10.0.1",
"lint-staged": "^12.3.5",
- "mini-css-extract-plugin": "^2.2.0",
+ "mini-css-extract-plugin": "^2.6.0",
"postcss-flexbugs-fixes": "^5.0.2",
- "postcss-loader": "^6.1.1",
+ "postcss-loader": "^6.2.1",
"postcss-normalize": "^10.0.0",
"postcss-preset-env": "^7.4.3",
- "prettier": "^2.3.2",
- "react-router-config": "^5.1.1",
- "style-loader": "^2.0.0",
+ "prettier": "^2.6.1",
+ "style-loader": "^3.3.1",
"ts-jest": "^26.4.4",
"url-loader": "^4.1.1",
"webpack-bundle-analyzer": "^4.5.0",
- "webpack-cli": "^4.3.0",
- "webpack-dev-server": "^3.11.0"
+ "webpack-cli": "^4.9.2",
+ "webpack-dev-server": "^4.7.4"
},
"lint-staged": {
"*.js": "eslint --cache --fix"
diff --git a/frontend/src/app.tsx b/frontend/src/app.tsx
index b603f7b..1db0db6 100644
--- a/frontend/src/app.tsx
+++ b/frontend/src/app.tsx
@@ -16,8 +16,6 @@
// under the License.
import React from 'react';
-import { hot } from 'react-hot-loader/root';
-import { BrowserRouter as Router, Switch } from 'react-router-dom';
import { useTranslation } from 'react-i18next';
import { ConfigProvider } from 'antd';
import zh from 'antd/lib/locale/zh_CN';
@@ -39,4 +37,4 @@ const App = () => {
);
};
-export default hot(App);
+export default App;
diff --git a/frontend/src/assets/space/u288.png b/frontend/src/assets/space/u288.png
deleted file mode 100644
index e28440a..0000000
Binary files a/frontend/src/assets/space/u288.png and /dev/null differ
diff --git a/frontend/src/assets/space/u296.png b/frontend/src/assets/space/u296.png
deleted file mode 100644
index 617e2e7..0000000
Binary files a/frontend/src/assets/space/u296.png and /dev/null differ
diff --git a/frontend/src/assets/space/u919.png b/frontend/src/assets/space/u919.png
deleted file mode 100644
index 7a5413b..0000000
Binary files a/frontend/src/assets/space/u919.png and /dev/null differ
diff --git a/frontend/src/common/common.data.ts b/frontend/src/common/common.data.ts
index ac9f96f..d3572e1 100644
--- a/frontend/src/common/common.data.ts
+++ b/frontend/src/common/common.data.ts
@@ -43,7 +43,6 @@ export enum TableTypeEnum {
AGG_KEYS = 'AGG_KEYS',
}
-
export const TABLE_TYPE_KEYS = [
{
value: TableTypeEnum.PRIMARY_KEYS,
@@ -91,12 +90,7 @@ export const FIRST_COLUMN_FIELD_TYPES = FIELD_TYPES.filter(
(field: any) => !FIRST_COLUMN_FIELD_TYPE_CANNOT_BE.includes(field),
);
-export const ANALYTICS_URL = '/login';
-export const STUDIO_INDEX_URL = `/meta/index`; //待确认
-export const MANAGE_INDEX_URL = `/super-admin/space/list`;
-
-
export enum AuthTypeEnum {
LDAP = 'ldap',
- STUDIO = 'studio',
-}
\ No newline at end of file
+ LOCAL = 'local',
+}
diff --git a/frontend/src/routes/tree/create-menu/create.module.less b/frontend/src/components/auths/auth-route.tsx
similarity index 60%
rename from frontend/src/routes/tree/create-menu/create.module.less
rename to frontend/src/components/auths/auth-route.tsx
index 9be4205..3c755f4 100644
--- a/frontend/src/routes/tree/create-menu/create.module.less
+++ b/frontend/src/components/auths/auth-route.tsx
@@ -15,13 +15,21 @@
// specific language governing permissions and limitations
// under the License.
-.create-drop {
- :global .ant-dropdown-menu {
- border-radius: 15px;
+import { RequireAuth } from './require-auth';
+import { RequireInitialized } from './require-initialized';
+interface AuthRouteProps {
+ children: JSX.Element;
+ requireInitialized?: boolean;
+}
- .ant-dropdown-menu-item:hover {
- background-color: #a5bbf1 !important;
- border-radius: 10px;
+export function AuthRoute({ children, requireInitialized = true }: AuthRouteProps) {
+ if (requireInitialized) {
+ return (
+ <RequireInitialized>
+ <RequireAuth>{children}</RequireAuth>
+ </RequireInitialized>
+ );
+ } else {
+ return <RequireAuth>{children}</RequireAuth>;
}
- }
}
diff --git a/frontend/src/routes/node/dashboard/monitor.less b/frontend/src/components/auths/auth.interface.ts
similarity index 78%
rename from frontend/src/routes/node/dashboard/monitor.less
rename to frontend/src/components/auths/auth.interface.ts
index 8383000..0920abc 100644
--- a/frontend/src/routes/node/dashboard/monitor.less
+++ b/frontend/src/components/auths/auth.interface.ts
@@ -15,10 +15,10 @@
// specific language governing permissions and limitations
// under the License.
-.monitor {
- min-height: 100%;
+import { UserInfo } from '@src/common/common.interface';
- h4 {
- margin-left: 10px;
- }
+export interface AuthContextType {
+ userInfo: UserInfo;
+ signIn: (user: string, callback: VoidFunction) => void;
+ signOut: (callback: VoidFunction) => void;
}
diff --git a/frontend/src/routes/initialize/auths/ldap/ldap-admin-user/use-ldap-user.hooks.ts b/frontend/src/components/auths/doris-auth-provider.ts
similarity index 51%
rename from frontend/src/routes/initialize/auths/ldap/ldap-admin-user/use-ldap-user.hooks.ts
rename to frontend/src/components/auths/doris-auth-provider.ts
index 028297b..17a8ffd 100644
--- a/frontend/src/routes/initialize/auths/ldap/ldap-admin-user/use-ldap-user.hooks.ts
+++ b/frontend/src/components/auths/doris-auth-provider.ts
@@ -15,25 +15,30 @@
// specific language governing permissions and limitations
// under the License.
-import { InitializeAPI } from '@src/routes/initialize/initialize.api';
-import { isSuccess } from '@src/utils/http';
-import { Dispatch, SetStateAction, useState, useEffect } from 'react';
-
-export function useLDAPUsers(): {
- ldapUsers: any[];
- setLDAPUsers: Dispatch<SetStateAction<any[]>>;
- getLDAPUsers: () => void;
-} {
- const [ldapUsers, setLDAPUsers] = useState<any>();
- useEffect(() => {
- getLDAPUsers();
- }, []);
-
- async function getLDAPUsers() {
- const res = await InitializeAPI.getLDAPUser();
- if (isSuccess(res)) {
- setLDAPUsers(res.data);
+const dorisAuthProvider = {
+ isAuthenticated: false,
+ checkInitialized(): boolean {
+ const initialized: boolean = JSON.parse(localStorage.getItem('initialized') as string);
+ if (initialized) {
+ return true;
}
- }
- return { ldapUsers, getLDAPUsers, setLDAPUsers };
-}
+ return false;
+ },
+ checkLogin(): boolean {
+ const login: any = JSON.parse(localStorage.getItem('login') as string);
+ if (login) {
+ return true;
+ }
+ return false;
+ },
+ signIn(callback: VoidFunction) {
+ dorisAuthProvider.isAuthenticated = true;
+ setTimeout(callback, 100);
+ },
+ signOut(callback: VoidFunction) {
+ dorisAuthProvider.isAuthenticated = false;
+ setTimeout(callback, 100);
+ },
+};
+
+export { dorisAuthProvider };
diff --git a/frontend/src/routes/query/query-details/query.module.less b/frontend/src/components/auths/require-auth.tsx
similarity index 51%
rename from frontend/src/routes/query/query-details/query.module.less
rename to frontend/src/components/auths/require-auth.tsx
index 61eb866..9dc4ea8 100644
--- a/frontend/src/routes/query/query-details/query.module.less
+++ b/frontend/src/components/auths/require-auth.tsx
@@ -15,42 +15,20 @@
// specific language governing permissions and limitations
// under the License.
-.textBox {
- width: 100%;
- min-height: 500px;
- max-height: 70vh;
- overflow-y: scroll;
- border: 1px solid #ddd;
- }
+import { Navigate, useLocation } from 'react-router';
+import { dorisAuthProvider } from './doris-auth-provider';
-.profileBox {
- display: flex;
- :global {
- .ant-tree .ant-tree-treenode-disabled .ant-tree-node-content-wrapper{
- color: #666 !important;
- }
- }
-
- .fragment {
- flex-shrink: 0;
- width: 270px;
- height: 70vh;
- overflow: scroll;
- border: 1px solid #ddd;
- }
+export function RequireAuth({ children }: { children: JSX.Element }) {
+ const location = useLocation();
+ const isPassportLogin = location.pathname.includes('/passport/login');
- .graph {
- flex: 1;
- max-height: 70vh;
- overflow-y: scroll;
- font-size: 14px;
- color: #fff;
- background-color: #000;
+ if (dorisAuthProvider.checkLogin() || isPassportLogin) {
+ return children;
+ } else {
+ // Redirect them to the /login page, but save the current location they were
+ // trying to go to when they were redirected. This allows us to send them
+ // along to that page after they login, which is a nicer user experience
+ // than dropping them off on the home page.
+ return <Navigate to="/passport/login" state={{ from: location }} replace />;
}
}
-
-:global {
- .ant-tree .ant-tree-treenode-disabled .ant-tree-node-content-wrapper{
- color: #666 !important;
- }
-}
\ No newline at end of file
diff --git a/frontend/src/routes/dashboard/components/dashboard-item/message-item.less b/frontend/src/components/auths/require-initialized.tsx
similarity index 54%
rename from frontend/src/routes/dashboard/components/dashboard-item/message-item.less
rename to frontend/src/components/auths/require-initialized.tsx
index ed4f212..8a191b2 100644
--- a/frontend/src/routes/dashboard/components/dashboard-item/message-item.less
+++ b/frontend/src/components/auths/require-initialized.tsx
@@ -15,43 +15,19 @@
// specific language governing permissions and limitations
// under the License.
-/** @format */
+import { Navigate, useLocation } from 'react-router';
+import { dorisAuthProvider } from './doris-auth-provider';
-.mess-item {
- position: relative;
- display: flex;
- // height: 64px;
- width: 49%;
- // height: 28vh;
- padding: 5vh;
- margin-top: 20px;
- background: #edf2f5;
- border-radius: 20px;
- // box-shadow: 3px 3px 3px #e2dede;
+export function RequireInitialized({ children }: { children: JSX.Element }) {
+ const location = useLocation();
- .mess-item-title {
- width: 35%;
- text-align: center;
-
- .mess-item-icon {
- margin: 0;
- font-size: 5vw;
- color: #6536cc;
- }
-
- .mess-item-name {
- margin: 0;
- font-size: 1vw;
- color: #7f7f7f;
+ if (!dorisAuthProvider.checkInitialized()) {
+ // Redirect them to the /initialize page, but save the current location they were
+ // trying to go to when they were redirected. This allows us to send them
+ // along to that page after they initialize, which is a nicer user experience
+ // than dropping them off on the home page.
+ return <Navigate to="initialize" state={{ from: location }} replace />;
}
- }
- .mess-item-content {
- display: flex;
- align-items: center;
- justify-content: center;
- width: 65%;
- font-size: 4vw;
- // vertical-align: middle;
- }
+ return children;
}
diff --git a/frontend/src/components/common-header/header.tsx b/frontend/src/components/common-header/header.tsx
index 2fc9f81..ab633d6 100644
--- a/frontend/src/components/common-header/header.tsx
+++ b/frontend/src/components/common-header/header.tsx
@@ -17,20 +17,19 @@
/** @format */
-import React, { useState, useCallback, useEffect } from 'react';
+import { useState } from 'react';
import styles from './header.module.less';
import { HeaderProps } from './header.interface';
import { SyncOutlined } from '@ant-design/icons';
import { HeaderAPI } from './header.api';
import CSSModules from 'react-css-modules';
-const EventEmitter = require('events').EventEmitter;
+// eslint-disable-next-line @typescript-eslint/no-var-requires
+const EventEmitter = require('events').EventEmitter;
const event = new EventEmitter();
export function Header(props: HeaderProps) {
const [loading, setLoading] = useState(false);
- // useEffect(() => {
- // HeaderAPI.refreshData();
- // }, []);
+
function refresh() {
HeaderAPI.refreshData();
event.emit('refreshData');
@@ -58,4 +57,4 @@ export function Header(props: HeaderProps) {
);
}
-export const CommonHeader = CSSModules(styles)(Header);
\ No newline at end of file
+export const CommonHeader = CSSModules(styles)(Header);
diff --git a/frontend/src/components/header/header.tsx b/frontend/src/components/header/header.tsx
index 099866d..3610430 100644
--- a/frontend/src/components/header/header.tsx
+++ b/frontend/src/components/header/header.tsx
@@ -16,57 +16,41 @@
// under the License.
import { Menu, Col, Row, Dropdown, Button } from 'antd';
-import {SettingOutlined } from '@ant-design/icons';
-import React, { useContext, useState } from 'react';
+import { SettingOutlined } from '@ant-design/icons';
+import { useContext } from 'react';
import { LayoutAPI } from './header.api';
-import { useHistory } from 'react-router-dom';
import { useTranslation } from 'react-i18next';
import styles from './index.module.less';
import { UserInfoContext } from '@src/common/common.context';
import Swal from 'sweetalert2';
-const VERSION = require('../../../package.json').version;
+import { useNavigate } from 'react-router';
+import { VERSION } from '@src/config';
-type HeaderMode = 'normal' | 'initialize' | 'super-admin';
-interface HeaderProps {
- mode: HeaderMode;
-}
-
-export function Header(props: HeaderProps) {
+export function Header() {
const { t, i18n } = useTranslation();
- const history = useHistory();
- const [statisticInfo, setStatisticInfo] = useState<any>({});
- const user = JSON.parse(window.localStorage.getItem('user') as string);
- const userInfo = useContext(UserInfoContext);
- function getCurrentUser() {
- LayoutAPI.getCurrentUser()
- .then(res => {
- window.localStorage.setItem('user', JSON.stringify(res.data))
- LayoutAPI.getSpaceName(res.data.space_id).then(res1 => {
- setStatisticInfo(res1.data || {});
- })
- })
- .catch(err => {
- console.log(err);
- });
- }
+ const navigate = useNavigate();
+ const user = useContext(UserInfoContext);
function onAccountSettings() {
- history.push( `/user-setting`);
+ navigate(`/user-setting`);
}
function onLogout() {
- LayoutAPI.signOut()
- .then(res => {
- console.log(res)
- if (res.code === 0) {
- localStorage.removeItem('login');
- history.push(`/login`);
- }
- })
-
+ LayoutAPI.signOut().then(res => {
+ console.log(res);
+ if (res.code === 0) {
+ localStorage.removeItem('login');
+ navigate(`/login`);
+ }
+ });
}
const menu = (
<Menu>
- <Menu.Item style={{ padding: '10px 20px' }} onClick={onAccountSettings}>{t`accountSettings`}</Menu.Item>
<Menu.Item
+ key="account_setting"
+ style={{ padding: '10px 20px' }}
+ onClick={onAccountSettings}
+ >{t`accountSettings`}</Menu.Item>
+ <Menu.Item
+ key="about"
onClick={() => {
Swal.fire({
width: '480px',
@@ -83,38 +67,27 @@ export function Header(props: HeaderProps) {
>
{t`About`} Doris Manager
</Menu.Item>
- <Menu.Item style={{ padding: '10px 20px' }} onClick={onLogout}>{t`Logout`}</Menu.Item>
+ <Menu.Item key="logout" style={{ padding: '10px 20px' }} onClick={onLogout}>{t`Logout`}</Menu.Item>
</Menu>
);
return (
<div
- className={user && user?.is_super_admin ? styles['adminStyle']: styles['userStyle']}
+ className={user && user?.is_super_admin ? styles['adminStyle'] : styles['userStyle']}
style={{ padding: 0, borderBottom: '1px solid #d9d9d9' }}
- >
- <Row justify="end" align="middle" style={{paddingBottom: 8}}>
- {/* {
- user && user.is_super_admin ? (
- <div
- className={styles['logo']}
- />
- ) :(
- <Col style={{ marginLeft: '2em' }}>
- <span>{t`namespace`}:{(userInfo as UserInfo)?.space_name}</span>
- </Col>
- )
- } */}
- <Button
+ >
+ <Row justify="end" align="middle" style={{ paddingBottom: 8 }}>
+ <Button
type="link"
- style={{marginTop: 2}}
+ style={{ marginTop: 2 }}
onClick={() => {
i18n.changeLanguage(i18n.language === 'zh' ? 'en' : 'zh');
}}
>
{i18n.language === 'zh' ? 'Switch to English' : '切换为中文'}
</Button>
- <Col style={{ cursor: 'pointer', marginRight: 20, fontSize: 22}}>
+ <Col style={{ cursor: 'pointer', marginRight: 20, fontSize: 22 }}>
<Dropdown overlay={menu} placement="bottomLeft">
- <span onClick={e=> e.preventDefault()}>
+ <span onClick={e => e.preventDefault()}>
<SettingOutlined />
</span>
</Dropdown>
diff --git a/frontend/src/components/helper/helper.less b/frontend/src/components/helper/helper.less
index b5922eb..e6a85ba 100644
--- a/frontend/src/components/helper/helper.less
+++ b/frontend/src/components/helper/helper.less
@@ -15,7 +15,7 @@
// specific language governing permissions and limitations
// under the License.
-.palo-studio-helper {
+.palo-manager-helper {
font-size: 16px;
color: @primary-color;
text-align: left;
diff --git a/frontend/src/components/helper/helper.tsx b/frontend/src/components/helper/helper.tsx
index 8c4afa7..e25a3f7 100644
--- a/frontend/src/components/helper/helper.tsx
+++ b/frontend/src/components/helper/helper.tsx
@@ -24,7 +24,7 @@ import './helper.less';
export function Helper(props: TooltipProps) {
return (
<Tooltip {...props}>
- <QuestionCircleFilled style={{ cursor: 'pointer', ...props.style }} className="palo-studio-helper" />
+ <QuestionCircleFilled style={{ cursor: 'pointer', ...props.style }} className="palo-manager-helper" />
</Tooltip>
);
}
diff --git a/frontend/src/components/initialized-route/initialized-route.tsx b/frontend/src/components/initialized-route/initialized-route.tsx
index 04d0809..179d463 100644
--- a/frontend/src/components/initialized-route/initialized-route.tsx
+++ b/frontend/src/components/initialized-route/initialized-route.tsx
@@ -15,19 +15,26 @@
// specific language governing permissions and limitations
// under the License.
-import { auth } from "@src/utils/auth";
-import React from "react";
-import { Redirect, Route } from "react-router";
+import { auth } from '@src/utils/auth';
+import React from 'react';
+import { Navigate, Route } from 'react-router';
export function InitializedRoute({ children, ...rest }) {
- const isPassportLogin = location.pathname.includes("/passport/login");
+ const isPassportLogin = location.pathname.includes('/passport/login');
return (
- <Route {...rest} render={props => {
- if (!auth.checkInitialized()) {
- return <Redirect to="/initialize" />;
- } else {
- return auth.checkLogin() || isPassportLogin ? children : <Redirect to="/passport/login" />;
- }
- }} />
- )
+ <Route
+ {...rest}
+ render={() => {
+ if (!auth.checkInitialized()) {
+ return <Navigate to="/initialize" />;
+ } else {
+ return auth.checkLogin() || isPassportLogin ? (
+ children
+ ) : (
+ <Route path="/" render={() => <Navigate to="/passport/login" />} />
+ );
+ }
+ }}
+ />
+ );
}
diff --git a/frontend/src/components/metadata/index.tsx b/frontend/src/components/metadata/index.tsx
deleted file mode 100644
index 8091089..0000000
--- a/frontend/src/components/metadata/index.tsx
+++ /dev/null
@@ -1,128 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements. See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership. The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License. You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing,
-// software distributed under the License is distributed on an
-// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-// KIND, either express or implied. See the License for the
-// specific language governing permissions and limitations
-// under the License.
-
-import React, { useState } from 'react';
-import { Tree } from 'antd';
-const TREE_DATA = [
- {
- title: '0-0',
- key: '0-0',
- children: [
- {
- title: '0-0-0',
- key: '0-0-0',
- children: [
- {
- title: '0-0-0-0',
- key: '0-0-0-0',
- },
- {
- title: '0-0-0-1',
- key: '0-0-0-1',
- },
- {
- title: '0-0-0-2',
- key: '0-0-0-2',
- },
- ],
- },
- {
- title: '0-0-1',
- key: '0-0-1',
- children: [
- {
- title: '0-0-1-0',
- key: '0-0-1-0',
- },
- {
- title: '0-0-1-1',
- key: '0-0-1-1',
- },
- {
- title: '0-0-1-2',
- key: '0-0-1-2',
- },
- ],
- },
- {
- title: '0-0-2',
- key: '0-0-2',
- },
- ],
- },
- {
- title: '0-1',
- key: '0-1',
- children: [
- {
- title: '0-1-0-0',
- key: '0-1-0-0',
- },
- {
- title: '0-1-0-1',
- key: '0-1-0-1',
- },
- {
- title: '0-1-0-2',
- key: '0-1-0-2',
- },
- ],
- },
- {
- title: '0-2',
- key: '0-2',
- },
-];
-
-export function MetaDataTree() {
- const [expandedKeys, setExpandedKeys] = useState(['0-0-0', '0-0-1']);
- const [checkedKeys, setCheckedKeys] = useState(['0-0-0']);
- const [selectedKeys, setSelectedKeys] = useState([]);
- const [autoExpandParent, setAutoExpandParent] = useState(true);
-
- const onExpand = expandedKeysValue => {
- console.log('onExpand', expandedKeysValue); // if not set autoExpandParent to false, if children expanded, parent can not collapse.
- // or, you can remove all expanded children keys.
-
- setExpandedKeys(expandedKeysValue);
- setAutoExpandParent(false);
- };
-
- const onCheck = checkedKeysValue => {
- console.log('onCheck', checkedKeysValue);
- setCheckedKeys(checkedKeysValue);
- };
-
- const onSelect = (selectedKeysValue, info) => {
- console.log('onSelect', info);
- setSelectedKeys(selectedKeysValue);
- };
-
- return (
- <Tree
- checkable
- onExpand={onExpand}
- expandedKeys={expandedKeys}
- autoExpandParent={autoExpandParent}
- onCheck={onCheck}
- checkedKeys={checkedKeys}
- onSelect={onSelect}
- selectedKeys={selectedKeys}
- treeData={TREE_DATA}
- />
- );
-}
diff --git a/frontend/src/components/not-found/index.tsx b/frontend/src/components/not-found/index.tsx
index 27b88ef..8b25655 100644
--- a/frontend/src/components/not-found/index.tsx
+++ b/frontend/src/components/not-found/index.tsx
@@ -15,13 +15,12 @@
// specific language governing permissions and limitations
// under the License.
-import * as React from 'react';
-export const NotFound = () => {
- return (
- <>
- <div className="components-notfound">
- 404
- </div>
- </>
- );
-};
+import React from 'react';
+
+export function NotFound() {
+ return (
+ <>
+ <div className="components-notfound">404</div>
+ </>
+ );
+}
diff --git a/frontend/src/components/sidebar/sidebar.less b/frontend/src/components/sidebar/sidebar.less
index bc1e534..501646f 100644
--- a/frontend/src/components/sidebar/sidebar.less
+++ b/frontend/src/components/sidebar/sidebar.less
@@ -46,5 +46,4 @@
margin-left: 0px;
color: gray;
background-color: gray;
-
}
diff --git a/frontend/src/components/sidebar/sidebar.tsx b/frontend/src/components/sidebar/sidebar.tsx
index 3a4ae11..9399b49 100644
--- a/frontend/src/components/sidebar/sidebar.tsx
+++ b/frontend/src/components/sidebar/sidebar.tsx
@@ -17,16 +17,9 @@
import { Menu } from 'antd';
import Sider from 'antd/lib/layout/Sider';
-import {
- ClusterOutlined,
- ConsoleSqlOutlined,
- DatabaseOutlined,
- SettingOutlined,
- TableOutlined,
- AppstoreOutlined,
-} from '@ant-design/icons';
-import { Link, useHistory, useLocation } from 'react-router-dom';
-import React, { useState, useEffect, useContext, useMemo } from 'react';
+import { ClusterOutlined, DatabaseOutlined, SettingOutlined, TableOutlined, AppstoreOutlined } from '@ant-design/icons';
+import { Link, useLocation, useNavigate } from 'react-router-dom';
+import { useState, useEffect, useContext, useMemo } from 'react';
import { useTranslation } from 'react-i18next';
import styles from './sidebar.less';
@@ -41,30 +34,25 @@ export function Sidebar(props: any) {
const { mode } = props;
const user = useContext(UserInfoContext);
- const history = useHistory();
- const { pathname } = useLocation();
+ const navigate = useNavigate();
+ const location = useLocation();
const isSuperAdmin = user?.is_super_admin;
const isSpaceAdmin = user?.is_admin;
const isInSpace = !GLOBAL_PATHS.includes(selectedKeys);
const logoRoute = useMemo(
- () => (GLOBAL_PATHS.some(path => pathname.startsWith(path)) ? '/space' : '/cluster'),
- [pathname],
+ () => (GLOBAL_PATHS.some(path => location.pathname.startsWith(path)) ? '/space' : '/cluster'),
+ [location.pathname],
);
+ const MENU_KEYS = ['/cluster', '/space', '/settings', '/admin', '/meta'];
useEffect(() => {
- if (history.location.pathname.includes('configuration')) {
- setSelectedKeys('/configuration');
- } else if (history.location.pathname.startsWith('/cluster')) {
- setSelectedKeys('/cluster');
- } else if (history.location.pathname.startsWith('/space')) {
- setSelectedKeys('/space');
- } else if (history.location.pathname.startsWith('/settings')) {
- setSelectedKeys('/settings');
- } else if (history.location.pathname.startsWith('/admin')) {
- setSelectedKeys('/admin');
- } else {
- setSelectedKeys(history.location.pathname);
- }
- }, [history.location.pathname]);
+ let selectKey = location.pathname;
+ MENU_KEYS.forEach(key => {
+ if (location.pathname.startsWith(key)) {
+ selectKey = key;
+ }
+ });
+ setSelectedKeys(selectKey);
+ }, [location.pathname]);
function onCollapse() {
setCollapsed(!collapsed);
@@ -102,7 +90,7 @@ export function Sidebar(props: any) {
>
<div
className={collapsed ? styles['logo-collapsed'] : styles['logo']}
- onClick={() => history.push(`/meta/index`)}
+ onClick={() => navigate(`/meta/index`)}
/>
</Menu.Item>
</Menu>
@@ -127,7 +115,6 @@ export function Sidebar(props: any) {
>
<Menu.Item
style={{
- height: 60,
backgroundColor: '#00284D',
marginTop: 0,
display: 'flex',
@@ -135,7 +122,7 @@ export function Sidebar(props: any) {
alignItems: 'center',
}}
key="/logo"
- onClick={() => history.push(logoRoute)}
+ onClick={() => navigate(logoRoute)}
>
<div className={collapsed ? styles['logo-collapsed'] : styles['logo']} />
</Menu.Item>
@@ -147,9 +134,6 @@ export function Sidebar(props: any) {
<Menu.Item key="/meta" icon={<TableOutlined />}>
<Link to={`/meta`}>{t`data`}</Link>
</Menu.Item>
- {/* <Menu.Item key="/query" icon={<ConsoleSqlOutlined />}>
- <Link to={`/query`}>{t`Query`}</Link>
- </Menu.Item> */}
{(isSuperAdmin || isSpaceAdmin) && (
<Menu.Item key="/admin" icon={<AppstoreOutlined />}>
<Link to={`/admin`}>{t`Space Manager`}</Link>
@@ -159,7 +143,7 @@ export function Sidebar(props: any) {
</>
)}
<Menu.Item key="/space" icon={<DatabaseOutlined />}>
- <Link to={`/space/list`}>{t`Space List`}</Link>
+ <Link to={`/space`}>{t`Space List`}</Link>
</Menu.Item>
{isSuperAdmin && (
<Menu.Item id="aaaa" key="/settings" icon={<SettingOutlined />}>
diff --git a/frontend/src/components/studio-header/header.api.ts b/frontend/src/components/studio-header/header.api.ts
deleted file mode 100644
index 5333ee5..0000000
--- a/frontend/src/components/studio-header/header.api.ts
+++ /dev/null
@@ -1,37 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements. See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership. The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License. You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing,
-// software distributed under the License is distributed on an
-// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-// KIND, either express or implied. See the License for the
-// specific language governing permissions and limitations
-// under the License.
-
-/* eslint-disable prettier/prettier */
-/** @format */
-
-import { http } from '@src/utils/http';
-function getCurrentUser() {
- return http.get(`/api/user/current`);
-}
-
-function getSpaceName(data: any) {
- return http.get(`/api/space/${data}`);
-}
-
-function signOut() {
- return http.delete(`/api/session/`);
-}
-export const LayoutAPI = {
- getCurrentUser,
- getSpaceName,
- signOut,
-};
diff --git a/frontend/src/components/studio-header/header.tsx b/frontend/src/components/studio-header/header.tsx
deleted file mode 100644
index c860a6d..0000000
--- a/frontend/src/components/studio-header/header.tsx
+++ /dev/null
@@ -1,148 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements. See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership. The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License. You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing,
-// software distributed under the License is distributed on an
-// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-// KIND, either express or implied. See the License for the
-// specific language governing permissions and limitations
-// under the License.
-
-import logo from '@assets/logo_nav.png';
-import React, { useEffect, useMemo, useState } from 'react';
-import styles from './index.module.less';
-// import queryString from 'query-string';
-import { Anchor, Col, Dropdown, Input, Layout, Menu, message, Row, Tooltip } from 'antd';
-import {
- AppstoreAddOutlined,
- LeftOutlined,
- SearchOutlined,
-} from '@ant-design/icons';
-import { Link, RouteComponentProps, useHistory, useRouteMatch } from 'react-router-dom';
-import { useTranslation } from 'react-i18next';
-import { SettingsIcon } from '../settings-icon/settings-icon';
-import { auth } from '@src/utils/auth';
-
-type HeaderMode = 'normal' | 'initialize' | 'super-admin';
-interface HeaderProps {
- mode: HeaderMode;
-}
-
-export function Header(props: HeaderProps) {
- const { t } = useTranslation();
- const history = useHistory();
- // const { q } = queryString.parse(history.location.search) as { q: string };
- const { mode = 'normal' } = props;
- const showHeaderFuncs = mode !== 'initialize' && mode !== 'super-admin';
- const isHistoryQueryPage = history.location.pathname.includes('history-query');
-
- const initialized = auth.checkInitialized();
-
- // const searchBar = useMemo(
- // () => (
- // <Input
- // key={q}
- // placeholder={t`search`}
- // prefix={<SearchOutlined className={styles['search-icon']} />}
- // defaultValue={q}
- // onPressEnter={val => {
- // history.push({ pathname: '/search', search: `?q=${val.target.value}` });
- // }}
- // />
- // ),
- // [q],
- // );
- return (
- <div className={styles['palo-header']}>
- <div className={styles['palo-logo']} onClick={() => {
- history.push(`/space`);
- }}>
- <img src={logo} alt="" />
- </div>
- {/* {showHeaderFuncs && <div className={styles['palo-search']}>{searchBar}</div>} */}
- <div className={styles['palo-opt-box']}>
- {/* {showHeaderFuncs && (
- <div>
- <Tooltip placement="bottom" title={t`workspace`}>
- <AppstoreAddOutlined
- className={styles['icon']}
- onClick={() => {
- history.push(`/collection`);
- }}
- />
- </Tooltip>
- </div>
- )} */}
- {/* <div>
- <ContainerOutlined
- className={styles['icon']}
- onClick={() => (window.location.href = `${window.location.origin}`)}
- />
- <span className={styles['icon-tip']}>创建查询</span>
- </div>
- <div>
- <Tooltip placement="bottom" title={t`databse`}>
- <HddOutlined
- className={styles['icon']}
- onClick={() => (window.location.href = `${window.location.origin}/new-studio/browse`)}
- />
- </Tooltip>
- </div>
- <div>
- <Tooltip placement="bottom" title={t`workspace`}>
- <AppstoreAddOutlined
- className={styles['icon']}
- onClick={() => (window.location.href = `${window.location.origin}/new-studio/`)}
- />
- </Tooltip>
- </div>
- {statisticInfo.manager_enable && (
- <div>
- <Tooltip placement="bottom" title={"运维监控"}>
- <DesktopOutlined
- className={styles['icon']}
- onClick={() => (window.location.href = `${window.location.origin}/d-stack`)}
- />
- </Tooltip>
- </div>
- )
- }
- <div>
- <Tooltip placement="bottom" title={t`help`}>
- <QuestionCircleOutlined
- className={styles['icon']}
- onClick={() => {
- const analyticsUrl = `${window.location.origin}/docs/pages/产品概述/产品介绍.html`;
- window.open(analyticsUrl);
- }}
- />
- </Tooltip>
- </div> */}
- {showHeaderFuncs && isHistoryQueryPage && (
- <div>
- <Tooltip placement="bottom" title={t`backTo` + 'Studio'}>
- <LeftOutlined
- className={styles['icon']}
- onClick={() =>
- (window.location.href = `${window.location.origin}/question#eyJkYXRhc2V0X3F1ZXJ5Ijp7ImRhdGFiYXNlIjpudWxsLCJuYXRpdmUiOnsicXVlcnkiOiIiLCJ0ZW1wbGF0ZS10YWdzIjp7fX0sInR5cGUiOiJOQVRJVkUifSwiZGlzcGxheSI6InRhYmxlIiwidmlzdWFsaXphdGlvbl9zZXR0aW5ncyI6e319`)
- }
- />
- </Tooltip>
- </div>
- )}
- {initialized && (
- <div>
- <SettingsIcon mode="super-admin" />
- </div>
- )}
- </div>
- </div>
- );
-}
diff --git a/frontend/src/components/studio-header/index.module.less b/frontend/src/components/studio-header/index.module.less
deleted file mode 100644
index d89dd29..0000000
--- a/frontend/src/components/studio-header/index.module.less
+++ /dev/null
@@ -1,85 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements. See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership. The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License. You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing,
-// software distributed under the License is distributed on an
-// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-// KIND, either express or implied. See the License for the
-// specific language governing permissions and limitations
-// under the License.
-
-.palo-header {
- width: 100%;
- height: 65px;
- background: #000;
- color: #fff;
- font-size: 14px;
- display: flex;
- align-items: center;
- padding: 8px 16px;
- justify-content: space-between;
-
- .palo-logo{
- width: 146px;
- height: 60px;
- margin-right: 8px;
- background-image: url('../../assets/logo_nav.png');
- img{
- height: 100%;
- }
- }
-
- .palo-search{
- flex: 1;
- .search-icon{
- font-size: 16px;
- color: #FFF;
- }
- &>span{
- width: 480px;
- height: 50px;
- background: rgb(59, 59, 59);
- border-radius: 6px;
- border: none;
- input{
- background: transparent;
- color: #fff;
- font-size: 1em;
- }
- }
- }
-
- .palo-opt-box{
- display: flex;
- height: 50px;
- align-items: center;
- div{
- margin-right: 16px;
- padding: 10px;
- cursor: pointer;
- .icon{
- font-size: 20px;
- }
- .icon-tip{
- margin-left: 0.5rem;
- vertical-align: text-bottom;
- }
- }
- div:hover{
- border-radius: 8px;
- background: rgb(32,78,171);
- }
- div:last-child{
- margin-right: 0;
- }
- }
-}
-
-
diff --git a/frontend/src/components/tabs-header/index.tsx b/frontend/src/components/tabs-header/index.tsx
index 3ec754d..4503335 100644
--- a/frontend/src/components/tabs-header/index.tsx
+++ b/frontend/src/components/tabs-header/index.tsx
@@ -15,8 +15,7 @@
// specific language governing permissions and limitations
// under the License.
-import React from 'react';
-import { useLocation, useHistory } from 'react-router-dom';
+import { useLocation, useNavigate } from 'react-router-dom';
import { Tabs } from 'antd';
const { TabPane } = Tabs;
@@ -31,10 +30,10 @@ interface TabsHeaderProps {
export default function TabsHeader(props: TabsHeaderProps) {
const { routes } = props;
const { pathname } = useLocation();
- const history = useHistory();
+ const navigate = useNavigate();
const handleTabChange = (key: string) => {
- history.replace(key);
+ navigate(key);
};
const findActiveKey = (pathname: string) => {
diff --git a/frontend/src/config.ts b/frontend/src/config.ts
index 442dc5a..06a5b98 100644
--- a/frontend/src/config.ts
+++ b/frontend/src/config.ts
@@ -16,13 +16,13 @@
// under the License.
import { getDefaultPageSize } from './utils/utils';
-import version from '../version.json';
+import packageInfo from '../package.json';
export const TABLE_DELAY = 150;
export const PAGESIZE_OPTIONS = ['10', '20', '50', '100', '200'];
export const PAGINATION = {
current: 1,
pageSize: getDefaultPageSize(),
- // total: 0
+ total: 0,
};
-export const VERSION = `v${version.version}`;
+export const VERSION = `v${packageInfo.version}`;
diff --git a/frontend/src/hooks/use-auth.ts b/frontend/src/hooks/use-auth.ts
index 956423f..36a96ea 100644
--- a/frontend/src/hooks/use-auth.ts
+++ b/frontend/src/hooks/use-auth.ts
@@ -15,17 +15,18 @@
// specific language governing permissions and limitations
// under the License.
+import { AuthTypeEnum } from '@src/common/common.data';
import { InitializeAPI } from '@src/routes/initialize/initialize.api';
import { isSuccess } from '@src/utils/http';
import { useEffect, useState } from 'react';
-import { useHistory, useLocation } from 'react-router';
+import { useLocation, useNavigate } from 'react-router';
export function useAuth() {
const [initialized, setInitialized] = useState(false);
const { pathname } = useLocation();
- const history = useHistory();
+ const navigate = useNavigate();
const [initStep, setInitStep] = useState(0);
- const [authType, setAuthType] = useState();
+ const [authType, setAuthType] = useState<AuthTypeEnum>();
useEffect(() => {
getInitProperties();
}, []);
@@ -34,15 +35,15 @@ export function useAuth() {
const res = await InitializeAPI.getInitProperties();
if (isSuccess(res)) {
setInitStep(res.data.initStep);
- setAuthType(res.data.auth_type);
+ setAuthType(res.data.auth_type === 'studio' ? AuthTypeEnum.LOCAL : AuthTypeEnum.LDAP);
if (res.data.completed) {
localStorage.setItem('initialized', 'true');
setInitialized(true);
} else {
localStorage.setItem('initialized', 'false');
setInitialized(false);
- if (!pathname.includes('/initialize')) {
- history.push('/initialize');
+ if (!pathname.includes('initialize')) {
+ navigate('initialize');
}
}
}
diff --git a/frontend/src/index.css b/frontend/src/index.css
index d0539c4..a19ca45 100644
--- a/frontend/src/index.css
+++ b/frontend/src/index.css
@@ -59,6 +59,7 @@ h1,h2,h3,h4,h5,h6 {
}
.ant-layout-sider {
position: fixed !important;
+ background-color: #001528 !important;
}
.ant-layout-sider-collapsed {
@@ -66,10 +67,22 @@ h1,h2,h3,h4,h5,h6 {
min-width: 64px !important;
flex: 0 0 64px !important;
}
+.ant-menu-inline-collapsed {
+ width: 100% !important;
+}
.ant-layout-sider-collapsed .ant-layout-sider-trigger {
width: 64px !important;
}
+.ant-layout-sider-trigger {
+ color: white;
+ text-align: center;
+ padding: 12px 0;
+ cursor: pointer;
+ position: fixed;
+ bottom: 0;
+ background-color: #002140 !important;
+}
.ant-menu-item {
height: 48px !important;
@@ -80,6 +93,9 @@ h1,h2,h3,h4,h5,h6 {
margin: 8px !important;
border-radius: 2px;
}
+.ant-layout-sider .ant-menu-item:first-child {
+ height: 60px !important;
+}
.ant-layout-sider-collapsed .ant-menu-item:first-child {
width: 100% !important;
margin: 0 !important;
diff --git a/frontend/src/index.tsx b/frontend/src/index.tsx
index 936ef70..3e26488 100644
--- a/frontend/src/index.tsx
+++ b/frontend/src/index.tsx
@@ -21,5 +21,4 @@ import ReactDOM from 'react-dom';
import './index.css';
import './i18n';
-
-ReactDOM.render(<App />, document.querySelector("#root"));
+ReactDOM.render(<App />, document.querySelector('#root'));
diff --git a/frontend/src/routes.tsx b/frontend/src/routes.tsx
index df577e4..1bdc3dd 100644
--- a/frontend/src/routes.tsx
+++ b/frontend/src/routes.tsx
@@ -15,44 +15,69 @@
// specific language governing permissions and limitations
// under the License.
-import React from 'react';
import { Loading } from './components/loading';
import { NotFound } from './components/not-found';
import { Suspense } from 'react';
-
-import { Route, Switch, BrowserRouter as Router } from 'react-router-dom';
-import { InitializedRoute } from './components/initialized-route/initialized-route';
+import { Route, BrowserRouter, Routes, Navigate } from 'react-router-dom';
import { Settings } from './routes/settings/settings';
-import { Initialize } from './routes/initialize/initialize.route';
+import { Initialize } from './routes/initialize/initialize';
import { SuperAdminContainer } from './routes/super-admin-container';
import { Admin } from './routes/admin/admin';
import { Login } from './routes/passport/login';
import { Container } from './routes/container';
+import { RequireInitialized } from './components/auths/require-initialized';
+import { AuthRoute } from './components/auths/auth-route';
const routes = (
<Suspense fallback={<Loading />}>
- <Router>
- <Switch>
- <InitializedRoute path="/passport/login">
- <Login />
- </InitializedRoute>
- <Route path="/initialize" component={Initialize} />
- <InitializedRoute path="/settings">
- <Settings />
- </InitializedRoute>
- <InitializedRoute path="/space">
- <SuperAdminContainer />
- </InitializedRoute>
- <InitializedRoute path="/admin">
- <Admin />
- </InitializedRoute>
- <InitializedRoute path="/">
- <Container />
- </InitializedRoute>
- <Route component={NotFound} />
- </Switch>
- </Router>
+ <BrowserRouter>
+ <Routes>
+ <Route
+ path="/passport/login"
+ element={
+ <RequireInitialized>
+ <Login />
+ </RequireInitialized>
+ }
+ />
+ <Route path="/initialize/*" element={<Initialize />} />
+ <Route
+ path="/space/*"
+ element={
+ <AuthRoute>
+ <SuperAdminContainer />
+ </AuthRoute>
+ }
+ />
+ <Route
+ path="/settings/*"
+ element={
+ <AuthRoute>
+ <Settings />
+ </AuthRoute>
+ }
+ />
+ <Route
+ path="/admin/*"
+ element={
+ <AuthRoute>
+ <Admin />
+ </AuthRoute>
+ }
+ />
+ <Route
+ path="/*"
+ element={
+ <AuthRoute>
+ <Container />
+ </AuthRoute>
+ }
+ />
+ <Route path="/" element={<Navigate to="space" replace />} />
+ <Route path="*" element={<NotFound />} />
+ </Routes>
+ </BrowserRouter>
</Suspense>
);
diff --git a/frontend/src/routes/admin/admin.tsx b/frontend/src/routes/admin/admin.tsx
index ecfc2a2..042b013 100644
--- a/frontend/src/routes/admin/admin.tsx
+++ b/frontend/src/routes/admin/admin.tsx
@@ -15,8 +15,8 @@
// specific language governing permissions and limitations
// under the License.
-import React, { Suspense, useEffect, useMemo, useState } from 'react';
-import { Redirect, Switch, Route, useHistory } from 'react-router-dom';
+import { Suspense, useEffect, useMemo, useState } from 'react';
+import { Navigate, Route, Routes, useNavigate } from 'react-router-dom';
import { Card } from 'antd';
import { useTranslation } from 'react-i18next';
import styles from './admin.module.less';
@@ -30,14 +30,14 @@ import { useUserInfo } from '@src/hooks/use-userinfo.hooks';
import LoadingLayout from '@src/components/loading-layout';
export function Admin() {
- const {t} = useTranslation()
- const history = useHistory();
+ const { t } = useTranslation();
+ const navigate = useNavigate();
const [loading, setLoading] = useState(true);
const [userInfo] = useUserInfo();
useEffect(() => {
if (userInfo.id == null) return;
if (userInfo.id != null && !userInfo.is_super_admin && !userInfo.is_admin) {
- history.push('/');
+ navigate('/');
return;
}
setLoading(false);
@@ -61,11 +61,11 @@ export function Admin() {
fallback={<LoadingLayout loading wrapperStyle={{ textAlign: 'center', marginTop: 200 }} />}
>
<LoadingLayout loading={loading} wrapperStyle={{ textAlign: 'center', marginTop: 200 }}>
- <Switch>
- <Route path="/admin/space/:spaceId" component={SpaceDetail} />
- <Route path="/admin/people" component={People} />
- <Redirect to={`/admin/space/${userInfo.space_id}`} />
- </Switch>
+ <Routes>
+ <Route path="space/:spaceId" element={<SpaceDetail />} />
+ <Route path="people/*" element={<People />} />
+ <Route path="/" element={<Navigate replace to={`space/${userInfo.space_id}`} />} />
+ </Routes>
</LoadingLayout>
</Suspense>
</Card>
diff --git a/frontend/src/routes/admin/people/people.tsx b/frontend/src/routes/admin/people/people.tsx
index 1aa6728..6f05d4d 100644
--- a/frontend/src/routes/admin/people/people.tsx
+++ b/frontend/src/routes/admin/people/people.tsx
@@ -15,21 +15,18 @@
// specific language governing permissions and limitations
// under the License.
-import React from 'react';
import { Role } from './role/role';
-import { Redirect, Route, Switch } from 'react-router-dom';
+import { Navigate, Route, Routes } from 'react-router';
import { User } from './user/user';
-export function People(props: any) {
- const { match } = props;
- console.log(match)
+export function People() {
return (
<>
- <Switch>
- <Route path={`${match.path}/user`} component={User} />
- <Route path={`${match.path}/role`} component={Role} />
- <Redirect to={`${match.path}/role`} />
- </Switch>
+ <Routes>
+ <Route path="user" element={<User />} />
+ <Route path="role/*" element={<Role />} />
+ <Route path="/" element={<Navigate replace to="role" />} />
+ </Routes>
</>
);
}
diff --git a/frontend/src/routes/admin/people/role/list/list.tsx b/frontend/src/routes/admin/people/role/list/list.tsx
index c623923..062565e 100644
--- a/frontend/src/routes/admin/people/role/list/list.tsx
+++ b/frontend/src/routes/admin/people/role/list/list.tsx
@@ -21,28 +21,25 @@ import { FlatBtnGroup, FlatBtn } from '@src/components/flatbtn';
import { useRoles } from '@src/hooks/use-roles.hooks';
import { isSuccess } from '@src/utils/http';
import { showName } from '@src/utils/utils';
-import { Button, Table, Modal, message, Row } from 'antd';
+import { Table, Modal, message, Row } from 'antd';
import { useForm } from 'antd/lib/form/Form';
-import React, { useState } from 'react';
+import { useState } from 'react';
import { useTranslation } from 'react-i18next';
-import { useRouteMatch } from 'react-router';
import { RoleAPI } from '../role.api';
import { CreateOrEditRoleModal } from './create-or-edit-modal';
-export function RoleList(props: any) {
+export function RoleList() {
const { t } = useTranslation();
const { roles, getRoles, loading } = useRoles();
const [visible, setVisible] = useState(false);
const [currentRole, setCurrentRole] = useState<IRole | undefined>();
- const [modalLoading, setModalLoading] = useState(false);
- const match = useRouteMatch();
const [form] = useForm();
const { confirm } = Modal;
const columns = [
{
title: t`roleName`,
key: 'name',
- render: (record: IRole) => <FlatBtn to={`${match.path}/${record.id}`}>{showName(record.name)}</FlatBtn>,
+ render: (record: IRole) => <FlatBtn to={record.id}>{showName(record.name)}</FlatBtn>,
},
{
title: t`members`,
@@ -95,37 +92,10 @@ export function RoleList(props: any) {
},
});
}
- function onCancel() {
- setVisible(false);
- }
- // async function handleCreate(values: any) {
- // setCurrentRole(undefined);
- // setModalLoading(true);
- // const res = await RoleAPI.createRole(values);
- // setModalLoading(false);
- // if (isSuccess(res)) {
- // message.success('创建成功');
- // setVisible(false);
- // getRoles();
- // }
- // }
- async function handleEdit(values: any) {}
return (
<>
<Row justify="space-between" align="middle" style={{ marginBottom: 20 }}>
- <span style={{ color: '#aaa' }}>
- {t`roleTopMessage`}
- </span>
- {/* <Button
- key="1"
- type="primary"
- onClick={() => {
- setVisible(true);
- setCurrentRole(undefined);
- }}
- >
- {t`create`}
- </Button> */}
+ <span style={{ color: '#aaa' }}>{t`roleTopMessage`}</span>
</Row>
<Table
diff --git a/frontend/src/routes/admin/people/role/member/member.tsx b/frontend/src/routes/admin/people/role/member/member.tsx
index fd6e203..678b62b 100644
--- a/frontend/src/routes/admin/people/role/member/member.tsx
+++ b/frontend/src/routes/admin/people/role/member/member.tsx
@@ -22,23 +22,24 @@ import { useRoleMember } from '@src/hooks/use-roles.hooks';
import { useSpaceUsers } from '@src/hooks/use-users.hooks';
import { isSuccess } from '@src/utils/http';
import { showName } from '@src/utils/utils';
-import { Button, Table, Modal, Form, Select, message, Row } from 'antd';
+import { Table, Modal, Form, Select, message, Row } from 'antd';
import { useForm } from 'antd/lib/form/Form';
import { ColumnsType } from 'antd/lib/table';
-import React, { useContext, useState } from 'react';
+import { useContext, useState } from 'react';
import { useTranslation } from 'react-i18next';
-import { useRouteMatch } from 'react-router';
import { RoleAPI } from '../role.api';
import commonStyles from '../../people.less';
+import { useMatch } from 'react-router';
-export function RoleMembers(props: any) {
+export function RoleMembers() {
const { t } = useTranslation();
- const match = useRouteMatch<{ roleId: string }>();
+ const match = useMatch('admin/role/:roleId');
+ const roleId = match?.params.roleId as string;
const { users } = useSpaceUsers();
- const { members, getRoleMembers, loading } = useRoleMember(match.params.roleId);
+ const { members, getRoleMembers, loading } = useRoleMember(roleId);
const [visible, setVisible] = useState(false);
const [confirmLoading, setConfirmLoading] = useState(false);
- const userInfo = useContext(UserInfoContext)!;
+ const userInfo = useContext(UserInfoContext);
const [form] = useForm();
const isAllUser = members?.name.includes('All Users');
const { confirm } = Modal;
@@ -72,7 +73,7 @@ export function RoleMembers(props: any) {
const forbiddenEditRole =
members.name === 'All Users_1' ||
(members.name === 'Administrators_1' && members?.members.length <= 1) ||
- userInfo.name === record.name;
+ userInfo?.name === record.name;
return (
<FlatBtn disabled={forbiddenEditRole} onClick={() => handleDelete(record)}>
{t`remove`}
@@ -86,7 +87,7 @@ export function RoleMembers(props: any) {
setConfirmLoading(true);
const res = await RoleAPI.addMember({
user_ids: values.user,
- group_id: +match.params.roleId,
+ group_id: +roleId,
});
setConfirmLoading(false);
if (isSuccess(res)) {
diff --git a/frontend/src/routes/admin/people/role/role.tsx b/frontend/src/routes/admin/people/role/role.tsx
index 37c941d..c2d448e 100644
--- a/frontend/src/routes/admin/people/role/role.tsx
+++ b/frontend/src/routes/admin/people/role/role.tsx
@@ -15,20 +15,18 @@
// specific language governing permissions and limitations
// under the License.
-import React from 'react';
-import { Redirect, Route, Switch } from 'react-router-dom';
+import { Navigate, Route, Routes } from 'react-router-dom';
import { RoleList } from './list/list';
import { RoleMembers } from './member/member';
-export function Role(props: any) {
- const { match } = props;
+export function Role() {
return (
<>
- <Switch>
- <Route exact path={`${match.path}`} component={RoleList} />
- <Route path={`${match.path}/:roleId`} component={RoleMembers} />
- <Redirect to={`${match.path}`} />
- </Switch>
+ <Routes>
+ <Route path="list" element={<RoleList />} />
+ <Route path=":roleId" element={<RoleMembers />} />
+ <Route path="/" element={<Navigate replace to="list" />} />
+ </Routes>
</>
);
}
diff --git a/frontend/src/routes/cluster/cluster.tsx b/frontend/src/routes/cluster/cluster.tsx
index c5b43cc..a7413bf 100644
--- a/frontend/src/routes/cluster/cluster.tsx
+++ b/frontend/src/routes/cluster/cluster.tsx
@@ -15,9 +15,8 @@
// specific language governing permissions and limitations
// under the License.
-import React, { useEffect, useMemo, useState } from 'react';
-import { Steps } from 'antd';
-import { Switch, Route, Redirect, useRouteMatch } from 'react-router';
+import { useEffect, useMemo, useState } from 'react';
+import { Routes, Route, Navigate } from 'react-router';
import { useTranslation } from 'react-i18next';
import styles from './cluster.module.less';
import { UserInfoContext } from '@src/common/common.context';
@@ -28,8 +27,7 @@ import TabsHeader from '@src/components/tabs-header';
import { useUserInfo } from '@src/hooks/use-userinfo.hooks';
import LoadingLayout from '@src/components/loading-layout';
-export function Cluster(props: any) {
- // const match = useRouteMatch();
+export function Cluster() {
const { t } = useTranslation();
const [loading, setLoading] = useState(true);
const [userInfo] = useUserInfo();
@@ -50,12 +48,12 @@ export function Cluster(props: any) {
<div className={styles.container}>
<TabsHeader routes={tabRoutes} />
<LoadingLayout loading={loading} wrapperStyle={{ textAlign: 'center', marginTop: 200 }}>
- <Switch>
- <Route path="/cluster/overview" component={ClusterOverview} />
- <Route path="/cluster/nodes" component={Nodes} />
- <Route path="/cluster/configuration" component={Configuration} />
- <Redirect to="/cluster/overview" />
- </Switch>
+ <Routes>
+ <Route path="overview" element={<ClusterOverview />} />
+ <Route path="nodes" element={<Nodes />} />
+ <Route path="configuration" element={<Configuration />} />
+ <Route path="/" element={<Navigate replace to="overview" />} />
+ </Routes>
</LoadingLayout>
</div>
</UserInfoContext.Provider>
diff --git a/frontend/src/routes/cluster/list/list.tsx b/frontend/src/routes/cluster/list/list.tsx
deleted file mode 100644
index 65d92d4..0000000
--- a/frontend/src/routes/cluster/list/list.tsx
+++ /dev/null
@@ -1,65 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements. See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership. The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License. You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing,
-// software distributed under the License is distributed on an
-// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-// KIND, either express or implied. See the License for the
-// specific language governing permissions and limitations
-// under the License.
-
-import { Button, PageHeader, Row, Space, Table } from 'antd';
-import React from 'react';
-import { useHistory, useRouteMatch } from 'react-router';
-
-export function ClusterList(props: any) {
- const history = useHistory();
- const match = useRouteMatch();
- const columns = [
- {
- title: '集群',
- dataIndex: 'cluster',
- key: 'cluster',
- },
- {
- title: '创建时间',
- dataIndex: 'createTime',
- key: 'createTime',
- },
- {
- title: '状态',
- dataIndex: 'status',
- key: 'status',
- },
- {
- title: '链接信息',
- dataIndex: 'connect_info',
- key: 'connect_info',
- },
- ];
- const [clusterList, setClusterList] = React.useState([]);
- return (
- <div style={{ padding: '0 20px', backgroundColor: 'white', marginTop: 20, minHeight: 'calc(100% - 60px)' }}>
- <PageHeader className="site-page-header" title="集群列表" style={{ paddingLeft: 0 }} />
- <Row justify="end" style={{marginBottom: 20}}>
- <Space>
- <Button type="primary" onClick={() => history.push(`/cluster/new`)}>新建集群</Button>
- <Button type="primary">接入集群</Button>
- </Space>
- </Row>
- <Table
- columns={columns}
- dataSource={clusterList}
- rowKey={(record: any[]) => record[Object.keys(record).length - 1]}
- size="middle"
- />
- </div>
- );
-}
diff --git a/frontend/src/routes/container.tsx b/frontend/src/routes/container.tsx
index 449a266..d9ffa91 100644
--- a/frontend/src/routes/container.tsx
+++ b/frontend/src/routes/container.tsx
@@ -15,62 +15,41 @@
// specific language governing permissions and limitations
// under the License.
-import React from 'react';
import styles from './container.less';
import { Layout } from 'antd';
-import { Redirect, Route, Router, Switch, useHistory } from 'react-router-dom';
+import { Navigate, Route, Routes } from 'react-router-dom';
import { Sidebar } from '@src/components/sidebar/sidebar';
import { Header } from '@src/components/header/header';
-import { CommonAPI } from '@src/common/common.api';
import { UserInfoContext } from '@src/common/common.context';
-import { UserInfo } from '@src/common/common.interface';
-import { Dashboard } from './dashboard/dashboard';
import { Meta } from './meta/meta';
-import { NodeDashboard } from './node/dashboard';
-import {NodeList} from './node/list';
-import { Configuration } from './node/list/configuration';
-import { FEConfiguration } from './node/list/fe-configuration';
-import { BEConfiguration } from './node/list/be-configuration';
-import { Query } from './query';
-import { QueryDetails } from './query/query-details';
import { Cluster } from './cluster/cluster';
import { UserSetting } from './user-setting';
import { useUserInfo } from '@src/hooks/use-userinfo.hooks';
import VisualQuery from './visual-query/visual-query';
-export function Container(props: any) {
+
+export function Container() {
const [userInfo] = useUserInfo();
- const history = useHistory();
return (
- <Router history={history}>
- <UserInfoContext.Provider value={userInfo}>
- <Layout style={{ height: '100vh' }}>
- <Layout>
- <Sidebar width={200} />
- <div className={styles['container']}>
- <Header mode="normal"></Header>
- <div className={styles['container-content']}>
- <Switch>
- <Route path="/dashboard" component={Dashboard} />
- <Route path="/meta" component={Meta} />
- <Route path="/cluster" component={Cluster} />
- <Route path="/list" component={NodeList} />
- <Route path="/configuration/fe" component={FEConfiguration} />
- <Route path="/configuration/be" component={BEConfiguration} />
- <Route path="/configuration" component={Configuration} />
- <Route path="/node-dashboard" component={NodeDashboard} />
- {/* <Route path="/query" component={Query} /> */}
- <Route path="/details/:queryId" component={QueryDetails} />
- <Route path="/user-setting" component={UserSetting} />
- <Route path="/visual-query" component={VisualQuery} />
- <Redirect to="/cluster" />
- </Switch>
- </div>
+ <UserInfoContext.Provider value={userInfo}>
+ <Layout style={{ height: '100vh' }}>
+ <Layout>
+ <Sidebar width={200} />
+ <div className={styles['container']}>
+ <Header mode="normal"></Header>
+ <div className={styles['container-content']}>
+ <Routes>
+ <Route path="/meta/*" element={<Meta />} />
+ <Route path="/cluster/*" element={<Cluster />} />
+ <Route path="/user-setting/*" element={<UserSetting />} />
+ <Route path="/visual-query/*" element={<VisualQuery />} />
+ <Route path="/" element={<Navigate replace to="meta" />} />
+ </Routes>
</div>
- </Layout>
+ </div>
</Layout>
- </UserInfoContext.Provider>
- </Router>
+ </Layout>
+ </UserInfoContext.Provider>
);
}
diff --git a/frontend/src/routes/dashboard/components/dashboard-item/index.tsx b/frontend/src/routes/dashboard/components/dashboard-item/index.tsx
deleted file mode 100644
index f6af493..0000000
--- a/frontend/src/routes/dashboard/components/dashboard-item/index.tsx
+++ /dev/null
@@ -1,37 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements. See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership. The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License. You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing,
-// software distributed under the License is distributed on an
-// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-// KIND, either express or implied. See the License for the
-// specific language governing permissions and limitations
-// under the License.
-
-import CSSModules from 'react-css-modules';
-import React, { useCallback, useState } from 'react';
-import styles from './message-item.less';
-import { messItemProps } from './message-item.interface';
-
-function MessageItem(props: messItemProps) {
- return (
- <div styleName="mess-item">
- <div styleName="mess-item-title">
- <p styleName="mess-item-icon">{props.icon}</p>
- <p styleName="mess-item-name">{props.title}</p>
- </div>
- <div styleName="mess-item-content">
- <span>{props.des}</span>
- </div>
- </div>
- );
-}
-
-export const DashboardItem = CSSModules(styles)(MessageItem);
diff --git a/frontend/src/routes/dashboard/components/dashboard-item/message-item.interface.ts b/frontend/src/routes/dashboard/components/dashboard-item/message-item.interface.ts
deleted file mode 100644
index 89bff2b..0000000
--- a/frontend/src/routes/dashboard/components/dashboard-item/message-item.interface.ts
+++ /dev/null
@@ -1,23 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements. See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership. The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License. You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing,
-// software distributed under the License is distributed on an
-// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-// KIND, either express or implied. See the License for the
-// specific language governing permissions and limitations
-// under the License.
-
-/** @format */
-export interface messItemProps {
- title: string;
- icon: any;
- des: number | string;
-}
diff --git a/frontend/src/routes/dashboard/connect-info/connect-info.less b/frontend/src/routes/dashboard/connect-info/connect-info.less
deleted file mode 100644
index 1b25c82..0000000
--- a/frontend/src/routes/dashboard/connect-info/connect-info.less
+++ /dev/null
@@ -1,23 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements. See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership. The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License. You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing,
-// software distributed under the License is distributed on an
-// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-// KIND, either express or implied. See the License for the
-// specific language governing permissions and limitations
-// under the License.
-
-.connect-info-container {
- display: flex;
- flex-wrap: wrap;
- justify-content: space-between;
- padding: 0 3px 3px 0;
-}
\ No newline at end of file
diff --git a/frontend/src/routes/dashboard/connect-info/connect-info.tsx b/frontend/src/routes/dashboard/connect-info/connect-info.tsx
deleted file mode 100644
index 6d6aef9..0000000
--- a/frontend/src/routes/dashboard/connect-info/connect-info.tsx
+++ /dev/null
@@ -1,68 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements. See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership. The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License. You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing,
-// software distributed under the License is distributed on an
-// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-// KIND, either express or implied. See the License for the
-// specific language governing permissions and limitations
-// under the License.
-
-import CSSModules from 'react-css-modules';
-import React, { useEffect, useState } from 'react';
-import { useTranslation } from 'react-i18next';
-import styles from './connect-info.less';
-import { Card, message } from 'antd';
-import { DashboardAPI } from '../dashboard.api';
-
-export function Component(props: any) {
- const { t } = useTranslation();
- const [spaceList, setSpaceList] = useState<any>({});
- const [https, setHttps] = useState<any>([]);
- const [mysqls, setMysqls] = useState<any>([]);
- useEffect(() => {
- getOverviewInfo();
- }, []);
- async function getOverviewInfo() {
- DashboardAPI.getSpaceList().then(res1 => {
- const { msg, data, code } = res1;
- let http = '';
- let mysql = '';
- if (code === 0) {
- if (res1.data) {
- setSpaceList(res1.data);
- for (let i = 0; i < res1.data.http.length; i++) {
- http += res1.data.http[i] + '; ';
- }
- for (let i = 0; i < res1.data.mysql.length; i++) {
- mysql += res1.data.mysql[i] + '; ';
- }
- setHttps(http);
- setMysqls(mysql);
- }
- } else if (code === 404) {
- message.error(t`updateDoris`);
- window.location.href = `${window.location.origin}`;
- } else {
- message.error(msg);
- }
- });
- }
- return (
- <div styleName="connect-info-container">
- <Card style={{ width: '100%' }}>
- <p>{t`httpInfo`} {https}</p>
- <p>{t`JDBCInfo`} {mysqls}</p>
- </Card>
- </div>
- );
-}
-
-export const ConnectInfo = CSSModules(styles)(Component);
diff --git a/frontend/src/routes/dashboard/dashboard.api.ts b/frontend/src/routes/dashboard/dashboard.api.ts
deleted file mode 100644
index 6750f5b..0000000
--- a/frontend/src/routes/dashboard/dashboard.api.ts
+++ /dev/null
@@ -1,31 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements. See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership. The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License. You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing,
-// software distributed under the License is distributed on an
-// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-// KIND, either express or implied. See the License for the
-// specific language governing permissions and limitations
-// under the License.
-
-import { http } from '@src/utils/http';
-import { IResult } from '@src/interfaces/http.interface';
-import { MetaInfoResponse } from './dashboard.interface';
-
-function getMetaInfo(): Promise<IResult<MetaInfoResponse>> {
- return http.get(`/api/cluster/overview`);
-}
-function getSpaceList() {
- return http.get(`/api/rest/v2/manager/cluster/cluster_info/conn_info`);
-}
-export const DashboardAPI = {
- getMetaInfo,
- getSpaceList,
-};
diff --git a/frontend/src/routes/dashboard/dashboard.data.ts b/frontend/src/routes/dashboard/dashboard.data.ts
deleted file mode 100644
index d225780..0000000
--- a/frontend/src/routes/dashboard/dashboard.data.ts
+++ /dev/null
@@ -1,21 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements. See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership. The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License. You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing,
-// software distributed under the License is distributed on an
-// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-// KIND, either express or implied. See the License for the
-// specific language governing permissions and limitations
-// under the License.
-
-export enum DashboardTabEnum {
- Overview = 'overview',
- ConnectInfo = 'connect-info',
-}
\ No newline at end of file
diff --git a/frontend/src/routes/dashboard/dashboard.interface.ts b/frontend/src/routes/dashboard/dashboard.interface.ts
deleted file mode 100644
index 8522a6f..0000000
--- a/frontend/src/routes/dashboard/dashboard.interface.ts
+++ /dev/null
@@ -1,33 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements. See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership. The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License. You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing,
-// software distributed under the License is distributed on an
-// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-// KIND, either express or implied. See the License for the
-// specific language governing permissions and limitations
-// under the License.
-
-import { RouteComponentProps } from 'react-router';
-
-export interface DashboardProps extends RouteComponentProps<any> {
-
-}
-export interface GetMetaInfoRequestParams {
- nsId: string;
-}
-export interface MetaInfoResponse {
- beCount: number;
- dbCount: number;
- diskOccupancy: number;
- feCount: number;
- remainDisk: number;
- tblCount: number;
-}
diff --git a/frontend/src/routes/dashboard/dashboard.less b/frontend/src/routes/dashboard/dashboard.less
deleted file mode 100644
index 27bd9ed..0000000
--- a/frontend/src/routes/dashboard/dashboard.less
+++ /dev/null
@@ -1,27 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements. See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership. The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License. You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing,
-// software distributed under the License is distributed on an
-// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-// KIND, either express or implied. See the License for the
-// specific language governing permissions and limitations
-// under the License.
-
-/** @format */
-
-.home-main {
- background: #f9fbfc;
- border-radius: 16px;
-
- .home-content {
- padding: 0 38px 15px;
- }
-}
diff --git a/frontend/src/routes/dashboard/dashboard.tsx b/frontend/src/routes/dashboard/dashboard.tsx
deleted file mode 100644
index fd1c014..0000000
--- a/frontend/src/routes/dashboard/dashboard.tsx
+++ /dev/null
@@ -1,75 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements. See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership. The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License. You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing,
-// software distributed under the License is distributed on an
-// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-// KIND, either express or implied. See the License for the
-// specific language governing permissions and limitations
-// under the License.
-
-import CSSModules from 'react-css-modules';
-import React, { useState } from 'react';
-import styles from './dashboard.less';
-import { CommonHeader } from '@src/components/common-header/header';
-import { ConnectInfo } from './connect-info/connect-info';
-import { DashboardTabEnum } from './dashboard.data';
-import { HomeOutlined } from '@ant-design/icons';
-import { Link, match, Redirect, Route, Switch, useHistory, useLocation } from 'react-router-dom';
-import { Overview } from './overview/overview';
-import { Tabs } from 'antd';
-import { useTranslation } from 'react-i18next';
-
-const ICON_HOME = <HomeOutlined />;
-const { TabPane } = Tabs;
-
-function DashboardComponent(props: any) {
- const { match } = props;
- const { t } = useTranslation();
- const [refreshToken, setRefreshToken] = useState(new Date().getTime());
- const history = useHistory();
- const location = useLocation();
- const [activeKey, setTabsActiveKey] = useState<DashboardTabEnum>(DashboardTabEnum.Overview);
- React.useEffect( ()=>{
- if(location.pathname.includes(DashboardTabEnum.ConnectInfo)) {
- setTabsActiveKey(DashboardTabEnum.ConnectInfo);
- } else {
- setTabsActiveKey(DashboardTabEnum.Overview);
- }
- }, [])
- return (
- <div styleName="home-main">
- <CommonHeader
- title={t`dataWarehouse`}
- icon={ICON_HOME}
- callback={() => setRefreshToken(new Date().getTime())}
- ></CommonHeader>
- <div styleName="home-content">
- <Tabs activeKey={activeKey} onChange={(key: any) => {
- setTabsActiveKey(key);
- if (key === DashboardTabEnum.Overview) {
- history.push(`${match.path}/overview`);
- } else {
- history.push(`${match.path}/connect-info`);
- }
- }}>
- <TabPane tab={t`ClusterIinformationOverview`} key={DashboardTabEnum.Overview}></TabPane>
- <TabPane tab={t`ConnectionInformation`} key={DashboardTabEnum.ConnectInfo}></TabPane>
- </Tabs>
- </div>
- <Switch>
- <Route path={`${match.path}/overview`} component={Overview} />
- <Route path={`${match.path}/connect-info`} component={ConnectInfo} />
- <Redirect to={`${match.path}/overview`} />
- </Switch>
- </div>
- );
-}
-export const Dashboard = CSSModules(styles)(DashboardComponent);
diff --git a/frontend/src/routes/dashboard/overview/overview.less b/frontend/src/routes/dashboard/overview/overview.less
deleted file mode 100644
index 93c5539..0000000
--- a/frontend/src/routes/dashboard/overview/overview.less
+++ /dev/null
@@ -1,23 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements. See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership. The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License. You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing,
-// software distributed under the License is distributed on an
-// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-// KIND, either express or implied. See the License for the
-// specific language governing permissions and limitations
-// under the License.
-
-.overview-container {
- display: flex;
- flex-wrap: wrap;
- justify-content: space-between;
- margin: 0 40px;
-}
\ No newline at end of file
diff --git a/frontend/src/routes/dashboard/overview/overview.tsx b/frontend/src/routes/dashboard/overview/overview.tsx
deleted file mode 100644
index d8c0559..0000000
--- a/frontend/src/routes/dashboard/overview/overview.tsx
+++ /dev/null
@@ -1,69 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements. See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership. The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License. You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing,
-// software distributed under the License is distributed on an
-// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-// KIND, either express or implied. See the License for the
-// specific language governing permissions and limitations
-// under the License.
-
-import CSSModules from 'react-css-modules';
-import React, { useEffect, useState } from 'react';
-import styles from './overview.less';
-import { useTranslation } from 'react-i18next';
-import { DashboardAPI } from '../dashboard.api';
-import { DashboardItem } from '../components/dashboard-item';
-import { HddOutlined, LaptopOutlined, PieChartOutlined, TableOutlined } from '@ant-design/icons';
-import { message } from 'antd';
-import { MetaInfoResponse } from '../dashboard.interface';
-
-export function Component(props: any) {
- const { t } = useTranslation();
- const [metaInfo, setMetaInfo] = useState<MetaInfoResponse>({
- beCount: 0,
- dbCount: 0,
- diskOccupancy: 0,
- feCount: 0,
- remainDisk: 0,
- tblCount: 0,
- });
- useEffect(() => {
- getOverviewInfo();
- }, []);
- async function getOverviewInfo() {
- const res = await DashboardAPI.getMetaInfo();
- const { msg, data, code } = res;
- if (code === 0) {
- if (res.data) {
- res.data.remainDisk = res.data.remainDisk / 1024;
- setMetaInfo(res.data);
- }
- } else {
- message.error(msg);
- }
- }
- return (
- <div styleName="overview-container">
- <DashboardItem title={t`DatabseNum`} icon={<HddOutlined />} des={metaInfo.dbCount} />
- <DashboardItem title={t`DataTableNum`} icon={<TableOutlined />} des={metaInfo.tblCount} />
- <DashboardItem
- title={t`DiskUsage`}
- icon={<PieChartOutlined />}
- des={
- metaInfo.diskOccupancy == 0 ? metaInfo.diskOccupancy + '%' : metaInfo.diskOccupancy.toFixed(2) + '%'
- }
- />
- <DashboardItem title={t`RemainingDiskSpace`} icon={<LaptopOutlined />} des={metaInfo.remainDisk.toFixed(2) + 'TB'} />
- </div>
- );
-}
-
-export const Overview = CSSModules(styles)(Component);
diff --git a/frontend/src/routes/database/index.tsx b/frontend/src/routes/database/index.tsx
index 2edf4a8..85e05a4 100644
--- a/frontend/src/routes/database/index.tsx
+++ b/frontend/src/routes/database/index.tsx
@@ -15,13 +15,10 @@
// specific language governing permissions and limitations
// under the License.
-/** @format */
-
-import React, { useState, useEffect } from 'react';
+import { useState, useEffect } from 'react';
import styles from './database.module.less';
import CSSModules from 'react-css-modules';
-import { useHistory } from 'react-router-dom';
-import { Layout, Form, Tabs, Button, message } from 'antd';
+import { Layout, Form, Tabs, message } from 'antd';
import { HddOutlined } from '@ant-design/icons';
import { CommonHeader } from '@src/components/common-header/header';
import { DatabaseAPI } from './database.api';
@@ -29,7 +26,7 @@ import { DatabaseInfoResponse } from './database.interface';
import { useTranslation } from 'react-i18next';
import { getShowTime } from '@src/utils/utils';
-const { Content, Sider } = Layout;
+const { Content } = Layout;
const iconDatabase = <HddOutlined />;
const { TabPane } = Tabs;
const layout = {
@@ -38,7 +35,6 @@ const layout = {
};
function Database(props: any) {
- const history = useHistory();
const { t } = useTranslation();
const [dbName, setDbName] = useState<any>('');
const [databaseInfo, setDatabaseInfo] = useState<DatabaseInfoResponse>({
@@ -58,7 +54,7 @@ function Database(props: any) {
}
setDbName(name);
DatabaseAPI.getDatabaseInfo({ dbId: id }).then(res => {
- const { msg, code, data } = res;
+ const { msg, code } = res;
if (code === 0) {
setDatabaseInfo(res.data);
} else {
@@ -78,7 +74,9 @@ function Database(props: any) {
<Form.Item label={t`DatabaseDescriptionInformation`}>
{databaseInfo.describe ? databaseInfo.describe : '-'}
</Form.Item>
- <Form.Item label={t`CreationTime`}>{getShowTime(databaseInfo.createTime) ? getShowTime(databaseInfo.createTime) : '-'}</Form.Item>
+ <Form.Item label={t`CreationTime`}>
+ {getShowTime(databaseInfo.createTime) ? getShowTime(databaseInfo.createTime) : '-'}
+ </Form.Item>
</Form>
</div>
</TabPane>
diff --git a/frontend/src/routes/initialize/auths/auth.tsx b/frontend/src/routes/initialize/auths/auth.tsx
index df04116..e351d71 100644
--- a/frontend/src/routes/initialize/auths/auth.tsx
+++ b/frontend/src/routes/initialize/auths/auth.tsx
@@ -15,18 +15,16 @@
// specific language governing permissions and limitations
// under the License.
-import React from "react";
-import { Redirect, Route, Switch, useRouteMatch } from "react-router";
-import { AuthLDAP } from "./ldap/ldap";
-import { AuthStudio } from "./studio/studio";
+import { Navigate, Route, Routes } from 'react-router';
+import { AuthLocal } from './local/local';
-export function InitializeAuth(props: any) {
- const match = useRouteMatch();
+export function InitializeAuth() {
return (
- <Switch>
- <Route path={`${match.path}/ldap`} component={AuthLDAP} />
- <Route path={`${match.path}/studio`} component={AuthStudio} />
- <Redirect to={`${match.path}/studio`} />
- </Switch>
- )
+ <>
+ <Routes>
+ <Route path="local/*" element={<AuthLocal />} />
+ <Route path="/" element={<Navigate replace to="local" />} />
+ </Routes>
+ </>
+ );
}
diff --git a/frontend/src/routes/initialize/auths/components/admin-user/admin-user.tsx b/frontend/src/routes/initialize/auths/components/admin-user/admin-user.tsx
index e42479d..54db3ab 100644
--- a/frontend/src/routes/initialize/auths/components/admin-user/admin-user.tsx
+++ b/frontend/src/routes/initialize/auths/components/admin-user/admin-user.tsx
@@ -18,21 +18,16 @@
import { InitializeAPI } from '@src/routes/initialize/initialize.api';
import { isSuccess } from '@src/utils/http';
import { Form, Input, Button, message } from 'antd';
-import { useForm } from 'antd/lib/form/Form';
-import React from 'react';
-import { RouteProps, useHistory, useRouteMatch } from 'react-router';
+import { useNavigate } from 'react-router';
import styles from './admin-user.less';
-interface AdminUserProps extends RouteProps {}
-export function AdminUser(props: AdminUserProps) {
- const [form] = useForm();
- const history = useHistory();
- const match = useRouteMatch();
+export function AdminUser() {
+ const navigate = useNavigate();
async function onFinish(values: any) {
- const { password_confirm, username, ...params } = values;
+ const { username, ...params } = values;
const res = await InitializeAPI.setAdmin({ ...params, name: username });
if (isSuccess(res)) {
- history.push('/initialize/auth/studio/finish');
+ navigate('/initialize/auth/local/finish');
} else {
message.error(res.msg);
}
@@ -40,13 +35,7 @@ export function AdminUser(props: AdminUserProps) {
return (
<div className={styles['admin-user']}>
- <Form
- name="basic"
- layout="vertical"
- onFinish={onFinish}
- // onFinishFailed={onFinishFailed}
- autoComplete="off"
- >
+ <Form name="basic" layout="vertical" onFinish={onFinish} autoComplete="off">
<Form.Item
label="Admin用户名"
tooltip="用于访问Palo Studio最高级管理员权限"
diff --git a/frontend/src/routes/initialize/auths/components/finish/finish.tsx b/frontend/src/routes/initialize/auths/components/finish/finish.tsx
index 725868b..96c9af5 100644
--- a/frontend/src/routes/initialize/auths/components/finish/finish.tsx
+++ b/frontend/src/routes/initialize/auths/components/finish/finish.tsx
@@ -16,21 +16,24 @@
// under the License.
import { Result, Button } from 'antd';
-import React from 'react';
-import { useHistory } from 'react-router';
+import { useNavigate } from 'react-router';
export function AuthFinish(props: any) {
- const history = useHistory();
+ const navigate = useNavigate();
const authType = props.mode === 'ldap' ? 'LDAP' : '本地';
return (
<Result
status="success"
title={`恭喜!${authType}认证完成!`}
extra={[
- <Button type="primary" key="go-login" onClick={() => {
- localStorage.setItem('initialized', 'true');
- history.push('/passport/login');
- }}>
+ <Button
+ type="primary"
+ key="go-login"
+ onClick={() => {
+ localStorage.setItem('initialized', 'true');
+ navigate('/passport/login');
+ }}
+ >
跳转至登录页面
</Button>,
]}
diff --git a/frontend/src/routes/initialize/auths/ldap/ldap-admin-user/ldap-admin-user.tsx b/frontend/src/routes/initialize/auths/ldap/ldap-admin-user/ldap-admin-user.tsx
deleted file mode 100644
index 8af8002..0000000
--- a/frontend/src/routes/initialize/auths/ldap/ldap-admin-user/ldap-admin-user.tsx
+++ /dev/null
@@ -1,75 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements. See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership. The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License. You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing,
-// software distributed under the License is distributed on an
-// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-// KIND, either express or implied. See the License for the
-// specific language governing permissions and limitations
-// under the License.
-
-import { InitializeAPI } from '@src/routes/initialize/initialize.api';
-import { isSuccess } from '@src/utils/http';
-import { Form, Button, message, Select, Space } from 'antd';
-import React from 'react';
-import { RouteProps, useHistory } from 'react-router';
-import { useLDAPUsers } from './use-ldap-user.hooks';
-const { Option } = Select;
-
-interface AdminUserProps extends RouteProps {}
-
-export function LDAPAdminUser(props: AdminUserProps) {
- const history = useHistory();
- const { ldapUsers } = useLDAPUsers();
- async function onFinish(values: any) {
- const { username } = values;
- const res = await InitializeAPI.setAdmin({ name: username });
- if (isSuccess(res)) {
- history.push('/initialize/auth/ldap/finish');
- } else {
- message.error(res.msg);
- }
- }
-
- return (
- <div>
- <Form name="basic" layout="vertical" onFinish={onFinish} autoComplete="off">
- <Form.Item
- label="选择超级管理员"
- tooltip="用于访问Palo Studio最高级管理员权限"
- name="username"
- rules={[{ required: true, message: '请选择超级管理员' }]}
- >
- <Select showSearch={true} placeholder="请选择超级管理员" allowClear optionFilterProp="filter" optionLabelProp="title">
- {ldapUsers?.map(user => (
- <Option
- key={user.id}
- value={user.id}
- title={user.name}
- filter={user.name}
- >
- <Space>
- <strong>{user.name}</strong>
- {user.email && <span>({user.email})</span>}
- </Space>
- </Option>
- ))}
- </Select>
- </Form.Item>
-
- <Form.Item>
- <Button type="primary" htmlType="submit">
- 保存
- </Button>
- </Form.Item>
- </Form>
- </div>
- );
-}
diff --git a/frontend/src/routes/initialize/auths/ldap/ldap-config/ldap-config.tsx b/frontend/src/routes/initialize/auths/ldap/ldap-config/ldap-config.tsx
deleted file mode 100644
index e1bb5fb..0000000
--- a/frontend/src/routes/initialize/auths/ldap/ldap-config/ldap-config.tsx
+++ /dev/null
@@ -1,152 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements. See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership. The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License. You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing,
-// software distributed under the License is distributed on an
-// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-// KIND, either express or implied. See the License for the
-// specific language governing permissions and limitations
-// under the License.
-
-import { InitializeAPI } from '@src/routes/initialize/initialize.api';
-import { isSuccess } from '@src/utils/http';
-import { Form, Input, Button, message, Radio, InputNumber } from 'antd';
-import React, { useState } from 'react';
-import { useHistory } from 'react-router';
-
-export function LDAPConfig(props: any) {
- const history = useHistory();
- const [loading, setLoading] = useState(false);
-
- async function onFinish(values: any) {
- const { password_confirm, username, ...params } = values;
- setLoading(true);
- const res = await InitializeAPI.setLDAP({
- authType: 'ldap',
- ldapSetting: {
- ...values,
- ['ldap-user-base']: [values['ldap-user-base']],
- },
- });
- setLoading(false);
- if (isSuccess(res)) {
- console.log(res);
- history.push('/initialize/auth/ldap/ldap-info');
- } else {
- message.error(res.msg);
- history.push('/initialize/auth/ldap/admin-user');
- }
- }
- return (
- <div style={{ paddingBottom: 40 }}>
- <h2>服务器</h2>
- <Form
- name="ldap_server"
- layout="vertical"
- onFinish={onFinish}
- autoComplete="off"
- >
- <Form.Item
- label="LDAP主机"
- tooltip="服务器主机名"
- name="ldap-host"
- rules={[{ required: true, message: '请输入LDAP服务器主机名' }]}
- >
- <Input placeholder="请输入LDAP服务器主机名" />
- </Form.Item>
-
- <Form.Item
- name="ldap-port"
- label="LDAP端口"
- rules={[{ required: true, message: '请输入LDAP端口' }]}
- tooltip="服务器端口,如果使用SSL,端口号通常为389或636"
- >
- <InputNumber min={0} placeholder="389" />
- </Form.Item>
- <Form.Item label="LDAP安全性" name="ldap-security" required>
- <Radio.Group>
- <Radio.Button value="none">None</Radio.Button>
- <Radio.Button value="ssl">SSL</Radio.Button>
- <Radio.Button value="startTLS">StartTLS</Radio.Button>
- </Radio.Group>
- </Form.Item>
- <Form.Item
- label="用户名或DN"
- tooltip="LDAP中管理员用户名(Distinguished Name),Studio将使用管理员账号查找其他用户信息"
- name="ldap-bind-dn"
- required
- rules={[{ required: true, message: '请输入用户名或DN' }]}
- >
- <Input placeholder="请输入LDAP服务器主机名" />
- </Form.Item>
- <Form.Item
- name="ldap-password"
- rules={[{ required: true, message: '请输入密码' }]}
- tooltip="对应管理员登录LDAP的密码"
- label="密码"
- required
- >
- <Input type="password" placeholder="请输入密码" />
- </Form.Item>
- {/* </Form> */}
- <h2>用户结构</h2>
- {/* <Form name="ldap_user" layout="vertical" onFinish={onFinish} autoComplete="off"> */}
- <Form.Item
- label="用户搜索库"
- tooltip="LDAP中的搜索基础(将采用递归检索)"
- name="ldap-user-base"
- rules={[{ required: true, message: '请输入用户搜索库' }]}
- >
- <Input placeholder="ou=users,dc=example,dc=org" />
- </Form.Item>
- <Form.Item
- label="用户筛选"
- tooltip="LDAP中的用户查询筛选,占位符'{Login}'将被用户提供的登录信息替换"
- name="ldap-user-filter"
- rules={[{ required: true, message: '请输入用户筛选' }]}
- >
- <Input placeholder="objectClass=inetOrgPerson" />
- </Form.Item>
- {/* </Form> */}
- <h2>属性</h2>
- {/* <Form name="ldap_attribute" layout="vertical" onFinish={onFinish} autoComplete="off"> */}
- <Form.Item
- label="电子邮件属性"
- tooltip="LDAP中用户的'Email'属性。(通常是'mail', 'email' or 'userPrincipalName')"
- name="ldap-attribute-email"
- rules={[{ required: true, message: '请输入电子邮件属性' }]}
- >
- <Input placeholder="Mail" />
- </Form.Item>
- <Form.Item
- label="名字属性"
- tooltip="LDAP中用户的'Last name'属性(通常是‘SN’)"
- name="ldap-attribute-lastname"
- rules={[{ required: true, message: '请输入名字属性' }]}
- >
- <Input placeholder="uid" />
- </Form.Item>
- <Form.Item
- label="姓氏属性"
- tooltip="LDAP中用户的'First name'属性(通常是‘givenName’)"
- name="ldap-attribute-firstname"
- rules={[{ required: true, message: '请输入姓氏属性' }]}
- >
- <Input placeholder="sn" />
- </Form.Item>
- <Form.Item>
- <Button loading={loading} type="primary" htmlType="submit">
- 保存
- </Button>
- </Form.Item>
- </Form>
- </div>
- );
-}
diff --git a/frontend/src/routes/initialize/auths/ldap/ldap.tsx b/frontend/src/routes/initialize/auths/ldap/ldap.tsx
deleted file mode 100644
index f90c848..0000000
--- a/frontend/src/routes/initialize/auths/ldap/ldap.tsx
+++ /dev/null
@@ -1,55 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements. See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership. The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License. You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing,
-// software distributed under the License is distributed on an
-// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-// KIND, either express or implied. See the License for the
-// specific language governing permissions and limitations
-// under the License.
-
-import { Steps } from "antd";
-import { pathToRegexp } from "path-to-regexp";
-import React, { useEffect, useState } from "react";
-import { Redirect, Route, Switch, useHistory, useRouteMatch } from "react-router";
-import { LDAPStepsEnum } from "../../initialize.data";
-import { AuthFinish } from "../components/finish/finish";
-import { LDAPAdminUser } from "./ldap-admin-user/ldap-admin-user";
-import { LDAPConfig } from "./ldap-config/ldap-config";
-const { Step } = Steps;
-
-export function AuthLDAP(props: any) {
- const match = useRouteMatch();
- const [step, setStep] = useState(LDAPStepsEnum['ldap-info']);
- const history = useHistory();
- useEffect(() => {
- const regexp = pathToRegexp(`${match.path}/:step`);
- const paths = regexp.exec(history.location.pathname);
- const step = (paths as string[])[1];
- setStep(LDAPStepsEnum[step]);
- }, [history.location.pathname]);
- return (
- <div>
- <Steps current={step}>
- <Step title="LDAP认证" />
- <Step title="指定超级管理员" />
- <Step title="完成" />
- </Steps>
- <div style={{marginTop: 60}}>
- <Switch>
- <Route path={`${match.path}/ldap-info`} component={LDAPConfig} />
- <Route path={`${match.path}/admin-user`} component={LDAPAdminUser} />
- <Route path={`${match.path}/finish`} render={() => <AuthFinish mode="ldap" />} />
- <Redirect to={`${match.path}/ldap-info`} />
- </Switch>
- </div>
- </div>
- )
-}
diff --git a/frontend/src/routes/initialize/auths/local/local.tsx b/frontend/src/routes/initialize/auths/local/local.tsx
new file mode 100644
index 0000000..e61285c
--- /dev/null
+++ b/frontend/src/routes/initialize/auths/local/local.tsx
@@ -0,0 +1,53 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+import { Steps } from 'antd';
+import { useEffect, useState } from 'react';
+import { Navigate, Route, Routes, useLocation, useMatch } from 'react-router';
+import { LocalStepsEnum } from '../../initialize.data';
+import { AdminUser } from '../components/admin-user/admin-user';
+import { AuthFinish } from '../components/finish/finish';
+
+const { Step } = Steps;
+
+export function AuthLocal() {
+ const match = useMatch('/initialize/auth/:authType/:step');
+ const [step, setStep] = useState(LocalStepsEnum['admin-user']);
+
+ const location = useLocation();
+
+ useEffect(() => {
+ const step = match?.params.step as string;
+ setStep(LocalStepsEnum[step]);
+ }, [location.pathname]);
+
+ return (
+ <>
+ <Steps current={step}>
+ <Step title="本地认证" />
+ <Step title="完成" />
+ </Steps>
+ <div style={{ marginTop: 80 }}>
+ <Routes>
+ <Route path="admin-user" element={<AdminUser />} />
+ <Route path="finish" element={<AuthFinish />} />
+ <Route path="/" element={<Navigate replace to="admin-user" />} />
+ </Routes>
+ </div>
+ </>
+ );
+}
diff --git a/frontend/src/routes/initialize/auths/studio/studio.tsx b/frontend/src/routes/initialize/auths/studio/studio.tsx
deleted file mode 100644
index da2fbc5..0000000
--- a/frontend/src/routes/initialize/auths/studio/studio.tsx
+++ /dev/null
@@ -1,55 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements. See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership. The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License. You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing,
-// software distributed under the License is distributed on an
-// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-// KIND, either express or implied. See the License for the
-// specific language governing permissions and limitations
-// under the License.
-
-import { Steps } from "antd";
-import React, { useEffect, useState } from "react";
-import { Redirect, Route, Switch, useHistory, useRouteMatch } from "react-router";
-import { pathToRegexp } from 'path-to-regexp';
-import { StudioStepsEnum } from "../../initialize.data";
-import { AdminUser } from "../components/admin-user/admin-user";
-import { AuthFinish } from "../components/finish/finish";
-
-const { Step } = Steps;
-
-export function AuthStudio(props: any) {
- const match = useRouteMatch();
- const [step, setStep] = useState(StudioStepsEnum['admin-user']);
- const history = useHistory();
- useEffect(() => {
- const regexp = pathToRegexp(`${match.path}/:step`);
- const paths = regexp.exec(history.location.pathname);
- const step = (paths as string[])[1];
- setStep(StudioStepsEnum[step]);
- }, [history.location.pathname]);
- return (
- <div>
- <Steps current={step}>
- <Step title="本地认证" />
- <Step title="完成" />
- </Steps>
- <div style={{marginTop: 80}}>
- <Switch>
- <Route path={`${match.path}/admin-user`} component={AdminUser} />
- <Route path={`${match.path}/finish`} render={() => <AuthFinish mode="studio" />} />
- <Redirect to={`${match.path}/admin-user`} />
- </Switch>
- </div>
- </div>
- )
-}
-
-
diff --git a/frontend/src/routes/initialize/initialize.tsx b/frontend/src/routes/initialize/initialize-set-type.tsx
similarity index 70%
copy from frontend/src/routes/initialize/initialize.tsx
copy to frontend/src/routes/initialize/initialize-set-type.tsx
index 50d783a..2a004c5 100644
--- a/frontend/src/routes/initialize/initialize.tsx
+++ b/frontend/src/routes/initialize/initialize-set-type.tsx
@@ -17,20 +17,20 @@
import { AuthTypeEnum } from '@src/common/common.data';
import { isSuccess } from '@src/utils/http';
-import { Button, Card, message, Radio, Row, Space, Steps } from 'antd';
-import React, { useState } from 'react';
-import { useHistory, useRouteMatch } from 'react-router';
+import { Button, Card, message, Radio, Row, Space } from 'antd';
+import { useState } from 'react';
+import { useNavigate } from 'react-router';
import { InitializeAPI } from './initialize.api';
import styles from './initialize.less';
-export function InitializePage(props: any) {
- const [authType, setAuthType] = useState<AuthTypeEnum>(AuthTypeEnum.STUDIO);
- const match = useRouteMatch();
- const history = useHistory();
+export function InitializeSetType() {
+ console.log('hello');
+ const [authType, setAuthType] = useState<AuthTypeEnum>(AuthTypeEnum.LOCAL);
+ const navigate = useNavigate();
async function handleSetAuthType() {
- const res = await InitializeAPI.setAuthType({authType});
+ const res = await InitializeAPI.setAuthType({ authType });
if (isSuccess(res)) {
- history.push(`${match.path}auth/${authType}`);
+ navigate(authType);
} else {
message.error(res.msg);
}
@@ -42,13 +42,14 @@ export function InitializePage(props: any) {
<Card type="inner" title="管理用户">
<Radio.Group onChange={e => setAuthType(e.target.value)} value={authType}>
<Space direction="vertical">
- <Radio value={AuthTypeEnum.STUDIO}>本地认证</Radio>
- {/* <Radio value={AuthTypeEnum.LDAP}>LDAP认证</Radio> */}
+ <Radio value={AuthTypeEnum.LOCAL}>本地认证</Radio>
</Space>
</Radio.Group>
- <p style={{marginTop: 10}}>注意,初始化选择好认证方式后不可再改变。</p>
+ <p style={{ marginTop: 10 }}>注意,初始化选择好认证方式后不可再改变。</p>
<Row justify="end">
- <Button type="primary" onClick={() => handleSetAuthType()}>去配置</Button>
+ <Button type="primary" onClick={() => handleSetAuthType()}>
+ 去配置
+ </Button>
</Row>
</Card>
</div>
diff --git a/frontend/src/routes/initialize/initialize.data.ts b/frontend/src/routes/initialize/initialize.data.ts
index 243187d..189ee69 100644
--- a/frontend/src/routes/initialize/initialize.data.ts
+++ b/frontend/src/routes/initialize/initialize.data.ts
@@ -15,13 +15,13 @@
// specific language governing permissions and limitations
// under the License.
-export enum StudioStepsEnum {
+export enum LocalStepsEnum {
'admin-user',
- 'finish'
+ 'finish',
}
export enum LDAPStepsEnum {
'ldap-info',
'admin-user',
- 'finish'
-}
\ No newline at end of file
+ 'finish',
+}
diff --git a/frontend/src/routes/initialize/initialize.route.tsx b/frontend/src/routes/initialize/initialize.route.tsx
deleted file mode 100644
index 25a0a8a..0000000
--- a/frontend/src/routes/initialize/initialize.route.tsx
+++ /dev/null
@@ -1,73 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements. See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership. The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License. You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing,
-// software distributed under the License is distributed on an
-// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-// KIND, either express or implied. See the License for the
-// specific language governing permissions and limitations
-// under the License.
-
-import { AuthTypeEnum } from '@src/common/common.data';
-import { Sidebar } from '@src/components/sidebar/sidebar';
-import { useAuth } from '@src/hooks/use-auth';
-import React, { useEffect } from 'react';
-import { Route, Redirect, useRouteMatch, Switch, useHistory } from 'react-router';
-import { InitializeAuth } from './auths/auth';
-import { InitializePage } from './initialize';
-import { StudioStepsEnum, LDAPStepsEnum } from './initialize.data';
-import styles from './initialize.less';
-
-export function Initialize(props: any) {
- const match = useRouteMatch();
- const history = useHistory();
- const { initStep, authType: currentAuthType, initialized } = useAuth();
-
- useEffect(() => {
- if (currentAuthType && initStep) {
- const feStep = initStep ? initStep - 1 : 1;
- let stepPage = '';
- if (currentAuthType === AuthTypeEnum.STUDIO) {
- stepPage = StudioStepsEnum[feStep];
- } else if (currentAuthType === AuthTypeEnum.LDAP) {
- stepPage = LDAPStepsEnum[feStep];
- }
- if (initialized) {
- if (currentAuthType === AuthTypeEnum.STUDIO) {
- stepPage = StudioStepsEnum[feStep];
- if (feStep === 1) {
- history.push('/space');
- }
- } else if (currentAuthType === AuthTypeEnum.LDAP) {
- stepPage = LDAPStepsEnum[feStep];
- if (feStep === 2) {
- history.push('/space');
- }
- }
- } else {
- history.push(`${match.path}/auth/${currentAuthType}/${stepPage}`);
- }
- }
- }, [currentAuthType, initialized, initStep]);
- return (
- <div>
- <Sidebar mode="initialize" />
- <div style={{ marginLeft: 80 }}>
- <div className={styles['initialize-container']}>
- <Switch>
- <Route exact path={`${match.path}/`} component={InitializePage} />
- <Route path={`${match.path}/auth`} component={InitializeAuth} />
- <Redirect to={`${match.path}/`} />
- </Switch>
- </div>
- </div>
- </div>
- );
-}
diff --git a/frontend/src/routes/initialize/initialize.tsx b/frontend/src/routes/initialize/initialize.tsx
index 50d783a..b517e33 100644
--- a/frontend/src/routes/initialize/initialize.tsx
+++ b/frontend/src/routes/initialize/initialize.tsx
@@ -16,41 +16,48 @@
// under the License.
import { AuthTypeEnum } from '@src/common/common.data';
-import { isSuccess } from '@src/utils/http';
-import { Button, Card, message, Radio, Row, Space, Steps } from 'antd';
-import React, { useState } from 'react';
-import { useHistory, useRouteMatch } from 'react-router';
-import { InitializeAPI } from './initialize.api';
+import { Sidebar } from '@src/components/sidebar/sidebar';
+import { useAuth } from '@src/hooks/use-auth';
+import { useEffect } from 'react';
+import { Route, Routes, useNavigate } from 'react-router';
+import { InitializeAuth } from './auths/auth';
+import { InitializeSetType } from './initialize-set-type';
+import { LocalStepsEnum } from './initialize.data';
import styles from './initialize.less';
-export function InitializePage(props: any) {
- const [authType, setAuthType] = useState<AuthTypeEnum>(AuthTypeEnum.STUDIO);
- const match = useRouteMatch();
- const history = useHistory();
- async function handleSetAuthType() {
- const res = await InitializeAPI.setAuthType({authType});
- if (isSuccess(res)) {
- history.push(`${match.path}auth/${authType}`);
- } else {
- message.error(res.msg);
- }
- }
+export function Initialize() {
+ const navigate = useNavigate();
+ const { initStep, authType: currentAuthType, initialized } = useAuth();
+ useEffect(() => {
+ if (currentAuthType && initStep) {
+ const feStep = initStep ? initStep - 1 : 1;
+ let stepPage = '';
+ if (currentAuthType === AuthTypeEnum.LOCAL) {
+ stepPage = LocalStepsEnum[feStep];
+ }
+ if (initialized) {
+ if (currentAuthType === AuthTypeEnum.LOCAL) {
+ stepPage = LocalStepsEnum[feStep];
+ if (feStep === 1) {
+ navigate('/space');
+ }
+ }
+ } else {
+ navigate(`auth/${currentAuthType}/${stepPage}`);
+ }
+ }
+ }, [currentAuthType, initialized, initStep]);
return (
- <div className={styles['initialize']}>
- <div className={styles['initialize-steps-content']}>
- <Card type="inner" title="管理用户">
- <Radio.Group onChange={e => setAuthType(e.target.value)} value={authType}>
- <Space direction="vertical">
- <Radio value={AuthTypeEnum.STUDIO}>本地认证</Radio>
- {/* <Radio value={AuthTypeEnum.LDAP}>LDAP认证</Radio> */}
- </Space>
- </Radio.Group>
- <p style={{marginTop: 10}}>注意,初始化选择好认证方式后不可再改变。</p>
- <Row justify="end">
- <Button type="primary" onClick={() => handleSetAuthType()}>去配置</Button>
- </Row>
- </Card>
+ <div>
+ <Sidebar mode="initialize" />
+ <div style={{ marginLeft: 80 }}>
+ <div className={styles['initialize-container']}>
+ <Routes>
+ <Route path="/" element={<InitializeSetType />} />
+ <Route path="auth/*" element={<InitializeAuth />} />
+ </Routes>
+ </div>
</div>
</div>
);
diff --git a/frontend/src/routes/meta/meta.tsx b/frontend/src/routes/meta/meta.tsx
index 4d06a88..81e8e78 100644
--- a/frontend/src/routes/meta/meta.tsx
+++ b/frontend/src/routes/meta/meta.tsx
@@ -15,18 +15,14 @@
// specific language governing permissions and limitations
// under the License.
-/**
- * @format
- */
-import React, { useEffect, useState } from 'react';
import styles from './meta.less';
import { PageSide } from '@src/layout/page-side/index';
import { MetaBaseTree } from '../tree/index';
-import { Redirect, Route, Router, Switch } from 'react-router-dom';
+import { Routes, Route, Router } from 'react-router-dom';
import TableContent from '../table-content';
import Database from '../database';
-export function Meta(props: any) {
+export function Meta() {
return (
<div className={styles['palo-new-main']}>
<div className={styles['new-main-sider']}>
@@ -42,10 +38,10 @@ export function Meta(props: any) {
height: 'calc(100vh - 95px)',
}}
>
- <Switch>
- <Route path="/meta/table/:tableId" component={TableContent}/>
- <Route path="/meta/database" component={Database}/>
- </Switch>
+ <Routes>
+ <Route path="table/:tableId/*" element={<TableContent />} />
+ <Route path="database/*" element={<Database />} />
+ </Routes>
</div>
</div>
);
diff --git a/frontend/src/routes/node/dashboard/index.module.less b/frontend/src/routes/node/dashboard/index.module.less
deleted file mode 100644
index 08e1fc5..0000000
--- a/frontend/src/routes/node/dashboard/index.module.less
+++ /dev/null
@@ -1,20 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements. See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership. The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License. You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing,
-// software distributed under the License is distributed on an
-// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-// KIND, either express or implied. See the License for the
-// specific language governing permissions and limitations
-// under the License.
-
-.dashboard {
- //
-}
diff --git a/frontend/src/routes/node/dashboard/index.tsx b/frontend/src/routes/node/dashboard/index.tsx
deleted file mode 100644
index bd6f1b3..0000000
--- a/frontend/src/routes/node/dashboard/index.tsx
+++ /dev/null
@@ -1,336 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements. See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership. The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License. You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing,
-// software distributed under the License is distributed on an
-// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-// KIND, either express or implied. See the License for the
-// specific language governing permissions and limitations
-// under the License.
-
-import { Row, Col, Select, Collapse, Button, Divider, AutoComplete } from 'antd';
-import React, { useEffect, useState } from 'react';
-import { useTranslation } from 'react-i18next';
-import ReactEChartsCore from 'echarts-for-react/lib/core';
-import * as echarts from 'echarts/core';
-import dayjs from 'dayjs';
-import './monitor.less';
-
-import { LineChart } from 'echarts/charts';
-import {
- GridComponent,
- PolarComponent,
- RadarComponent,
- GeoComponent,
- SingleAxisComponent,
- ParallelComponent,
- CalendarComponent,
- GraphicComponent,
- ToolboxComponent,
- TooltipComponent,
- TitleComponent,
- LegendComponent,
-} from 'echarts/components';
-import { CanvasRenderer } from 'echarts/renderers';
-import { MonitorAPI } from './monitor.api';
-import { CHARTS_OPTIONS, getTimes } from './monitor.data';
-import { deepClone, formatBytes } from '@src/utils/utils';
-
-echarts.use([
- LineChart,
- CanvasRenderer,
- TitleComponent,
- GridComponent,
- PolarComponent,
- RadarComponent,
- GeoComponent,
- SingleAxisComponent,
- ParallelComponent,
- CalendarComponent,
- GraphicComponent,
- ToolboxComponent,
- TooltipComponent,
- LegendComponent,
-]);
-
-const { Panel } = Collapse;
-const { Option } = Select;
-
-export function NodeDashboard() {
- const { t } = useTranslation();
- const [TIMES, setTIMES] = useState(() => getTimes(dayjs()));
- const [beNodes, setBENodes] = useState<string[]>([]);
- const [selectedBENodes, setSelectedBENodes] = useState<string[]>([]);
- const [currentTime, setCurrentTime] = useState(TIMES[1]);
- const [be_cpu_idle, setBE_CPU_IDLE] = useState({});
- const [be_mem, setBE_Mem] = useState({});
- const [be_disk_io, setBE_DISK_IO] = useState({});
- const [be_base_compaction_score, setBE_base_compaction_score] = useState({});
- const [be_cumu_compaction_score, setBE_cumu_compaction_score] = useState({});
-
- useEffect(() => {
- init();
- }, [currentTime.value, currentTime.start]);
-
- useEffect(() => {
- updateBECharts();
- }, [selectedBENodes, currentTime.value, currentTime.start]);
-
- function handleBENodeChange(value: any) {
- setSelectedBENodes(value);
- }
- function init() {
- getBENodes();
- }
-
- function formatData(response: any, title: string) {
- console.log(response);
- const option = deepClone(CHARTS_OPTIONS);
- // option.title.text = title;
- const xAxisData = response?.x_value.map((item: string) => dayjs(item).format(currentTime.format));
- option.xAxis.data = xAxisData;
- const series: any[] = [];
- const legendData: any[] = [];
-
- function transformChartsData(y_value: string, formatter?: string) {
- for (const [key, value] of Object.entries(y_value).sort()) {
- if (Array.isArray(value)) {
- legendData.push(key);
- series.push({
- name: key,
- data: value.map(item => {
- if (formatter === 'MB') {
- return typeof item === 'number' ? formatBytes(item, 2, false) : item;
- }
- return typeof item === 'number' ? item.toFixed(3) : item;
- }),
- type: 'line',
- });
- } else {
- transformChartsData(value);
- }
- }
- return series;
- }
- if (title === '节点内存使用量') {
- transformChartsData(response?.y_value, 'MB');
- } else {
- transformChartsData(response?.y_value);
- }
- option.legend = {
- bottom: '0',
- left: 0,
- height: 80,
- width: 'auto',
- type: 'scroll',
- itemHeight: 10,
- data: legendData,
- orient: 'vertical',
- pageIconSize: 7,
- textStyle: {
- overflow: 'breakAll',
- },
- };
- (option.grid = {
- bottom: 110,
- }),
- (option.series = series);
- return option;
- }
-
- // BE NODES REQUEST
- function updateBECharts() {
- getBE_CPU_IDLE();
- getBE_Mem();
- getBE_DiskIO();
- getBE_base_compaction_score();
- getBE_cumu_compaction_score();
- }
- function getBENodes() {
- MonitorAPI.getBENodes().then(res => {
- console.log(res.data);
- setBENodes(res.data);
- setSelectedBENodes(res.data);
- });
- }
- function getBE_CPU_IDLE() {
- MonitorAPI.getBE_CPU_IDLE(currentTime.start, currentTime.end, {
- nodes: selectedBENodes,
- }).then(res => {
- const option = formatData(res.data, 'CPU空闲率(%)');
- setBE_CPU_IDLE(option);
- });
- }
- function getBE_Mem() {
- MonitorAPI.getBE_Mem(currentTime.start, currentTime.end, {
- nodes: selectedBENodes,
- }).then(res => {
- const option = formatData(res.data, '节点内存使用量');
- setBE_Mem(option);
- });
- }
- function getBE_DiskIO() {
- MonitorAPI.getBE_DiskIO(currentTime.start, currentTime.end, {
- nodes: selectedBENodes,
- }).then(res => {
- const option = formatData(res.data, 'IO利用率');
- setBE_DISK_IO(option);
- });
- }
- function getBE_base_compaction_score() {
- MonitorAPI.getBE_base_compaction_score(currentTime.start, currentTime.end, {
- nodes: selectedBENodes,
- }).then(res => {
- const option = formatData(res.data, '基线数据版本合并情况');
- option.legend.left = 20;
- option.yAxis = {
- type: 'value',
- minInterval: 1,
-
- boundaryGap: [0, 0.1],
- };
- setBE_base_compaction_score(option);
- });
- }
- function getBE_cumu_compaction_score() {
- MonitorAPI.getBE_cumu_compaction_score(currentTime.start, currentTime.end, {
- nodes: selectedBENodes,
- }).then(res => {
- const option = formatData(res.data, '增量数据版本合并情况');
- option.legend.left = 20;
- option.yAxis = {
- type: 'value',
- minInterval: 1,
-
- boundaryGap: [0, 0.1],
- };
- setBE_cumu_compaction_score(option);
- });
- }
- return (
- <div style={{ background: '#fafafa' }}>
- <Row justify="space-between" align="middle">
- <Col> </Col>
- <Row justify="start" align="middle" style={{ marginTop: '4px' }}>
- <Col>{t`viewTime`}: </Col>
- <Col style={{ margin: '0 10px' }}>
- <Select
- style={{ width: 200 }}
- value={currentTime.value}
- onChange={(v: string) => {
- const time = TIMES.filter(item => item.value === v)[0];
- setCurrentTime(time);
- }}
- >
- {TIMES.map(time => {
- return (
- <Select.Option key={time.value} value={time.value}>
- {time.text}
- </Select.Option>
- );
- })}
- </Select>
- </Col>
- <Col>
- <Button
- type="primary"
- onClick={() => {
- const UPDATED_TIMES = getTimes(dayjs());
- setTIMES(UPDATED_TIMES);
- const time = UPDATED_TIMES.filter(item => item.value === currentTime.value)[0];
- setCurrentTime(time);
- }}
- >
- {t`refresh`}
- </Button>
- </Col>
- </Row>
- </Row>
- <div style={{ marginTop: 10 }}>
- <Collapse defaultActiveKey="1">
- <Panel header={t`BENodeStatusMonitoring`} key="1">
- <Row justify="start" align="middle" style={{ padding: '20px 20px' }}>
- <span>{t`nodeSelection`}:</span>
- <Select
- mode="multiple"
- allowClear
- style={{ width: 600 }}
- placeholder={t`PleaseSelectNode`}
- defaultValue={[...beNodes]}
- onChange={handleBENodeChange}
- >
- {beNodes.map(item => (
- <Option key={item} value={item}>
- {item}
- </Option>
- ))}
- </Select>
- </Row>
- <Row justify="start">
- <Row style={{ height: 340, width: 'calc(100% / 3)' }}>
- <h4>{t`CPUidleRate`}</h4>
- <ReactEChartsCore
- echarts={echarts}
- option={be_cpu_idle}
- notMerge={true}
- lazyUpdate={true}
- style={{ height: 340, width: '100%', top: '-20px' }}
- />
- </Row>
- <Row style={{ height: 340, width: 'calc(100% / 3)' }}>
- <h4>{t`nodeMemoryUsage`}</h4>
- <ReactEChartsCore
- echarts={echarts}
- option={be_mem}
- notMerge={true}
- lazyUpdate={true}
- style={{ height: 340, width: '100%', top: '-20px' }}
- />
- </Row>
- <Row style={{ height: 340, width: 'calc(100% / 3)' }}>
- <h4>{t`IOutilization`}</h4>
- <ReactEChartsCore
- echarts={echarts}
- option={be_disk_io}
- notMerge={true}
- lazyUpdate={true}
- style={{ height: 340, width: '100%', top: '-20px' }}
- />
- </Row>
- </Row>
- <Divider />
- <Row justify="start">
- <Row style={{ height: 340, width: 'calc(100% / 2)' }}>
- <h4 style={{ marginLeft: '25px' }}>{t`BaselineDataVersionConsolidation`}</h4>
- <ReactEChartsCore
- echarts={echarts}
- option={be_base_compaction_score}
- notMerge={true}
- lazyUpdate={true}
- style={{ height: 340, width: '100%', top: '-20px' }}
- />
- </Row>
- <Row style={{ height: 340, width: 'calc(100% / 2)' }}>
- <h4 style={{ marginLeft: '25px' }}>{t`IncrementalDataVersionConsolidation`}</h4>
- <ReactEChartsCore
- echarts={echarts}
- option={be_cumu_compaction_score}
- notMerge={true}
- lazyUpdate={true}
- style={{ height: 340, width: '100%', top: '-20px' }}
- />
- </Row>
- </Row>
- </Panel>
- </Collapse>
- </div>
- </div>
- );
-}
diff --git a/frontend/src/routes/node/dashboard/monitor.api.ts b/frontend/src/routes/node/dashboard/monitor.api.ts
deleted file mode 100644
index c1a4e01..0000000
--- a/frontend/src/routes/node/dashboard/monitor.api.ts
+++ /dev/null
@@ -1,61 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements. See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership. The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License. You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing,
-// software distributed under the License is distributed on an
-// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-// KIND, either express or implied. See the License for the
-// specific language governing permissions and limitations
-// under the License.
-
-/** @format */
-
-import { http } from '@src/utils/http';
-import { IResult } from 'src/interfaces/http.interface';
-
-function getBENodes(): Promise<IResult<any>> {
- return http.get(`/api/rest/v2/manager/monitor/value/be_list`);
-}
-
-function getBE_CPU_IDLE(start?: any, end?: any, data?: any): Promise<IResult<any>> {
- return http.post(`/api/rest/v2/manager/monitor/timeserial/be_cpu_idle?start=${start}&end=${end}`, data);
-}
-
-function getBE_Mem(start?: any, end?: any, data?: any): Promise<IResult<any>> {
- return http.post(`/api/rest/v2/manager/monitor/timeserial/be_mem?start=${start}&end=${end}`, data);
-}
-
-function getBE_DiskIO(start?: any, end?: any, data?: any): Promise<IResult<any>> {
- return http.post(`/api/rest/v2/manager/monitor/timeserial/be_disk_io?start=${start}&end=${end}`, data);
-}
-
-function getBE_base_compaction_score(start?: any, end?: any, data?: any): Promise<IResult<any>> {
- console.log(data);
- return http.post(
- `/api/rest/v2/manager/monitor/timeserial/be_base_compaction_score?start=${start}&end=${end}`,
- data,
- );
-}
-
-function getBE_cumu_compaction_score(start?: any, end?: any, data?: any): Promise<IResult<any>> {
- return http.post(
- `/api/rest/v2/manager/monitor/timeserial/be_cumu_compaction_score?start=${start}&end=${end}`,
- data,
- );
-}
-
-export const MonitorAPI = {
- getBENodes,
- getBE_CPU_IDLE,
- getBE_Mem,
- getBE_DiskIO,
- getBE_base_compaction_score,
- getBE_cumu_compaction_score,
-};
diff --git a/frontend/src/routes/node/dashboard/monitor.data.ts b/frontend/src/routes/node/dashboard/monitor.data.ts
deleted file mode 100644
index e633fae..0000000
--- a/frontend/src/routes/node/dashboard/monitor.data.ts
+++ /dev/null
@@ -1,96 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements. See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership. The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License. You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing,
-// software distributed under the License is distributed on an
-// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-// KIND, either express or implied. See the License for the
-// specific language governing permissions and limitations
-// under the License.
-
-import dayjs from 'dayjs';
-export function getTimes(now: dayjs.Dayjs) {
- return [
- {
- value: '1',
- text: '最近半小时',
- end: new Date().getTime(),
- start: now.subtract(30, 'minute').valueOf(),
- format: 'HH:mm',
- },
- {
- value: '2',
- text: '最近1小时',
- end: new Date().getTime(),
- start: now.subtract(1, 'hour').valueOf(),
- format: 'HH:mm',
- },
- {
- value: '3',
- text: '最近6小时',
- end: new Date().getTime(),
- start: now.subtract(6, 'hour').valueOf(),
- format: 'HH:mm',
- },
- {
- value: '4',
- text: '最近1天',
- end: new Date().getTime(),
- start: now.subtract(1, 'day').valueOf(),
- format: 'HH:mm',
- },
- {
- value: '5',
- text: '最近三天',
- end: new Date().getTime(),
- start: now.subtract(3, 'day').valueOf(),
- format: 'MM/DD HH:mm',
- },
- {
- value: '6',
- text: '最近一周',
- end: new Date().getTime(),
- start: now.subtract(1, 'week').valueOf(),
- format: 'MM/DD HH:mm',
- },
- {
- value: '7',
- text: '最近半个月',
- end: new Date().getTime(),
- start: now.subtract(15, 'day').valueOf(),
- format: 'MM/DD HH:mm',
- },
- {
- value: '8',
- text: '最近一个月',
- end: new Date().getTime(),
- start: now.subtract(1, 'month').valueOf(),
- format: 'MM/DD HH:mm',
- },
- ];
-}
-
-export const CHARTS_OPTIONS = {
- title: { text: '' },
- legend: {
- data: [],
- left: 'center',
- },
- tooltip: {
- trigger: 'axis',
- },
- xAxis: {
- type: 'category',
- boundaryGap: false,
- data: [],
- },
- yAxis: { type: 'value' },
- series: [],
-};
diff --git a/frontend/src/routes/node/list/be-configuration/be-config.api.ts b/frontend/src/routes/node/list/be-configuration/be-config.api.ts
deleted file mode 100644
index 9873cf6..0000000
--- a/frontend/src/routes/node/list/be-configuration/be-config.api.ts
+++ /dev/null
@@ -1,37 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements. See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership. The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License. You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing,
-// software distributed under the License is distributed on an
-// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-// KIND, either express or implied. See the License for the
-// specific language governing permissions and limitations
-// under the License.
-
-import { http } from '@src/utils/http';
-
-function getConfigSelect() {
- return http.get(`/api/rest/v2/manager/node/configuration_name`);
-}
-function getNodeSelect() {
- return http.get(`/api/rest/v2/manager/node/node_list`);
-}
-function getConfigurationsInfo(data: any, type: string) {
- return http.post(`/api/rest/v2/manager/node/configuration_info?type=${type}`, data);
-}
-function setConfig(data: any) {
- return http.post(`/api/rest/v2/manager/node/set_config/be`, data);
-}
-export const BeConfigAPI = {
- getConfigSelect,
- getNodeSelect,
- getConfigurationsInfo,
- setConfig,
-};
diff --git a/frontend/src/routes/node/list/be-configuration/index.tsx b/frontend/src/routes/node/list/be-configuration/index.tsx
deleted file mode 100644
index ddca4db..0000000
--- a/frontend/src/routes/node/list/be-configuration/index.tsx
+++ /dev/null
@@ -1,534 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements. See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership. The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License. You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing,
-// software distributed under the License is distributed on an
-// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-// KIND, either express or implied. See the License for the
-// specific language governing permissions and limitations
-// under the License.
-
-/* eslint-disable prettier/prettier */
-import React, { useEffect, useState } from 'react';
-import { Descriptions, Radio, Select, Table, Space, Modal, Form, Input, Tooltip, message, Divider } from 'antd';
-import { InfoCircleOutlined } from '@ant-design/icons';
-const { Option } = Select;
-import { ConfigurationTypeEnum } from '@src/common/common.data';
-import { BeConfigAPI } from './be-config.api';
-import { useHistory } from 'react-router-dom';
-import { useTranslation } from 'react-i18next';
-import { FILTERS } from '../config.data'
-
-export function BEConfiguration() {
- const { t } = useTranslation();
- const history = useHistory();
- const [beColumn, setBeColumn] = useState<any>([]);
- const [tableData, setTableData] = useState<any>([]);
- const [configSelect, setConfigSelect] = useState<any>([]);
- const [nodeSelect, setNodeSelect] = useState<any>([]);
- const [confName, setConfName] = useState<any>([]);
- const [nodeName, setNodeName] = useState<any>([]);
- const [isModalVisible, setIsModalVisible] = useState(false);
- const [selectedRowKeys, setSelectedRowKeys] = useState<any>([]);
- const [selectedRows, setSelectedRows] = useState<any>([]);
- const [isBatchEdit, setIsBatchEdit] = useState<boolean>(true);
- const [rowData, setRowsData] = useState<any>({});
- const [changeCurrent, setChangeCurrent] = useState<number>();
- const [nodevalue, setNodevalue] = useState<any>([]);
- function changeConfig(record: any) {
- setRowsData(record);
- setIsBatchEdit(true);
- setIsModalVisible(true);
- }
-
- const [form] = Form.useForm();
-
- const rowSelection = {
- selectedRowKeys,
- onChange: (selectedRowKeys: React.Key[], selectedRows: any) => {
- console.log(selectedRows)
- let newSelectedRowKeys = [];
- let newSelectedRows: any[] = [];
- newSelectedRowKeys = selectedRowKeys.filter((key, index) => {
- if (selectedRows[index][Object.keys(selectedRows[index]).length - 2] === 'true') {
- newSelectedRows.push(selectedRows[index]);
- return true;
- }
- return false;
- });
- setSelectedRowKeys(newSelectedRowKeys);
- setSelectedRows(newSelectedRows);
- },
- getCheckboxProps: (record: any) => {
- const arr = Object.keys(record);
- return {
- disabled: record[arr.length - 2] === 'false',
- key: record[arr.length - 1],
- };
- },
- selections: [
- Table.SELECTION_ALL,
- Table.SELECTION_NONE,
- {
- text: t`SelectOnlyTheCurrentPage`,
- onSelect(selectedRowKeys: React.Key[], selectedRows: any) {
- setSelectedRowKeys(selectedRowKeys)
- let newSelectedRows: any[] = [];
- for (let i = 0; i < selectedRowKeys.length; i++) {
- newSelectedRows.push(tableData[selectedRowKeys[i]])
- }
- setSelectedRows(newSelectedRows)
- },
- },
- ],
- };
- const [typeValue, setTypeValue] = React.useState(ConfigurationTypeEnum.BE);
- function onChange(e: any) {
- setTypeValue(e.target.value);
- if (e.target.value === ConfigurationTypeEnum.BE) {
- localStorage.setItem("nodeText","");
- history.push(`/configuration/be`);
- } else {
- localStorage.setItem("nodeText","");
- history.push(`/configuration/fe`);
- }
- }
- const handleOk = (values: any) => {
- if (isBatchEdit) {
- let name = rowData[0];
- let data = {};
- data[name] = {
- node: [rowData[1]],
- value: values.value,
- persist: values.persist,
- };
-
- BeConfigAPI.setConfig(data).then(res => {
- if (res.code === 0) {
- setIsModalVisible(false);
- getTable()
- if (res.data.failed && res.data.failed.length !== 0) {
- warning(res.data.failed)
- } else {
- message.success(t`SuccessfullyModified`);
- }
- } else {
-
- message.error(res.msg);
- }
- });
- } else {
- let name = "";
- let data = {};
- for (let i = 0; i < selectedRows.length; i++) {
- let nodes: any[] = [];
- name = selectedRows[i][0]
- selectedRows.map((item: any[], index: any) => {
- if (item[0] === selectedRows[i][0]) {
- nodes.push(item[1])
- }
- });
- data[name] = {
- node: nodes,
- value: values.value,
- persist: values.persist,
- };
- }
- BeConfigAPI.setConfig(data).then(res => {
- if (res.code === 0) {
- setIsModalVisible(false);
- getTable()
- if (res.data.failed && res.data.failed.length !== 0) {
- warning(res.data.failed)
- } else {
- message.success(t`SuccessfullyModified`);
- }
- } else {
- message.error(res.msg);
- }
- });
- }
- console.log(values, isBatchEdit, rowData);
- //setIsModalVisible(false);
- };
-
- const handleCancel = () => {
- setIsModalVisible(false);
- };
-
- function getTable() {
- let data = {};
- if (confName.length === 0 && nodeName.length !== 0) {
- data = { type: typeValue, node: nodeName };
- }
- if (confName.length !== 0 && nodeName.length === 0) {
- data = { type: typeValue, conf_name: confName };
- }
- if (confName.length === 0 && nodeName.length === 0) {
- data = { type: typeValue };
- }
- if (confName.length !== 0 && nodeName.length !== 0) {
- data = { type: typeValue, conf_name: confName, node: nodeName };
- }
- setTable(data,typeValue)
- }
- function refresh() {
- let data = {};
- const nodeText = localStorage.getItem("nodeText")
- if (nodeText !== "") {
- setNodevalue(nodeText)
- nodeName.push(nodeText)
- const node = [];
- node.push(nodeText)
- if (confName.length === 0 && node.length !== 0) {
- data = { type: typeValue, node: node };
- }
- if (confName.length !== 0 && node.length === 0) {
- data = { type: typeValue, conf_name: confName };
- }
- if (confName.length === 0 && node.length === 0) {
- data = { type: typeValue };
- }
- if (confName.length !== 0 && node.length !== 0) {
- data = { type: typeValue, conf_name: confName, node: node };
- }
- } else {
- if (confName.length === 0 && nodeName.length !== 0) {
- data = { type: typeValue, node: nodeName };
- }
- if (confName.length !== 0 && nodeName.length === 0) {
- data = { type: typeValue, conf_name: confName };
- }
- if (confName.length === 0 && nodeName.length === 0) {
- data = { type: typeValue };
- }
- if (confName.length !== 0 && nodeName.length !== 0) {
- data = { type: typeValue, conf_name: confName, node: nodeName };
- }
- }
-
- setTable(data,typeValue)
-
- BeConfigAPI.getConfigSelect().then((res: { data: any; code: any; msg: any }) => {
- if (res.code === 0) {
- const { data, code, msg } = res;
- console.log(data);
- const { backend, frontend } = data;
- const configSelect = backend.map((item: string, index: number) => {
- return (
- <Option key={item} value={item}>
- {item}
- </Option>
- );
- });
- setConfigSelect(configSelect);
- } else {
- message.warning(res.msg);
- }
- });
- BeConfigAPI.getNodeSelect().then((res: { data: any; code: any; msg: any }) => {
- if (res.code === 0) {
- const { data, code, msg } = res;
- const { backend, frontend } = data;
- const nodeSelect = backend.map((item: string, index: number) => {
- return (
- <Option key={item} value={item}>
- {item}
- </Option>
- );
- });
- setNodeSelect(nodeSelect);
- } else {
- message.warning(res.msg);
- }
- });
- }
-
- function batchEditing() {
- if (selectedRowKeys.length === 0) {
- message.warning(t`PleaseCheckTheConfigurationYouWantToModify`);
- } else {
- setIsModalVisible(true);
- setIsBatchEdit(false);
- }
- }
- useEffect(() => {
- refresh();
- }, []);
- function configSelectChange(_value: any) {
- setSelectedRowKeys([])
- setSelectedRows([])
- const newArray = _value.map(x => x.trim())
- setConfName(newArray);
- let data = {};
- if (newArray.length === 0 && nodeName.length !== 0) {
- data = { type: typeValue, node: nodeName };
- }
- if (newArray.length !== 0 && nodeName.length === 0) {
- data = { type: typeValue, conf_name: newArray };
- }
- if (newArray.length === 0 && nodeName.length === 0) {
- data = { type: typeValue };
- }
- if (newArray.length !== 0 && nodeName.length !== 0) {
- data = { conf_name: newArray, node: nodeName };
- }
- setTable(data,typeValue)
- }
-
- function setTable(data: any,typeValue: any) {
- BeConfigAPI.getConfigurationsInfo(data, typeValue).then(res => {
- if (res.code == 0) {
- const { column_names, rows } = res.data;
- const columns = column_names.map((item: string, index: number) => {
- if (item === '可修改') {
- return {
- title: t`operate`,
- dataIndex: item,
- render: (text: any, record: any, index: any) => (
- <Space size="middle">
- {record[Object.keys(record).length - 2] === 'true' ? (
- <a onClick={() => changeConfig(record)}>{ t`edit`}</a>
- ) : (
- <></>
- )}
- </Space>
- ),
- fixed: 'right',
- width: 100,
- };
- }
- if (item === 'MasterOnly') {
- return {
- title: item,
- dataIndex: `${index}`,
- key: item,
- columnWidth: 10,
- filters: FILTERS,
- onFilter: (value: any, record: any) => onFilterCols(value,record),
- };
- }
- else {
- return {
- title: item,
- dataIndex: index,
- columnWidth: 10,
- };
- }
- });
- setBeColumn(columns);
-
- for (let i = 0; i < rows.length; i++) {
- rows[i].push('' + i + '');
- }
- setTableData(rows.map((item: string[]) => ({ ...item })));
- if (data.conf_name) {
- setChangeCurrent(1)
- }
- } else {
- message.warning(res.msg);
- }
- });
- }
-
- function onFilterCols(value: any, record: any) {
- return record[6].indexOf(value) === 0
- }
-
- function nodeSelectChange(value: any) {
- setSelectedRowKeys([])
- setSelectedRows([])
- if (value.length === 0) {
- setNodevalue([])
-
- } else {
- setNodevalue(value)
- }
- localStorage.setItem("nodeText", "");
- const newArray = value.map(x => x.trim())
- setNodeName(newArray);
- let data = {};
- if (confName.length === 0 && newArray.length !== 0) {
- data = { type: typeValue, node: newArray };
- }
- if (confName.length !== 0 && newArray.length === 0) {
- data = { type: typeValue, conf_name: confName };
- }
- if (confName.length === 0 && newArray.length === 0) {
- data = { type: typeValue };
- }
- if (confName.length !== 0 && newArray.length !== 0) {
- data = { type: typeValue, conf_name: confName, node: newArray };
- }
- setTable(data,typeValue)
- }
-
- function pageSizeChange(current: React.SetStateAction<number | undefined>, pageSize: number | undefined) {
- setChangeCurrent(current)
- }
- const [configvalue, setConfigvalue] = React.useState<any>([]);
- const configSelectProps = {
- mode: 'multiple' as const,
- style: { width: '100%' },
- configvalue,
- onChange: (newValue: string[]) => {
- setConfigvalue(newValue);
- },
- maxTagCount: 'responsive' as const,
- };
- const nodeSelectProps = {
- mode: 'multiple' as const,
- style: { width: '100%' },
- nodevalue,
- onChange: (newValue: string[]) => {
- setNodevalue(newValue);
- },
- maxTagCount: 'responsive' as const,
- };
- return (
- <div>
- <Descriptions style={{ marginTop: 20 }}>
- <Descriptions.Item style={{ paddingLeft: 40 }}>
- <span>{t`nodeSelection`}:</span>
- <Radio.Group onChange={onChange} value={typeValue} style={{ marginTop: '4px' }}>
- <Radio value={ConfigurationTypeEnum.FE}>FE节点</Radio>
- <Radio value={ConfigurationTypeEnum.BE}>BE节点</Radio>
- </Radio.Group>
- </Descriptions.Item>
- <Descriptions.Item style={{ paddingLeft: 40 }}>
- <span>{ t`ConfigurationItem`}:</span>
- <Select
- {...configSelectProps}
- mode="tags"
- allowClear
- placeholder={t`SearchConfigurationItems`}
- onChange={configSelectChange}
- style={{ width: 250 }}
-
- >
- {configSelect}
- </Select>
- </Descriptions.Item>
- <Descriptions.Item style={{ paddingLeft: 40 }}>
- <span>{ t`Node`}:</span>
- <Select
- {...nodeSelectProps}
- mode="tags"
- allowClear
- placeholder={ t`SearchNode`}
- onChange={nodeSelectChange}
- value={nodevalue}
- style={{ width: 250 }}
- >
- {nodeSelect}
- </Select>
- </Descriptions.Item>
- </Descriptions>
- <Descriptions style={{ margin: '0 0 0 3em' }}>
- <Descriptions.Item >
- <span >
- { t`CurrentlySelected`} {selectedRowKeys.length} {t`StripData`}
- </span>
- </Descriptions.Item>
-
- <Descriptions.Item >
- <a onClick={batchEditing} style={{marginLeft: '86%' }} >
- {t`BatchEditing`}
- </a>
- </Descriptions.Item>
- </Descriptions>
- <div>
- <Table
- columns={beColumn}
- dataSource={tableData}
- rowSelection={{
- ...rowSelection
- }}
- bordered
- rowKey={(record: any[]) => record[Object.keys(record).length - 1]}
- size="middle"
- scroll={{ x: 1300 }}
- pagination={{
- position: ['bottomCenter'],
- total: beColumn,
- current:changeCurrent,
- showSizeChanger: true,
- showQuickJumper: true,
- onChange: (current, pageSize) => pageSizeChange(current, pageSize),
- showTotal: (total: any) => {t`total`+`${total}` +t`strip`},
- }}
- ></Table>
- </div>
- <Modal
- title={ t`EditConfigurationItems`}
- visible={isModalVisible}
- onCancel={handleCancel}
- onOk={() => {
- form.validateFields()
- .then((values: any) => {
- form.resetFields();
- handleOk(values);
- })
- .catch((info: any) => {
- console.log('Validate Failed:', info);
- });
- }}
- >
- <Form form={form} name="form_in_modal" initialValues={{ modifier: 'public' }}>
- <Form.Item label={ t`ConfigurationValue`+":"} name="value" rules={[{ required: true, message: '配置值不能为空' }]}>
- <Input placeholder={ t`PleaseEnterTheConfigurationValue`} />
- </Form.Item>
- <Form.Item
- name="persist"
- label={ t`EffectiveState`+":"}
- rules={[{ required: true, message: t`PleaseSelectAnEffectiveState` }]}
- >
- <Radio.Group value={'false'}>
- <Radio value="false">
- {t`TemporarilyEffective`}
- <Tooltip title={t`TemporarilyEffectiveTooltip`}>
- <InfoCircleOutlined style={{ marginLeft: '0.2em' }} />
- </Tooltip>
- </Radio>
- <Radio value="true">
- { t`Permanent`}
- <Tooltip title={ t`PermanentTooltip`}>
- <InfoCircleOutlined style={{ marginLeft: '0.2em' }} />
- </Tooltip>
- </Radio>
- </Radio.Group>
- </Form.Item>
- </Form>
- </Modal>
- </div>
- );
- function warning(failed: []) {
- const arr = failed.map((failedMsg:any) => {
- return <><span style={{ color: 'red' }}>{failedMsg.node}</span><span>{ t`Node`}</span><span style = {{color:'red'}}>{failedMsg.config_name}</span><span>{t`Error`+":"} {failedMsg.err_info}</span><br></br></>
- })
- Modal.error({
- content: <>
- <Divider />
- <h4>{ t`ConfigurationError`}</h4>
- <div style={{ height: '150px', width: '100%', overflow: 'auto', }}>
- {arr}
- </div>
- </>
- ,
- title: <span style={{ color: 'red' }}>{ t`FailToEdit`}</span>,
- // eslint-disable-next-line @typescript-eslint/no-empty-function
- onOk() { },
- bodyStyle: { height: '250px' },
- width: '520px',
- closable:true
-
- });
- }
-}
diff --git a/frontend/src/routes/node/list/config.data.ts b/frontend/src/routes/node/list/config.data.ts
deleted file mode 100644
index 7227a88..0000000
--- a/frontend/src/routes/node/list/config.data.ts
+++ /dev/null
@@ -1,26 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements. See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership. The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License. You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing,
-// software distributed under the License is distributed on an
-// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-// KIND, either express or implied. See the License for the
-// specific language governing permissions and limitations
-// under the License.
-
-export enum MASTER_MAP {
- TRUE = 'true',
- FALSE = 'false',
-}
-
-export const FILTERS = [
- { text: MASTER_MAP.TRUE, value: MASTER_MAP.TRUE },
- { text: MASTER_MAP.FALSE, value: MASTER_MAP.FALSE },
-];
\ No newline at end of file
diff --git a/frontend/src/routes/node/list/configuration/index.tsx b/frontend/src/routes/node/list/configuration/index.tsx
deleted file mode 100644
index 8f7f881..0000000
--- a/frontend/src/routes/node/list/configuration/index.tsx
+++ /dev/null
@@ -1,106 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements. See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership. The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License. You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing,
-// software distributed under the License is distributed on an
-// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-// KIND, either express or implied. See the License for the
-// specific language governing permissions and limitations
-// under the License.
-
-import React, { useState } from 'react';
-import { Descriptions, Radio, Select, Table, message } from 'antd';
-import { ConfigurationTypeEnum } from '@src/common/common.data';
-import { useHistory } from 'react-router-dom';
-import { useTranslation } from 'react-i18next';
-
-export function Configuration() {
- const history = useHistory();
- const { t } = useTranslation();
- const [feColumn, setFeColumn] = useState<any>([]);
-
- const [tableData, setTableData] = useState<any>([]);
-
- const [configSelect, setConfigSelect] = useState<any>([]);
-
- const [nodeSelect, setNodeSelect] = useState<any>([]);
-
- const [selectedRowKeys, setSelectedRowKeys] = useState<any>([]);
-
- const rowSelection = {};
-
- function batchEditing() {
- if (selectedRowKeys.length === 0) {
- message.warning( t`PleaseCheckTheConfiguration`);
- }
- }
- function onChange(e: any) {
- if (e.target.value === ConfigurationTypeEnum.BE) {
- localStorage.setItem("nodeText","");
- history.push(`/configuration/be`);
- } else {
- localStorage.setItem("nodeText","");
- history.push(`/configuration/fe`);
- }
- }
-
- return (
- <>
- <Descriptions style={{ marginTop: 20 }}>
- <Descriptions.Item style={{ paddingLeft: 40 }}>
- <span> {t`nodeSelection`+":"}</span>
- <Radio.Group onChange={onChange} style={{ marginTop: '4px' }}>
- <Radio value={ConfigurationTypeEnum.FE}>FE{t`Node`}</Radio>
- <Radio value={ConfigurationTypeEnum.BE}>BE{t`Node`}</Radio>
- </Radio.Group>
- </Descriptions.Item>
- <Descriptions.Item style={{ paddingLeft: 40 }}>
- <span>{ t`ConfigurationItem`}:</span>
- <Select mode="tags" allowClear placeholder={ t`SearchConfigurationItems`} style={{ width: 200 }}>
- {configSelect}
- </Select>
- </Descriptions.Item>
- <Descriptions.Item style={{ paddingLeft: 40 }}>
- <span>{ t`Node`}:</span>
- <Select mode="tags" allowClear placeholder={ t`SearchNode`} style={{ width: 200 }}>
- {nodeSelect}
- </Select>
- </Descriptions.Item>
- <Descriptions.Item>
- {' '}
- <a style={{ width: '100%', marginLeft: '90%' }} onClick={batchEditing}>
- { t`BatchEditing`}
- </a>
- </Descriptions.Item>
- </Descriptions>
- <div>
- <Table
- columns={feColumn}
- dataSource={tableData}
- rowSelection={{
- ...rowSelection,
- }}
- bordered
- rowKey={(record: any[]) => record[Object.keys(record).length - 1]}
- size="middle"
- scroll={{ x: 1300 }}
- pagination={{
- position: ['bottomCenter'],
- total: tableData.length,
- showSizeChanger: true,
- showQuickJumper: true,
- showTotal: (total: any) => {t`total`+`${total}` +t`strip`},
- }}
- ></Table>
- </div>
- </>
- );
-}
-
diff --git a/frontend/src/routes/node/list/fe-configuration/fe-config.api.ts b/frontend/src/routes/node/list/fe-configuration/fe-config.api.ts
deleted file mode 100644
index 28419f8..0000000
--- a/frontend/src/routes/node/list/fe-configuration/fe-config.api.ts
+++ /dev/null
@@ -1,37 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements. See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership. The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License. You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing,
-// software distributed under the License is distributed on an
-// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-// KIND, either express or implied. See the License for the
-// specific language governing permissions and limitations
-// under the License.
-
-import { http } from '@src/utils/http';
-
-function getConfigSelect() {
- return http.get(`/api/rest/v2/manager/node/configuration_name`);
-}
-function getNodeSelect() {
- return http.get(`/api/rest/v2/manager/node/node_list`);
-}
-function getConfigurationsInfo(data: any, type: string) {
- return http.post(`/api/rest/v2/manager/node/configuration_info?type=${type}`, data);
-}
-function setConfig(data: any) {
- return http.post(`/api/rest/v2/manager/node/set_config/fe`, data);
-}
-export const FeConfigAPI = {
- getConfigSelect,
- getNodeSelect,
- getConfigurationsInfo,
- setConfig,
-};
diff --git a/frontend/src/routes/node/list/fe-configuration/index.tsx b/frontend/src/routes/node/list/fe-configuration/index.tsx
deleted file mode 100644
index b5fc695..0000000
--- a/frontend/src/routes/node/list/fe-configuration/index.tsx
+++ /dev/null
@@ -1,535 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements. See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership. The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License. You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing,
-// software distributed under the License is distributed on an
-// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-// KIND, either express or implied. See the License for the
-// specific language governing permissions and limitations
-// under the License.
-/* eslint-disable prettier/prettier */
-import React, { useEffect, useState } from 'react';
-import { Descriptions, Radio, Select, Table, Space, Modal, Form, Input, Tooltip, message, Divider } from 'antd';
-import { FallOutlined, InfoCircleOutlined } from '@ant-design/icons';
-const { Option } = Select;
-import { ConfigurationTypeEnum } from '@src/common/common.data';
-import { FeConfigAPI } from './fe-config.api';
-import { useHistory } from 'react-router-dom';
-import { useTranslation } from 'react-i18next';
-import { FILTERS } from '../config.data'
-
-export function FEConfiguration() {
- const { t } = useTranslation();
- const [modal, contextHolder] = Modal.useModal();
- const history = useHistory();
- const [feColumn, setFeColumn] = useState<any>([]);
- const [tableData, setTableData] = useState<any>([]);
- const [configSelect, setConfigSelect] = useState<any>([]);
- const [nodeSelect, setNodeSelect] = useState<any>([]);
- const [confName, setConfName] = useState<any>([]);
- const [nodeName, setNodeName] = useState<any>([]);
- const [isModalVisible, setIsModalVisible] = useState(false);
- const [selectedRowKeys, setSelectedRowKeys] = useState<any>([]);
- const [selectedRows, setSelectedRows] = useState<any>([]);
- const [isBatchEdit, setIsBatchEdit] = useState<boolean>(true);
- const [rowData, setRowsData] = useState<any>({});
- const [changeCurrent, setChangeCurrent] = useState<number>();
- const [nodevalue, setNodevalue] = useState<any>([]);
- function changeConfig(record: any) {
- setRowsData(record);
- setIsBatchEdit(true);
- setIsModalVisible(true);
- }
-
- const [form] = Form.useForm();
-
- const rowSelection = {
- selectedRowKeys,
- onChange: (selectedRowKeys: React.Key[], selectedRows: any) => {
- console.log(selectedRows)
- let newSelectedRowKeys = [];
- const newSelectedRows: any[] = [];
- newSelectedRowKeys = selectedRowKeys.filter((key, index) => {
- if (selectedRows[index][Object.keys(selectedRows[index]).length - 2] === 'true') {
- newSelectedRows.push(selectedRows[index]);
- return true;
- }
- return false;
- });
- setSelectedRowKeys(newSelectedRowKeys);
- setSelectedRows(newSelectedRows);
- },
- getCheckboxProps: (record: any) => {
- const arr = Object.keys(record);
- return {
- disabled: record[arr.length - 2] === 'false',
- key: record[arr.length - 1],
- };
- },
- selections: [
- Table.SELECTION_ALL,
- Table.SELECTION_NONE,
- {
- text: t`SelectOnlyTheCurrentPage`,
- onSelect(selectedRowKeys: React.Key[], selectedRows: any) {
- setSelectedRowKeys(selectedRowKeys)
- const newSelectedRows: any[] = [];
- for (let i = 0; i < selectedRowKeys.length; i++) {
- newSelectedRows.push(tableData[selectedRowKeys[i]])
- }
- setSelectedRows(newSelectedRows)
- },
- },
- ],
- };
- const [typeValue, setTypeValue] = React.useState(ConfigurationTypeEnum.FE);
- function onChange(e: any) {
- setTypeValue(e.target.value);
- if (e.target.value === ConfigurationTypeEnum.BE) {
- localStorage.setItem("nodeText","");
- history.push(`/configuration/be`);
- } else {
- localStorage.setItem("nodeText","");
- history.push(`/configuration/fe`);
- }
- }
- const handleOk = (values: any) => {
- if (isBatchEdit) {
- const name = rowData[0];
- const data = {};
- data[name] = {
- node: [rowData[1]],
- value: values.value,
- persist: values.persist,
- };
-
- FeConfigAPI.setConfig(data).then(res => {
- if (res.code === 0) {
- setIsModalVisible(false);
- getTable()
- if (res.data.failed && res.data.failed.length !== 0) {
- warning(res.data.failed)
- } else {
- message.success(t`SuccessfullyModified`);
- }
- } else {
- message.error(res.msg);
- }
- });
- } else {
- let name = "";
- const data = {};
- for (let i = 0; i < selectedRows.length; i++) {
- const nodes: any[] = [];
- name = selectedRows[i][0]
- selectedRows.map((item: any[], index: any) => {
- if (item[0] === selectedRows[i][0]) {
- nodes.push(item[1])
- }
- });
- data[name] = {
- node: nodes,
- value: values.value,
- persist: values.persist,
- };
- }
- FeConfigAPI.setConfig(data).then(res => {
- if (res.code === 0) {
- setIsModalVisible(false);
- getTable()
- if (res.data.failed && res.data.failed.length !== 0) {
- warning(res.data.failed)
- } else {
- message.success(t`SuccessfullyModified`);
- }
- } else {
- message.error(res.msg);
- }
- });
- }
- console.log(values, isBatchEdit, rowData);
- //setIsModalVisible(false);
- };
-
- const handleCancel = () => {
- setIsModalVisible(false);
- };
-
- function getTable() {
- let data = {};
- if (confName.length === 0 && nodeName.length !== 0) {
- data = { type: typeValue, node: nodeName };
- }
- if (confName.length !== 0 && nodeName.length === 0) {
- data = { type: typeValue, conf_name: confName };
- }
- if (confName.length === 0 && nodeName.length === 0) {
- data = { type: typeValue };
- }
- if (confName.length !== 0 && nodeName.length !== 0) {
- data = { type: typeValue, conf_name: confName, node: nodeName };
- }
- setTable(data,typeValue)
- }
- function refresh() {
- let data = {};
- const nodeText = localStorage.getItem("nodeText")
- if (nodeText !== "") {
- setNodevalue(nodeText)
- nodeName.push(nodeText)
- const node = [];
- node.push(nodeText)
- if (confName.length === 0 && node.length !== 0) {
- data = { type: typeValue, node: node };
- }
- if (confName.length !== 0 && node.length === 0) {
- data = { type: typeValue, conf_name: confName };
- }
- if (confName.length === 0 && node.length === 0) {
- data = { type: typeValue };
- }
- if (confName.length !== 0 && node.length !== 0) {
- data = { type: typeValue, conf_name: confName, node: node };
- }
- } else {
- if (confName.length === 0 && nodeName.length !== 0) {
- data = { type: typeValue, node: nodeName };
- }
- if (confName.length !== 0 && nodeName.length === 0) {
- data = { type: typeValue, conf_name: confName };
- }
- if (confName.length === 0 && nodeName.length === 0) {
- data = { type: typeValue };
- }
- if (confName.length !== 0 && nodeName.length !== 0) {
- data = { type: typeValue, conf_name: confName, node: nodeName };
- }
- }
-
- setTable(data,typeValue)
-
- FeConfigAPI.getConfigSelect().then((res: { data: any; code: any; msg: any }) => {
- if (res.code === 0) {
- const { data, code, msg } = res;
- console.log(data);
- const { backend, frontend } = data;
- const configSelect = frontend.map((item: string, index: number) => {
- return (
- <Option key={item} value={item}>
- {item}
- </Option>
- );
- });
- setConfigSelect(configSelect);
- } else {
- message.warning(res.msg);
- }
- });
- FeConfigAPI.getNodeSelect().then((res: { data: any; code: any; msg: any }) => {
- if (res.code === 0) {
- const { data, code, msg } = res;
- const { backend, frontend } = data;
- const nodeSelect = frontend.map((item: string, index: number) => {
- return (
- <Option key={item} value={item}>
- {item}
- </Option>
- );
- });
- setNodeSelect(nodeSelect);
- } else {
- message.warning(res.msg);
- }
- });
- }
-
- function batchEditing() {
- if (selectedRowKeys.length === 0) {
- message.warning(t`PleaseCheckTheConfigurationYouWantToModify`);
- } else {
- setIsModalVisible(true);
- setIsBatchEdit(false);
- }
- }
- useEffect(() => {
- refresh();
- }, []);
-
- function configSelectChange(_value: any) {
- setSelectedRowKeys([])
- setSelectedRows([])
- const newArray = _value.map(x => x.trim())
- setConfName(newArray);
- let data = {};
- if (newArray.length === 0 && nodeName.length !== 0) {
- data = { type: typeValue, node: nodeName };
- }
- if (newArray.length !== 0 && nodeName.length === 0) {
- data = { type: typeValue, conf_name: newArray };
- }
- if (newArray.length === 0 && nodeName.length === 0) {
- data = { type: typeValue };
- }
- if (newArray.length !== 0 && nodeName.length !== 0) {
- data = { conf_name: newArray, node: nodeName };
- }
- setTable(data,typeValue)
- }
-
- function setTable(data: any,typeValue: any) {
- FeConfigAPI.getConfigurationsInfo(data, typeValue).then(res => {
- if (res.code == 0) {
- const { column_names, rows } = res.data;
- const columns = column_names.map((item: string, index: number) => {
- if (item === '可修改') {
- return {
- title: t`operate`,
- dataIndex: item,
- render: (text: any, record: any, index: any) => (
- <Space size="middle">
- {record[Object.keys(record).length - 2] === 'true' ? (
- <a onClick={() => changeConfig(record)}>{ t`edit`}</a>
- ) : (
- <></>
- )}
- </Space>
- ),
- fixed: 'right',
- width: 100,
- };
- }
- if (item === 'MasterOnly') {
- return {
- title: item,
- dataIndex: `${index}`,
- key: item,
- columnWidth: 10,
- filters: FILTERS,
- onFilter: (value: any, record: any) => onFilterCols(value,record),
- };
- }
- else {
- return {
- title: item,
- dataIndex: index,
- columnWidth: 10,
- };
- }
- });
- setFeColumn(columns);
-
- for (let i = 0; i < rows.length; i++) {
- rows[i].push('' + i + '');
- }
- setTableData(rows.map((item: string[]) => ({ ...item })));
- if (data.conf_name) {
- setChangeCurrent(1)
- }
- } else {
- message.warning(res.msg);
- }
- });
- }
-
- function onFilterCols(value: any, record: any) {
- return record[4].indexOf(value) === 0
- }
-
- function nodeSelectChange(value: any) {
- setSelectedRowKeys([])
- setSelectedRows([])
- if (value.length === 0) {
- setNodevalue([])
- } else {
- setNodevalue(value)
- }
-
- localStorage.setItem("nodeText", "");
- const newArray = value.map(x => x.trim())
- setNodeName(newArray);
- let data = {};
- if (confName.length === 0 && newArray.length !== 0) {
- data = { type: typeValue, node: newArray };
- }
- if (confName.length !== 0 && newArray.length === 0) {
- data = { type: typeValue, conf_name: confName };
- }
- if (confName.length === 0 && newArray.length === 0) {
- data = { type: typeValue };
- }
- if (confName.length !== 0 && newArray.length !== 0) {
- data = { type: typeValue, conf_name: confName, node: newArray };
- }
- setTable(data,typeValue)
- }
-
- function pageSizeChange(current: React.SetStateAction<number | undefined>, pageSize: number | undefined) {
- setChangeCurrent(current)
- }
- const [configvalue, setConfigvalue] = React.useState<any>([]);
- const configSelectProps = {
- mode: 'multiple' as const,
- style: { width: '100%' },
- configvalue,
- onChange: (newValue: string[]) => {
- setConfigvalue(newValue);
- },
- maxTagCount: 'responsive' as const,
- };
- const nodeSelectProps = {
- mode: 'multiple' as const,
- style: { width: '100%' },
- nodevalue,
- onChange: (newValue: string[]) => {
- setNodevalue(newValue);
- },
- maxTagCount: 'responsive' as const,
- };
- return (
- <div>
- <Descriptions style={{ marginTop: 20 }}>
- <Descriptions.Item style={{ paddingLeft: 40 }}>
- <span>{t`nodeSelection`}:</span>
- <Radio.Group onChange={onChange} value={typeValue} style={{ marginTop: '4px' }}>
- <Radio value={ConfigurationTypeEnum.FE}>FE节点</Radio>
- <Radio value={ConfigurationTypeEnum.BE}>BE节点</Radio>
- </Radio.Group>
- </Descriptions.Item>
- <Descriptions.Item style={{ paddingLeft: 40 }}>
- <span>{ t`ConfigurationItem`}:</span>
- <Select
- {...configSelectProps}
- mode="tags"
- allowClear
- placeholder={t`SearchConfigurationItems`}
- onChange={configSelectChange}
- style={{ width: 250 }}
-
- >
- { configSelect}
- </Select>
- </Descriptions.Item>
- <Descriptions.Item style={{ paddingLeft: 40 }}>
- <span>{ t`Node`}:</span>
- <Select
- {...nodeSelectProps}
- mode="tags"
- allowClear
- placeholder={ t`SearchNode`}
- onChange={nodeSelectChange}
- value={nodevalue}
- style={{ width: 250 }}
- >
- {nodeSelect}
- </Select>
- </Descriptions.Item>
- </Descriptions>
- <Descriptions style={{ margin: '0 0 0 3em' }}>
- <Descriptions.Item >
- <span >
- { t`CurrentlySelected`} {selectedRowKeys.length} {t`StripData`}
- </span>
- </Descriptions.Item>
- <Descriptions.Item >
- <a onClick={batchEditing} style={{marginLeft: '86%' }}>
- {t`BatchEditing`}
- </a>
- </Descriptions.Item>
- </Descriptions>
- <div>
- <Table
- columns={feColumn}
- dataSource={tableData}
- rowSelection={{
- ...rowSelection
- }}
- bordered
- rowKey={(record: any[]) => record[Object.keys(record).length - 1]}
- size="middle"
- scroll={{ x: 1300 }}
- pagination={{
- position: ['bottomCenter'],
- total: feColumn,
- current:changeCurrent,
- showSizeChanger: true,
- showQuickJumper: true,
- onChange: (current, pageSize) => pageSizeChange(current, pageSize),
- showTotal: (total: any) => {t`total`+`${total}` +t`strip`},
- }}
- ></Table>
- </div>
- <Modal
- title={ t`EditConfigurationItems`}
- visible={isModalVisible}
- onCancel={handleCancel}
- onOk={() => {
- form.validateFields()
- .then((values: any) => {
- form.resetFields();
- handleOk(values);
- })
- .catch((info: any) => {
- console.log('Validate Failed:', info);
- });
- }}
- >
- <Form form={form} name="form_in_modal" initialValues={{ modifier: 'public' }}>
- <Form.Item label={ t`ConfigurationValue`+":"} name="value" rules={[{ required: true, message: '配置值不能为空' }]}>
- <Input placeholder={ t`PleaseEnterTheConfigurationValue`} />
- </Form.Item>
- <Form.Item
- name="persist"
- label={ t`EffectiveState`+":"}
- rules={[{ required: true, message: t`PleaseSelectAnEffectiveState` }]}
- >
- <Radio.Group value={'false'}>
- <Radio value="false">
- {t`TemporarilyEffective`}
- <Tooltip title={t`TemporarilyEffectiveTooltip`}>
- <InfoCircleOutlined style={{ marginLeft: '0.2em' }} />
- </Tooltip>
- </Radio>
- <Radio value="true">
- { t`Permanent`}
- <Tooltip title={ t`PermanentTooltip`}>
- <InfoCircleOutlined style={{ marginLeft: '0.2em' }} />
- </Tooltip>
- </Radio>
- </Radio.Group>
- </Form.Item>
- </Form>
- </Modal>
- </div>
- );
- function warning(failed: []) {
- const arr = failed.map((failedMsg:any) => {
- return <><span style={{ color: 'red' }}>{failedMsg.node}</span><span>{ t`Node`}</span><span style = {{color:'red'}}>{failedMsg.config_name}</span><span>{t`Error`+":"} {failedMsg.err_info}</span><br></br></>
- })
- Modal.error({
- content: <>
- <Divider />
- <h4>{ t`ConfigurationError`}</h4>
- <div style={{ height: '150px', width: '100%', overflow: 'auto', }}>
- {arr}
- </div>
- </>
- ,
- title: <span style={{ color: 'red' }}>{ t`FailToEdit`}</span>,
- // eslint-disable-next-line @typescript-eslint/no-empty-function
- onOk() { },
- bodyStyle: { height: '250px' },
- width: '520px',
- closable:true
-
- });
- }
-}
-
-
diff --git a/frontend/src/routes/node/list/index.tsx b/frontend/src/routes/node/list/index.tsx
deleted file mode 100644
index 25b9eea..0000000
--- a/frontend/src/routes/node/list/index.tsx
+++ /dev/null
@@ -1,190 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements. See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership. The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License. You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing,
-// software distributed under the License is distributed on an
-// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-// KIND, either express or implied. See the License for the
-// specific language governing permissions and limitations
-// under the License.
-
-/* eslint-disable prettier/prettier */
-import React, { useEffect, useState } from 'react';
-import { Table, Space, message } from 'antd';
-import { NodeAPI } from './node.api';
-import { useHistory } from 'react-router-dom';
-import { useTranslation } from 'react-i18next';
-export function NodeList() {
- const history = useHistory();
- const { t } = useTranslation();
- const [feColumns, setFeColumns] = useState<any>([]);
- const [beColumns, setBeColumns] = useState<any>([]);
- const [brokersColumns, setBrokersColumns] = useState<any>([]);
- const [beTableData, setBeTableData] = useState<any>([]);
- const [feTableData, setFeTableData] = useState<any>([]);
- const [brokersTableData, setBrokersTableData] = useState<any>([]);
- function refresh() {
- NodeAPI.getFrontends().then(res => {
- const { msg, data, code } = res;
- const { column_names, rows } = data;
- if (code === 0) {
- const column = column_names.map((item: string, index: number) => {
- if (index === 0) {
- return {
- title: 'FE '+t`Node`,
- dataIndex: index,
- key: item,
- width: 200,
- };
- } else {
- return {
- title: item,
- dataIndex: index,
- key: item,
- width:200,
- };
- }
- });
- column.push({
- title: 'CONF',
- key: 'action',
- render: (text: any, record: any, index: any) => (
- <Space size="middle">
- <a onClick={() => toFeDetailsPage(record)}>{t`Details`}</a>
- </Space>
- ),
- fixed: 'right',
- width:100,
- });
- setFeColumns(column);
- setFeTableData(rows.map((item: string[]) => ({ ...item })));
- } else {
- message.error(msg);
- }
- });
- NodeAPI.getBrokers().then(res => {
- const { msg, data, code } = res;
- const { column_names, rows } = data;
- if (code === 0) {
- const column = column_names.map((item: string, index: number) => {
- if (index === 0) {
- return {
- title: 'Brokers',
- dataIndex: index,
- key: item,
- width: 200,
- };
- } else {
- return {
- title: item,
- dataIndex: index,
- key: item,
- width:200,
- };
- }
- });
- setBrokersColumns(column);
- setBrokersTableData(rows.map((item: string[]) => ({ ...item })));
- } else {
- message.error(msg);
- }
- });
- NodeAPI.getBackends().then(res => {
- const { msg, data, code } = res;
- const { column_names, rows } = data;
- if (code === 0) {
- const column = column_names.map((item: string, index: number) => {
- if (index === 0) {
- return {
- title: 'BE '+t`Node`,
- dataIndex: index,
- key: item,
- width: 200,
- };
- } else {
- return {
- title: item,
- dataIndex: index,
- key: item,
- width:200,
- };
- }
- }
- );
- column.push({
- title: 'CONF',
- key: 'CONF',
- render: (text: any, record: any, index: any) => (
- <Space>
- <a onClick={() => toBeDetailsPage(record)} >{ t`Details`}</a>
- </Space>
- ),
- fixed: 'right',
- width:100,
- });
- setBeColumns(column);
- setBeTableData(rows.map((item: string[]) => ({ ...item })));
- } else {
- message.error(msg);
- }
- });
- }
- useEffect(() => {
- refresh();
- }, []);
-
- function toBeDetailsPage(record: any) {
- let node = "";
- node += record[2]+":"+record[6]
- localStorage.setItem("nodeText", node);
- history.push(`/configuration/be`)
- }
-
- function toFeDetailsPage(record: any) {
- let node = "";
- node += record[1]+":"+record[4]
- localStorage.setItem("nodeText", node);
- history.push(`/configuration/fe`) ;
- }
- return (
- <>
- <Table
- tableLayout="fixed"
- columns={feColumns}
- dataSource={feTableData}
- bordered
- scroll={{ x: 1300 }}
- size="middle"
- style={{ padding: '40px 0px' }}
- pagination={false}
- ></Table>
- <Table
- tableLayout="fixed"
- columns={beColumns}
- dataSource={beTableData}
- bordered
- scroll={{ x: 1300 }}
- size="middle"
- style={{ padding: '40px 0px' }}
- pagination={false}
- ></Table>
- <Table
- tableLayout="fixed"
- columns={brokersColumns}
- dataSource={brokersTableData}
- bordered
- scroll={{ x: 1300 }}
- size="middle"
- style={{ padding: '40px 0px' }}
- pagination={false}
- ></Table>
- </>
- );
-}
diff --git a/frontend/src/routes/node/list/node.api.ts b/frontend/src/routes/node/list/node.api.ts
deleted file mode 100644
index 4241e6b..0000000
--- a/frontend/src/routes/node/list/node.api.ts
+++ /dev/null
@@ -1,33 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements. See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership. The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License. You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing,
-// software distributed under the License is distributed on an
-// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-// KIND, either express or implied. See the License for the
-// specific language governing permissions and limitations
-// under the License.
-
-import { http } from '@src/utils/http';
-function getFrontends() {
- return http.get(`/api/rest/v2/manager/node/frontends`);
-}
-function getBrokers() {
- return http.get(`/api/rest/v2/manager/node/brokers`);
-}
-function getBackends() {
- return http.get(`/api/rest/v2/manager/node/backends`);
-}
-
-export const NodeAPI = {
- getFrontends,
- getBrokers,
- getBackends,
-};
diff --git a/frontend/src/routes/passport/forgot.login.tsx b/frontend/src/routes/passport/forgot.login.tsx
deleted file mode 100644
index 4393c46..0000000
--- a/frontend/src/routes/passport/forgot.login.tsx
+++ /dev/null
@@ -1,37 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements. See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership. The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License. You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing,
-// software distributed under the License is distributed on an
-// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-// KIND, either express or implied. See the License for the
-// specific language governing permissions and limitations
-// under the License.
-
-/** @format */
-import Link from 'antd/lib/typography/Link';
-import React, { useState } from 'react';
-import styles from './index.module.less';
-
-function ForgotLogin(props: any) {
- return (
- <div className={styles['not-found']}>
- <div className={styles['input-gird']}>
- <h3>Please contact an administrator to have them reset your password</h3>
- <br />
- <Link style={{ fontSize: '14px' }} onClick={() => props.history.push(`/login`)}>
- Back to login
- </Link>
- </div>
- </div>
- );
-}
-
-export default ForgotLogin;
diff --git a/frontend/src/routes/passport/login.tsx b/frontend/src/routes/passport/login.tsx
index 121d0d8..00a09f7 100644
--- a/frontend/src/routes/passport/login.tsx
+++ b/frontend/src/routes/passport/login.tsx
@@ -15,43 +15,44 @@
// specific language governing permissions and limitations
// under the License.
-import React, { useEffect, useState } from 'react';
-import { Form, Input, Button, Radio, Checkbox, message } from 'antd';
+import { Form, Input, Button, Checkbox, message } from 'antd';
import styles from './index.module.less';
import { PassportAPI } from './passport.api';
import { useTranslation } from 'react-i18next';
-import { useHistory } from 'react-router-dom';
-import { useAuth } from '@src/hooks/use-auth';
-export function Login(props: any) {
+import { useNavigate } from 'react-router';
+import { useEffect } from 'react';
+import { dorisAuthProvider } from '@src/components/auths/doris-auth-provider';
+export function Login() {
const [form] = Form.useForm();
- const { t } = useTranslation();
- const history = useHistory();
- const {initialized} = useAuth();
+ const { t } = useTranslation();
+ const navigate = useNavigate();
function handleLogin(_value: any) {
PassportAPI.SessionLogin(_value).then(res => {
if (res.code === 0) {
PassportAPI.getCurrentUser().then(user => {
- window.localStorage.setItem('login', 'true')
+ window.localStorage.setItem('login', 'true');
window.localStorage.setItem('user', JSON.stringify(user.data));
- history.push('/space/list');
- })
+ navigate('/space/list');
+ });
} else {
message.warn(res.msg);
}
});
}
+ useEffect(() => {
+ const login = dorisAuthProvider.checkLogin();
+ if (login) {
+ navigate('/');
+ }
+ }, []);
+
return (
<div className={styles['not-found']}>
<div className={styles['login-container']}>
- <Form
- form={form}
- layout="vertical"
- requiredMark={true}
- onFinish={handleLogin}
- >
- <h2 style={{ textAlign: 'center' }}>{ t`login`}</h2>
- <Form.Item label={ t`Username or Mail`} required name="username">
+ <Form form={form} layout="vertical" requiredMark={true} onFinish={handleLogin}>
+ <h2 style={{ textAlign: 'center' }}>{t`login`}</h2>
+ <Form.Item label={t`Username or Mail`} required name="username">
<Input placeholder={t`Please input the username or email`} />
</Form.Item>
<Form.Item label={t`password`} required name="password">
@@ -65,19 +66,11 @@ export function Login(props: any) {
</Form.Item>
<Form.Item>
<Button type="primary" style={{ width: '100%', borderRadius: 4, height: 45 }} htmlType="submit">
- { t`SignIn`}
+ {t`SignIn`}
</Button>
</Form.Item>
- {/* <Form.Item style={{ textAlign: 'center' }}>
- <Link
- style={{ fontSize: '14px', color: '#C7CFD4' }}
- onClick={() => props.history.push(`/forgot`)}
- >
- { t`ForgetThePassword`}
- </Link>
- </Form.Item> */}
</Form>
</div>
</div>
);
-};
+}
diff --git a/frontend/src/routes/query/index.tsx b/frontend/src/routes/query/index.tsx
deleted file mode 100644
index 0c36147..0000000
--- a/frontend/src/routes/query/index.tsx
+++ /dev/null
@@ -1,147 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements. See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership. The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License. You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing,
-// software distributed under the License is distributed on an
-// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-// KIND, either express or implied. See the License for the
-// specific language governing permissions and limitations
-// under the License.
-
-/* eslint-disable prettier/prettier */
-import React, { useState, useEffect } from 'react';
-import { Table, Card, Space, Input } from 'antd';
-import { useTranslation } from 'react-i18next';
-import { getQueryInfo } from './query.api';
-import { ColumnsType } from 'antd/es/table';
-import { FILTERS } from './query.data';
-import { useHistory } from 'react-router-dom';
-import { ClippedText } from '@src/components/clipped-text/clipped-text';
-const { Search } = Input;
-
-interface ICol {
- [propName: string]: any;
-}
-
-export function Query() {
- const { t } = useTranslation();
- const history = useHistory();
- const [tableData, setTableData] = useState<ICol[]>([]);
- const [tableColumn, setTableColumn] = useState<ColumnsType<ICol>>([]);
-
- function queryDetails(record: any) {
- console.log(record)
- history.push(`/details/${record[0]}`)
- }
- useEffect(() => {
- getQueryInfo().then(res => {
- const { column_names, rows } = res.data;
- handleResult(column_names, rows);
- });
- }, []);
- const onSearch = (value: string) => {
- let newValue = encodeURI(value)
- getQueryInfo({
- search: newValue,
- }).then(res => {
- const { column_names, rows } = res.data;
- handleResult(column_names, rows);
- });
- };
-
- const handleResult = (column_names: string[], rows: [][]) => {
- const columns = column_names.map((item: string, index: number) => {
- if (item === 'Query ID') {
- return {
- title: item,
- dataIndex: `${index}`,
- key: item,
- columnWidth: 10,
- render: (text: any, record: any, index: any) => (
- <ClippedText text={text}>
- <Space size="middle">
- <a onClick={() => queryDetails(record)}>{text}</a>
- </Space>
- </ClippedText>
-
- ),
- };
- }
- if (item === '状态') {
- return {
- title: item,
- dataIndex: `${index}`,
- key: item,
- columnWidth: 10,
- filters: FILTERS,
- onFilter: (value: any, record: any) => record[index].indexOf(value) === 0,
- };
- }
- if (item === 'FE节点') {
- return {
- title: item,
- dataIndex: index,
- key: item,
- width: 150,
- ellipsis: true,
- };
- }
- if (item === '开始时间') {
- return {
- title: item,
- dataIndex: index,
- key: item,
- width: 150,
- ellipsis: true,
- };
- }
- if (item === '结束时间') {
- return {
- title: item,
- dataIndex: index,
- key: item,
- width: 150,
- ellipsis: true,
- };
- }
- return {
- title: item,
- dataIndex: index,
- key: item,
- columnWidth: 10,
- ellipsis: true,
- };
- });
- setTableColumn(columns);
- setTableData(rows.map((item: string[]) => ({ ...item })));
- };
-
- return (
- <>
- <Card
- style={{ width: '100%' }}
- title={t`queryProfileFirst`}
- extra={<Search placeholder="搜索" onSearch={onSearch} allowClear/>}
- >
- <Table<ICol>
- columns={tableColumn}
- dataSource={tableData}
- bordered
- scroll={{ x: 1300 }}
- size="middle"
- pagination={{
- pageSizeOptions: ['10', '20', '50'],
- }}
- locale={{emptyText: t`noDate` }}
- ></Table>
- </Card>
- </>
- );
-}
diff --git a/frontend/src/routes/query/query-details/code.css b/frontend/src/routes/query/query-details/code.css
deleted file mode 100644
index e58d417..0000000
--- a/frontend/src/routes/query/query-details/code.css
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
-Licensed to the Apache Software Foundation (ASF) under one
-or more contributor license agreements. See the NOTICE file
-distributed with this work for additional information
-regarding copyright ownership. The ASF licenses this file
-to you under the Apache License, Version 2.0 (the
-"License"); you may not use this file except in compliance
-with the License. You may obtain a copy of the License at
-
-http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing,
-software distributed under the License is distributed on an
-"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-KIND, either express or implied. See the License for the
-specific language governing permissions and limitations
-under the License.
- */
-
-.hljs {
- color: #24292e;
- background: #ffffff;
- }
-
- .hljs-doctag,
- .hljs-keyword,
- .hljs-meta .hljs-keyword,
- .hljs-template-tag,
- .hljs-template-variable,
- .hljs-type,
- .hljs-variable.language_ {
- /* prettylights-syntax-keyword */
- color: #d73a49;
- }
-
- .hljs-title,
- .hljs-title.class_,
- .hljs-title.class_.inherited__,
- .hljs-title.function_ {
- /* prettylights-syntax-entity */
- color: #6f42c1;
- }
-
- .hljs-attr,
- .hljs-attribute,
- .hljs-literal,
- .hljs-meta,
- .hljs-number,
- .hljs-operator,
- .hljs-variable,
- .hljs-selector-attr,
- .hljs-selector-class,
- .hljs-selector-id {
- /* prettylights-syntax-constant */
- color: #005cc5;
- }
-
- .hljs-regexp,
- .hljs-string,
- .hljs-meta .hljs-string {
- /* prettylights-syntax-string */
- color: #032f62;
- }
-
- .hljs-built_in,
- .hljs-symbol {
- /* prettylights-syntax-variable */
- color: #e36209;
- }
-
- .hljs-comment,
- .hljs-code,
- .hljs-formula {
- /* prettylights-syntax-comment */
- color: #6a737d;
- }
-
- .hljs-name,
- .hljs-quote,
- .hljs-selector-tag,
- .hljs-selector-pseudo {
- /* prettylights-syntax-entity-tag */
- color: #22863a;
- }
-
- .hljs-subst {
- /* prettylights-syntax-storage-modifier-import */
- color: #24292e;
- }
-
- .hljs-section {
- /* prettylights-syntax-markup-heading */
- color: #005cc5;
- font-weight: bold;
- }
-
- .hljs-bullet {
- /* prettylights-syntax-markup-list */
- color: #735c0f;
- }
-
- .hljs-emphasis {
- /* prettylights-syntax-markup-italic */
- color: #24292e;
- font-style: italic;
- }
-
- .hljs-strong {
- /* prettylights-syntax-markup-bold */
- color: #24292e;
- font-weight: bold;
- }
-
- .hljs-addition {
- /* prettylights-syntax-markup-inserted */
- color: #22863a;
- background-color: #f0fff4;
- }
-
- .hljs-deletion {
- /* prettylights-syntax-markup-deleted */
- color: #b31d28;
- background-color: #ffeef0;
- }
-
- .hljs-char.escape_,
- .hljs-link,
- .hljs-params,
- .hljs-property,
- .hljs-punctuation,
- .hljs-tag {
- /* purposely ignored */
- }
-
\ No newline at end of file
diff --git a/frontend/src/routes/query/query-details/index.tsx b/frontend/src/routes/query/query-details/index.tsx
deleted file mode 100644
index 56d45dc..0000000
--- a/frontend/src/routes/query/query-details/index.tsx
+++ /dev/null
@@ -1,122 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements. See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership. The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License. You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing,
-// software distributed under the License is distributed on an
-// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-// KIND, either express or implied. See the License for the
-// specific language governing permissions and limitations
-// under the License.
-
-import React, { useState, useEffect, useCallback } from 'react';
-import { useParams } from 'react-router-dom';
-import { Table, Card } from 'antd';
-import { getSQLText, getProfileText, getQueryInfo } from './../query.api';
-import Profile from './profile';
-import styles from './query.module.less';
-import { ColumnsType } from 'antd/es/table';
-import { ClippedText } from '@src/components/clipped-text/clipped-text';
-import hljs from 'highlight.js'
-import './code.css';
-type tabType = 'sql' | 'text' | 'profile';
-interface ICol {
- [propName: string]: any;
-}
-export function QueryDetails() {
- const [currentTab, setCurrentTab] = useState<tabType>('sql');
- const [currentSQL, setCurrentSQL] = useState('sql');
- const [currentText, setCurrentText] = useState('sql');
- const [tableData, setTableData] = useState([]);
- const [tableColumn, setTableColumn] = useState<ColumnsType<ICol>>([]);
- const params = useParams<{ queryId: string }>();
- const queryId = params.queryId;
- const tabListNoTitle = [
- {
- key: 'sql',
- tab: 'SQL语句',
- },
- {
- key: 'text',
- tab: 'Text',
- },
- {
- key: 'profile',
- tab: 'Visualization',
- },
- ];
-
- const contentListNoTitle = {
- sql: (
- <div className={styles.textBox}>
- <div dangerouslySetInnerHTML={{__html:hljs.highlight(currentSQL, {language: 'sql'}).value}}></div>
- </div>
- ),
- text: (
- <div className={styles.textBox}>
- <pre>{currentText}</pre>
- </div>
- ),
- profile: <Profile></Profile>,
- };
-
- useEffect(() => {
- getQueryInfo({ query_id: queryId }).then(res => {
- const { column_names, rows } = res.data;
- const columns = column_names.map((item: string, index: number) => {
- if (item === 'Query ID') {
- return {
- title: item,
- dataIndex: `${index}`,
- key: item,
- columnWidth: 10,
- render: (text: any, record: any, index: any) => (
- <ClippedText>{text}</ClippedText>
- ),
- };
- }
- return {
- title: item,
- dataIndex: index,
- key: item,
- columnWidth: '10px',
- ellipsis: true,
- };
- });
- setTableColumn(columns);
- setTableData(rows.map((item: string[]) => ({ ...item })));
- });
- }, []);
- useEffect(() => {
- getSQLText({ queryId }).then(res => {
- setCurrentSQL(res.data?.sql || '--');
- });
- getProfileText({ queryId }).then(res => {
- setCurrentText(res.data?.profile || '--');
- });
- }, []);
-
- return (
- <>
- <Card style={{ width: '100%', border: 'none' }} bordered={false}>
- <Table columns={tableColumn} dataSource={tableData} size="middle" pagination={false}></Table>
- </Card>
- <Card
- style={{ width: '100%', border: 'none' }}
- tabList={tabListNoTitle}
- activeTabKey={currentTab}
- onTabChange={key => {
- setCurrentTab(key as tabType);
- }}
- >
- {contentListNoTitle[currentTab]}
- </Card>
- </>
- );
-}
diff --git a/frontend/src/routes/query/query-details/profile.tsx b/frontend/src/routes/query/query-details/profile.tsx
deleted file mode 100644
index de32091..0000000
--- a/frontend/src/routes/query/query-details/profile.tsx
+++ /dev/null
@@ -1,93 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements. See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership. The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License. You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing,
-// software distributed under the License is distributed on an
-// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-// KIND, either express or implied. See the License for the
-// specific language governing permissions and limitations
-// under the License.
-
-/* eslint-disable prettier/prettier */
-import React, { FC, useState, useEffect, useCallback } from 'react';
-import { useParams } from 'react-router-dom';
-import { Tree, Tag, Space, Card, Tabs } from 'antd';
-import { getProfileFragments, getProfileGraph } from '../query.api';
-import styles from './query.module.less'
-
-interface IFragment {
- fragment_id: string;
- instance_id: string[];
- time: string;
-}
-const Profile: FC = () => {
- const [value, setValue] = useState<string>('');
- const [treeData, setTreeData] = useState();
- const params = useParams<{ queryId: string }>();
- const queryId = params.queryId;
-
- useEffect(() => {
- getProfileFragments({ queryId }).then(res => {
- const temp = res.data.map((item: IFragment) => ({
-
- title: `Fragment${item.fragment_id} -- ${item.time}`,
- key: item.fragment_id,
- disabled: true,
- children: Object.keys(item.instance_id).map(instance => ({
- title: `${instance} -- ${item.instance_id[instance]}` ,
- key: instance,
- isLeaf: true,
- parent: item.fragment_id,
- })),
- }));
- setTreeData(temp);
- });
- getProfileGraph({
- queryId,
- }).then(res => {
- setValue(res.data.graph);
- });
- }, []);
-
- const treeChange = (keys: React.Key[], info: any) => {
- setValue('');
- const { key, parent } = info.node;
- getProfileGraph({
- queryId,
- fragmentId: parent,
- instanceId: key,
- }).then(res => {
- setValue(res.data.graph);
- });
- };
- function overview() {
- getProfileGraph({
- queryId,
- }).then(res => {
- setValue(res.data.graph);
- });
- }
-
- return (
- <div className={styles.profileBox}>
- <div className={styles.fragment}>
- <a onClick={() => overview()} style = {{margin: '0 0 0 27px'}}>Over View</a>
- <Tree showLine defaultExpandAll treeData={treeData} onSelect={treeChange}></Tree>
- </div>
- <div className={styles.graph}>
- <pre>
- <code>{value}</code>
- </pre>
- </div>
- </div>
- );
-};
-
-export default Profile;
diff --git a/frontend/src/routes/query/query.api.ts b/frontend/src/routes/query/query.api.ts
deleted file mode 100644
index 49ba9f3..0000000
--- a/frontend/src/routes/query/query.api.ts
+++ /dev/null
@@ -1,49 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements. See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership. The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License. You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing,
-// software distributed under the License is distributed on an
-// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-// KIND, either express or implied. See the License for the
-// specific language governing permissions and limitations
-// under the License.
-
-/** @format */
-
-import { http } from '@src/utils/http';
-import { IResult } from '@src/interfaces/http.interface';
-
-// 查询主页
-export function getQueryInfo(data?: any): Promise<IResult<any>> {
- return http.get(`/api/rest/v2/manager/query/query_info`, data);
-}
-
-// sql语句
-export function getSQLText(data?: any): Promise<IResult<any>> {
- return http.get(`/api/rest/v2/manager/query/sql/${data.queryId}`, {}, { responseType: 'json' });
-}
-
-// profile text
-export function getProfileText(data?: any): Promise<IResult<any>> {
- return http.get(`/api/rest/v2/manager/query/profile/text/${data.queryId}`);
-}
-
-// profile fragments
-export function getProfileFragments(data?: any): Promise<IResult<any>> {
- return http.get(`/api/rest/v2/manager/query/profile/fragments/${data.queryId}`);
-}
-
-// profile graph
-export function getProfileGraph(data?: any): Promise<IResult<any>> {
- return http.get(`/api/rest/v2/manager/query/profile/graph/${data.queryId}`, {
- fragment_id: data.fragmentId,
- instance_id: data.instanceId,
- });
-}
diff --git a/frontend/src/routes/query/query.data.ts b/frontend/src/routes/query/query.data.ts
deleted file mode 100644
index d613380..0000000
--- a/frontend/src/routes/query/query.data.ts
+++ /dev/null
@@ -1,28 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements. See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership. The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License. You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing,
-// software distributed under the License is distributed on an
-// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-// KIND, either express or implied. See the License for the
-// specific language governing permissions and limitations
-// under the License.
-
-export enum STATUS_MAP {
- RUNNING = 'RUNNING',
- EOF = 'EOF',
- ERR = 'ERR',
-}
-
-export const FILTERS = [
- { text: STATUS_MAP.RUNNING, value: STATUS_MAP.RUNNING },
- { text: STATUS_MAP.EOF, value: STATUS_MAP.EOF },
- { text: STATUS_MAP.ERR, value: STATUS_MAP.ERR },
-];
diff --git a/frontend/src/routes/settings/components/settings-header/settings-header.less b/frontend/src/routes/settings/components/settings-header/settings-header.less
deleted file mode 100644
index 24b55c7..0000000
--- a/frontend/src/routes/settings/components/settings-header/settings-header.less
+++ /dev/null
@@ -1,53 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements. See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership. The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License. You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing,
-// software distributed under the License is distributed on an
-// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-// KIND, either express or implied. See the License for the
-// specific language governing permissions and limitations
-// under the License.
-
-.admin-header {
- display: flex;
- width: 100%;
- background-color: #001529;
-}
-.admin-header-logo {
- color: white;
- width: 240px;
- padding-left: 40px;
- line-height: 48px;
- cursor: pointer;
-}
-.palo-opt-box{
- display: flex;
- height: 50px;
- align-items: center;
- div{
- margin-right: 16px;
- padding: 10px;
- cursor: pointer;
- .icon{
- font-size: 20px;
- }
- .icon-tip{
- margin-left: 0.5rem;
- vertical-align: text-bottom;
- }
- }
- div:hover{
- border-radius: 8px;
- background: rgb(32,78,171);
- }
- div:last-child{
- margin-right: 0;
- }
-}
\ No newline at end of file
diff --git a/frontend/src/routes/settings/components/settings-header/settings-header.tsx b/frontend/src/routes/settings/components/settings-header/settings-header.tsx
deleted file mode 100644
index 0ec08c2..0000000
--- a/frontend/src/routes/settings/components/settings-header/settings-header.tsx
+++ /dev/null
@@ -1,72 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements. See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership. The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License. You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing,
-// software distributed under the License is distributed on an
-// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-// KIND, either express or implied. See the License for the
-// specific language governing permissions and limitations
-// under the License.
-
-import { SettingOutlined } from '@ant-design/icons';
-import { UserInfoContext } from '@src/common/common.context';
-import { Menu, Space } from 'antd';
-import React, { useContext, useState } from 'react';
-import { useHistory, useRouteMatch } from 'react-router';
-import { SettingsIcon } from '../../../../components/settings-icon/settings-icon';
-import styles from './settings-header.less';
-
-export function SettingsHeader(props: any) {
- const history = useHistory();
- const match = useRouteMatch();
- const [current, setCurrent] = useState(() => {
- let tab = 'user';
- ['global', 'user'].map(key => {
- if (history.location.pathname.includes(key)) {
- tab = key;
- }
- });
- return tab;
- });
- const userInfo = useContext(UserInfoContext);
- function handleClick(e) {
- setCurrent(e.key);
- if (e.key === 'space') {
- history.push(`${match.path}/space/${userInfo.space_id}`);
- return;
- }
- history.push(`${match.path}/${e.key}`);
- }
- return (
- <div className={styles['admin-header']} style={{ display: 'flex'}}>
- <div className={styles['admin-header-logo']} onClick={() => {
- history.push(`/space`);
- }}>
- <Space>
- <SettingOutlined />
- Palo Studio平台管理
- </Space>
- </div>
- <Menu theme="dark" onClick={handleClick} selectedKeys={[current]} mode="horizontal" className={styles['admin-header']}>
- <Menu.Item key="user">
- 用户
- </Menu.Item>
- <Menu.Item key="global">
- 平台设置
- </Menu.Item>
- </Menu>
- <div className={styles['palo-opt-box']} style={{marginRight: 20}}>
- <div>
- <SettingsIcon context="global" />
- </div>
- </div>
- </div>
- );
-}
diff --git a/frontend/src/routes/settings/components/tabs-header/index.tsx b/frontend/src/routes/settings/components/tabs-header/index.tsx
index d9bbe05..2aae3b3 100644
--- a/frontend/src/routes/settings/components/tabs-header/index.tsx
+++ b/frontend/src/routes/settings/components/tabs-header/index.tsx
@@ -15,8 +15,7 @@
// specific language governing permissions and limitations
// under the License.
-import React from 'react';
-import { useLocation, useHistory } from 'react-router-dom';
+import { useLocation, useNavigate } from 'react-router-dom';
import { Tabs } from 'antd';
import { useTranslation } from 'react-i18next';
@@ -24,12 +23,12 @@ const { TabPane } = Tabs;
export default function TabsHeader() {
const { pathname } = useLocation();
- const history = useHistory();
+ const navigate = useNavigate();
- const {t} = useTranslation()
+ const { t } = useTranslation();
const handleTabChange = (key: string) => {
- history.replace(key);
+ navigate(key);
};
return (
diff --git a/frontend/src/routes/settings/settings.tsx b/frontend/src/routes/settings/settings.tsx
index abdebd6..f8a0ef9 100644
--- a/frontend/src/routes/settings/settings.tsx
+++ b/frontend/src/routes/settings/settings.tsx
@@ -15,9 +15,9 @@
// specific language governing permissions and limitations
// under the License.
-import React, { useEffect, useState } from 'react';
+import { useEffect, useState } from 'react';
import { Card } from 'antd';
-import { Redirect, Route, Switch, useRouteMatch, useHistory } from 'react-router-dom';
+import { Navigate, Route, Routes, useNavigate } from 'react-router-dom';
import styles from './settings.module.less';
import { UserInfoContext } from '@src/common/common.context';
import { Sidebar } from '@src/components/sidebar/sidebar';
@@ -27,15 +27,14 @@ import { User } from './user/user';
import { useUserInfo } from '@src/hooks/use-userinfo.hooks';
import LoadingLayout from './global/components/loading-layout';
-export function Settings(props: any) {
- const match = useRouteMatch();
- const history = useHistory();
+export function Settings() {
+ const navigate = useNavigate();
const [loading, setLoading] = useState(true);
const [userInfo] = useUserInfo();
useEffect(() => {
if (userInfo.id == null) return;
if (userInfo.id != null && !userInfo.is_super_admin) {
- history.push('/space');
+ navigate('/space');
return;
}
setLoading(false);
@@ -49,10 +48,10 @@ export function Settings(props: any) {
<Card className={styles.card}>
<TabsHeader />
<LoadingLayout loading={loading} wrapperStyle={{ textAlign: 'center', marginTop: 200 }}>
- <Switch>
- <Route path={`${match.path}/user`} component={User} />
- <Redirect to={`${match.path}/user`} />
- </Switch>
+ <Routes>
+ <Route path="users/*" element={<User />} />
+ <Route path="/" element={<Navigate replace to="users" />} />
+ </Routes>
</LoadingLayout>
</Card>
</div>
diff --git a/frontend/src/routes/settings/user/user.tsx b/frontend/src/routes/settings/user/user.tsx
index db6dbfc..d0f7dfb 100644
--- a/frontend/src/routes/settings/user/user.tsx
+++ b/frontend/src/routes/settings/user/user.tsx
@@ -15,18 +15,16 @@
// specific language governing permissions and limitations
// under the License.
-import React from 'react';
-import { Redirect, Route, Switch } from 'react-router-dom';
+import { Navigate, Route, Routes } from 'react-router-dom';
import { UserList } from './list/list';
-export function User(props: any) {
- const { match } = props;
+export function User() {
return (
<>
- <Switch>
- <Route exact path={`${match.path}`} component={UserList} />
- <Redirect to={`${match.path}`} />
- </Switch>
+ <Routes>
+ <Route path="list" element={<UserList />} />
+ <Route path="/" element={<Navigate replace to="list" />} />
+ </Routes>
</>
);
}
diff --git a/frontend/src/routes/space/access-cluster/access-cluster.tsx b/frontend/src/routes/space/access-cluster/access-cluster.tsx
index eefec29..2cec6c6 100644
--- a/frontend/src/routes/space/access-cluster/access-cluster.tsx
+++ b/frontend/src/routes/space/access-cluster/access-cluster.tsx
@@ -18,8 +18,6 @@
import ProCard from '@ant-design/pro-card';
import { Button, message, Row, Space, Steps } from 'antd';
import React, { useEffect, useState } from 'react';
-import { Redirect, useRouteMatch, useHistory } from 'react-router';
-import CacheRoute, { CacheSwitch } from 'react-router-cache-route';
import { pathToRegexp } from 'path-to-regexp';
import { NewSpaceInfoContext } from '@src/common/common.context';
import { useForm } from 'antd/lib/form/Form';
@@ -31,20 +29,24 @@ import { NodeVerify } from '../components/node-verify/node-verify';
import { isSuccess } from '@src/utils/http';
import { SpaceAPI } from '../space.api';
import { ClusterAccessParams } from '../space.interface';
-import { useRecoilState, useRecoilValue } from 'recoil';
+import { useRecoilState } from 'recoil';
import { requestInfoState, stepDisabledState } from './access-cluster.recoil';
import { ClusterVerify } from './steps/cluster-verify/cluster-verify';
import { SpaceAccessFinish } from './steps/finish/finish';
import { checkParam } from '../space.utils';
+import { Navigate, Route, Routes, useLocation, useMatch, useNavigate, useSearchParams } from 'react-router-dom';
const { Step } = Steps;
-export function AccessCluster(props: any) {
- const match = useRouteMatch<{ requestId: string }>();
- const history = useHistory();
+export function AccessCluster() {
+ const location = useLocation();
+ const navigate = useNavigate();
+ const [searchParams] = useSearchParams();
const [step, setStep] = React.useState(0);
const [loading, setLoading] = useState(false);
const [requestInfo, setRequestInfo] = useRecoilState(requestInfoState);
const [stepDisabled, setStepDisabled] = useRecoilState(stepDisabledState);
+ const requestId = searchParams.get('requestId');
+ const match = useMatch('space/access/:requestId/:step');
const hidePrevSteps = [
AccessClusterStepsEnum['space-register'],
AccessClusterStepsEnum['node-verify'],
@@ -53,26 +55,23 @@ export function AccessCluster(props: any) {
];
useEffect(() => {
- if (history.location.pathname === '/space/list') {
+ if (location.pathname === '/space/list') {
return;
}
- const regexp = pathToRegexp(`${match.path}/:step`);
- const paths = regexp.exec(history.location.pathname);
- const step = (paths as string[])[2];
+ const step = match?.params.step as string;
setStep(AccessClusterStepsEnum[step]);
setStepDisabled({ ...stepDisabled, next: false });
- if (match.params.requestId && +match.params.requestId !== 0) {
+ if (requestId && +requestId !== 0) {
getRequestInfo();
}
- }, [history.location.pathname]);
+ }, [location.pathname]);
const [form] = useForm();
async function getRequestInfo() {
- const requestId = match.params.requestId;
- const res = await SpaceAPI.getRequestInfo(requestId);
+ const res = await SpaceAPI.getRequestInfo(requestId as string);
if (isSuccess(res)) {
setRequestInfo(res.data);
}
@@ -124,8 +123,8 @@ export function AccessCluster(props: any) {
isParamsValid =
checkParam(params.authInfo.sshUser, '请填写SSH用户') &&
checkParam(params.authInfo.sshPort, '请填写SSH端口') &&
- checkParam(params.authInfo.sshKey, '请填写SSH私钥') &&
- checkParam(params.installInfo, '请填写安装路径')
+ checkParam(params.authInfo.sshKey, '请填写SSH私钥') &&
+ checkParam(params.installInfo, '请填写安装路径');
}
if (!isParamsValid) return;
setLoading(true);
@@ -136,7 +135,7 @@ export function AccessCluster(props: any) {
setStep(newStep);
setStepDisabled({ ...stepDisabled, next: false });
setTimeout(() => {
- history.push(`/space/access/${res.data.requestId}/${AccessClusterStepsEnum[newStep]}`);
+ navigate(`/space/access/${res.data.requestId}/${AccessClusterStepsEnum[newStep]}`);
}, 0);
} else {
message.error(res.msg);
@@ -147,11 +146,11 @@ export function AccessCluster(props: any) {
const newStep = step - 1;
setStep(newStep);
setStepDisabled({ ...stepDisabled, prev: false });
- history.push(`/space/access/${requestInfo.requestId}/${AccessClusterStepsEnum[newStep]}`);
+ navigate(`/space/access/${requestInfo.requestId}/${AccessClusterStepsEnum[newStep]}`);
}
function finish() {
- history.push('/space/list');
+ navigate('/space/list');
}
return (
@@ -175,24 +174,15 @@ export function AccessCluster(props: any) {
</Steps>
</div>
<div style={{ marginRight: 240 }}>
- <CacheSwitch>
- <CacheRoute path={`${match.path}/${AccessClusterStepsEnum[0]}`} component={SpaceRegister} />
- <CacheRoute
- path={`${match.path}/${AccessClusterStepsEnum[1]}`}
- component={ConnectCluster}
- />
- <CacheRoute
- path={`${match.path}/${AccessClusterStepsEnum[2]}`}
- component={ManagedOptions}
- />
- <CacheRoute path={`${match.path}/${AccessClusterStepsEnum[3]}`} component={NodeVerify} />
- <CacheRoute path={`${match.path}/${AccessClusterStepsEnum[4]}`} component={ClusterVerify} />
- <CacheRoute
- path={`${match.path}/${AccessClusterStepsEnum[5]}`}
- component={SpaceAccessFinish}
- />
- <Redirect to={`${match.path}/${AccessClusterStepsEnum[0]}`} />
- </CacheSwitch>
+ <Routes>
+ <Route path={`${AccessClusterStepsEnum[0]}`} element={<SpaceRegister />} />
+ <Route path={`${AccessClusterStepsEnum[1]}`} element={<ConnectCluster />} />
+ <Route path={`${AccessClusterStepsEnum[2]}`} element={<ManagedOptions />} />
+ <Route path={`${AccessClusterStepsEnum[3]}`} element={<NodeVerify />} />
+ <Route path={`${AccessClusterStepsEnum[4]}`} element={<ClusterVerify />} />
+ <Route path={`${AccessClusterStepsEnum[5]}`} element={<SpaceAccessFinish />} />
+ <Route path="/" element={<Navigate replace to={AccessClusterStepsEnum[0]} />} />
+ </Routes>
<Row justify="end" style={{ marginTop: 20 }}>
<Space>
{hidePrevSteps.includes(step) ? (
diff --git a/frontend/src/routes/space/access-cluster/steps/cluster-verify/cluster-verify.tsx b/frontend/src/routes/space/access-cluster/steps/cluster-verify/cluster-verify.tsx
index 20143ef..5839eb9 100644
--- a/frontend/src/routes/space/access-cluster/steps/cluster-verify/cluster-verify.tsx
+++ b/frontend/src/routes/space/access-cluster/steps/cluster-verify/cluster-verify.tsx
@@ -15,11 +15,9 @@
// specific language governing permissions and limitations
// under the License.
-import React, { useContext, useEffect, useLayoutEffect, useState } from 'react';
+import React, { useContext, useEffect, useState } from 'react';
import { PageContainer } from '@ant-design/pro-layout';
-import ProCard from '@ant-design/pro-card';
-import { Button, message, Row, Space, Steps, Table, Tabs } from 'antd';
-import { useHistory, useRouteMatch } from 'react-router';
+import { message, Steps, Table, Tabs } from 'antd';
import TabPane from '@ant-design/pro-card/lib/components/TabPane';
import { isSuccess } from '@src/utils/http';
import { NewSpaceInfoContext } from '@src/common/common.context';
@@ -38,7 +36,6 @@ const ERROR_STATUS = [OperateStatusEnum.FAIL, OperateStatusEnum.CANCEL];
export function ClusterVerify(props: any) {
const [activeKey, setActiveKey] = useState(DorisNodeTypeEnum.FE);
const { reqInfo } = useContext(NewSpaceInfoContext);
- const match = useRouteMatch<{ spaceId: string }>();
const [instance, setInstance] = useState([]);
const [nodeTypes, setNodeTypes] = useState<any[]>([]);
const [feNodes, setFENodes] = useState([]);
@@ -93,7 +90,7 @@ export function ClusterVerify(props: any) {
const feNodes = res.data.filter(item => item.moduleName?.toUpperCase() === DorisNodeTypeEnum.FE);
const beNodes = res.data.filter(item => item.moduleName?.toUpperCase() === DorisNodeTypeEnum.BE);
const brokerNodes = res.data.filter(
- item => item.moduleName?.toUpperCase() === DorisNodeTypeEnum.BROKER,
+ (item: any) => item.moduleName?.toUpperCase() === DorisNodeTypeEnum.BROKER,
);
setFENodes(feNodes);
setBENodes(beNodes);
diff --git a/frontend/src/routes/space/components/finish/finish.tsx b/frontend/src/routes/space/components/finish/finish.tsx
index 4eb8874..687a1fc 100644
--- a/frontend/src/routes/space/components/finish/finish.tsx
+++ b/frontend/src/routes/space/components/finish/finish.tsx
@@ -17,13 +17,11 @@
import { PageContainer } from '@ant-design/pro-layout';
import { NewSpaceInfoContext } from '@src/common/common.context';
-import { Result, Button, Checkbox, Form, Input, Row, Space } from 'antd';
+import { Result, Form, Input, Row, Space } from 'antd';
import React, { useContext } from 'react';
-import { useHistory } from 'react-router';
-export function SpaceCreateFinish(props: any) {
+export function SpaceCreateFinish() {
const { form } = useContext(NewSpaceInfoContext);
- const history = useHistory();
const onFinish = (values: any) => {
console.log('Success:', values);
};
diff --git a/frontend/src/routes/space/components/result-modal.tsx b/frontend/src/routes/space/components/result-modal.tsx
index 48a3612..94e2b13 100644
--- a/frontend/src/routes/space/components/result-modal.tsx
+++ b/frontend/src/routes/space/components/result-modal.tsx
@@ -16,27 +16,26 @@
// under the License.
import React, { useEffect, useState } from 'react';
-import { PageContainer } from '@ant-design/pro-layout';
-import { Button, Row, Space, Table, Modal, message } from 'antd';
-import { useHistory } from 'react-router';
-import { nodeStatusQuery, fresh , modalState, stepState, processId} from '../new-cluster/recoils/index'
-import { useRecoilState, useRecoilValue, useSetRecoilState } from 'recoil';
+import { Button, Space, Table, Modal, message } from 'antd';
+import { fresh, modalState, stepState, processId } from '../new-cluster/recoils/index';
+import { useRecoilState, useRecoilValue } from 'recoil';
import API from '../new-cluster/new-cluster.api';
import { isSuccess } from '@src/utils/http';
import * as types from '../new-cluster/types/index.type';
-import { NewClusterStepsEnum } from '../new-cluster/new-cluster.data'
+import { NewClusterStepsEnum } from '../new-cluster/new-cluster.data';
import ProCard from '@ant-design/pro-card';
import { DorisNodeTypeEnum } from '../new-cluster/types/index.type';
+import { useNavigate } from 'react-router';
export function ResultModal(props: any) {
- const history = useHistory();
+ const navigate = useNavigate();
// const nodeStatus = useRecoilValue(nodeStatusQuery);
const [modal, setModal] = useRecoilState(modalState);
const [refresh, setFresh] = useRecoilState(fresh);
const [step, setStep] = useRecoilState(stepState);
const processID = useRecoilValue(processId);
const [data, setData] = useState<types.ItaskResult[]>([]);
- const [loading, setloading] = useState(false)
+ const [loading, setloading] = useState(false);
const columns = [
{
title: '序号',
@@ -52,18 +51,26 @@ export function ResultModal(props: any) {
title: '状态信息',
dataIndex: 'status',
key: 'status',
- render: (_, record:any) => (
+ render: (_, record: any) => (
<Space>
- <span>{record.status} {record.result}</span>
+ <span>
+ {record.status} {record.result}
+ </span>
</Space>
),
},
{
title: '操作',
key: 'option',
- render: (_, record:any) => (
+ render: (_, record: any) => (
<Space>
- <Button type="link" disabled={record.status !== types.taskStatusEnum.FAILURE} onClick={() => reTry(record)}>重试</Button>
+ <Button
+ type="link"
+ disabled={record.status !== types.taskStatusEnum.FAILURE}
+ onClick={() => reTry(record)}
+ >
+ 重试
+ </Button>
{/* <Button type="link" disabled={record.status !== types.taskStatusEnum.FAILURE} onClick={() => doSkip(record)}>跳过</Button>
<Button type="link" onClick={() => viewLog(record)}>查看日志</Button> */}
</Space>
@@ -71,104 +78,121 @@ export function ResultModal(props: any) {
},
];
- const handleOk = (() => {
- setStep(step + 1)
+ const handleOk = () => {
+ setStep(step + 1);
setModal({
...modal,
- visible: false
- })
- console.log(NewClusterStepsEnum[step + 1])
+ visible: false,
+ });
+ console.log(NewClusterStepsEnum[step + 1]);
// window.location.reload() //todo
- history.replace(`/cluster/new/${NewClusterStepsEnum[step + 1]}`)
- })
- const handleCancel = (() => {
+ navigate(`/cluster/new/${NewClusterStepsEnum[step + 1]}`);
+ };
+ const handleCancel = () => {
setModal({
...modal,
- visible: false
- })
- })
+ visible: false,
+ });
+ };
const reTry = (record: any) => {
API.reTryTask(record.id).then(res => {
- if(isSuccess(res)){
- message.success(res.msg)
- setFresh(refresh + 1)
- setData([])
+ if (isSuccess(res)) {
+ message.success(res.msg);
+ setFresh(refresh + 1);
+ setData([]);
fetchNode();
- }else{
- message.warn(res.msg)
+ } else {
+ message.warn(res.msg);
}
- })
- }
- const doSkip = (record: any) => {
- API.skipTask(record.id).then(res => {
- if(isSuccess(res)){
- message.success(res.msg)
- setFresh(refresh + 1)
- setData([])
- fetchNode();
- }else{
- message.warn(res.msg)
- }
- })
- }
- const viewLog = (record: any) => {
- history.push({
- pathname: `/cluster/logs/${record.id}`
- })
- }
+ });
+ };
const fetchNode = () => {
setloading(true);
API.getTaskStatus(processID).then(res => {
- setData(res.data)
+ setData(res.data);
setloading(false);
- })
- }
+ });
+ };
useEffect(() => {
fetchNode();
- }, [modal.visible])
+ }, [modal.visible]);
useEffect(() => {
let timer: any = null;
- console.log('00000')
- let len = data.filter(item => (item.status === types.taskStatusEnum.SUCCESS) || (item.status === types.taskStatusEnum.FAILURE)).length;
- if(modal.visible && (len < data.length || data.length === 0)){
+ console.log('00000');
+ const len = data.filter(
+ item => item.status === types.taskStatusEnum.SUCCESS || item.status === types.taskStatusEnum.FAILURE,
+ ).length;
+ if (modal.visible && (len < data.length || data.length === 0)) {
timer = window.setTimeout(() => {
- setFresh(refresh + 1)
- fetchNode()
- }, 5000)
+ setFresh(refresh + 1);
+ fetchNode();
+ }, 5000);
}
return () => {
- window.clearTimeout(timer)
- }
- }, [refresh, modal.visible])
+ window.clearTimeout(timer);
+ };
+ }, [refresh, modal.visible]);
return (
- <Modal title="节点状态" visible={modal.visible} onOk={handleOk} onCancel={handleCancel} width={'80%'}
+ <Modal
+ title="节点状态"
+ visible={modal.visible}
+ onOk={handleOk}
+ onCancel={handleCancel}
+ width={'80%'}
maskClosable={false}
footer={[
- <Button key="back" onClick={handleCancel}>取消</Button>,
- <Button key="submit" type="primary" onClick={handleOk} disabled={(data.filter(item => item.status === types.taskStatusEnum.SUCCESS).length) !== data.length}>下一步</Button>
+ <Button key="back" onClick={handleCancel}>
+ 取消
+ </Button>,
+ <Button
+ key="submit"
+ type="primary"
+ onClick={handleOk}
+ disabled={data.filter(item => item.status === types.taskStatusEnum.SUCCESS).length !== data.length}
+ >
+ 下一步
+ </Button>,
// <Button key="submit" type="primary" onClick={handleOk}>下一步</Button>
- ]}>
- {
- step === 0 ?
- <Table columns={columns} dataSource={data} rowKey="id" key={1} loading={loading}/>
- :
+ ]}
+ >
+ {step === 0 ? (
+ <Table columns={columns} dataSource={data} rowKey="id" key={1} loading={loading} />
+ ) : (
<>
<ProCard bordered title={'FE节点'}>
- <Table columns={columns} dataSource={data.filter(item => (item.taskRole === DorisNodeTypeEnum.FE))} rowKey="id" pagination={false} loading={loading}/>
+ <Table
+ columns={columns}
+ dataSource={data.filter(item => item.taskRole === DorisNodeTypeEnum.FE)}
+ rowKey="id"
+ pagination={false}
+ loading={loading}
+ />
</ProCard>
<ProCard bordered title={'BE节点'}>
- <Table columns={columns} dataSource={data.filter(item => (item.taskRole === DorisNodeTypeEnum.BE))} rowKey="id" pagination={false} loading={loading}/>
+ <Table
+ columns={columns}
+ dataSource={data.filter(item => item.taskRole === DorisNodeTypeEnum.BE)}
+ rowKey="id"
+ pagination={false}
+ loading={loading}
+ />
</ProCard>
<ProCard bordered title={'BROKER节点'}>
- <Table columns={columns} dataSource={data.filter(item => (item.taskRole === DorisNodeTypeEnum.BROKER))} rowKey="id" pagination={false} loading={loading}/>
+ <Table
+ columns={columns}
+ dataSource={data.filter(item => item.taskRole === DorisNodeTypeEnum.BROKER)}
+ rowKey="id"
+ pagination={false}
+ loading={loading}
+ />
</ProCard>
</>
- }
+ )}
</Modal>
);
-}
\ No newline at end of file
+}
diff --git a/frontend/src/routes/space/detail/space-detail.tsx b/frontend/src/routes/space/detail/space-detail.tsx
index 29f9977..912c900 100644
--- a/frontend/src/routes/space/detail/space-detail.tsx
+++ b/frontend/src/routes/space/detail/space-detail.tsx
@@ -15,17 +15,13 @@
// specific language governing permissions and limitations
// under the License.
-import React, { useEffect, useState } from 'react';
+import { useEffect, useState } from 'react';
import styles from '../space.less';
import { Button, Form, Input, Row, Space, Select, Col, InputNumber, Tag } from 'antd';
-import { Divider, message } from 'antd';
+import { message } from 'antd';
import { SpaceAPI } from '../space.api';
-import { useHistory, useParams } from 'react-router-dom';
+import { useNavigate, useParams } from 'react-router-dom';
import { useTranslation } from 'react-i18next';
-import { RequiredMark } from 'antd/lib/form/Form';
-import { modal } from '@src/components/doris-modal/doris-modal';
-import { useRecoilValue } from 'recoil';
-import { usersQuery } from '../space.recoil';
import { useUserInfo } from '@src/hooks/use-userinfo.hooks';
import { useAsync } from '@src/hooks/use-async';
import { isSuccess } from '@src/utils/http';
@@ -35,13 +31,12 @@ export function SpaceDetail() {
const [form] = Form.useForm();
const [userInfo, setUserInfo] = useUserInfo();
const params = useParams<{ spaceId: string }>();
- const [buttonType, setButtonType] = useState<'primary' | 'default'>('default');
const [saveButtonDisable, setSaveButtonDisable] = useState(true);
const [initForm, setInitForm] = useState<any>({});
- const history = useHistory();
+ const navigate = useNavigate();
const { data: allUsers, loading, run: runGetAllUsers } = useAsync<any[]>({ data: [], loading: true });
function getSpaceInfo() {
- SpaceAPI.spaceGet(params.spaceId).then(res => {
+ SpaceAPI.spaceGet(params.spaceId as string).then(res => {
const { msg, data, code } = res;
if (code === 0) {
if (res.data) {
@@ -74,36 +69,18 @@ export function SpaceDetail() {
getSpaceInfo();
}, [loading]);
- function handleDelete() {
- const spaceId = params.spaceId;
- modal.confirm(t`notice`, t`SpaceDeleteTips`, async () => {
- SpaceAPI.spaceDelete(spaceId).then(result => {
- if (result && result.code !== 0) {
- modal.error('空间删除失败', result.msg);
- } else {
- modal.success('空间删除成功').then(result => {
- if (result.isConfirmed) {
- history.push(`/space/list`);
- }
- });
- }
- });
- });
- }
-
const handleSave = () => {
form.validateFields().then(value => {
SpaceAPI.spaceUpdate({
describe: value.describe,
name: value.name.trim(),
spaceAdminUsers: value.spaceAdminUserId,
- spaceId: params.spaceId,
+ spaceId: params.spaceId as string,
}).then(res => {
console.log(res);
if (res.code === 0) {
message.success(res.msg);
setSaveButtonDisable(true);
- // history.push('/')
} else {
message.error(res.msg);
}
@@ -111,19 +88,6 @@ export function SpaceDetail() {
});
};
- const handleMeta = () => {
- SpaceAPI.metaOption().then(res => {
- if (res.code === 0) {
- setButtonType('primary');
- window.setTimeout(() => {
- setButtonType('default');
- }, 2000);
- } else {
- message.error(res.msg);
- }
- });
- };
-
return (
<div style={{ padding: '50px' }}>
<Row justify="center">
@@ -149,7 +113,7 @@ export function SpaceDetail() {
if (value === initForm?.name) {
return Promise.resolve();
}
- let resData = await SpaceAPI.spaceCheck(value);
+ const resData = await SpaceAPI.spaceCheck(value);
if (resData.code === 0) {
return Promise.resolve();
}
@@ -210,28 +174,9 @@ export function SpaceDetail() {
<Row justify="center">
<Space>
- {/* <Button
- type="primary"
- onClick={() => {
- history.push(`/space/list`);
- }}
- >
- 取消
- </Button>
- {
- userInfo?.is_super_admin && (
- <Button type="primary" danger onClick={handleDelete}>
- 删除
- </Button>
- )
- } */}
- {/* {
- userInfo?.is_admin && ( */}
<Button type="primary" onClick={handleSave} disabled={saveButtonDisable}>
{t`Save`}
</Button>
- {/* )
- } */}
</Space>
</Row>
</div>
diff --git a/frontend/src/routes/space/list/list.tsx b/frontend/src/routes/space/list/list.tsx
index 0488cfd..02dbf1b 100644
--- a/frontend/src/routes/space/list/list.tsx
+++ b/frontend/src/routes/space/list/list.tsx
@@ -14,14 +14,14 @@
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
-import React, { useContext, useEffect, useState } from 'react';
+
+import { useContext, useEffect, useState } from 'react';
import { Button, Dropdown, Menu, Row, Table, Tabs } from 'antd';
import { Space } from 'antd';
import { SpaceAPI } from '../space.api';
import moment from 'moment';
import { FlatBtn, FlatBtnGroup } from '@src/components/flatbtn';
import { TABLE_DELAY } from '@src/config';
-import { useHistory } from 'react-router';
import { PageContainer } from '@ant-design/pro-layout';
import { useRequest } from 'ahooks';
import { DownOutlined } from '@ant-design/icons';
@@ -32,12 +32,13 @@ import { requestInfoState } from '../access-cluster/access-cluster.recoil';
import { UserInfoContext } from '@src/common/common.context';
import { useTranslation } from 'react-i18next';
import { NewClusterStepsEnum } from '../new-cluster/new-cluster.data';
+import { useNavigate } from 'react-router';
const { TabPane } = Tabs;
type SpaceListType = 'finished' | 'draft';
export const SpaceList = () => {
const userInfo = useContext(UserInfoContext);
- const history = useHistory();
+ const navigate = useNavigate();
const [activeKey, setActiveKey] = useState<SpaceListType>('finished');
const [requestInfo, setRequestInfo] = useRecoilState(requestInfoState);
const { t } = useTranslation();
@@ -80,14 +81,14 @@ export const SpaceList = () => {
async function recover(record: any) {
record.requestInfo.type === 'CREATION'
- ? history.push(`/space/new/${record.requestId}/${NewClusterStepsEnum[record.eventType]}`)
- : history.push(`/space/access/${record.requestId}/${AccessClusterStepsEnum[record.eventType]}`);
+ ? navigate(`/space/new/${record.requestId}/${NewClusterStepsEnum[record.eventType]}`)
+ : navigate(`/space/access/${record.requestId}/${AccessClusterStepsEnum[record.eventType]}`);
}
const enterSpace = (record: any) => {
SpaceAPI.switchSpace(record.id).then(res => {
if (res.code === 0) {
- history.push('/');
+ navigate('/cluster');
}
});
};
@@ -169,14 +170,14 @@ export const SpaceList = () => {
<Menu.Item
onClick={() => {
setRequestInfo(ACCESS_CLUSTER_REQUEST_INIT_PARAMS);
- history.push('/space/new/0');
+ navigate('/space/new/0');
}}
key="1"
>{t`New Cluster`}</Menu.Item>
<Menu.Item
onClick={() => {
setRequestInfo(ACCESS_CLUSTER_REQUEST_INIT_PARAMS);
- history.push('/space/access/0');
+ navigate('/space/access/0');
}}
key="2"
>{t`Cluster hosting`}</Menu.Item>
diff --git a/frontend/src/routes/space/new-cluster/logs/logs.tsx b/frontend/src/routes/space/new-cluster/logs/logs.tsx
index 8d0d391..a8201ad 100644
--- a/frontend/src/routes/space/new-cluster/logs/logs.tsx
+++ b/frontend/src/routes/space/new-cluster/logs/logs.tsx
@@ -15,32 +15,40 @@
// specific language governing permissions and limitations
// under the License.
-import React, {useEffect, useState} from 'react';
+import React, { useEffect, useState } from 'react';
import { PageContainer } from '@ant-design/pro-layout';
-import { useHistory, useParams } from 'react-router';
+import { useNavigate, useParams } from 'react-router';
import API from '../new-cluster.api';
import { Button } from 'antd';
-export function Logs(props: any) {
- const history = useHistory();
- const params = useParams<{taskId: string}>();
+export function Logs() {
+ const navigate = useNavigate();
+ const params = useParams<{ taskId: string }>();
const [logText, setlogText] = useState('');
useEffect(() => {
- API.getTaskLog(params.taskId).then(res => {
- setlogText(res.data.log)
- })
- }, [])
+ API.getTaskLog(params.taskId as string).then(res => {
+ setlogText(res.data.log);
+ });
+ }, []);
return (
<PageContainer
header={{
title: '日志',
}}
extra={[
- <Button key="1" type="primary" onClick={() => {history.goBack()}}>返回</Button>,
- ]}
+ <Button
+ key="1"
+ type="primary"
+ onClick={() => {
+ navigate(-1);
+ }}
+ >
+ 返回
+ </Button>,
+ ]}
>
- <div style={{width: '100%', background: '#000', color: '#fff', height:'80vh', overflow: "scroll"}}>
+ <div style={{ width: '100%', background: '#000', color: '#fff', height: '80vh', overflow: 'scroll' }}>
<code>{logText}</code>
</div>
</PageContainer>
diff --git a/frontend/src/routes/space/new-cluster/new-cluster.tsx b/frontend/src/routes/space/new-cluster/new-cluster.tsx
index 6958a69..6654991 100644
--- a/frontend/src/routes/space/new-cluster/new-cluster.tsx
+++ b/frontend/src/routes/space/new-cluster/new-cluster.tsx
@@ -18,15 +18,10 @@
import ProCard from '@ant-design/pro-card';
import { Button, message, Row, Space, Steps } from 'antd';
import React, { useEffect, useState } from 'react';
-import { Switch, Route, Redirect, useRouteMatch, useHistory } from 'react-router';
import { NewClusterStepsEnum } from './new-cluster.data';
import { ClusterPlan } from './steps/cluster-plan/cluster-plan';
import { NodeConfig } from './steps/node-config/node-config';
-import { RunCluster } from './steps/run-cluster/run-cluster';
-import { stepState, CurrentProcessQuery, processId } from './recoils/index';
-import { useRecoilState, useRecoilValue } from 'recoil';
-import CacheRoute, { CacheSwitch } from 'react-router-cache-route';
-import { pathToRegexp } from 'path-to-regexp';
+import { useRecoilState } from 'recoil';
import { AddNode } from './steps/add-node/add-node';
import { InstallOptions } from './steps/install-options/install-options';
import { ClusterDeploy } from './steps/cluster-deploy/cluster-deploy';
@@ -41,44 +36,44 @@ import { requestInfoState, stepDisabledState } from '../access-cluster/access-cl
import { checkParam } from '../space.utils';
import { useTranslation } from 'react-i18next';
+import { Navigate, Route, Routes, useLocation, useMatch, useNavigate } from 'react-router';
+import { useSearchParams } from 'react-router-dom';
const { Step } = Steps;
const PREV_DISABLED_STEPS = [NewClusterStepsEnum[3], NewClusterStepsEnum[6], NewClusterStepsEnum[7]];
const NEXT_DISABLED_STEPS = [NewClusterStepsEnum[3], NewClusterStepsEnum[6]];
-export function NewCluster(props: any) {
- const {t} = useTranslation()
- const match = useRouteMatch<{ requestId: string }>();
- const history = useHistory();
+export function NewCluster() {
+ const { t } = useTranslation();
+ const navigate = useNavigate();
+ const location = useLocation();
const [step, setStep] = React.useState(0);
const [stepDisabled, setStepDisabled] = useRecoilState(stepDisabledState);
- // const [curStep, setStepState] = useRecoilState(stepState);
- const [curProcessId, setProcessId] = useRecoilState(processId);
const [requestInfo, setRequestInfo] = useRecoilState(requestInfoState);
const [loading, setLoading] = useState(false);
const [form] = useForm();
+ const [searchParams] = useSearchParams();
+ const requestId = searchParams.get('requestId');
+ const match = useMatch('space/new/:requestId/:step');
useEffect(() => {
- if (history.location.pathname === '/space/list') {
+ if (location.pathname === '/space/list') {
return;
}
- const regexp = pathToRegexp(`${match.path}/:step`);
- const paths = regexp.exec(history.location.pathname);
- const step = (paths as string[])[2];
+ const step = match?.params.step as string;
setStep(NewClusterStepsEnum[step]);
setStepDisabled({
...stepDisabled,
next: NEXT_DISABLED_STEPS.includes(step),
prev: PREV_DISABLED_STEPS.includes(step),
});
- if (match.params.requestId && +match.params.requestId !== 0) {
+ if (requestId && +requestId !== 0) {
getRequestInfo();
}
- }, [history.location.pathname]);
+ }, [location.pathname]);
async function getRequestInfo() {
- const requestId = match.params.requestId;
- const res = await SpaceAPI.getRequestInfo(requestId);
+ const res = await SpaceAPI.getRequestInfo(requestId as string);
if (isSuccess(res)) {
setRequestInfo(res.data);
}
@@ -145,7 +140,7 @@ export function NewCluster(props: any) {
setRequestInfo(res.data);
setStep(newStep);
setTimeout(() => {
- history.push(`/space/new/${res.data.requestId}/${NewClusterStepsEnum[newStep]}`);
+ navigate(`/space/new/${res.data.requestId}/${NewClusterStepsEnum[newStep]}`);
}, 0);
} else {
message.error(res.msg);
@@ -155,7 +150,7 @@ export function NewCluster(props: any) {
function prevStep() {
const newStep = step - 1;
setStep(newStep);
- history.push(`/space/new/${requestInfo.requestId}/${NewClusterStepsEnum[newStep]}`);
+ navigate(`/space/new/${requestInfo.requestId}/${NewClusterStepsEnum[newStep]}`);
}
async function finish() {
@@ -173,7 +168,7 @@ export function NewCluster(props: any) {
const res = await SpaceAPI.createCluster(params);
setLoading(false);
if (isSuccess(res)) {
- history.push(`/space/list`);
+ navigate(`/space/list`);
} else {
message.error(res.msg);
}
@@ -201,18 +196,18 @@ export function NewCluster(props: any) {
<Step title={t`creationComplete`} description=" " />
</Steps>
</div>
- <div style={{ marginRight: 300 }}>
- <CacheSwitch>
- <CacheRoute path={`${match.path}/register-space`} component={SpaceRegister} />
- <CacheRoute path={`${match.path}/add-node`} component={AddNode} />
- <CacheRoute path={`${match.path}/install-options`} component={InstallOptions} />
- <CacheRoute path={`${match.path}/verify-node`} component={NodeVerify} />
- <CacheRoute path={`${match.path}/cluster-plan`} component={ClusterPlan} />
- <CacheRoute path={`${match.path}/node-config`} component={NodeConfig} />
- <CacheRoute path={`${match.path}/cluster-deploy`} component={ClusterDeploy} />
- <CacheRoute path={`${match.path}/finish`} component={SpaceCreateFinish} />
- <Redirect to={`${match.path}/register-space`} />
- </CacheSwitch>
+ <div style={{ marginRight: 240 }}>
+ <Routes>
+ <Route path={`register-space`} element={<SpaceRegister />} />
+ <Route path={`add-node`} element={<AddNode />} />
+ <Route path={`install-options`} element={<InstallOptions />} />
+ <Route path={`verify-node`} element={<NodeVerify />} />
+ <Route path={`cluster-plan`} element={<ClusterPlan />} />
+ <Route path={`node-config`} element={<NodeConfig />} />
+ <Route path={`cluster-deploy`} element={<ClusterDeploy />} />
+ <Route path={`finish`} element={<SpaceCreateFinish />} />
+ <Route path="/" element={<Navigate replace to="register-space" />} />
+ </Routes>
<Row justify="end" style={{ marginTop: 20 }}>
<Space>
{step === 0 ? (
diff --git a/frontend/src/routes/space/new-cluster/steps/cluster-deploy/cluster-deploy.tsx b/frontend/src/routes/space/new-cluster/steps/cluster-deploy/cluster-deploy.tsx
index 3542362..c851fe1 100644
--- a/frontend/src/routes/space/new-cluster/steps/cluster-deploy/cluster-deploy.tsx
+++ b/frontend/src/routes/space/new-cluster/steps/cluster-deploy/cluster-deploy.tsx
@@ -17,10 +17,8 @@
import React, { useContext, useEffect, useState } from 'react';
import { PageContainer } from '@ant-design/pro-layout';
-import ProCard from '@ant-design/pro-card';
-import { Button, Row, Space, Table, Tabs, message, Steps } from 'antd';
-import { LoadingOutlined, PlayCircleFilled } from '@ant-design/icons';
-import { useHistory } from 'react-router';
+import { Table, Tabs, message, Steps } from 'antd';
+import { LoadingOutlined } from '@ant-design/icons';
import { useRequest } from 'ahooks';
import TabPane from '@ant-design/pro-card/lib/components/TabPane';
import { DorisNodeTypeEnum } from '../../types/params.type';
@@ -29,7 +27,6 @@ import { SpaceAPI } from '@src/routes/space/space.api';
import { OperateStatusEnum } from '@src/routes/space/space.data';
import { isSuccess } from '@src/utils/http';
import { NewSpaceInfoContext } from '@src/common/common.context';
-import { useDidCache, useDidRecover } from 'react-router-cache-route';
import { useRecoilState } from 'recoil';
import { stepDisabledState } from '@src/routes/space/access-cluster/access-cluster.recoil';
@@ -45,7 +42,6 @@ const STEP_MAP = {
export function ClusterDeploy(props: any) {
const { reqInfo, step } = useContext(NewSpaceInfoContext);
- const history = useHistory();
const [activeKey, setActiveKey] = useState(DorisNodeTypeEnum.FE);
const [instances, setInstances] = useState<any[]>([]);
const [stepDisabled, setStepDisabled] = useRecoilState(stepDisabledState);
@@ -106,17 +102,6 @@ export function ClusterDeploy(props: any) {
},
);
- useDidCache(() => {
- getClusterInstances.cancel();
- getClusterInstances.cancel();
- });
-
- useDidRecover(() => {
- if (reqInfo.cluster_id && step === 6) {
- getClusterInstances.run(reqInfo.cluster_id);
- }
- });
-
useEffect(() => {
if (reqInfo.cluster_id && step === 6) {
getClusterInstances.run(reqInfo.cluster_id);
diff --git a/frontend/src/routes/space/new-cluster/steps/node-config/node-config.tsx b/frontend/src/routes/space/new-cluster/steps/node-config/node-config.tsx
index 779c5a2..f74363c 100644
--- a/frontend/src/routes/space/new-cluster/steps/node-config/node-config.tsx
+++ b/frontend/src/routes/space/new-cluster/steps/node-config/node-config.tsx
@@ -16,24 +16,19 @@
// under the License.
import React, { useState, useEffect, useReducer, useContext, useCallback } from 'react';
-import { Table, Input, Button, Popconfirm, Form, Row, Space, Switch, Tabs, message } from 'antd';
-import { FormInstance } from 'antd/lib/form';
+import { Form, Tabs, message } from 'antd';
import { PageContainer } from '@ant-design/pro-layout';
import { CustomConfig } from './components/custom-config';
-import ProCard from '@ant-design/pro-card';
import type { ProColumns } from '@ant-design/pro-table';
import { EditableProTable } from '@ant-design/pro-table';
-import { useHistory } from 'react-router';
-import { BASE_BE_CONFIG, BASE_FE_CONFIG, BASE_BROKER_CONFIG } from './data';
-import * as types from './../../types/index.type';
-import API from './../../new-cluster.api';
-import { processId, roleListQuery, stepState } from './../../recoils/index';
+import { processId, stepState } from './../../recoils/index';
import { useRecoilState, useRecoilValue } from 'recoil';
import { isSuccess } from '@src/utils/http';
import { DorisNodeTypeEnum } from './../../types/index.type';
import { NewSpaceInfoContext } from '@src/common/common.context';
import { useAsync } from '@src/hooks/use-async';
import { SpaceAPI } from '@src/routes/space/space.api';
+import { useNavigate } from 'react-router';
const { TabPane } = Tabs;
interface DataType {
@@ -146,8 +141,6 @@ export function NodeConfig() {
export function NodeConfigContent(props: any) {
const { reqInfo } = useContext(NewSpaceInfoContext);
- const history = useHistory();
- const [step, setStep] = useRecoilState(stepState);
const [customState, dispatch] = useReducer(reducer, initData);
const [activeKey, setActiveKey] = useState(DorisNodeTypeEnum.FE);
const { data: clusterModules, run: runGetClusterModules, loading } = useAsync<any[]>({ data: [], loading: true });
@@ -217,7 +210,7 @@ export function NodeConfigContent(props: any) {
);
useEffect(() => {
- const newClusterModules = clusterModules!.map(module => ({
+ const newClusterModules = clusterModules?.map(module => ({
moduleName: module.name,
configs: getNewConfigs(module.name),
}));
diff --git a/frontend/src/routes/space/new-cluster/steps/run-cluster/run-cluster.tsx b/frontend/src/routes/space/new-cluster/steps/run-cluster/run-cluster.tsx
deleted file mode 100644
index 953b6a2..0000000
--- a/frontend/src/routes/space/new-cluster/steps/run-cluster/run-cluster.tsx
+++ /dev/null
@@ -1,158 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements. See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership. The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License. You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing,
-// software distributed under the License is distributed on an
-// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-// KIND, either express or implied. See the License for the
-// specific language governing permissions and limitations
-// under the License.
-
-import ProCard from '@ant-design/pro-card';
-import { Button, message, Row, Space, Steps, Table } from 'antd';
-import React, {useEffect, useState } from 'react';
-import { useHistory } from 'react-router-dom';
-import { processId, roleListQuery, stepState } from './../../recoils/index';
-import { useRecoilState, useRecoilValue } from 'recoil';
-import API from '../../new-cluster.api';
-import * as types from '../../types/index.type'
-import { isSuccess } from '@src/utils/http';
-import { NewClusterStepsEnum } from '../../new-cluster.data';
-import { DorisNodeTypeEnum } from '../../types/index.type';
-
-export function RunCluster(props: any) {
- const history = useHistory();
- const processID = useRecoilValue(processId)
- const {fe, be} = useRecoilValue(roleListQuery);
- const [taskInfo, setTaskInfo] = useState<types.ItaskResult[]>([])
- const [step, setStep] = useRecoilState(stepState);
- const [completed, setCompleted] = useState(false);
-
- useEffect(() => {
- const feArr = fe.map(item => ({ host: item, role: DorisNodeTypeEnum.FE}))
- const beArr = be.map(item => ({ host: item, role: DorisNodeTypeEnum.BE}))
- API.startService({
- processId: processID,
- dorisStarts: [...feArr, ...beArr]
- }).then(res => {
- if(isSuccess(res)){
- API.getTaskStatus(processID).then(cur => {
- setTaskInfo(cur.data)
- })
- }
- })
- }, [fe,be])
-
- const columns = [
- {
- title: '序号',
- dataIndex: 'id',
- key: 'id',
- },
- {
- title: '节点IP',
- dataIndex: 'host',
- key: 'host',
- },
- {
- title: '状态信息',
- dataIndex: 'status',
- key: 'status',
- render: (_, record:any) => (
- <Space>
- <span>{record.status} {record.result}</span>
- </Space>
- ),
- },
- {
- title: '操作',
- key: 'option',
- render: (_, record:any) => (
- <Space>
- <Button type="link" disabled={record.status !== types.taskStatusEnum.FAILURE} onClick={() => reTry(record)}>重试</Button>
- <Button type="link" disabled={record.status !== types.taskStatusEnum.FAILURE} onClick={() => doSkip(record)}>跳过</Button>
- <Button type="link" onClick={() => viewLog(record)}>查看日志</Button>
- </Space>
- ),
- },
- ];
-
- const reTry = (record: any) => {
- API.reTryTask(record.id).then(res => {
- if(isSuccess(res)){
- message.success(res.msg)
- }else{
- message.warn(res.msg)
- }
- })
- }
- const doSkip = (record: any) => {
- API.skipTask(record.id).then(res => {
- if(isSuccess(res)){
- message.success(res.msg)
- }else{
- message.warn(res.msg)
- }
- })
- }
- const viewLog = (record: any) => {
- history.push({
- pathname: `/cluster/logs/${record.id}`
- })
- }
-
- const startCluster = () => {
- API.getTaskStatus(processID).then(cur => {
- if(!isSuccess(cur)){
- message.error(cur.msg)
- return;
- }
- let JOIN_BE = cur.data.filter((item: any) => item.taskType === "JOIN_BE")
- if(JOIN_BE?.length){
- message.info('已经组建过了哦')
- return;
- }
- setTaskInfo(cur.data)
- let len = cur.data.filter((item: any) => item.status !== "SUCCESS")
- if(len?.length > 0){
- message.info('部分节点还未安装成功,请稍后重试!')
- }else{
- API.startCluster({
- processId: processID,
- feHosts: fe,
- beHosts: be
- }).then(res => {
- message.success(res.msg)
- if(res.code === 0){
- setCompleted(true)
- }
- })
- }
- })
-
- }
-
- return (
- <>
- <ProCard bordered title={'启动FE节点'}>
- <Table columns={columns} dataSource={taskInfo.filter(item => (item.taskRole === DorisNodeTypeEnum.FE))} rowKey="id" pagination={false}/>
- </ProCard>
- <ProCard bordered title={'启动BE节点'}>
- <Table columns={columns} dataSource={taskInfo.filter(item => (item.taskRole === DorisNodeTypeEnum.BE))} rowKey="id" pagination={false}/>
- </ProCard>
- <ProCard bordered title={'启动BROKER节点'}>
- <Table columns={columns} dataSource={taskInfo.filter(item => (item.taskRole === DorisNodeTypeEnum.BROKER))} rowKey="id" pagination={false}/>
- </ProCard>
- <ProCard bordered title={'组建集群'}
- extra={<Button type="primary" onClick={startCluster} disabled={completed}>开始组建</Button>}>
- </ProCard>
- </>
- );
-}
diff --git a/frontend/src/routes/space/space.tsx b/frontend/src/routes/space/space.tsx
index a517d72..30ac018 100644
--- a/frontend/src/routes/space/space.tsx
+++ b/frontend/src/routes/space/space.tsx
@@ -15,27 +15,22 @@
// specific language governing permissions and limitations
// under the License.
-import React from 'react';
-import { Switch, Route, Redirect, useRouteMatch } from 'react-router';
+import { Navigate, Route, Routes } from 'react-router';
+import { AccessCluster } from './access-cluster/access-cluster';
+import { SpaceDetail } from './detail/space-detail';
import { SpaceList } from './list/list';
+import { Logs } from './new-cluster/logs/logs';
import { NewCluster } from './new-cluster/new-cluster';
-import { Logs } from './new-cluster/logs/logs'
-import { SpaceDetail } from './detail/space-detail';
-import { AccessCluster } from './access-cluster/access-cluster';
export function Space() {
- const match = useRouteMatch();
return (
- <>
- <Switch>
- <Route path={`${match.path}/list`} component={SpaceList} />
- <Route path={`${match.path}/new/:requestId`} component={NewCluster} />
- <Route path={`${match.path}/access/:requestId`} component={AccessCluster} />
- <Route path={`${match.path}/detail/:spaceId`} component={SpaceDetail} />
- <Route path={`${match.path}/logs/:taskId`} component={Logs} />
- <Redirect to={`${match.path}/list`} />
- </Switch>
- </>
+ <Routes>
+ <Route path="list" element={<SpaceList />} />
+ <Route path={`new/:requestId/*`} element={<NewCluster />} />
+ <Route path={`access/:requestId/*`} element={<AccessCluster />} />
+ <Route path={`detail/:spaceId`} element={<SpaceDetail />} />
+ <Route path={`logs/:taskId`} element={<Logs />} />
+ <Route path="/" element={<Navigate replace to="list" />} />
+ </Routes>
);
}
-
diff --git a/frontend/src/routes/super-admin-container.tsx b/frontend/src/routes/super-admin-container.tsx
index 8de6802..dc4ab8b 100644
--- a/frontend/src/routes/super-admin-container.tsx
+++ b/frontend/src/routes/super-admin-container.tsx
@@ -19,12 +19,10 @@ import { UserInfoContext } from '@src/common/common.context';
import { Header } from '@src/components/header/header';
import { Sidebar } from '@src/components/sidebar/sidebar';
import { useUserInfo } from '@src/hooks/use-userinfo.hooks';
-import React from 'react';
-import { Redirect, Route, Switch, useRouteMatch } from 'react-router-dom';
+import { Navigate, Route, Routes } from 'react-router-dom';
import { Space } from './space/space';
-export function SuperAdminContainer(props: any) {
- const match = useRouteMatch();
+export function SuperAdminContainer() {
const [userInfo] = useUserInfo();
return (
@@ -34,10 +32,10 @@ export function SuperAdminContainer(props: any) {
<div style={{ marginLeft: 80 }}>
<Header mode="super-admin" />
<div>
- <Switch>
- <Route path={`${match.path}`} component={Space} />
- <Redirect to={`${match.path}`} />
- </Switch>
+ <Routes>
+ <Route path="*" element={<Space />} />
+ {/* <Route path="/" element={<Navigate replace to="space" />} /> */}
+ </Routes>
</div>
</div>
</UserInfoContext.Provider>
diff --git a/frontend/src/routes/table-content/index.tsx b/frontend/src/routes/table-content/index.tsx
index d652a14..339d0f4 100644
--- a/frontend/src/routes/table-content/index.tsx
+++ b/frontend/src/routes/table-content/index.tsx
@@ -17,96 +17,71 @@
/** @format */
-import React, { useState, useEffect, useCallback } from 'react';
+import { useState, useEffect } from 'react';
import styles from './table-content.module.less';
import CSSModules from 'react-css-modules';
-import { Layout, Menu, Tabs, Button } from 'antd';
+import { Layout, Tabs } from 'antd';
import { TableOutlined } from '@ant-design/icons';
import { CommonHeader } from '@src/components/common-header/header';
-import { TableInfoResponse } from './table.interface';
-import { TableAPI } from './table.api';
-import { useHistory } from 'react-router-dom';
-
import BaseInfo from './tabs/baseInfo';
import { Schema } from './schema/schema';
-import DataImportTab from './tabs/data-import';
import { TableInfoTabTypeEnum } from './table-content.data';
-import { Redirect, Route, Switch } from 'react-router-dom';
-import { pathToRegexp } from 'path-to-regexp';
+import { Navigate, Route, Routes, useMatch, useNavigate } from 'react-router-dom';
import DataPreview from './tabs/data.pre';
-const { Content, Sider } = Layout;
+const { Content } = Layout;
const iconTable = <TableOutlined />;
import { isTableIdSame } from '@src/utils/utils';
import { useTranslation } from 'react-i18next';
const { TabPane } = Tabs;
-let id: any = '',
- name: any = '';
+
function TableContent(props: any) {
- const { t } = useTranslation()
- const history = useHistory();
- const { match } = props;
+ const { t } = useTranslation();
+ console.log(props);
+ const navigate = useNavigate();
+ const [id, setId] = useState(() => localStorage.getItem('table_id'));
+ const [name, setName] = useState(() => localStorage.getItem('table_name'));
const [dbId, setDbId] = useState<any>();
- const matchedPath = pathToRegexp(`${match.path}/:tabType`).exec(props.location.pathname);
+ const match = useMatch('/meta/table/:tableId/:tabType');
useEffect(() => {
- id = localStorage.getItem('table_id');
- name = localStorage.getItem('table_name');
setDbId(localStorage.getItem('database_id'));
isTableIdSame();
}, [window.location.href]);
- function refresh(router: any) {
+ function refresh() {
//
}
function handleTabChange(activeTab: string) {
- props.history.push({
- pathname: `${match.url}/${activeTab}`,
+ navigate(`${activeTab}`, {
state: { id: id, name: name },
});
}
return (
<Content styleName="table-main">
- <CommonHeader title={name} icon={iconTable} callback={refresh}></CommonHeader>
+ <CommonHeader title={name as string} icon={iconTable} callback={refresh}></CommonHeader>
<div styleName="table-content">
<Tabs
- // defaultActiveKey={`${ma}`}
- activeKey={matchedPath ? matchedPath[2] : TableInfoTabTypeEnum.BasicInfo}
+ activeKey={match?.params.tabType ? match?.params.tabType : TableInfoTabTypeEnum.BasicInfo}
onChange={(activeTab: string) => handleTabChange(activeTab)}
>
- <TabPane tab={t`BasicInfo`} key={TableInfoTabTypeEnum.BasicInfo}>
- {/* <BaseInfo tableInfo={tableInfo} /> */}
- </TabPane>
- <TabPane tab={t`DataPreview`} key={TableInfoTabTypeEnum.DataPreview}>
- {/* 12312 */}
- </TabPane>
+ <TabPane tab={t`BasicInfo`} key={TableInfoTabTypeEnum.BasicInfo}></TabPane>
+ <TabPane tab={t`DataPreview`} key={TableInfoTabTypeEnum.DataPreview}></TabPane>
<TabPane tab="Schema" key={TableInfoTabTypeEnum.Schema}></TabPane>
</Tabs>
- <Switch>
- <Route
- path={`${match.path}/${TableInfoTabTypeEnum.BasicInfo}`}
- render={props => <BaseInfo tableId={match.params.tableId} />}
- />
+ <Routes>
<Route
- path={`${match.path}/${TableInfoTabTypeEnum.DataPreview}`}
- render={props => <DataPreview tableId={match.params.tableId} />}
+ path={TableInfoTabTypeEnum.BasicInfo}
+ element={<BaseInfo tableId={match?.params.tableId} />}
/>
<Route
- path={`${match.path}/${TableInfoTabTypeEnum.DataImport}`}
- render={props => <DataImportTab tableId={match.params.tableId} tableName={name} />}
- />
- <Route
- path={`${match.path}/${TableInfoTabTypeEnum.Schema}`}
- render={props => <Schema tableId={match.params.tableId} />}
- />
- <Redirect
- to={{
- pathname: `${match.path}/${TableInfoTabTypeEnum.BasicInfo}`,
- state: { id: id, name: name },
- }}
+ path={TableInfoTabTypeEnum.DataPreview}
+ element={<DataPreview tableId={match?.params.tableId} />}
/>
- </Switch>
+ <Route path={TableInfoTabTypeEnum.Schema} element={<Schema tableId={match?.params.tableId} />} />
+ <Route path="/" element={<Navigate replace to={TableInfoTabTypeEnum.BasicInfo} />} />
+ </Routes>
</div>
</Content>
);
diff --git a/frontend/src/routes/table-content/schema/schema.tsx b/frontend/src/routes/table-content/schema/schema.tsx
index e54b89f..c41bc40 100644
--- a/frontend/src/routes/table-content/schema/schema.tsx
+++ b/frontend/src/routes/table-content/schema/schema.tsx
@@ -18,7 +18,7 @@
import { useRequest } from 'ahooks';
import { Form, Row, Table } from 'antd';
import { ColumnsType } from 'antd/lib/table';
-import React, { useState, useEffect } from 'react';
+import { useState, useEffect } from 'react';
import { TableTypeEnum, TABLE_TYPE_KEYS } from '@src/common/common.data';
import { LoadingWrapper } from '@src/components/loadingwrapper/loadingwrapper';
import { IResult } from 'src/interfaces/http.interface';
@@ -29,7 +29,7 @@ import { useTranslation } from 'react-i18next';
import styles from '../tabs/tabs.module.less';
export function Schema(props: any) {
- const {t } = useTranslation()
+ const { t } = useTranslation();
const [dataSource, setDataSource] = useState([]);
const [columns, setColumns] = useState<ColumnsType<any>>([]);
const [tableType, setTableType] = useState('');
@@ -40,16 +40,12 @@ export function Schema(props: any) {
});
return unListen;
}, []);
- const { loading } = useRequest<IResult<any>>(() => SchemaAPI.getSchema(tableId), {
+ const { loading } = useRequest<IResult<any>, any>(() => SchemaAPI.getSchema(tableId), {
refreshDeps: [tableId],
onSuccess: async (res: any) => {
if (isSuccess(res)) {
- const {
- TABLE_COLUMN_DUPLICATE,
- TABLE_COLUMN_AGGREGATE,
- TABLE_COLUMN_UNIQUE,
- BASIC_COLUMN,
- } = await import('./schema.data');
+ const { TABLE_COLUMN_DUPLICATE, TABLE_COLUMN_AGGREGATE, TABLE_COLUMN_UNIQUE, BASIC_COLUMN } =
+ await import('./schema.data');
setDataSource(res.data.schema);
const type =
TABLE_TYPE_KEYS.filter(tableType => tableType.value === res.data.keyType)[0]?.text || '元数据表';
diff --git a/frontend/src/routes/table-content/tabs/data-import.tsx b/frontend/src/routes/table-content/tabs/data-import.tsx
deleted file mode 100644
index 63b2221..0000000
--- a/frontend/src/routes/table-content/tabs/data-import.tsx
+++ /dev/null
@@ -1,250 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements. See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership. The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License. You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing,
-// software distributed under the License is distributed on an
-// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-// KIND, either express or implied. See the License for the
-// specific language governing permissions and limitations
-// under the License.
-
-/** @format */
-
-import React, { useState, useEffect } from 'react';
-import styles from './tabs.module.less';
-import CSSModules from 'react-css-modules';
-import { Table, Tag, Button, Row, Col, Modal, message, Empty } from 'antd';
-import { useHistory } from 'react-router-dom';
-import EventEmitter from '@src/utils/event-emitter';
-import ImportMenu from './dataImport-menu';
-import { TableAPI } from './tabs.api';
-import { getShowTime } from '../../../utils/utils';
-import i18n from '../../../i18n';
-const columns = [
- {
- title: '任务名称',
- dataIndex: 'taskName',
- key: 'taskName',
- width: 250,
- // render: (text: any) => <a>{text}</a>,
- },
- {
- title: '任务类型',
- dataIndex: 'importType',
- key: 'importType',
- width: 100,
- render: function (text: any, record: any) {
- return <span>{text === 'file' ? '本地文件导入' : 'hdfs文件导入'}</span>;
- },
- },
- {
- title: '创建人',
- dataIndex: 'creator',
- key: 'creator',
- width: 110,
- },
- {
- title: '创建时间',
- key: 'createTime',
- dataIndex: 'createTime',
- width: 150,
- render: function (text: any, record: any) {
- return <span>{getShowTime(record.createTime)}</span>;
- },
- },
- {
- title: '任务状态',
- dataIndex: 'status',
- key: 'status',
- width: 70,
- render: function (text: any, record: any) {
- return <Tag color={STATUS_TYPES[record.status]?.key}>{STATUS_TYPES[record.status]?.value}</Tag>;
- },
- },
-];
-const STATUS_TYPES = {
- PENDING: {
- key: 'warning',
- value: '等待执行',
- },
- LOADING: {
- key: 'processing',
- value: '执行中',
- },
- Success: { key: 'success', value: i18n.t('Finished') },
- FINISHED: { key: 'success', value: i18n.t('Finished') },
- CANCELLED: { key: 'error', value: '失败' },
- Fail: { key: 'error', value: '失败' },
-};
-
-function DataImportTab(props: any) {
- const [tableData, setTableData] = useState([]);
- const [total, setTotal] = useState();
- const [selectItem, setSelectItem] = useState<any>({});
- const [isModalVisible, setIsModalVisible] = useState(false);
-
- useEffect(() => {
- refresh({});
- const unListen = EventEmitter.on('refreshData', () => {
- refresh;
- });
- return unListen;
- }, []);
- function refresh(pageInfo: any) {
- TableAPI.getTableList({
- tableId: localStorage.getItem('table_id'),
- page: pageInfo.current ? pageInfo.current : 1,
- pageSize: 10,
- }).then(res => {
- const { msg, code, data } = res;
- if (code === 0) {
- setTableData(data.taskRespList);
- setTotal(data.totalSize);
- } else {
- setTableData([]);
- message.error(msg);
- }
- });
- }
- function rowClick(e: any, record: any) {
- setSelectItem(record);
- showModal();
- }
-
- const showModal = () => {
- setIsModalVisible(true);
- };
-
- const handleCancel = () => {
- setIsModalVisible(false);
- };
- function getShowUrl(str: string) {
- if (str && str.indexOf('fileUrl') >= 0) {
- str.split(';')[0].split('Url:')[1];
- } else {
- return str;
- }
- }
- return (
- <div styleName="dataImport-content-des">
- <Row>
- <ImportMenu />
- </Row>
-
- <Table
- bordered
- columns={columns}
- rowKey="taskName"
- dataSource={tableData}
- scroll={{ x: '500', y: '49vh' }}
- className={styles['import-table']}
- onRow={record => {
- return {
- onClick: event => {
- rowClick(event, record);
- },
- };
- }}
- pagination={{ total: total }}
- onChange={pagination => {
- refresh(pagination);
- }}
- size="small"
- locale={{
- emptyText: (
- <Empty image={Empty.PRESENTED_IMAGE_SIMPLE} description={<span>未发现数据导入任务</span>} />
- ),
- }}
- />
- <Modal
- title={'任务名称: ' + selectItem.taskName}
- visible={isModalVisible}
- className={styles['import-item-modal']}
- width="600px"
- footer={
- [] // 设置footer为空,去掉 取消 确定默认按钮
- }
- onCancel={handleCancel}
- >
- <Row>
- <Col span={6} className={styles['label']}>
- 传输类型:
- </Col>
- <Col>{selectItem.importType === 'hdfs' ? '文件系统导入' : '本地上传文件'}</Col>
- </Row>
- <Row>
- <Col span={6} className={styles['label']}>
- 数据源:
- </Col>
- <Col span={18}>
- {selectItem.fileInfo && selectItem.fileInfo.indexOf('fileUrl') >= 0
- ? selectItem.fileInfo.split(';')[0].split('Url:')[1]
- : selectItem.fileInfo}
- </Col>
- </Row>
- <Row>
- <Col span={6} className={styles['label']}>
- 数据目的地:
- </Col>
- <Col>{localStorage.getItem('database_name') + '.' + localStorage.getItem('table_name')}</Col>
- </Row>
- <Row>
- <Col span={6} className={styles['label']}>
- 任务创建人:
- </Col>
- <Col>{selectItem.creator}</Col>
- </Row>
- <Row>
- <Col span={6} className={styles['label']}>
- 创建时间:
- </Col>
- <Col>{getShowTime(selectItem.createTime)}</Col>
- </Row>
- <Row>
- <Col span={6} className={styles['label']}>
- 任务状态:
- </Col>
- <Col span={14}>
- <Tag color={STATUS_TYPES[selectItem.status]?.key}>{STATUS_TYPES[selectItem.status]?.value}</Tag>
- </Col>
- {selectItem.status === 'CANCELLED' || selectItem.status === 'Fail' ? (
- <Col>
- <Tag
- color={STATUS_TYPES[selectItem.status]?.key}
- style={{
- border: 'none',
- background: 'none',
- marginTop: '7px',
- }}
- >
- <span
- style={{ textDecoration: 'underline', cursor: 'pointer' }}
- onClick={() => {
- if (selectItem.errorMsg) {
- window.open(selectItem.errorMsg);
- } else {
- message.error(selectItem.errorInfo);
- }
- }}
- >
- 任务详情
- </span>
- </Tag>
- </Col>
- ) : (
- ''
- )}
- </Row>
- </Modal>
- </div>
- );
-}
-
-export default CSSModules(styles)(DataImportTab);
diff --git a/frontend/src/routes/table-content/tabs/dataImport-menu/index.tsx b/frontend/src/routes/table-content/tabs/dataImport-menu/index.tsx
deleted file mode 100644
index d3b71b1..0000000
--- a/frontend/src/routes/table-content/tabs/dataImport-menu/index.tsx
+++ /dev/null
@@ -1,79 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements. See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership. The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License. You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing,
-// software distributed under the License is distributed on an
-// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-// KIND, either express or implied. See the License for the
-// specific language governing permissions and limitations
-// under the License.
-
-/** @format */
-
-import React from 'react';
-import { Menu, Dropdown, Button } from 'antd';
-import { UploadOutlined } from '@ant-design/icons';
-import { useHistory } from 'react-router-dom';
-import { FileWordOutlined, CloudServerOutlined } from '@ant-design/icons';
-import styles from '../tabs.module.less';
-const getMenu = (history: any, props: any) => {
- return (
- <Menu>
- <Menu.Item>
- <a
- style={{ padding: '10px 25px', textAlign: 'center', color: '#757272' }}
- onClick={() => {
- history.push({
- pathname: `/local-import/${localStorage.table_id}`,
- });
- }}
- >
- <FileWordOutlined style={{ paddingRight: '15px', fontSize: '20px', verticalAlign: 'middle' }} />
- 本地上传文件
- </a>
- </Menu.Item>
- <Menu.Item>
- <a
- style={{ padding: '10px 25px', textAlign: 'center', color: '#757272' }}
- onClick={() => {
- history.push({
- pathname: `/system-import/${localStorage.table_id}`,
- });
- }}
- >
- <CloudServerOutlined style={{ paddingRight: '15px', fontSize: '20px', verticalAlign: 'middle' }} />
- 文件系统导入
- </a>
- </Menu.Item>
- </Menu>
- );
-};
-
-function ImportMenu(props: any) {
- const history = useHistory();
- const MENU = getMenu(history, props);
-
- return (
- <div style={{ width: '100%' }}>
- <Dropdown overlay={MENU} placement="bottomCenter" overlayClassName={styles['import-drop']}>
- <Button
- type="primary"
- style={{ margin: '0 10px 15px', float: 'right' }}
- shape="round"
- icon={<UploadOutlined />}
- >
- 导入数据
- </Button>
- </Dropdown>
- </div>
- );
-}
-
-export default ImportMenu;
diff --git a/frontend/src/routes/tree/create-menu/databaseModal.tsx b/frontend/src/routes/tree/create-menu/databaseModal.tsx
deleted file mode 100644
index 118787d..0000000
--- a/frontend/src/routes/tree/create-menu/databaseModal.tsx
+++ /dev/null
@@ -1,107 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements. See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership. The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License. You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing,
-// software distributed under the License is distributed on an
-// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-// KIND, either express or implied. See the License for the
-// specific language governing permissions and limitations
-// under the License.
-
-import React, { useState, useEffect, useRef } from 'react';
-import { Modal, Form, Input, message, Button } from 'antd';
-import { TreeAPI } from '../tree.api';
-import EventEmitter from 'src/utils/event-emitter';
-const DatabaseModal = (props: any) => {
- const modalRef: any = useRef();
- const inputName: any = useRef();
- const inputDes: any = useRef();
- const [isModalVisible, setIsModalVisible] = useState(false);
- const [formData, setFormData] = useState({
- describe: '',
- name: '',
- });
- useEffect(() => {
- setIsModalVisible(props.isShow);
- }, [props.isShow]);
- const showModal = () => {
- setIsModalVisible(true);
- };
-
- const handleOk = () => {
- modalRef.current.validateFields().then((res: any) => {
- TreeAPI.newDatabase(formData).then((res: any) => {
- const { msg, code, data } = res;
- if (code === 0) {
- message.success('创建成功!');
- // setFormData({ describe: '', name: '' });
- props.changeShow(false);
- EventEmitter.emit('refreshTreeData');
- } else {
- message.error(msg);
- }
- });
- });
-
- // setIsModalVisible(false);
- };
-
- const handleCancel = () => {
- // setFormData({ describe: '', name: '' });
- setTimeout(() => {
- props.changeShow(false);
- }, 200);
- };
- function handleChange(value: any, key: string) {
- const item = value.target.value;
- const localData = JSON.parse(JSON.stringify(formData));
- localData[key] = item;
- setFormData(localData);
- }
- return (
- <>
- <Modal
- title="创建新的数据库"
- visible={isModalVisible}
- footer={[
- <Button key="submit" type="primary" onClick={handleOk}>
- 提交创建
- </Button>,
- ]}
- onOk={handleOk}
- onCancel={handleCancel}
- >
- <Form ref={modalRef} name="basic" initialValues={{ remember: true }} layout="vertical">
- <Form.Item label="数据库名称" name="name" rules={[{ required: true, message: '请输入数据库名称' }]}>
- <Input
- placeholder="输入你的数据库名称"
- value={formData.name}
- ref={inputName}
- onChange={value => handleChange(value, 'name')}
- />
- </Form.Item>
- <Form.Item
- label="描述信息"
- name="describe"
- rules={[{ required: false, message: '请输入数据库描述' }]}
- >
- <Input
- placeholder="输入你数据库描述信息,非必填写项,但便于后期运维建议填写"
- value={formData.describe}
- ref={inputDes}
- onChange={value => handleChange(value, 'describe')}
- />
- </Form.Item>
- </Form>
- </Modal>
- </>
- );
-};
-export default DatabaseModal;
diff --git a/frontend/src/routes/tree/create-menu/index.tsx b/frontend/src/routes/tree/create-menu/index.tsx
deleted file mode 100644
index 2d29448..0000000
--- a/frontend/src/routes/tree/create-menu/index.tsx
+++ /dev/null
@@ -1,79 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements. See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership. The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License. You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing,
-// software distributed under the License is distributed on an
-// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-// KIND, either express or implied. See the License for the
-// specific language governing permissions and limitations
-// under the License.
-
-/** @format */
-
-import React, { useState, useCallback } from 'react';
-import styles from './create.module.less';
-// import CSSModules from 'react-css-modules';
-import { Menu, Dropdown, Button, Space } from 'antd';
-import { TableOutlined, HddOutlined, PlusOutlined } from '@ant-design/icons';
-import { useHistory } from 'react-router-dom';
-import DatabaseModal from './databaseModal';
-const getMenu = (history: any, setIsShow: any) => {
- return (
- <Menu>
- <Menu.Item
- onClick={() => {
- setIsShow(true);
- }}
- >
- <a style={{ padding: '15px 0', textAlign: 'center', color: '#757272' }}>
- <HddOutlined style={{ paddingRight: '8px', fontSize: '20px', verticalAlign: 'middle' }} />
- 创建数据库
- </a>
- </Menu.Item>
- <Menu.Item
- onClick={() => {
- history.push(`/new-table`);
- }}
- >
- <a style={{ padding: '15px 0', textAlign: 'center', color: '#757272' }}>
- <TableOutlined style={{ paddingRight: '8px', fontSize: '20px', verticalAlign: 'middle' }} />
- 创建数据表
- </a>
- </Menu.Item>
- </Menu>
- );
-};
-
-function CreateMenu() {
- const history = useHistory();
- const [isShow, setIsShow] = useState();
- const MENU = getMenu(history, setIsShow);
-
- function refresh() {
- console.log(1111);
- }
- return (
- <div style={{ width: '100%' }}>
- <Dropdown overlay={MENU} placement="bottomCenter" overlayClassName={styles['create-drop']}>
- <Button icon={<PlusOutlined />} type="primary" style={{ width: '100%', borderRadius: '10px' }}>
- 创建数据
- </Button>
- </Dropdown>
- <DatabaseModal
- isShow={isShow}
- changeShow={(e: any) => {
- setIsShow(e);
- }}
- />
- </div>
- );
-}
-
-export default CreateMenu;
diff --git a/frontend/src/routes/tree/index.tsx b/frontend/src/routes/tree/index.tsx
index 6c6dbbd..dd986bb 100644
--- a/frontend/src/routes/tree/index.tsx
+++ b/frontend/src/routes/tree/index.tsx
@@ -17,25 +17,24 @@
/** @format */
-import React, { useState, useEffect } from 'react';
-import { Tree, Spin, Input, message } from 'antd';
-import { useHistory } from 'react-router-dom';
+import { useState, useEffect } from 'react';
+import { Tree, message } from 'antd';
import { TableOutlined, HddOutlined, HomeOutlined } from '@ant-design/icons';
import { TreeAPI } from './tree.api';
import { DataNode } from './tree.interface';
import { updateTreeData } from './tree.service';
import { ContentRouteKeyEnum } from './tree.data';
-import CreateMenu from './create-menu/index';
import styles from './tree.module.less';
import EventEmitter from '@src/utils/event-emitter';
import { useTranslation } from 'react-i18next';
-// import { LoadingWrapper } from '@src/components/loadingwrapper/loadingwrapper';
+import { useNavigate } from 'react-router';
+
const initTreeDate: DataNode[] = [];
-export function MetaBaseTree(props: any) {
+export function MetaBaseTree() {
const [treeData, setTreeData] = useState(initTreeDate);
const [loading, setLoading] = useState(true);
- const history = useHistory();
- const { t } = useTranslation()
+ const { t } = useTranslation();
+ const navigate = useNavigate();
useEffect(() => {
initTreeData();
EventEmitter.on('refreshData', initTreeData);
@@ -71,7 +70,7 @@ export function MetaBaseTree(props: any) {
const tables = res.data;
const children: Array<any> = [];
if (tables.length) {
- tables.forEach((item, index) => {
+ tables.forEach((item: any) => {
children.push({
title: `${item.name}`,
key: `2¥${db_id}¥${db_name}¥${item.id}¥${item.name}`,
@@ -97,39 +96,32 @@ export function MetaBaseTree(props: any) {
});
}
- function handleTreeSelect(keys: any[], info: any) {
+ function handleTreeSelect(keys: any[]) {
if (keys.length > 0) {
const [storey, db_id, db_name, id, name] = keys[0].split('¥');
if (storey === '1') {
localStorage.setItem('database_id', id);
localStorage.setItem('database_name', name);
- history.push({
- pathname: `/meta/${ContentRouteKeyEnum.Database}/${id}`,
- state: { id: id, name: name },
- });
+ navigate(`/meta/${ContentRouteKeyEnum.Database}/${id}`, { state: { id, name: name } });
} else {
localStorage.setItem('database_id', db_id);
localStorage.setItem('database_name', db_name);
localStorage.setItem('table_id', id);
localStorage.setItem('table_name', name);
- history.push({
- pathname: `/meta/${ContentRouteKeyEnum.Table}/${id}`,
- state: { id: id, name: name },
- });
+ navigate(`/meta/${ContentRouteKeyEnum.Table}/${id}`, { state: { id, name: name } });
}
}
}
function goHome() {
- history.push(`/meta`);
+ navigate(`/meta`);
}
return (
<div className={styles['palo-tree-container']}>
<h2 className={styles['palo-tree-title']}>
<HomeOutlined onClick={goHome} />
- { t`DataTree` }
+ {t`DataTree`}
</h2>
- {/* <LoadingWrapper loading={loading}> */}
<div className={styles['palo-tree-wrapper']}>
<Tree
showIcon={true}
@@ -139,7 +131,6 @@ export function MetaBaseTree(props: any) {
onSelect={(selectedKeys, info) => handleTreeSelect(selectedKeys, info)}
/>
</div>
- {/* </LoadingWrapper> */}
</div>
);
}
diff --git a/frontend/src/routes/user-setting/index.tsx b/frontend/src/routes/user-setting/index.tsx
index adfe069..6510014 100644
--- a/frontend/src/routes/user-setting/index.tsx
+++ b/frontend/src/routes/user-setting/index.tsx
@@ -16,14 +16,14 @@
// under the License.
/** @format */
-import React, { useEffect, useState } from 'react';
+import { useEffect, useState } from 'react';
import styles from './index.module.less';
import { Row, Tabs, Avatar, Col, Button, Form, Input, message } from 'antd';
import { RequiredMark } from 'antd/lib/form/Form';
import { UserSettingAPI } from './user.api';
const { TabPane } = Tabs;
import { useTranslation } from 'react-i18next';
-import {PassportAPI} from '@src/routes/passport/passport.api'
+import { PassportAPI } from '@src/routes/passport/passport.api';
export function UserSetting() {
useEffect(() => {
getCurrentInfo();
@@ -68,7 +68,7 @@ export function UserSetting() {
UserSettingAPI.modifyUserInfo(userInfo.id, _value).then(res => {
if (res.code === 0) {
message.success(t`Successfully`);
- setUserInfo(res.data)
+ setUserInfo(res.data);
} else {
message.warning(res.msg);
}
@@ -80,8 +80,8 @@ export function UserSetting() {
message.success(t`PasswordResetComplete`);
PassportAPI.SessionLogin({
password: _value.new_password,
- username: userInfo.name
- })
+ username: userInfo.name,
+ });
} else {
message.warning(res.msg);
}
diff --git a/frontend/src/routes/visual-query/components/visual-content/visual-editor.tsx b/frontend/src/routes/visual-query/components/visual-content/visual-editor.tsx
index e2a7e9f..0974e79 100644
--- a/frontend/src/routes/visual-query/components/visual-content/visual-editor.tsx
+++ b/frontend/src/routes/visual-query/components/visual-content/visual-editor.tsx
@@ -77,7 +77,7 @@ export default function VisualEditor(props: VisualEditorProps) {
>
<Editor
height="100%"
- language="sql"
+ defaultLanguage="sql"
theme={THEME_NAME}
options={{
minimap: {
diff --git a/frontend/src/utils/http.ts b/frontend/src/utils/http.ts
index 2a115b3..6ec07b7 100644
--- a/frontend/src/utils/http.ts
+++ b/frontend/src/utils/http.ts
@@ -20,7 +20,6 @@
import axios, { AxiosRequestConfig, AxiosResponse, AxiosError } from 'axios';
import { message } from 'antd';
import { IResult } from '../interfaces/http.interface';
-import { ANALYTICS_URL } from '@src/common/common.data';
interface HTTPConfig extends AxiosRequestConfig {
message?: string;
@@ -48,7 +47,7 @@ axios.interceptors.response.use(
(result): AxiosResponse<IResult<any>> => {
if (result.data.code !== 0) {
// console.log(result);
- if(result.data.code === 401){
+ if (result.data.code === 401) {
window.localStorage.removeItem('login');
window.localStorage.removeItem('user');
}
@@ -72,7 +71,7 @@ class HttpClient {
}
const result: AxiosResponse = await axios.get(url, config);
if (result.data.code === 401) {
- window.location.href = ANALYTICS_URL;
+ window.location.href = '/';
}
return result.data;
}
@@ -107,4 +106,4 @@ export const isSuccess = <T = any>(res: IResult<T>) => res.code === 0;
export function formatResultFn<T, P>(res: IResult<T>, defaultFormatValue = []): T | P | any {
return res.data ? res.data : defaultFormatValue;
-}
\ No newline at end of file
+}
diff --git a/frontend/theme.js b/frontend/theme.js
index ec290cd..458ac3c 100755
--- a/frontend/theme.js
+++ b/frontend/theme.js
@@ -47,6 +47,6 @@ module.exports = () => {
'@layout-header-height': '60px',
'@layout-header-background': '#1b1b1b',
'@layout-sider-background': '#fafafb',
- '@layout-body-background': '#fff'
+ '@layout-body-background': '#fff',
};
-};
\ No newline at end of file
+};
diff --git a/frontend/tsconfig.json b/frontend/tsconfig.json
index 97c29cb..17bb6b1 100644
--- a/frontend/tsconfig.json
+++ b/frontend/tsconfig.json
@@ -18,7 +18,10 @@
{
"compileOnSave": true,
"compilerOptions": {
+ "module": "esnext",
"target": "es5",
+ "jsx": "react-jsx",
+ "strict": true,
"lib": [
"dom",
"dom.iterable",
@@ -28,15 +31,12 @@
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
- "strict": true,
"watch": true,
"forceConsistentCasingInFileNames": true,
- "module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
- "jsx": "react",
"declaration": true,
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@doris.apache.org
For additional commands, e-mail: commits-help@doris.apache.org