You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@dubbo.apache.org by ra...@apache.org on 2021/03/12 09:22:05 UTC
[dubbo-admin] branch dev-change-ui2antd updated: add
dubbo-admin-ui-antd module
This is an automated email from the ASF dual-hosted git repository.
ranke pushed a commit to branch dev-change-ui2antd
in repository https://gitbox.apache.org/repos/asf/dubbo-admin.git
The following commit(s) were added to refs/heads/dev-change-ui2antd by this push:
new 1dc93cd add dubbo-admin-ui-antd module
1dc93cd is described below
commit 1dc93cd37c621102e98a5b9c075d5d8fda43edc7
Author: 邪影oO <21...@qq.com>
AuthorDate: Fri Mar 12 17:15:03 2021 +0800
add dubbo-admin-ui-antd module
---
dubbo-admin-ui-antd/.editorconfig | 16 +
dubbo-admin-ui-antd/.eslintignore | 8 +
dubbo-admin-ui-antd/.eslintrc.js | 24 +
dubbo-admin-ui-antd/.gitignore | 40 ++
dubbo-admin-ui-antd/.prettierignore | 23 +
dubbo-admin-ui-antd/.prettierrc.js | 21 +
dubbo-admin-ui-antd/.stylelintrc.js | 21 +
dubbo-admin-ui-antd/README.md | 46 ++
dubbo-admin-ui-antd/README_zh.md | 50 ++
dubbo-admin-ui-antd/config/config.dev.ts | 31 ++
dubbo-admin-ui-antd/config/config.ts | 74 +++
dubbo-admin-ui-antd/config/defaultSettings.ts | 36 ++
dubbo-admin-ui-antd/config/oneapi.json | 593 +++++++++++++++++++++
dubbo-admin-ui-antd/config/proxy.ts | 39 ++
dubbo-admin-ui-antd/config/routes.ts | 68 +++
dubbo-admin-ui-antd/jest.config.js | 26 +
dubbo-admin-ui-antd/jsconfig.json | 10 +
dubbo-admin-ui-antd/mock/listTableList.ts | 191 +++++++
dubbo-admin-ui-antd/mock/notices.ts | 107 ++++
dubbo-admin-ui-antd/mock/route.ts | 21 +
dubbo-admin-ui-antd/mock/user.ts | 211 ++++++++
dubbo-admin-ui-antd/package.json | 108 ++++
dubbo-admin-ui-antd/public/favicon.ico | Bin 0 -> 4286 bytes
dubbo-admin-ui-antd/public/home_bg.png | Bin 0 -> 203330 bytes
dubbo-admin-ui-antd/public/icons/icon-128x128.png | Bin 0 -> 1329 bytes
dubbo-admin-ui-antd/public/icons/icon-192x192.png | Bin 0 -> 1856 bytes
dubbo-admin-ui-antd/public/icons/icon-512x512.png | Bin 0 -> 5082 bytes
dubbo-admin-ui-antd/public/logo.svg | 1 +
dubbo-admin-ui-antd/public/pro_icon.svg | 5 +
dubbo-admin-ui-antd/src/access.ts | 25 +
dubbo-admin-ui-antd/src/app.tsx | 165 ++++++
.../src/components/Footer/index.tsx | 21 +
.../src/components/HeaderDropdown/index.less | 32 ++
.../src/components/HeaderDropdown/index.tsx | 33 ++
.../src/components/HeaderSearch/index.less | 41 ++
.../src/components/HeaderSearch/index.tsx | 117 ++++
.../src/components/NoticeIcon/NoticeIcon.tsx | 142 +++++
.../src/components/NoticeIcon/NoticeList.less | 119 +++++
.../src/components/NoticeIcon/NoticeList.tsx | 129 +++++
.../src/components/NoticeIcon/index.less | 51 ++
.../src/components/NoticeIcon/index.tsx | 168 ++++++
.../src/components/RightContent/AvatarDropdown.tsx | 123 +++++
.../src/components/RightContent/index.less | 78 +++
.../src/components/RightContent/index.tsx | 89 ++++
dubbo-admin-ui-antd/src/components/index.md | 1 +
dubbo-admin-ui-antd/src/e2e/baseLayout.e2e.js | 73 +++
dubbo-admin-ui-antd/src/global.less | 69 +++
dubbo-admin-ui-antd/src/global.tsx | 101 ++++
dubbo-admin-ui-antd/src/locales/en-US.ts | 40 ++
dubbo-admin-ui-antd/src/locales/en-US/component.ts | 21 +
.../src/locales/en-US/globalHeader.ts | 33 ++
dubbo-admin-ui-antd/src/locales/en-US/menu.ts | 68 +++
dubbo-admin-ui-antd/src/locales/en-US/pages.ts | 85 +++
dubbo-admin-ui-antd/src/locales/en-US/pwa.ts | 22 +
.../src/locales/en-US/settingDrawer.ts | 47 ++
dubbo-admin-ui-antd/src/locales/en-US/settings.ts | 76 +++
dubbo-admin-ui-antd/src/locales/zh-CN.ts | 40 ++
dubbo-admin-ui-antd/src/locales/zh-CN/component.ts | 21 +
.../src/locales/zh-CN/globalHeader.ts | 33 ++
dubbo-admin-ui-antd/src/locales/zh-CN/menu.ts | 68 +++
dubbo-admin-ui-antd/src/locales/zh-CN/pages.ts | 82 +++
dubbo-admin-ui-antd/src/locales/zh-CN/pwa.ts | 22 +
.../src/locales/zh-CN/settingDrawer.ts | 47 ++
dubbo-admin-ui-antd/src/locales/zh-CN/settings.ts | 71 +++
dubbo-admin-ui-antd/src/manifest.json | 22 +
dubbo-admin-ui-antd/src/pages/404.tsx | 34 ++
dubbo-admin-ui-antd/src/pages/Admin.tsx | 59 ++
.../src/pages/TableList/components/UpdateForm.tsx | 225 ++++++++
dubbo-admin-ui-antd/src/pages/TableList/index.tsx | 393 ++++++++++++++
.../src/pages/User/login/index.less | 130 +++++
dubbo-admin-ui-antd/src/pages/User/login/index.tsx | 212 ++++++++
dubbo-admin-ui-antd/src/pages/Welcome.less | 24 +
dubbo-admin-ui-antd/src/pages/Welcome.tsx | 82 +++
dubbo-admin-ui-antd/src/pages/document.ejs | 208 ++++++++
dubbo-admin-ui-antd/src/service-worker.js | 82 +++
.../src/services/ant-design-pro/api.ts | 35 ++
.../src/services/ant-design-pro/index.ts | 26 +
.../src/services/ant-design-pro/login.ts | 37 ++
.../src/services/ant-design-pro/rule.ts | 63 +++
.../src/services/ant-design-pro/typings.d.ts | 117 ++++
dubbo-admin-ui-antd/src/typings.d.ts | 54 ++
dubbo-admin-ui-antd/src/utils/utils.less | 32 ++
dubbo-admin-ui-antd/src/utils/utils.test.ts | 53 ++
dubbo-admin-ui-antd/src/utils/utils.ts | 35 ++
dubbo-admin-ui-antd/tests/PuppeteerEnvironment.js | 57 ++
dubbo-admin-ui-antd/tests/beforeTest.js | 55 ++
dubbo-admin-ui-antd/tests/getBrowser.js | 61 +++
dubbo-admin-ui-antd/tests/run-tests.js | 68 +++
dubbo-admin-ui-antd/tests/setupTests.js | 26 +
dubbo-admin-ui-antd/tsconfig.json | 40 ++
90 files changed, 6353 insertions(+)
diff --git a/dubbo-admin-ui-antd/.editorconfig b/dubbo-admin-ui-antd/.editorconfig
new file mode 100644
index 0000000..7e3649a
--- /dev/null
+++ b/dubbo-admin-ui-antd/.editorconfig
@@ -0,0 +1,16 @@
+# http://editorconfig.org
+root = true
+
+[*]
+indent_style = space
+indent_size = 2
+end_of_line = lf
+charset = utf-8
+trim_trailing_whitespace = true
+insert_final_newline = true
+
+[*.md]
+trim_trailing_whitespace = false
+
+[Makefile]
+indent_style = tab
diff --git a/dubbo-admin-ui-antd/.eslintignore b/dubbo-admin-ui-antd/.eslintignore
new file mode 100644
index 0000000..8336e93
--- /dev/null
+++ b/dubbo-admin-ui-antd/.eslintignore
@@ -0,0 +1,8 @@
+/lambda/
+/scripts
+/config
+.history
+public
+dist
+.umi
+mock
\ No newline at end of file
diff --git a/dubbo-admin-ui-antd/.eslintrc.js b/dubbo-admin-ui-antd/.eslintrc.js
new file mode 100644
index 0000000..f854939
--- /dev/null
+++ b/dubbo-admin-ui-antd/.eslintrc.js
@@ -0,0 +1,24 @@
+/*
+ * 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.
+ */
+module.exports = {
+ extends: [require.resolve('@umijs/fabric/dist/eslint')],
+ globals: {
+ ANT_DESIGN_PRO_ONLY_DO_NOT_USE_IN_YOUR_PRODUCTION: true,
+ page: true,
+ REACT_APP_ENV: true,
+ },
+};
diff --git a/dubbo-admin-ui-antd/.gitignore b/dubbo-admin-ui-antd/.gitignore
new file mode 100644
index 0000000..7fd9f58
--- /dev/null
+++ b/dubbo-admin-ui-antd/.gitignore
@@ -0,0 +1,40 @@
+# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
+
+# dependencies
+**/node_modules
+# roadhog-api-doc ignore
+/src/utils/request-temp.js
+_roadhog-api-doc
+
+# production
+/dist
+/.vscode
+
+# misc
+.DS_Store
+npm-debug.log*
+yarn-error.log
+
+/coverage
+.idea
+yarn.lock
+package-lock.json
+*bak
+.vscode
+
+# visual studio code
+.history
+*.log
+functions/*
+.temp/**
+
+# umi
+.umi
+.umi-production
+
+# screenshot
+screenshot
+.firebase
+.eslintcache
+
+build
diff --git a/dubbo-admin-ui-antd/.prettierignore b/dubbo-admin-ui-antd/.prettierignore
new file mode 100644
index 0000000..d17efb4
--- /dev/null
+++ b/dubbo-admin-ui-antd/.prettierignore
@@ -0,0 +1,23 @@
+**/*.svg
+package.json
+.umi
+.umi-production
+/dist
+.dockerignore
+.DS_Store
+.eslintignore
+*.png
+*.toml
+docker
+.editorconfig
+Dockerfile*
+.gitignore
+.prettierignore
+LICENSE
+.eslintcache
+*.lock
+yarn-error.log
+.history
+CNAME
+/build
+/public
\ No newline at end of file
diff --git a/dubbo-admin-ui-antd/.prettierrc.js b/dubbo-admin-ui-antd/.prettierrc.js
new file mode 100644
index 0000000..64d2db1
--- /dev/null
+++ b/dubbo-admin-ui-antd/.prettierrc.js
@@ -0,0 +1,21 @@
+/*
+ * 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.
+ */
+const fabric = require('@umijs/fabric');
+
+module.exports = {
+ ...fabric.prettier,
+};
diff --git a/dubbo-admin-ui-antd/.stylelintrc.js b/dubbo-admin-ui-antd/.stylelintrc.js
new file mode 100644
index 0000000..22ebf98
--- /dev/null
+++ b/dubbo-admin-ui-antd/.stylelintrc.js
@@ -0,0 +1,21 @@
+/*
+ * 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.
+ */
+const fabric = require('@umijs/fabric');
+
+module.exports = {
+ ...fabric.stylelint,
+};
diff --git a/dubbo-admin-ui-antd/README.md b/dubbo-admin-ui-antd/README.md
new file mode 100644
index 0000000..4c9ea75
--- /dev/null
+++ b/dubbo-admin-ui-antd/README.md
@@ -0,0 +1,46 @@
+# dubbo-admin-ui-antd
+
+This project is initialized with Ant Design Pro v5. Follow is the quick guide for how to use.
+
+## Environment Prepare
+
+```bash
+npm install
+```
+
+## Build Setup
+
+
+### Start project
+
+```bash
+npm start
+```
+
+### Build project
+
+```bash
+npm run build
+```
+
+### Check code style
+
+```bash
+npm run lint
+```
+
+You can also use script to auto fix some lint error:
+
+```bash
+npm run lint:fix
+```
+
+### Test code
+
+```bash
+npm test
+```
+
+## Others
+
+[Reference documents](https://beta-pro.ant.design/docs/getting-started)
diff --git a/dubbo-admin-ui-antd/README_zh.md b/dubbo-admin-ui-antd/README_zh.md
new file mode 100644
index 0000000..78eb780
--- /dev/null
+++ b/dubbo-admin-ui-antd/README_zh.md
@@ -0,0 +1,50 @@
+# dubbo-admin-ui-antd
+
+这个项目是使用 Ant Design Pro v5 初始化的。下面是如何使用的快速指南。
+
+## 环境准备
+
+
+```bash
+npm install
+```
+
+or
+
+```bash
+npm install --registry=https://registry.npm.taobao.org
+```
+
+## 启动
+
+```bash
+npm start
+```
+
+## 编译
+
+```bash
+npm run build
+```
+
+## 检查代码样式
+
+```bash
+npm run lint
+```
+
+也可以使用脚本自动修复某些lint错误:
+
+```bash
+npm run lint:fix
+```
+
+## 测试
+
+```bash
+npm test
+```
+
+## 其他
+
+[参考文档](https://beta-pro.ant.design/docs/getting-started-cn)
diff --git a/dubbo-admin-ui-antd/config/config.dev.ts b/dubbo-admin-ui-antd/config/config.dev.ts
new file mode 100644
index 0000000..cc7bca2
--- /dev/null
+++ b/dubbo-admin-ui-antd/config/config.dev.ts
@@ -0,0 +1,31 @@
+/*
+ * 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.
+ */
+ // https://umijs.org/config/
+import { defineConfig } from 'umi';
+
+export default defineConfig({
+ plugins: [
+ // https://github.com/zthxxx/react-dev-inspector
+ 'react-dev-inspector/plugins/umi/react-inspector',
+ ],
+ // https://github.com/zthxxx/react-dev-inspector#inspector-loader-props
+ inspectorConfig: {
+ exclude: [],
+ babelPlugins: [],
+ babelOptions: {},
+ },
+});
diff --git a/dubbo-admin-ui-antd/config/config.ts b/dubbo-admin-ui-antd/config/config.ts
new file mode 100644
index 0000000..443a566
--- /dev/null
+++ b/dubbo-admin-ui-antd/config/config.ts
@@ -0,0 +1,74 @@
+/*
+ * 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.
+ */
+ // https://umijs.org/config/
+import { defineConfig } from 'umi';
+import { join } from 'path';
+import defaultSettings from './defaultSettings';
+import proxy from './proxy';
+import routes from './routes';
+
+const { REACT_APP_ENV } = process.env;
+
+export default defineConfig({
+ hash: true,
+ antd: {},
+ dva: {
+ hmr: true,
+ },
+ layout: {
+ // https://umijs.org/plugins/plugin-layout
+ locale: true,
+ siderWidth: 208,
+ ...defaultSettings,
+ },
+ // https://umijs.org/plugins/plugin-locale
+ locale: {
+ // default zh-CN
+ default: 'en-US',
+ antd: true,
+ // default true, when it is true, will use `navigator.language` overwrite default
+ baseNavigator: true,
+ },
+ dynamicImport: {
+ loading: '@ant-design/pro-layout/es/PageLoading',
+ },
+ targets: {
+ ie: 11,
+ },
+ // umi routes: https://umijs.org/docs/routing
+ routes,
+ // Theme for antd: https://ant.design/docs/react/customize-theme-cn
+ theme: {
+ 'primary-color': defaultSettings.primaryColor,
+ },
+ // esbuild is father build tools
+ // https://umijs.org/plugins/plugin-esbuild
+ esbuild: {},
+ title: false,
+ ignoreMomentLocale: true,
+ proxy: proxy[REACT_APP_ENV || 'dev'],
+ manifest: {
+ basePath: '/',
+ },
+ openAPI: {
+ requestLibPath: "import { request } from 'umi'",
+ // Or use the online version
+ // schemaPath: "https://gw.alipayobjects.com/os/antfincdn/M%24jrzTTYJN/oneapi.json"
+ schemaPath: join(__dirname, 'oneapi.json'),
+ mock: false,
+ },
+});
diff --git a/dubbo-admin-ui-antd/config/defaultSettings.ts b/dubbo-admin-ui-antd/config/defaultSettings.ts
new file mode 100644
index 0000000..d341acc
--- /dev/null
+++ b/dubbo-admin-ui-antd/config/defaultSettings.ts
@@ -0,0 +1,36 @@
+/*
+ * 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 { Settings as LayoutSettings } from '@ant-design/pro-layout';
+
+const Settings: LayoutSettings & {
+ pwa?: boolean;
+ logo?: string;
+} = {
+ navTheme: 'light',
+ primaryColor: '#1890ff',
+ layout: 'mix',
+ contentWidth: 'Fluid',
+ fixedHeader: false,
+ fixSiderbar: true,
+ colorWeak: false,
+ title: 'Ant Design Pro',
+ pwa: false,
+ logo: 'https://gw.alipayobjects.com/zos/rmsportal/KDpgvguMpGfqaHPjicRK.svg',
+ iconfontUrl: '',
+};
+
+export default Settings;
diff --git a/dubbo-admin-ui-antd/config/oneapi.json b/dubbo-admin-ui-antd/config/oneapi.json
new file mode 100644
index 0000000..77ad573
--- /dev/null
+++ b/dubbo-admin-ui-antd/config/oneapi.json
@@ -0,0 +1,593 @@
+{
+ "openapi": "3.0.1",
+ "info": {
+ "title": "Dubbo Admin",
+ "version": "1.0.0"
+ },
+ "servers": [
+ {
+ "url": "http://localhost:8000/"
+ },
+ {
+ "url": "https://localhost:8000/"
+ }
+ ],
+ "paths": {
+ "/api/currentUser": {
+ "get": {
+ "tags": ["api"],
+ "description": "Get the current user",
+ "operationId": "currentUser",
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/CurrentUser"
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ErrorResponse"
+ }
+ }
+ }
+ }
+ }
+ },
+ "x-swagger-router-controller": "api"
+ },
+ "/api/login/captcha": {
+ "post": {
+ "description": "Send verification code",
+ "operationId": "getFakeCaptcha",
+ "tags": ["login"],
+ "parameters": [
+ {
+ "name": "phone",
+ "in": "query",
+ "description": "mobile number",
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/FakeCaptcha"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/api/login/outLogin": {
+ "post": {
+ "description": "Login out interface",
+ "operationId": "outLogin",
+ "tags": ["login"],
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object"
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ErrorResponse"
+ }
+ }
+ }
+ }
+ }
+ },
+ "x-swagger-router-controller": "api"
+ },
+ "/api/login/account": {
+ "post": {
+ "tags": ["login"],
+ "description": "Login interface",
+ "operationId": "login",
+ "requestBody": {
+ "description": "login",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/LoginParams"
+ }
+ }
+ },
+ "required": true
+ },
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/LoginResult"
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ErrorResponse"
+ }
+ }
+ }
+ }
+ },
+ "x-codegen-request-body-name": "body"
+ },
+ "x-swagger-router-controller": "api"
+ },
+ "/api/notices": {
+ "summary": "getNotices",
+ "description": "NoticeIconItem",
+ "get": {
+ "tags": ["api"],
+ "operationId": "getNotices",
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/NoticeIconList"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/api/rule": {
+ "get": {
+ "tags": ["rule"],
+ "description": "Get rule list",
+ "operationId": "rule",
+ "parameters": [
+ {
+ "name": "current",
+ "in": "query",
+ "description": "Current page number",
+ "schema": {
+ "type": "number"
+ }
+ },
+ {
+ "name": "pageSize",
+ "in": "query",
+ "description": "page size",
+ "schema": {
+ "type": "number"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/RuleList"
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ErrorResponse"
+ }
+ }
+ }
+ }
+ }
+ },
+ "post": {
+ "tags": ["rule"],
+ "description": "new rule",
+ "operationId": "addRule",
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/RuleListItem"
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ErrorResponse"
+ }
+ }
+ }
+ }
+ }
+ },
+ "put": {
+ "tags": ["rule"],
+ "description": "update rule",
+ "operationId": "updateRule",
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/RuleListItem"
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ErrorResponse"
+ }
+ }
+ }
+ }
+ }
+ },
+ "delete": {
+ "tags": ["rule"],
+ "description": "remove rule",
+ "operationId": "removeRule",
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object"
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ErrorResponse"
+ }
+ }
+ }
+ }
+ }
+ },
+ "x-swagger-router-controller": "api"
+ },
+ "/swagger": {
+ "x-swagger-pipe": "swagger_raw"
+ }
+ },
+ "components": {
+ "schemas": {
+ "CurrentUser": {
+ "type": "object",
+ "properties": {
+ "name": {
+ "type": "string"
+ },
+ "avatar": {
+ "type": "string"
+ },
+ "userid": {
+ "type": "string"
+ },
+ "email": {
+ "type": "string"
+ },
+ "signature": {
+ "type": "string"
+ },
+ "title": {
+ "type": "string"
+ },
+ "group": {
+ "type": "string"
+ },
+ "tags": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "key": {
+ "type": "string"
+ },
+ "label": {
+ "type": "string"
+ }
+ }
+ }
+ },
+ "notifyCount": {
+ "type": "integer",
+ "format": "int32"
+ },
+ "unreadCount": {
+ "type": "integer",
+ "format": "int32"
+ },
+ "country": {
+ "type": "string"
+ },
+ "access": {
+ "type": "string"
+ },
+ "geographic": {
+ "type": "object",
+ "properties": {
+ "province": {
+ "type": "object",
+ "properties": {
+ "label": {
+ "type": "string"
+ },
+ "key": {
+ "type": "string"
+ }
+ }
+ },
+ "city": {
+ "type": "object",
+ "properties": {
+ "label": {
+ "type": "string"
+ },
+ "key": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ },
+ "address": {
+ "type": "string"
+ },
+ "phone": {
+ "type": "string"
+ }
+ }
+ },
+ "LoginResult": {
+ "type": "object",
+ "properties": {
+ "status": {
+ "type": "string"
+ },
+ "type": {
+ "type": "string"
+ },
+ "currentAuthority": {
+ "type": "string"
+ }
+ }
+ },
+ "PageParams": {
+ "type": "object",
+ "properties": {
+ "current": {
+ "type": "number"
+ },
+ "pageSize": {
+ "type": "number"
+ }
+ }
+ },
+ "RuleListItem": {
+ "type": "object",
+ "properties": {
+ "key": {
+ "type": "integer",
+ "format": "int32"
+ },
+ "disabled": {
+ "type": "boolean"
+ },
+ "href": {
+ "type": "string"
+ },
+ "avatar": {
+ "type": "string"
+ },
+ "name": {
+ "type": "string"
+ },
+ "owner": {
+ "type": "string"
+ },
+ "desc": {
+ "type": "string"
+ },
+ "callNo": {
+ "type": "integer",
+ "format": "int32"
+ },
+ "status": {
+ "type": "integer",
+ "format": "int32"
+ },
+ "updatedAt": {
+ "type": "string",
+ "format": "datetime"
+ },
+ "createdAt": {
+ "type": "string",
+ "format": "datetime"
+ },
+ "progress": {
+ "type": "integer",
+ "format": "int32"
+ }
+ }
+ },
+ "RuleList": {
+ "type": "object",
+ "properties": {
+ "data": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/RuleListItem"
+ }
+ },
+ "total": {
+ "type": "integer",
+ "description": "The total number of contents in the list",
+ "format": "int32"
+ },
+ "success": {
+ "type": "boolean"
+ }
+ }
+ },
+ "FakeCaptcha": {
+ "type": "object",
+ "properties": {
+ "code": {
+ "type": "integer",
+ "format": "int32"
+ },
+ "status": {
+ "type": "string"
+ }
+ }
+ },
+ "LoginParams": {
+ "type": "object",
+ "properties": {
+ "username": {
+ "type": "string"
+ },
+ "password": {
+ "type": "string"
+ },
+ "autoLogin": {
+ "type": "boolean"
+ },
+ "type": {
+ "type": "string"
+ }
+ }
+ },
+ "ErrorResponse": {
+ "required": ["errorCode"],
+ "type": "object",
+ "properties": {
+ "errorCode": {
+ "type": "string",
+ "description": "Error code of business agreement"
+ },
+ "errorMessage": {
+ "type": "string",
+ "description": "Business error messages"
+ },
+ "success": {
+ "type": "boolean",
+ "description": "Is the business request successful"
+ }
+ }
+ },
+ "NoticeIconList": {
+ "type": "object",
+ "properties": {
+ "data": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/NoticeIconItem"
+ }
+ },
+ "total": {
+ "type": "integer",
+ "description": "The total number of contents in the list",
+ "format": "int32"
+ },
+ "success": {
+ "type": "boolean"
+ }
+ }
+ },
+ "NoticeIconItemType": {
+ "title": "NoticeIconItemType",
+ "description": "Enumeration of read unread lists",
+ "type": "string",
+ "properties": {},
+ "enum": ["notification", "message", "event"]
+ },
+ "NoticeIconItem": {
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "string"
+ },
+ "extra": {
+ "type": "string",
+ "format": "any"
+ },
+ "key": { "type": "string" },
+ "read": {
+ "type": "boolean"
+ },
+ "avatar": {
+ "type": "string"
+ },
+ "title": {
+ "type": "string"
+ },
+ "status": {
+ "type": "string"
+ },
+ "datetime": {
+ "type": "string",
+ "format": "date"
+ },
+ "description": {
+ "type": "string"
+ },
+ "type": {
+ "extensions": {
+ "x-is-enum": true
+ },
+ "$ref": "#/components/schemas/NoticeIconItemType"
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/dubbo-admin-ui-antd/config/proxy.ts b/dubbo-admin-ui-antd/config/proxy.ts
new file mode 100644
index 0000000..94fc261
--- /dev/null
+++ b/dubbo-admin-ui-antd/config/proxy.ts
@@ -0,0 +1,39 @@
+/*
+ * 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 default {
+ dev: {
+ '/api/': {
+ target: 'http://localhost:8080/',
+ changeOrigin: true,
+ pathRewrite: { '^': '' },
+ },
+ },
+ test: {
+ '/api/': {
+ target: 'test',
+ changeOrigin: true,
+ pathRewrite: { '^': '' },
+ },
+ },
+ pre: {
+ '/api/': {
+ target: 'pre',
+ changeOrigin: true,
+ pathRewrite: { '^': '' },
+ },
+ },
+};
diff --git a/dubbo-admin-ui-antd/config/routes.ts b/dubbo-admin-ui-antd/config/routes.ts
new file mode 100644
index 0000000..b0965c2
--- /dev/null
+++ b/dubbo-admin-ui-antd/config/routes.ts
@@ -0,0 +1,68 @@
+/*
+ * 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 default [
+ {
+ path: '/user',
+ layout: false,
+ routes: [
+ {
+ path: '/user',
+ routes: [
+ {
+ name: 'login',
+ path: '/user/login',
+ component: './User/login',
+ },
+ ],
+ },
+ ],
+ },
+ {
+ path: '/welcome',
+ name: 'welcome',
+ icon: 'smile',
+ component: './Welcome',
+ },
+ {
+ path: '/admin',
+ name: 'admin',
+ icon: 'crown',
+ access: 'canAdmin',
+ component: './Admin',
+ routes: [
+ {
+ path: '/admin/sub-page',
+ name: 'sub-page',
+ icon: 'smile',
+ component: './Welcome',
+ },
+ ],
+ },
+ {
+ name: 'list.table-list',
+ icon: 'table',
+ path: '/list',
+ component: './TableList',
+ },
+ {
+ path: '/',
+ redirect: '/welcome',
+ },
+ {
+ component: './404',
+ },
+];
diff --git a/dubbo-admin-ui-antd/jest.config.js b/dubbo-admin-ui-antd/jest.config.js
new file mode 100644
index 0000000..0aa701f
--- /dev/null
+++ b/dubbo-admin-ui-antd/jest.config.js
@@ -0,0 +1,26 @@
+/*
+ * 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.
+ */
+module.exports = {
+ testURL: 'http://localhost:8000',
+ testEnvironment: './tests/PuppeteerEnvironment',
+ verbose: false,
+ extraSetupFiles: ['./tests/setupTests.js'],
+ globals: {
+ ANT_DESIGN_PRO_ONLY_DO_NOT_USE_IN_YOUR_PRODUCTION: false,
+ localStorage: null,
+ },
+};
diff --git a/dubbo-admin-ui-antd/jsconfig.json b/dubbo-admin-ui-antd/jsconfig.json
new file mode 100644
index 0000000..f87334d
--- /dev/null
+++ b/dubbo-admin-ui-antd/jsconfig.json
@@ -0,0 +1,10 @@
+{
+ "compilerOptions": {
+ "emitDecoratorMetadata": true,
+ "experimentalDecorators": true,
+ "baseUrl": ".",
+ "paths": {
+ "@/*": ["./src/*"]
+ }
+ }
+}
diff --git a/dubbo-admin-ui-antd/mock/listTableList.ts b/dubbo-admin-ui-antd/mock/listTableList.ts
new file mode 100644
index 0000000..c64631b
--- /dev/null
+++ b/dubbo-admin-ui-antd/mock/listTableList.ts
@@ -0,0 +1,191 @@
+/*
+ * 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-next-line import/no-extraneous-dependencies
+import { Request, Response } from 'express';
+import moment from 'moment';
+import { parse } from 'url';
+
+// mock tableListDataSource
+const genList = (current: number, pageSize: number) => {
+ const tableListDataSource: API.RuleListItem[] = [];
+
+ for (let i = 0; i < pageSize; i += 1) {
+ const index = (current - 1) * 10 + i;
+ tableListDataSource.push({
+ key: index,
+ disabled: i % 6 === 0,
+ href: 'https://ant.design',
+ avatar: [
+ 'https://gw.alipayobjects.com/zos/rmsportal/eeHMaZBwmTvLdIwMfBpg.png',
+ 'https://gw.alipayobjects.com/zos/rmsportal/udxAbMEhpwthVVcjLXik.png',
+ ][i % 2],
+ name: `TradeCode ${index}`,
+ owner: 'Apache Dubbo',
+ desc: 'This is a description',
+ callNo: Math.floor(Math.random() * 1000),
+ status: Math.floor(Math.random() * 10) % 4,
+ updatedAt: moment().format('YYYY-MM-DD'),
+ createdAt: moment().format('YYYY-MM-DD'),
+ progress: Math.ceil(Math.random() * 100),
+ });
+ }
+ tableListDataSource.reverse();
+ return tableListDataSource;
+};
+
+let tableListDataSource = genList(1, 100);
+
+function getRule(req: Request, res: Response, u: string) {
+ let realUrl = u;
+ if (!realUrl || Object.prototype.toString.call(realUrl) !== '[object String]') {
+ realUrl = req.url;
+ }
+ const { current = 1, pageSize = 10 } = req.query;
+ const params = (parse(realUrl, true).query as unknown) as API.PageParams &
+ API.RuleListItem & {
+ sorter: any;
+ filter: any;
+ };
+
+ let dataSource = [...tableListDataSource].slice(
+ ((current as number) - 1) * (pageSize as number),
+ (current as number) * (pageSize as number),
+ );
+ const sorter = JSON.parse(params.sorter || ('{}' as any));
+ if (sorter) {
+ dataSource = dataSource.sort((prev, next) => {
+ let sortNumber = 0;
+ Object.keys(sorter).forEach((key) => {
+ if (sorter[key] === 'descend') {
+ if (prev[key] - next[key] > 0) {
+ sortNumber += -1;
+ } else {
+ sortNumber += 1;
+ }
+ return;
+ }
+ if (prev[key] - next[key] > 0) {
+ sortNumber += 1;
+ } else {
+ sortNumber += -1;
+ }
+ });
+ return sortNumber;
+ });
+ }
+ if (params.filter) {
+ const filter = JSON.parse(params.filter as any) as {
+ [key: string]: string[];
+ };
+ if (Object.keys(filter).length > 0) {
+ dataSource = dataSource.filter((item) => {
+ return Object.keys(filter).some((key) => {
+ if (!filter[key]) {
+ return true;
+ }
+ if (filter[key].includes(`${item[key]}`)) {
+ return true;
+ }
+ return false;
+ });
+ });
+ }
+ }
+
+ if (params.name) {
+ dataSource = dataSource.filter((data) => data?.name?.includes(params.name || ''));
+ }
+ const result = {
+ data: dataSource,
+ total: tableListDataSource.length,
+ success: true,
+ pageSize,
+ current: parseInt(`${params.current}`, 10) || 1,
+ };
+
+ return res.json(result);
+}
+
+function postRule(req: Request, res: Response, u: string, b: Request) {
+ let realUrl = u;
+ if (!realUrl || Object.prototype.toString.call(realUrl) !== '[object String]') {
+ realUrl = req.url;
+ }
+
+ const body = (b && b.body) || req.body;
+ const { method, name, desc, key } = body;
+
+ switch (method) {
+ /* eslint no-case-declarations:0 */
+ case 'delete':
+ tableListDataSource = tableListDataSource.filter((item) => key.indexOf(item.key) === -1);
+ break;
+ case 'post':
+ (() => {
+ const i = Math.ceil(Math.random() * 10000);
+ const newRule: API.RuleListItem = {
+ key: tableListDataSource.length,
+ href: 'https://ant.design',
+ avatar: [
+ 'https://gw.alipayobjects.com/zos/rmsportal/eeHMaZBwmTvLdIwMfBpg.png',
+ 'https://gw.alipayobjects.com/zos/rmsportal/udxAbMEhpwthVVcjLXik.png',
+ ][i % 2],
+ name,
+ owner: 'Apache Dubbo',
+ desc,
+ callNo: Math.floor(Math.random() * 1000),
+ status: Math.floor(Math.random() * 10) % 2,
+ updatedAt: moment().format('YYYY-MM-DD'),
+ createdAt: moment().format('YYYY-MM-DD'),
+ progress: Math.ceil(Math.random() * 100),
+ };
+ tableListDataSource.unshift(newRule);
+ return res.json(newRule);
+ })();
+ return;
+
+ case 'update':
+ (() => {
+ let newRule = {};
+ tableListDataSource = tableListDataSource.map((item) => {
+ if (item.key === key) {
+ newRule = { ...item, desc, name };
+ return { ...item, desc, name };
+ }
+ return item;
+ });
+ return res.json(newRule);
+ })();
+ return;
+ default:
+ break;
+ }
+
+ const result = {
+ list: tableListDataSource,
+ pagination: {
+ total: tableListDataSource.length,
+ },
+ };
+
+ res.json(result);
+}
+
+export default {
+ 'GET /api/rule': getRule,
+ 'POST /api/rule': postRule,
+};
diff --git a/dubbo-admin-ui-antd/mock/notices.ts b/dubbo-admin-ui-antd/mock/notices.ts
new file mode 100644
index 0000000..8b16266
--- /dev/null
+++ b/dubbo-admin-ui-antd/mock/notices.ts
@@ -0,0 +1,107 @@
+/*
+ * 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 { Request, Response } from 'express';
+
+const getNotices = (req: Request, res: Response) => {
+ res.json({
+ data: [
+ {
+ id: '000000001',
+ avatar: 'https://gw.alipayobjects.com/zos/rmsportal/ThXAXghbEsBCCSDihZxY.png',
+ title: 'You've received 14 new weekly papers',
+ datetime: '2017-08-09',
+ type: 'notification',
+ },
+ {
+ id: '000000002',
+ avatar: 'https://gw.alipayobjects.com/zos/rmsportal/OKJXDXrmkNshAMvwtvhu.png',
+ title: 'The Xiao Ming you recommended has passed the third round of interview',
+ datetime: '2017-08-08',
+ type: 'notification',
+ },
+ {
+ id: '000000003',
+ avatar: 'https://gw.alipayobjects.com/zos/rmsportal/kISTdvpyTAhtGxpovNWd.png',
+ title: 'This template can distinguish multiple notification types',
+ datetime: '2017-08-07',
+ read: true,
+ type: 'notification',
+ },
+ {
+ id: '000000004',
+ avatar: 'https://gw.alipayobjects.com/zos/rmsportal/GvqBnKhFgObvnSGkDsje.png',
+ title: 'The icon on the left is used to distinguish different types',
+ datetime: '2017-08-07',
+ type: 'notification',
+ },
+ {
+ id: '000000005',
+ avatar: 'https://gw.alipayobjects.com/zos/rmsportal/ThXAXghbEsBCCSDihZxY.png',
+ title: 'The icon on the left is used to distinguish different types',
+ datetime: '2017-08-07',
+ type: 'notification',
+ },
+ {
+ id: '000000006',
+ avatar: 'https://gw.alipayobjects.com/zos/rmsportal/fcHMVNCjPOsbUGdEduuv.jpeg',
+ title: 'Xiao Ming commented on you',
+ description: 'Description information',
+ datetime: '2017-08-07',
+ type: 'message',
+ clickClose: true,
+ },
+ {
+ id: '000000007',
+ avatar: 'https://gw.alipayobjects.com/zos/rmsportal/fcHMVNCjPOsbUGdEduuv.jpeg',
+ title: 'Xiao Ming replied to you',
+ description: 'This kind of template is used to remind who interacts with you, and the head picture of "who" is placed on the left side',
+ datetime: '2017-08-07',
+ type: 'message',
+ clickClose: true,
+ },
+ {
+ id: '000000008',
+ avatar: 'https://gw.alipayobjects.com/zos/rmsportal/fcHMVNCjPOsbUGdEduuv.jpeg',
+ title: 'Title',
+ description: 'This kind of template is used to remind who interacts with you, and the head picture of "who" is placed on the left side',
+ datetime: '2017-08-07',
+ type: 'message',
+ clickClose: true,
+ },
+ {
+ id: '000000009',
+ title: 'Task name',
+ description: 'The task needs to be started before 20:00 on 2017-01-12 20:00',
+ extra: 'Not started',
+ status: 'todo',
+ type: 'event',
+ },
+ {
+ id: '000000010',
+ title: 'Third party emergency code change',
+ description: 'Xiao Ming submitted it on 2017-01-06, and needed to complete the code change task before 2017-01-07',
+ extra: 'Due soon',
+ status: 'urgent',
+ type: 'event',
+ },
+ ],
+ });
+};
+
+export default {
+ 'GET /api/notices': getNotices,
+};
diff --git a/dubbo-admin-ui-antd/mock/route.ts b/dubbo-admin-ui-antd/mock/route.ts
new file mode 100644
index 0000000..37dba9a
--- /dev/null
+++ b/dubbo-admin-ui-antd/mock/route.ts
@@ -0,0 +1,21 @@
+/*
+ * 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 default {
+ '/api/auth_routes': {
+ '/form/advanced-form': { authority: ['admin', 'user'] },
+ },
+};
diff --git a/dubbo-admin-ui-antd/mock/user.ts b/dubbo-admin-ui-antd/mock/user.ts
new file mode 100644
index 0000000..1ab9151
--- /dev/null
+++ b/dubbo-admin-ui-antd/mock/user.ts
@@ -0,0 +1,211 @@
+/*
+ * 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 { Request, Response } from 'express';
+
+const waitTime = (time: number = 100) => {
+ return new Promise((resolve) => {
+ setTimeout(() => {
+ resolve(true);
+ }, time);
+ });
+};
+
+async function getFakeCaptcha(req: Request, res: Response) {
+ await waitTime(2000);
+ return res.json('captcha-xxx');
+}
+
+const { ANT_DESIGN_PRO_ONLY_DO_NOT_USE_IN_YOUR_PRODUCTION } = process.env;
+
+/**
+ * The permission of the current user. If it is blank, it means no login
+ * current user access, if is '', user need login
+ */
+let access = ANT_DESIGN_PRO_ONLY_DO_NOT_USE_IN_YOUR_PRODUCTION === 'site' ? 'admin' : '';
+
+const getAccess = () => {
+ return access;
+};
+
+// The code will be compatible with the static data of local service mock and deployment site
+export default {
+ // Object and Array are supported
+ 'GET /api/currentUser': (req: Request, res: Response) => {
+ if (!getAccess()) {
+ res.status(401).send({
+ data: {
+ isLogin: false,
+ },
+ errorCode: '401',
+ errorMessage: 'Please log in first!',
+ success: true,
+ });
+ return;
+ }
+ res.send({
+ name: 'Serati Ma',
+ avatar: 'https://gw.alipayobjects.com/zos/antfincdn/XAosXuNZyF/BiazfanxmamNRoxxVxka.png',
+ userid: '00000001',
+ email: 'dev@dubbo.apache.com',
+ signature: 'The sea embraces all rivers, and tolerance is great',
+ title: 'Interaction expert',
+ group: 'Apache-Dubbo-Dubbo Admin',
+ tags: [
+ {
+ key: '0',
+ label: 'Interaction expert',
+ },
+ {
+ key: '1',
+ label: 'Focus on Design',
+ },
+ {
+ key: '2',
+ label: 'Spicy~',
+ },
+ {
+ key: '3',
+ label: 'long legs',
+ },
+ {
+ key: '4',
+ label: 'a Sichuan girl',
+ },
+ ],
+ notifyCount: 12,
+ unreadCount: 11,
+ country: 'China',
+ access: getAccess(),
+ geographic: {
+ province: {
+ label: 'Zhejiang Province',
+ key: '330000',
+ },
+ city: {
+ label: 'Hangzhou City',
+ key: '330100',
+ },
+ },
+ address: '77 gongzhuan Road, Xihu District',
+ phone: '0752-268888888',
+ });
+ },
+ // GET POST can be omitted
+ 'GET /api/users': [
+ {
+ key: '1',
+ name: 'John Brown',
+ age: 32,
+ address: 'New York No. 1 Lake Park',
+ },
+ {
+ key: '2',
+ name: 'Jim Green',
+ age: 42,
+ address: 'London No. 1 Lake Park',
+ },
+ {
+ key: '3',
+ name: 'Joe Black',
+ age: 32,
+ address: 'Sidney No. 1 Lake Park',
+ },
+ ],
+ 'POST /api/login/account': async (req: Request, res: Response) => {
+ const { password, username, type } = req.body;
+ await waitTime(2000);
+ if (password === 'ant.design' && username === 'admin') {
+ res.send({
+ status: 'ok',
+ type,
+ currentAuthority: 'admin',
+ });
+ access = 'admin';
+ return;
+ }
+ if (password === 'ant.design' && username === 'user') {
+ res.send({
+ status: 'ok',
+ type,
+ currentAuthority: 'user',
+ });
+ access = 'user';
+ return;
+ }
+ if (type === 'mobile') {
+ res.send({
+ status: 'ok',
+ type,
+ currentAuthority: 'admin',
+ });
+ access = 'admin';
+ return;
+ }
+
+ res.send({
+ status: 'error',
+ type,
+ currentAuthority: 'guest',
+ });
+ access = 'guest';
+ },
+ 'GET /api/login/outLogin': (req: Request, res: Response) => {
+ access = '';
+ res.send({ data: {}, success: true });
+ },
+ 'POST /api/register': (req: Request, res: Response) => {
+ res.send({ status: 'ok', currentAuthority: 'user', success: true });
+ },
+ 'GET /api/500': (req: Request, res: Response) => {
+ res.status(500).send({
+ timestamp: 1513932555104,
+ status: 500,
+ error: 'error',
+ message: 'error',
+ path: '/base/category/list',
+ });
+ },
+ 'GET /api/404': (req: Request, res: Response) => {
+ res.status(404).send({
+ timestamp: 1513932643431,
+ status: 404,
+ error: 'Not Found',
+ message: 'No message available',
+ path: '/base/category/list/2121212',
+ });
+ },
+ 'GET /api/403': (req: Request, res: Response) => {
+ res.status(403).send({
+ timestamp: 1513932555104,
+ status: 403,
+ error: 'Unauthorized',
+ message: 'Unauthorized',
+ path: '/base/category/list',
+ });
+ },
+ 'GET /api/401': (req: Request, res: Response) => {
+ res.status(401).send({
+ timestamp: 1513932555104,
+ status: 401,
+ error: 'Unauthorized',
+ message: 'Unauthorized',
+ path: '/base/category/list',
+ });
+ },
+
+ 'GET /api/login/captcha': getFakeCaptcha,
+};
diff --git a/dubbo-admin-ui-antd/package.json b/dubbo-admin-ui-antd/package.json
new file mode 100644
index 0000000..3d3f640
--- /dev/null
+++ b/dubbo-admin-ui-antd/package.json
@@ -0,0 +1,108 @@
+{
+ "name": "apache-dubbo-admin-ui",
+ "version": "0.4.0-SNAPSHOT",
+ "private": true,
+ "description": "apache-dubbo-admin-ui",
+ "author": "apache dubbo",
+ "scripts": {
+ "analyze": "cross-env ANALYZE=1 umi build",
+ "build": "umi build",
+ "deploy": "npm run site && npm run gh-pages",
+ "dev": "npm run start:dev",
+ "gh-pages": "gh-pages -d dist",
+ "i18n-remove": "pro i18n-remove --locale=zh-CN --write",
+ "postinstall": "umi g tmp",
+ "lint": "umi g tmp && npm run lint:js && npm run lint:style && npm run lint:prettier",
+ "lint-staged": "lint-staged",
+ "lint-staged:js": "eslint --ext .js,.jsx,.ts,.tsx ",
+ "lint:fix": "eslint --fix --cache --ext .js,.jsx,.ts,.tsx --format=pretty ./src && npm run lint:style",
+ "lint:js": "eslint --cache --ext .js,.jsx,.ts,.tsx --format=pretty ./src",
+ "lint:prettier": "prettier --check \"src/**/*\" --end-of-line auto",
+ "lint:style": "stylelint --fix \"src/**/*.less\" --syntax less",
+ "openapi": "umi openapi",
+ "precommit": "lint-staged",
+ "prettier": "prettier -c --write \"src/**/*\"",
+ "start": "cross-env UMI_ENV=dev umi dev",
+ "start:dev": "cross-env REACT_APP_ENV=dev MOCK=none UMI_ENV=dev umi dev",
+ "start:no-mock": "cross-env MOCK=none UMI_ENV=dev umi dev",
+ "start:no-ui": "cross-env UMI_UI=none UMI_ENV=dev umi dev",
+ "start:pre": "cross-env REACT_APP_ENV=pre UMI_ENV=dev umi dev",
+ "start:test": "cross-env REACT_APP_ENV=test MOCK=none UMI_ENV=dev umi dev",
+ "pretest": "node ./tests/beforeTest",
+ "test": "umi test",
+ "test:all": "node ./tests/run-tests.js",
+ "test:component": "umi test ./src/components",
+ "tsc": "tsc --noEmit"
+ },
+ "lint-staged": {
+ "**/*.less": "stylelint --syntax less",
+ "**/*.{js,jsx,ts,tsx}": "npm run lint-staged:js",
+ "**/*.{js,jsx,tsx,ts,less,md,json}": [
+ "prettier --write"
+ ]
+ },
+ "browserslist": [
+ "> 1%",
+ "last 2 versions",
+ "not ie <= 10"
+ ],
+ "dependencies": {
+ "@ant-design/icons": "^4.0.0",
+ "@ant-design/pro-descriptions": "^1.2.0",
+ "@ant-design/pro-form": "^1.3.0",
+ "@ant-design/pro-layout": "^6.9.0",
+ "@ant-design/pro-table": "^2.17.0",
+ "@umijs/plugin-openapi": "^1.0.1",
+ "@umijs/route-utils": "^1.0.33",
+ "antd": "^4.9.4",
+ "classnames": "^2.2.6",
+ "lodash": "^4.17.11",
+ "moment": "^2.25.3",
+ "omit.js": "^2.0.2",
+ "qs": "^6.9.0",
+ "react": "^17.0.0",
+ "react-dev-inspector": "^1.1.1",
+ "react-dom": "^17.0.0",
+ "react-helmet-async": "^1.0.4",
+ "umi": "^3.2.14",
+ "umi-request": "^1.0.8"
+ },
+ "devDependencies": {
+ "@ant-design/pro-cli": "^2.0.2",
+ "@types/classnames": "^2.2.7",
+ "@types/express": "^4.17.0",
+ "@types/history": "^4.7.2",
+ "@types/jest": "^26.0.0",
+ "@types/lodash": "^4.14.144",
+ "@types/qs": "^6.5.3",
+ "@types/react": "^17.0.0",
+ "@types/react-dom": "^17.0.0",
+ "@types/react-helmet": "^6.1.0",
+ "@umijs/fabric": "^2.5.2",
+ "@umijs/plugin-blocks": "^2.0.5",
+ "@umijs/plugin-esbuild": "^1.0.1",
+ "@umijs/preset-ant-design-pro": "^1.2.0",
+ "@umijs/preset-dumi": "^1.1.0-rc.6",
+ "@umijs/preset-react": "^1.7.4",
+ "@umijs/preset-ui": "^2.2.9",
+ "@umijs/yorkie": "^2.0.3",
+ "carlo": "^0.9.46",
+ "cross-env": "^7.0.0",
+ "cross-port-killer": "^1.1.1",
+ "detect-installer": "^1.0.1",
+ "enzyme": "^3.11.0",
+ "eslint": "^7.1.0",
+ "express": "^4.17.1",
+ "gh-pages": "^3.0.0",
+ "jsdom-global": "^3.0.2",
+ "lint-staged": "^10.0.0",
+ "mockjs": "^1.0.1-beta3",
+ "prettier": "^2.0.1",
+ "puppeteer-core": "^5.0.0",
+ "stylelint": "^13.0.0",
+ "typescript": "^4.0.3"
+ },
+ "engines": {
+ "node": ">=10.0.0"
+ }
+}
diff --git a/dubbo-admin-ui-antd/public/favicon.ico b/dubbo-admin-ui-antd/public/favicon.ico
new file mode 100644
index 0000000..e2e9325
Binary files /dev/null and b/dubbo-admin-ui-antd/public/favicon.ico differ
diff --git a/dubbo-admin-ui-antd/public/home_bg.png b/dubbo-admin-ui-antd/public/home_bg.png
new file mode 100644
index 0000000..7c92a4b
Binary files /dev/null and b/dubbo-admin-ui-antd/public/home_bg.png differ
diff --git a/dubbo-admin-ui-antd/public/icons/icon-128x128.png b/dubbo-admin-ui-antd/public/icons/icon-128x128.png
new file mode 100644
index 0000000..48d0e23
Binary files /dev/null and b/dubbo-admin-ui-antd/public/icons/icon-128x128.png differ
diff --git a/dubbo-admin-ui-antd/public/icons/icon-192x192.png b/dubbo-admin-ui-antd/public/icons/icon-192x192.png
new file mode 100644
index 0000000..938e9b5
Binary files /dev/null and b/dubbo-admin-ui-antd/public/icons/icon-192x192.png differ
diff --git a/dubbo-admin-ui-antd/public/icons/icon-512x512.png b/dubbo-admin-ui-antd/public/icons/icon-512x512.png
new file mode 100644
index 0000000..21fc108
Binary files /dev/null and b/dubbo-admin-ui-antd/public/icons/icon-512x512.png differ
diff --git a/dubbo-admin-ui-antd/public/logo.svg b/dubbo-admin-ui-antd/public/logo.svg
new file mode 100644
index 0000000..239bf69
--- /dev/null
+++ b/dubbo-admin-ui-antd/public/logo.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200" version="1.1" viewBox="0 0 200 200"><title>Group 28 Copy 5</title><desc>Created with Sketch.</desc><defs><linearGradient id="linearGradient-1" x1="62.102%" x2="108.197%" y1="0%" y2="37.864%"><stop offset="0%" stop-color="#4285EB"/><stop offset="100%" stop-color="#2EC7FF"/></linearGradient><linearGradient id="linearGradient-2" x1="69.644%" x2="54.043%" y1="0%" y2="108.457%"><stop of [...]
\ No newline at end of file
diff --git a/dubbo-admin-ui-antd/public/pro_icon.svg b/dubbo-admin-ui-antd/public/pro_icon.svg
new file mode 100644
index 0000000..e075b78
--- /dev/null
+++ b/dubbo-admin-ui-antd/public/pro_icon.svg
@@ -0,0 +1,5 @@
+<svg width="42" height="42" xmlns="http://www.w3.org/2000/svg">
+ <g>
+ <path fill="#070707" d="m6.717392,13.773912l5.6,0c2.8,0 4.7,1.9 4.7,4.7c0,2.8 -2,4.7 -4.9,4.7l-2.5,0l0,4.3l-2.9,0l0,-13.7zm2.9,2.2l0,4.9l1.9,0c1.6,0 2.6,-0.9 2.6,-2.4c0,-1.6 -0.9,-2.4 -2.6,-2.4l-1.9,0l0,-0.1zm8.9,11.5l2.7,0l0,-5.7c0,-1.4 0.8,-2.3 2.2,-2.3c0.4,0 0.8,0.1 1,0.2l0,-2.4c-0.2,-0.1 -0.5,-0.1 -0.8,-0.1c-1.2,0 -2.1,0.7 -2.4,2l-0.1,0l0,-1.9l-2.7,0l0,10.2l0.1,0zm11.7,0.1c-3.1,0 -5,-2 -5,-5.3c0,-3.3 2,-5.3 5,-5.3s5,2 5,5.3c0,3.4 -1.9,5.3 -5,5.3zm0,-2.1c1.4,0 2.2,-1.1 2.2,-3.2c0,-2 [...]
+ </g>
+</svg>
\ No newline at end of file
diff --git a/dubbo-admin-ui-antd/src/access.ts b/dubbo-admin-ui-antd/src/access.ts
new file mode 100644
index 0000000..d4a7ff9
--- /dev/null
+++ b/dubbo-admin-ui-antd/src/access.ts
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+/**
+ * @see https://umijs.org/zh-CN/plugins/plugin-access
+ * */
+export default function access(initialState: { currentUser?: API.CurrentUser | undefined }) {
+ const { currentUser } = initialState || {};
+ return {
+ canAdmin: currentUser && currentUser.access === 'admin',
+ };
+}
diff --git a/dubbo-admin-ui-antd/src/app.tsx b/dubbo-admin-ui-antd/src/app.tsx
new file mode 100644
index 0000000..26c361d
--- /dev/null
+++ b/dubbo-admin-ui-antd/src/app.tsx
@@ -0,0 +1,165 @@
+/*
+ * 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 from 'react';
+import type { Settings as LayoutSettings } from '@ant-design/pro-layout';
+import { PageLoading } from '@ant-design/pro-layout';
+import { notification } from 'antd';
+import type { RequestConfig, RunTimeLayoutConfig } from 'umi';
+import { history } from 'umi';
+import RightContent from '@/components/RightContent';
+import Footer from '@/components/Footer';
+import type { ResponseError } from 'umi-request';
+import { currentUser as queryCurrentUser } from './services/ant-design-pro/api';
+import { BookOutlined, LinkOutlined } from '@ant-design/icons';
+
+const isDev = process.env.NODE_ENV === 'development';
+
+export const initialStateConfig = {
+ loading: <PageLoading />,
+};
+
+/**
+ * @see https://umijs.org/plugins/plugin-initial-state
+ * */
+export async function getInitialState(): Promise<{
+ settings?: Partial<LayoutSettings>;
+ currentUser?: API.CurrentUser;
+ fetchUserInfo?: () => Promise<API.CurrentUser | undefined>;
+}> {
+ const fetchUserInfo = async () => {
+ try {
+ const currentUser = await queryCurrentUser();
+ return currentUser;
+ } catch (error) {
+ history.push('/user/login');
+ }
+ return undefined;
+ };
+ // If it is a login page, do not execute
+ if (history.location.pathname !== '/user/login') {
+ const currentUser = await fetchUserInfo();
+ return {
+ fetchUserInfo,
+ currentUser,
+ settings: {},
+ };
+ }
+ return {
+ fetchUserInfo,
+ settings: {},
+ };
+}
+
+// https://umijs.org/plugins/plugin-layout
+export const layout: RunTimeLayoutConfig = ({ initialState }) => {
+ return {
+ rightContentRender: () => <RightContent />,
+ disableContentMargin: false,
+ footerRender: () => <Footer />,
+ onPageChange: () => {
+ const { location } = history;
+ // If not, redirect to login
+ if (!initialState?.currentUser && location.pathname !== '/user/login') {
+ history.push('/user/login');
+ }
+ },
+ links: isDev
+ ? [
+ <>
+ <LinkOutlined />
+ <span
+ onClick={() => {
+ window.open('/umi/plugin/openapi');
+ }}
+ >
+ openAPI document
+ </span>
+ </>,
+ <>
+ <BookOutlined />
+ <span
+ onClick={() => {
+ window.open('/~docs');
+ }}
+ >
+ Business component document
+ </span>
+ </>,
+ ]
+ : [],
+ menuHeaderRender: undefined,
+ // Custom 403 page
+ // unAccessible: <div>unAccessible</div>,
+ ...initialState?.settings,
+ };
+};
+
+const codeMessage = {
+ 200: 'The server successfully returned the requested data.',
+ 201: 'Create or modify data successfully.',
+ 202: 'A request has entered the background queue (asynchronous task).',
+ 204: 'Delete data successfully.',
+ 400: 'There was an error in the request, and the server did not create or modify the data.',
+ 401: 'The user does not have permission (token, user name, password error).',
+ 403: 'Users are authorized, but access is prohibited.',
+ 404: 'The request is for a record that does not exist, and the server does not operate.',
+ 405: 'Request method is not allowed.',
+ 406: 'The format of the request is not available.',
+ 410: 'The requested resource is permanently deleted and will no longer be available.',
+ 422: 'A validation error occurred while creating an object.',
+ 500: 'Server error, please check the server.',
+ 502: 'Gateway error.',
+ 503: 'Service unavailable, server temporarily overloaded or maintained.',
+ 504: 'Gateway timed out.',
+};
+
+/** Exception handler
+ * @see https://beta-pro.ant.design/docs/request-cn
+ */
+const errorHandler = (error: ResponseError) => {
+ const { response } = error;
+ if (response && response.status) {
+ const errorText = codeMessage[response.status] || response.statusText;
+ const { status, url } = response;
+
+ notification.error({
+ message: `Request error ${status}: ${url}`,
+ description: errorText,
+ });
+ }
+
+ if (!response) {
+ notification.error({
+ description: 'Your network is abnormal, unable to connect to the server',
+ message: 'Network abnormality',
+ });
+ }
+ throw error;
+};
+
+const devRequestProcessInterceptors = (url: string, options: RequestOptionsInit) => {
+ return {
+ url: `/api/dev${url}`,
+ options: { ...options, interceptors: true },
+ };
+};
+
+// https://umijs.org/plugins/plugin-request
+export const request: RequestConfig = {
+ errorHandler,
+ requestInterceptors: [devRequestProcessInterceptors],
+};
diff --git a/dubbo-admin-ui-antd/src/components/Footer/index.tsx b/dubbo-admin-ui-antd/src/components/Footer/index.tsx
new file mode 100644
index 0000000..35b9407
--- /dev/null
+++ b/dubbo-admin-ui-antd/src/components/Footer/index.tsx
@@ -0,0 +1,21 @@
+/*
+ * 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 { DefaultFooter } from '@ant-design/pro-layout';
+
+export default () => (
+ <DefaultFooter copyright="2018-2021 The Apache Software Foundation." links={[]} />
+);
diff --git a/dubbo-admin-ui-antd/src/components/HeaderDropdown/index.less b/dubbo-admin-ui-antd/src/components/HeaderDropdown/index.less
new file mode 100644
index 0000000..27f051e
--- /dev/null
+++ b/dubbo-admin-ui-antd/src/components/HeaderDropdown/index.less
@@ -0,0 +1,32 @@
+/*
+ * 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 '~antd/es/style/themes/default.less';
+
+.container > * {
+ background-color: @popover-bg;
+ border-radius: 4px;
+ box-shadow: @shadow-1-down;
+}
+
+@media screen and (max-width: @screen-xs) {
+ .container {
+ width: 100% !important;
+ }
+ .container > * {
+ border-radius: 0 !important;
+ }
+}
diff --git a/dubbo-admin-ui-antd/src/components/HeaderDropdown/index.tsx b/dubbo-admin-ui-antd/src/components/HeaderDropdown/index.tsx
new file mode 100644
index 0000000..5391251
--- /dev/null
+++ b/dubbo-admin-ui-antd/src/components/HeaderDropdown/index.tsx
@@ -0,0 +1,33 @@
+/*
+ * 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 type { DropDownProps } from 'antd/es/dropdown';
+import { Dropdown } from 'antd';
+import React from 'react';
+import classNames from 'classnames';
+import styles from './index.less';
+
+export type HeaderDropdownProps = {
+ overlayClassName?: string;
+ overlay: React.ReactNode | (() => React.ReactNode) | any;
+ placement?: 'bottomLeft' | 'bottomRight' | 'topLeft' | 'topCenter' | 'topRight' | 'bottomCenter';
+} & Omit<DropDownProps, 'overlay'>;
+
+const HeaderDropdown: React.FC<HeaderDropdownProps> = ({ overlayClassName: cls, ...restProps }) => (
+ <Dropdown overlayClassName={classNames(styles.container, cls)} {...restProps} />
+);
+
+export default HeaderDropdown;
diff --git a/dubbo-admin-ui-antd/src/components/HeaderSearch/index.less b/dubbo-admin-ui-antd/src/components/HeaderSearch/index.less
new file mode 100644
index 0000000..37b5b23
--- /dev/null
+++ b/dubbo-admin-ui-antd/src/components/HeaderSearch/index.less
@@ -0,0 +1,41 @@
+/*
+ * 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 '~antd/es/style/themes/default.less';
+
+.headerSearch {
+ display: inline-flex;
+ align-items: center;
+ .input {
+ width: 0;
+ min-width: 0;
+ overflow: hidden;
+ background: transparent;
+ border-radius: 0;
+ transition: width 0.3s, margin-left 0.3s;
+ :global(.ant-select-selection) {
+ background: transparent;
+ }
+ input {
+ box-shadow: none !important;
+ }
+
+ &.show {
+ width: 210px;
+ margin-left: 8px;
+ }
+ }
+}
diff --git a/dubbo-admin-ui-antd/src/components/HeaderSearch/index.tsx b/dubbo-admin-ui-antd/src/components/HeaderSearch/index.tsx
new file mode 100644
index 0000000..109d800
--- /dev/null
+++ b/dubbo-admin-ui-antd/src/components/HeaderSearch/index.tsx
@@ -0,0 +1,117 @@
+/*
+ * 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 { SearchOutlined } from '@ant-design/icons';
+import { AutoComplete, Input } from 'antd';
+import useMergedState from 'rc-util/es/hooks/useMergedState';
+import type { AutoCompleteProps } from 'antd/es/auto-complete';
+import React, { useRef } from 'react';
+
+import classNames from 'classnames';
+import styles from './index.less';
+
+export type HeaderSearchProps = {
+ onSearch?: (value?: string) => void;
+ onChange?: (value?: string) => void;
+ onVisibleChange?: (b: boolean) => void;
+ className?: string;
+ placeholder?: string;
+ options: AutoCompleteProps['options'];
+ defaultVisible?: boolean;
+ visible?: boolean;
+ defaultValue?: string;
+ value?: string;
+};
+
+const HeaderSearch: React.FC<HeaderSearchProps> = (props) => {
+ const {
+ className,
+ defaultValue,
+ onVisibleChange,
+ placeholder,
+ visible,
+ defaultVisible,
+ ...restProps
+ } = props;
+
+ const inputRef = useRef<Input | null>(null);
+
+ const [value, setValue] = useMergedState<string | undefined>(defaultValue, {
+ value: props.value,
+ onChange: props.onChange,
+ });
+
+ const [searchMode, setSearchMode] = useMergedState(defaultVisible ?? false, {
+ value: props.visible,
+ onChange: onVisibleChange,
+ });
+
+ const inputClass = classNames(styles.input, {
+ [styles.show]: searchMode,
+ });
+ return (
+ <div
+ className={classNames(className, styles.headerSearch)}
+ onClick={() => {
+ setSearchMode(true);
+ if (searchMode && inputRef.current) {
+ inputRef.current.focus();
+ }
+ }}
+ onTransitionEnd={({ propertyName }) => {
+ if (propertyName === 'width' && !searchMode) {
+ if (onVisibleChange) {
+ onVisibleChange(searchMode);
+ }
+ }
+ }}
+ >
+ <SearchOutlined
+ key="Icon"
+ style={{
+ cursor: 'pointer',
+ }}
+ />
+ <AutoComplete
+ key="AutoComplete"
+ className={inputClass}
+ value={value}
+ options={restProps.options}
+ onChange={setValue}
+ >
+ <Input
+ size="small"
+ ref={inputRef}
+ defaultValue={defaultValue}
+ aria-label={placeholder}
+ placeholder={placeholder}
+ onKeyDown={(e) => {
+ if (e.key === 'Enter') {
+ if (restProps.onSearch) {
+ restProps.onSearch(value);
+ }
+ }
+ }}
+ onBlur={() => {
+ setSearchMode(false);
+ }}
+ />
+ </AutoComplete>
+ </div>
+ );
+};
+
+export default HeaderSearch;
diff --git a/dubbo-admin-ui-antd/src/components/NoticeIcon/NoticeIcon.tsx b/dubbo-admin-ui-antd/src/components/NoticeIcon/NoticeIcon.tsx
new file mode 100644
index 0000000..dbcb6ef
--- /dev/null
+++ b/dubbo-admin-ui-antd/src/components/NoticeIcon/NoticeIcon.tsx
@@ -0,0 +1,142 @@
+/*
+ * 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 { BellOutlined } from '@ant-design/icons';
+import { Badge, Spin, Tabs } from 'antd';
+import useMergedState from 'rc-util/es/hooks/useMergedState';
+import React from 'react';
+import classNames from 'classnames';
+import type { NoticeIconTabProps } from './NoticeList';
+import NoticeList from './NoticeList';
+import HeaderDropdown from '../HeaderDropdown';
+import styles from './index.less';
+
+const { TabPane } = Tabs;
+
+export type NoticeIconProps = {
+ count?: number;
+ bell?: React.ReactNode;
+ className?: string;
+ loading?: boolean;
+ onClear?: (tabName: string, tabKey: string) => void;
+ onItemClick?: (item: API.NoticeIconItem, tabProps: NoticeIconTabProps) => void;
+ onViewMore?: (tabProps: NoticeIconTabProps, e: MouseEvent) => void;
+ onTabChange?: (tabTile: string) => void;
+ style?: React.CSSProperties;
+ onPopupVisibleChange?: (visible: boolean) => void;
+ popupVisible?: boolean;
+ clearText?: string;
+ viewMoreText?: string;
+ clearClose?: boolean;
+ emptyImage?: string;
+ children?: React.ReactElement<NoticeIconTabProps>[];
+};
+
+const NoticeIcon: React.FC<NoticeIconProps> & {
+ Tab: typeof NoticeList;
+} = (props) => {
+ const getNotificationBox = (): React.ReactNode => {
+ const {
+ children,
+ loading,
+ onClear,
+ onTabChange,
+ onItemClick,
+ onViewMore,
+ clearText,
+ viewMoreText,
+ } = props;
+ if (!children) {
+ return null;
+ }
+ const panes: React.ReactNode[] = [];
+ React.Children.forEach(children, (child: React.ReactElement<NoticeIconTabProps>): void => {
+ if (!child) {
+ return;
+ }
+ const { list, title, count, tabKey, showClear, showViewMore } = child.props;
+ const len = list && list.length ? list.length : 0;
+ const msgCount = count || count === 0 ? count : len;
+ const tabTitle: string = msgCount > 0 ? `${title} (${msgCount})` : title;
+ panes.push(
+ <TabPane tab={tabTitle} key={tabKey}>
+ <NoticeList
+ clearText={clearText}
+ viewMoreText={viewMoreText}
+ list={list}
+ tabKey={tabKey}
+ onClear={(): void => onClear && onClear(title, tabKey)}
+ onClick={(item): void => onItemClick && onItemClick(item, child.props)}
+ onViewMore={(event): void => onViewMore && onViewMore(child.props, event)}
+ showClear={showClear}
+ showViewMore={showViewMore}
+ title={title}
+ />
+ </TabPane>,
+ );
+ });
+ return (
+ <>
+ <Spin spinning={loading} delay={300}>
+ <Tabs className={styles.tabs} onChange={onTabChange}>
+ {panes}
+ </Tabs>
+ </Spin>
+ </>
+ );
+ };
+
+ const { className, count, bell } = props;
+
+ const [visible, setVisible] = useMergedState<boolean>(false, {
+ value: props.popupVisible,
+ onChange: props.onPopupVisibleChange,
+ });
+ const noticeButtonClass = classNames(className, styles.noticeButton);
+ const notificationBox = getNotificationBox();
+ const NoticeBellIcon = bell || <BellOutlined className={styles.icon} />;
+ const trigger = (
+ <span className={classNames(noticeButtonClass, { opened: visible })}>
+ <Badge count={count} style={{ boxShadow: 'none' }} className={styles.badge}>
+ {NoticeBellIcon}
+ </Badge>
+ </span>
+ );
+ if (!notificationBox) {
+ return trigger;
+ }
+
+ return (
+ <HeaderDropdown
+ placement="bottomRight"
+ overlay={notificationBox}
+ overlayClassName={styles.popover}
+ trigger={['click']}
+ visible={visible}
+ onVisibleChange={setVisible}
+ >
+ {trigger}
+ </HeaderDropdown>
+ );
+};
+
+NoticeIcon.defaultProps = {
+ emptyImage: 'https://gw.alipayobjects.com/zos/rmsportal/wAhyIChODzsoKIOBHcBk.svg',
+};
+
+NoticeIcon.Tab = NoticeList;
+
+export default NoticeIcon;
diff --git a/dubbo-admin-ui-antd/src/components/NoticeIcon/NoticeList.less b/dubbo-admin-ui-antd/src/components/NoticeIcon/NoticeList.less
new file mode 100644
index 0000000..63e0a89
--- /dev/null
+++ b/dubbo-admin-ui-antd/src/components/NoticeIcon/NoticeList.less
@@ -0,0 +1,119 @@
+/*
+ * 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 '~antd/es/style/themes/default.less';
+
+.list {
+ max-height: 400px;
+ overflow: auto;
+ &::-webkit-scrollbar {
+ display: none;
+ }
+ .item {
+ padding-right: 24px;
+ padding-left: 24px;
+ overflow: hidden;
+ cursor: pointer;
+ transition: all 0.3s;
+
+ .meta {
+ width: 100%;
+ }
+
+ .avatar {
+ margin-top: 4px;
+ background: @component-background;
+ }
+ .iconElement {
+ font-size: 32px;
+ }
+
+ &.read {
+ opacity: 0.4;
+ }
+ &:last-child {
+ border-bottom: 0;
+ }
+ &:hover {
+ background: @primary-1;
+ }
+ .title {
+ margin-bottom: 8px;
+ font-weight: normal;
+ }
+ .description {
+ font-size: 12px;
+ line-height: @line-height-base;
+ }
+ .datetime {
+ margin-top: 4px;
+ font-size: 12px;
+ line-height: @line-height-base;
+ }
+ .extra {
+ float: right;
+ margin-top: -1.5px;
+ margin-right: 0;
+ color: @text-color-secondary;
+ font-weight: normal;
+ }
+ }
+ .loadMore {
+ padding: 8px 0;
+ color: @primary-6;
+ text-align: center;
+ cursor: pointer;
+ &.loadedAll {
+ color: rgba(0, 0, 0, 0.25);
+ cursor: unset;
+ }
+ }
+}
+
+.notFound {
+ padding: 73px 0 88px;
+ color: @text-color-secondary;
+ text-align: center;
+ img {
+ display: inline-block;
+ height: 76px;
+ margin-bottom: 16px;
+ }
+}
+
+.bottomBar {
+ height: 46px;
+ color: @text-color;
+ line-height: 46px;
+ text-align: center;
+ border-top: 1px solid @border-color-split;
+ border-radius: 0 0 @border-radius-base @border-radius-base;
+ transition: all 0.3s;
+ div {
+ display: inline-block;
+ width: 50%;
+ cursor: pointer;
+ transition: all 0.3s;
+ user-select: none;
+
+ &:only-child {
+ width: 100%;
+ }
+ &:not(:only-child):last-child {
+ border-left: 1px solid @border-color-split;
+ }
+ }
+}
diff --git a/dubbo-admin-ui-antd/src/components/NoticeIcon/NoticeList.tsx b/dubbo-admin-ui-antd/src/components/NoticeIcon/NoticeList.tsx
new file mode 100644
index 0000000..764afb4
--- /dev/null
+++ b/dubbo-admin-ui-antd/src/components/NoticeIcon/NoticeList.tsx
@@ -0,0 +1,129 @@
+/*
+ * 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 { Avatar, List } from 'antd';
+
+import React from 'react';
+import classNames from 'classnames';
+import styles from './NoticeList.less';
+
+export type NoticeIconTabProps = {
+ count?: number;
+ showClear?: boolean;
+ showViewMore?: boolean;
+ style?: React.CSSProperties;
+ title: string;
+ tabKey: API.NoticeIconItemType;
+ onClick?: (item: API.NoticeIconItem) => void;
+ onClear?: () => void;
+ emptyText?: string;
+ clearText?: string;
+ viewMoreText?: string;
+ list: API.NoticeIconItem[];
+ onViewMore?: (e: any) => void;
+};
+const NoticeList: React.FC<NoticeIconTabProps> = ({
+ list = [],
+ onClick,
+ onClear,
+ title,
+ onViewMore,
+ emptyText,
+ showClear = true,
+ clearText,
+ viewMoreText,
+ showViewMore = false,
+}) => {
+ if (!list || list.length === 0) {
+ return (
+ <div className={styles.notFound}>
+ <img
+ src="https://gw.alipayobjects.com/zos/rmsportal/sAuJeJzSKbUmHfBQRzmZ.svg"
+ alt="not found"
+ />
+ <div>{emptyText}</div>
+ </div>
+ );
+ }
+ return (
+ <div>
+ <List<API.NoticeIconItem>
+ className={styles.list}
+ dataSource={list}
+ renderItem={(item, i) => {
+ const itemCls = classNames(styles.item, {
+ [styles.read]: item.read,
+ });
+ // eslint-disable-next-line no-nested-ternary
+ const leftIcon = item.avatar ? (
+ typeof item.avatar === 'string' ? (
+ <Avatar className={styles.avatar} src={item.avatar} />
+ ) : (
+ <span className={styles.iconElement}>{item.avatar}</span>
+ )
+ ) : null;
+
+ return (
+ <List.Item
+ className={itemCls}
+ key={item.key || i}
+ onClick={() => {
+ onClick?.(item);
+ }}
+ >
+ <List.Item.Meta
+ className={styles.meta}
+ avatar={leftIcon}
+ title={
+ <div className={styles.title}>
+ {item.title}
+ <div className={styles.extra}>{item.extra}</div>
+ </div>
+ }
+ description={
+ <div>
+ <div className={styles.description}>{item.description}</div>
+ <div className={styles.datetime}>{item.datetime}</div>
+ </div>
+ }
+ />
+ </List.Item>
+ );
+ }}
+ />
+ <div className={styles.bottomBar}>
+ {showClear ? (
+ <div onClick={onClear}>
+ {clearText} {title}
+ </div>
+ ) : null}
+ {showViewMore ? (
+ <div
+ onClick={(e) => {
+ if (onViewMore) {
+ onViewMore(e);
+ }
+ }}
+ >
+ {viewMoreText}
+ </div>
+ ) : null}
+ </div>
+ </div>
+ );
+};
+
+export default NoticeList;
diff --git a/dubbo-admin-ui-antd/src/components/NoticeIcon/index.less b/dubbo-admin-ui-antd/src/components/NoticeIcon/index.less
new file mode 100644
index 0000000..b259e6c
--- /dev/null
+++ b/dubbo-admin-ui-antd/src/components/NoticeIcon/index.less
@@ -0,0 +1,51 @@
+/*
+ * 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 '~antd/es/style/themes/default.less';
+
+.popover {
+ position: relative;
+ width: 336px;
+}
+
+.noticeButton {
+ display: inline-block;
+ cursor: pointer;
+ transition: all 0.3s;
+}
+.icon {
+ padding: 4px;
+ vertical-align: middle;
+}
+
+.badge {
+ font-size: 16px;
+}
+
+.tabs {
+ :global {
+ .ant-tabs-nav-list {
+ margin: auto;
+ }
+
+ .ant-tabs-nav-scroll {
+ text-align: center;
+ }
+ .ant-tabs-bar {
+ margin-bottom: 0;
+ }
+ }
+}
diff --git a/dubbo-admin-ui-antd/src/components/NoticeIcon/index.tsx b/dubbo-admin-ui-antd/src/components/NoticeIcon/index.tsx
new file mode 100644
index 0000000..8a06d37
--- /dev/null
+++ b/dubbo-admin-ui-antd/src/components/NoticeIcon/index.tsx
@@ -0,0 +1,168 @@
+/*
+ * 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, { useEffect, useState } from 'react';
+import { Tag, message } from 'antd';
+import { groupBy } from 'lodash';
+import moment from 'moment';
+import { useModel } from 'umi';
+import { getNotices } from '@/services/ant-design-pro/api';
+
+import NoticeIcon from './NoticeIcon';
+import styles from './index.less';
+
+export type GlobalHeaderRightProps = {
+ fetchingNotices?: boolean;
+ onNoticeVisibleChange?: (visible: boolean) => void;
+ onNoticeClear?: (tabName?: string) => void;
+};
+
+const getNoticeData = (notices: API.NoticeIconItem[]): Record<string, API.NoticeIconItem[]> => {
+ if (!notices || notices.length === 0 || !Array.isArray(notices)) {
+ return {};
+ }
+
+ const newNotices = notices.map((notice) => {
+ const newNotice = { ...notice };
+
+ if (newNotice.datetime) {
+ newNotice.datetime = moment(notice.datetime as string).fromNow();
+ }
+
+ if (newNotice.id) {
+ newNotice.key = newNotice.id;
+ }
+
+ if (newNotice.extra && newNotice.status) {
+ const color = {
+ todo: '',
+ processing: 'blue',
+ urgent: 'red',
+ doing: 'gold',
+ }[newNotice.status];
+ newNotice.extra = (
+ <Tag
+ color={color}
+ style={{
+ marginRight: 0,
+ }}
+ >
+ {newNotice.extra}
+ </Tag>
+ ) as any;
+ }
+
+ return newNotice;
+ });
+ return groupBy(newNotices, 'type');
+};
+
+const getUnreadData = (noticeData: Record<string, API.NoticeIconItem[]>) => {
+ const unreadMsg: Record<string, number> = {};
+ Object.keys(noticeData).forEach((key) => {
+ const value = noticeData[key];
+
+ if (!unreadMsg[key]) {
+ unreadMsg[key] = 0;
+ }
+
+ if (Array.isArray(value)) {
+ unreadMsg[key] = value.filter((item) => !item.read).length;
+ }
+ });
+ return unreadMsg;
+};
+
+const NoticeIconView = () => {
+ const { initialState } = useModel('@@initialState');
+ const { currentUser } = initialState || {};
+ const [notices, setNotices] = useState<API.NoticeIconItem[]>([]);
+
+ useEffect(() => {
+ getNotices().then(({ data }) => setNotices(data || []));
+ }, []);
+
+ const noticeData = getNoticeData(notices);
+ const unreadMsg = getUnreadData(noticeData || {});
+
+ const changeReadState = (id: string) => {
+ setNotices(
+ notices.map((item) => {
+ const notice = { ...item };
+ if (notice.id === id) {
+ notice.read = true;
+ }
+ return notice;
+ }),
+ );
+ };
+
+ const clearReadState = (title: string, key: string) => {
+ setNotices(
+ notices.map((item) => {
+ const notice = { ...item };
+ if (notice.type === key) {
+ notice.read = true;
+ }
+ return notice;
+ }),
+ );
+ message.success(`${'emptied'} ${title}`);
+ };
+
+ return (
+ <NoticeIcon
+ className={styles.action}
+ count={currentUser && currentUser.unreadCount}
+ onItemClick={(item) => {
+ changeReadState(item.id!);
+ }}
+ onClear={(title: string, key: string) => clearReadState(title, key)}
+ loading={false}
+ clearText="clean"
+ viewMoreText="See more"
+ onViewMore={() => message.info('Click on view more')}
+ clearClose
+ >
+ <NoticeIcon.Tab
+ tabKey="notification"
+ count={unreadMsg.notification}
+ list={noticeData.notification}
+ title="notice"
+ emptyText="You've seen all the notifications"
+ showViewMore
+ />
+ <NoticeIcon.Tab
+ tabKey="message"
+ count={unreadMsg.message}
+ list={noticeData.message}
+ title="news"
+ emptyText="You have read all the messages"
+ showViewMore
+ />
+ <NoticeIcon.Tab
+ tabKey="event"
+ title="To do list"
+ emptyText="You have finished all the to-do"
+ count={unreadMsg.event}
+ list={noticeData.event}
+ showViewMore
+ />
+ </NoticeIcon>
+ );
+};
+
+export default NoticeIconView;
diff --git a/dubbo-admin-ui-antd/src/components/RightContent/AvatarDropdown.tsx b/dubbo-admin-ui-antd/src/components/RightContent/AvatarDropdown.tsx
new file mode 100644
index 0000000..bd8a591
--- /dev/null
+++ b/dubbo-admin-ui-antd/src/components/RightContent/AvatarDropdown.tsx
@@ -0,0 +1,123 @@
+/*
+ * 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, { useCallback } from 'react';
+import { LogoutOutlined, SettingOutlined, UserOutlined } from '@ant-design/icons';
+import { Avatar, Menu, Spin } from 'antd';
+import { history, useModel } from 'umi';
+import { stringify } from 'querystring';
+import HeaderDropdown from '../HeaderDropdown';
+import styles from './index.less';
+import { outLogin } from '@/services/ant-design-pro/login';
+
+export type GlobalHeaderRightProps = {
+ menu?: boolean;
+};
+
+/**
+ * Log out and save the current URL
+ */
+const loginOut = async () => {
+ await outLogin();
+ const { query = {}, pathname } = history.location;
+ const { redirect } = query;
+ // Note: There may be security issues, please note
+ if (window.location.pathname !== '/user/login' && !redirect) {
+ history.replace({
+ pathname: '/user/login',
+ search: stringify({
+ redirect: pathname,
+ }),
+ });
+ }
+};
+
+const AvatarDropdown: React.FC<GlobalHeaderRightProps> = ({ menu }) => {
+ const { initialState, setInitialState } = useModel('@@initialState');
+
+ const onMenuClick = useCallback(
+ (event: {
+ key: React.Key;
+ keyPath: React.Key[];
+ item: React.ReactInstance;
+ domEvent: React.MouseEvent<HTMLElement>;
+ }) => {
+ const { key } = event;
+ if (key === 'logout' && initialState) {
+ setInitialState({ ...initialState, currentUser: undefined });
+ loginOut();
+ return;
+ }
+ history.push(`/account/${key}`);
+ },
+ [initialState, setInitialState],
+ );
+
+ const loading = (
+ <span className={`${styles.action} ${styles.account}`}>
+ <Spin
+ size="small"
+ style={{
+ marginLeft: 8,
+ marginRight: 8,
+ }}
+ />
+ </span>
+ );
+
+ if (!initialState) {
+ return loading;
+ }
+
+ const { currentUser } = initialState;
+
+ if (!currentUser || !currentUser.name) {
+ return loading;
+ }
+
+ const menuHeaderDropdown = (
+ <Menu className={styles.menu} selectedKeys={[]} onClick={onMenuClick}>
+ {menu && (
+ <Menu.Item key="center">
+ <UserOutlined />
+ Personal Center
+ </Menu.Item>
+ )}
+ {menu && (
+ <Menu.Item key="settings">
+ <SettingOutlined />
+ Personal settings
+ </Menu.Item>
+ )}
+ {menu && <Menu.Divider />}
+
+ <Menu.Item key="logout">
+ <LogoutOutlined />
+ Log out
+ </Menu.Item>
+ </Menu>
+ );
+ return (
+ <HeaderDropdown overlay={menuHeaderDropdown}>
+ <span className={`${styles.action} ${styles.account}`}>
+ <Avatar size="small" className={styles.avatar} src={currentUser.avatar} alt="avatar" />
+ <span className={`${styles.name} anticon`}>{currentUser.name}</span>
+ </span>
+ </HeaderDropdown>
+ );
+};
+
+export default AvatarDropdown;
diff --git a/dubbo-admin-ui-antd/src/components/RightContent/index.less b/dubbo-admin-ui-antd/src/components/RightContent/index.less
new file mode 100644
index 0000000..74fd6d0
--- /dev/null
+++ b/dubbo-admin-ui-antd/src/components/RightContent/index.less
@@ -0,0 +1,78 @@
+/*
+ * 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 '~antd/es/style/themes/default.less';
+
+@pro-header-hover-bg: rgba(0, 0, 0, 0.025);
+
+.menu {
+ :global(.anticon) {
+ margin-right: 8px;
+ }
+ :global(.ant-dropdown-menu-item) {
+ min-width: 160px;
+ }
+}
+
+.right {
+ display: flex;
+ float: right;
+ height: 48px;
+ margin-left: auto;
+ overflow: hidden;
+ .action {
+ display: flex;
+ align-items: center;
+ height: 48px;
+ padding: 0 12px;
+ cursor: pointer;
+ transition: all 0.3s;
+ > span {
+ vertical-align: middle;
+ }
+ &:hover {
+ background: @pro-header-hover-bg;
+ }
+ &:global(.opened) {
+ background: @pro-header-hover-bg;
+ }
+ }
+ .search {
+ padding: 0 12px;
+ &:hover {
+ background: transparent;
+ }
+ }
+ .account {
+ .avatar {
+ margin-right: 8px;
+ color: @primary-color;
+ vertical-align: top;
+ background: rgba(255, 255, 255, 0.85);
+ }
+ }
+}
+
+.dark {
+ .action {
+ &:hover {
+ background: #252a3d;
+ }
+ &:global(.opened) {
+ background: #252a3d;
+ }
+ }
+}
diff --git a/dubbo-admin-ui-antd/src/components/RightContent/index.tsx b/dubbo-admin-ui-antd/src/components/RightContent/index.tsx
new file mode 100644
index 0000000..e783c87
--- /dev/null
+++ b/dubbo-admin-ui-antd/src/components/RightContent/index.tsx
@@ -0,0 +1,89 @@
+/*
+ * 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 { Tag, Space } from 'antd';
+import { QuestionCircleOutlined } from '@ant-design/icons';
+import React from 'react';
+import { useModel, SelectLang } from 'umi';
+import Avatar from './AvatarDropdown';
+import HeaderSearch from '../HeaderSearch';
+import styles from './index.less';
+
+export type SiderTheme = 'light' | 'dark';
+
+const ENVTagColor = {
+ dev: 'orange',
+ test: 'green',
+ pre: '#87d068',
+};
+
+const GlobalHeaderRight: React.FC = () => {
+ const { initialState } = useModel('@@initialState');
+
+ if (!initialState || !initialState.settings) {
+ return null;
+ }
+
+ const { navTheme, layout } = initialState.settings;
+ let className = styles.right;
+
+ if ((navTheme === 'dark' && layout === 'top') || layout === 'mix') {
+ className = `${styles.right} ${styles.dark}`;
+ }
+ return (
+ <Space className={className}>
+ <HeaderSearch
+ className={`${styles.action} ${styles.search}`}
+ placeholder="On site search"
+ defaultValue="umi ui"
+ options={[
+ { label: <a href="https://umijs.org/zh/guide/umi-ui.html">umi ui</a>, value: 'umi ui' },
+ {
+ label: <a href="next.ant.design">Ant Design</a>,
+ value: 'Ant Design',
+ },
+ {
+ label: <a href="https://protable.ant.design/">Pro Table</a>,
+ value: 'Pro Table',
+ },
+ {
+ label: <a href="https://prolayout.ant.design/">Pro Layout</a>,
+ value: 'Pro Layout',
+ },
+ ]}
+ // onSearch={value => {
+ // console.log('input', value);
+ // }}
+ />
+ <span
+ className={styles.action}
+ onClick={() => {
+ window.open('https://pro.ant.design/docs/getting-started');
+ }}
+ >
+ <QuestionCircleOutlined />
+ </span>
+ <Avatar />
+ {REACT_APP_ENV && (
+ <span>
+ <Tag color={ENVTagColor[REACT_APP_ENV]}>{REACT_APP_ENV}</Tag>
+ </span>
+ )}
+ <SelectLang className={styles.action} />
+ </Space>
+ );
+};
+export default GlobalHeaderRight;
diff --git a/dubbo-admin-ui-antd/src/components/index.md b/dubbo-admin-ui-antd/src/components/index.md
new file mode 100644
index 0000000..848edd4
--- /dev/null
+++ b/dubbo-admin-ui-antd/src/components/index.md
@@ -0,0 +1 @@
+[see](https://github.com/ant-design/ant-design-pro/blob/v5/src/components/index.md)
diff --git a/dubbo-admin-ui-antd/src/e2e/baseLayout.e2e.js b/dubbo-admin-ui-antd/src/e2e/baseLayout.e2e.js
new file mode 100644
index 0000000..a8c29cf
--- /dev/null
+++ b/dubbo-admin-ui-antd/src/e2e/baseLayout.e2e.js
@@ -0,0 +1,73 @@
+/*
+ * 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.
+ */
+const { uniq } = require('lodash');
+const RouterConfig = require('../../config/config').default.routes;
+
+const BASE_URL = `http://localhost:${process.env.PORT || 8000}`;
+
+function formatter(routes, parentPath = '') {
+ const fixedParentPath = parentPath.replace(/\/{1,}/g, '/');
+ let result = [];
+ routes.forEach((item) => {
+ if (item.path) {
+ result.push(`${fixedParentPath}/${item.path}`.replace(/\/{1,}/g, '/'));
+ }
+ if (item.routes) {
+ result = result.concat(
+ formatter(item.routes, item.path ? `${fixedParentPath}/${item.path}` : parentPath),
+ );
+ }
+ });
+ return uniq(result.filter((item) => !!item));
+}
+
+beforeEach(async () => {
+ await page.goto(`${BASE_URL}`);
+ await page.evaluate(() => {
+ localStorage.setItem('antd-pro-authority', '["admin"]');
+ });
+});
+
+describe('Ant Design Pro E2E test', () => {
+ const testPage = (path) => async () => {
+ await page.goto(`${BASE_URL}${path}`);
+ await page.waitForSelector('footer', {
+ timeout: 2000,
+ });
+ const haveFooter = await page.evaluate(
+ () => document.getElementsByTagName('footer').length > 0,
+ );
+ expect(haveFooter).toBeTruthy();
+ };
+
+ const routers = formatter(RouterConfig);
+ routers.forEach((route) => {
+ it(`test pages ${route}`, testPage(route));
+ });
+
+ it('topmenu should have footer', async () => {
+ const params = '?navTheme=light&layout=topmenu';
+ await page.goto(`${BASE_URL}${params}`);
+ await page.waitForSelector('footer', {
+ timeout: 2000,
+ });
+ const haveFooter = await page.evaluate(
+ () => document.getElementsByTagName('footer').length > 0,
+ );
+ expect(haveFooter).toBeTruthy();
+ });
+});
diff --git a/dubbo-admin-ui-antd/src/global.less b/dubbo-admin-ui-antd/src/global.less
new file mode 100644
index 0000000..64853b7
--- /dev/null
+++ b/dubbo-admin-ui-antd/src/global.less
@@ -0,0 +1,69 @@
+/*
+ * 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 '~antd/es/style/themes/default.less';
+
+html,
+body,
+#root {
+ height: 100%;
+}
+
+.colorWeak {
+ filter: invert(80%);
+}
+
+.ant-layout {
+ min-height: 100vh;
+}
+
+canvas {
+ display: block;
+}
+
+body {
+ text-rendering: optimizeLegibility;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+}
+
+ul,
+ol {
+ list-style: none;
+}
+
+@media (max-width: @screen-xs) {
+ .ant-table {
+ width: 100%;
+ overflow-x: auto;
+ &-thead > tr,
+ &-tbody > tr {
+ > th,
+ > td {
+ white-space: pre;
+ > span {
+ display: block;
+ }
+ }
+ }
+ }
+}
+
+@media screen and(-ms-high-contrast: active), (-ms-high-contrast: none) {
+ body .ant-design-pro > .ant-layout {
+ min-height: 100vh;
+ }
+}
diff --git a/dubbo-admin-ui-antd/src/global.tsx b/dubbo-admin-ui-antd/src/global.tsx
new file mode 100644
index 0000000..5e382ee
--- /dev/null
+++ b/dubbo-admin-ui-antd/src/global.tsx
@@ -0,0 +1,101 @@
+/*
+ * 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, message, notification } from 'antd';
+
+import React from 'react';
+import { useIntl } from 'umi';
+import defaultSettings from '../config/defaultSettings';
+
+const { pwa } = defaultSettings;
+const isHttps = document.location.protocol === 'https:';
+
+// if pwa is true
+if (pwa) {
+ // Notify user if offline now
+ window.addEventListener('sw.offline', () => {
+ message.warning(useIntl().formatMessage({ id: 'app.pwa.offline' }));
+ });
+
+ // Pop up a prompt on the page asking the user if they want to use the latest version
+ window.addEventListener('sw.updated', (event: Event) => {
+ const e = event as CustomEvent;
+ const reloadSW = async () => {
+ // Check if there is sw whose state is waiting in ServiceWorkerRegistration
+ // https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerRegistration
+ const worker = e.detail && e.detail.waiting;
+ if (!worker) {
+ return true;
+ }
+ // Send skip-waiting event to waiting SW with MessageChannel
+ await new Promise((resolve, reject) => {
+ const channel = new MessageChannel();
+ channel.port1.onmessage = (msgEvent) => {
+ if (msgEvent.data.error) {
+ reject(msgEvent.data.error);
+ } else {
+ resolve(msgEvent.data);
+ }
+ };
+ worker.postMessage({ type: 'skip-waiting' }, [channel.port2]);
+ });
+ // Refresh current page to use the updated HTML and other assets after SW has skiped waiting
+ window.location.reload(true);
+ return true;
+ };
+ const key = `open${Date.now()}`;
+ const btn = (
+ <Button
+ type="primary"
+ onClick={() => {
+ notification.close(key);
+ reloadSW();
+ }}
+ >
+ {useIntl().formatMessage({ id: 'app.pwa.serviceworker.updated.ok' })}
+ </Button>
+ );
+ notification.open({
+ message: useIntl().formatMessage({ id: 'app.pwa.serviceworker.updated' }),
+ description: useIntl().formatMessage({ id: 'app.pwa.serviceworker.updated.hint' }),
+ btn,
+ key,
+ onClose: async () => null,
+ });
+ });
+} else if ('serviceWorker' in navigator && isHttps) {
+ // unregister service worker
+ const { serviceWorker } = navigator;
+ if (serviceWorker.getRegistrations) {
+ serviceWorker.getRegistrations().then((sws) => {
+ sws.forEach((sw) => {
+ sw.unregister();
+ });
+ });
+ }
+ serviceWorker.getRegistration().then((sw) => {
+ if (sw) sw.unregister();
+ });
+
+ // remove all caches
+ if (window.caches && window.caches.keys) {
+ caches.keys().then((keys) => {
+ keys.forEach((key) => {
+ caches.delete(key);
+ });
+ });
+ }
+}
diff --git a/dubbo-admin-ui-antd/src/locales/en-US.ts b/dubbo-admin-ui-antd/src/locales/en-US.ts
new file mode 100644
index 0000000..e6034d7
--- /dev/null
+++ b/dubbo-admin-ui-antd/src/locales/en-US.ts
@@ -0,0 +1,40 @@
+/*
+ * 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 component from './en-US/component';
+import globalHeader from './en-US/globalHeader';
+import menu from './en-US/menu';
+import pwa from './en-US/pwa';
+import settingDrawer from './en-US/settingDrawer';
+import settings from './en-US/settings';
+import pages from './en-US/pages';
+
+export default {
+ 'navBar.lang': 'Languages',
+ 'layout.user.link.help': 'Help',
+ 'layout.user.link.privacy': 'Privacy',
+ 'layout.user.link.terms': 'Terms',
+ 'app.preview.down.block': 'Download this page to your local project',
+ 'app.welcome.link.fetch-blocks': 'Get all block',
+ 'app.welcome.link.block-list': 'Quickly build standard, pages based on `block` development',
+ ...globalHeader,
+ ...menu,
+ ...settingDrawer,
+ ...settings,
+ ...pwa,
+ ...component,
+ ...pages,
+};
diff --git a/dubbo-admin-ui-antd/src/locales/en-US/component.ts b/dubbo-admin-ui-antd/src/locales/en-US/component.ts
new file mode 100644
index 0000000..3f9b2db
--- /dev/null
+++ b/dubbo-admin-ui-antd/src/locales/en-US/component.ts
@@ -0,0 +1,21 @@
+/*
+ * 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 default {
+ 'component.tagSelect.expand': 'Expand',
+ 'component.tagSelect.collapse': 'Collapse',
+ 'component.tagSelect.all': 'All',
+};
diff --git a/dubbo-admin-ui-antd/src/locales/en-US/globalHeader.ts b/dubbo-admin-ui-antd/src/locales/en-US/globalHeader.ts
new file mode 100644
index 0000000..362c376
--- /dev/null
+++ b/dubbo-admin-ui-antd/src/locales/en-US/globalHeader.ts
@@ -0,0 +1,33 @@
+/*
+ * 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 default {
+ 'component.globalHeader.search': 'Search',
+ 'component.globalHeader.search.example1': 'Search example 1',
+ 'component.globalHeader.search.example2': 'Search example 2',
+ 'component.globalHeader.search.example3': 'Search example 3',
+ 'component.globalHeader.help': 'Help',
+ 'component.globalHeader.notification': 'Notification',
+ 'component.globalHeader.notification.empty': 'You have viewed all notifications.',
+ 'component.globalHeader.message': 'Message',
+ 'component.globalHeader.message.empty': 'You have viewed all messsages.',
+ 'component.globalHeader.event': 'Event',
+ 'component.globalHeader.event.empty': 'You have viewed all events.',
+ 'component.noticeIcon.clear': 'Clear',
+ 'component.noticeIcon.cleared': 'Cleared',
+ 'component.noticeIcon.empty': 'No notifications',
+ 'component.noticeIcon.view-more': 'View more',
+};
diff --git a/dubbo-admin-ui-antd/src/locales/en-US/menu.ts b/dubbo-admin-ui-antd/src/locales/en-US/menu.ts
new file mode 100644
index 0000000..3e62acf
--- /dev/null
+++ b/dubbo-admin-ui-antd/src/locales/en-US/menu.ts
@@ -0,0 +1,68 @@
+/*
+ * 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 default {
+ 'menu.welcome': 'Welcome',
+ 'menu.more-blocks': 'More Blocks',
+ 'menu.home': 'Home',
+ 'menu.admin': 'Admin',
+ 'menu.admin.sub-page': 'Sub-Page',
+ 'menu.login': 'Login',
+ 'menu.register': 'Register',
+ 'menu.register.result': 'Register Result',
+ 'menu.dashboard': 'Dashboard',
+ 'menu.dashboard.analysis': 'Analysis',
+ 'menu.dashboard.monitor': 'Monitor',
+ 'menu.dashboard.workplace': 'Workplace',
+ 'menu.exception.403': '403',
+ 'menu.exception.404': '404',
+ 'menu.exception.500': '500',
+ 'menu.form': 'Form',
+ 'menu.form.basic-form': 'Basic Form',
+ 'menu.form.step-form': 'Step Form',
+ 'menu.form.step-form.info': 'Step Form(write transfer information)',
+ 'menu.form.step-form.confirm': 'Step Form(confirm transfer information)',
+ 'menu.form.step-form.result': 'Step Form(finished)',
+ 'menu.form.advanced-form': 'Advanced Form',
+ 'menu.list': 'List',
+ 'menu.list.table-list': 'Search Table',
+ 'menu.list.basic-list': 'Basic List',
+ 'menu.list.card-list': 'Card List',
+ 'menu.list.search-list': 'Search List',
+ 'menu.list.search-list.articles': 'Search List(articles)',
+ 'menu.list.search-list.projects': 'Search List(projects)',
+ 'menu.list.search-list.applications': 'Search List(applications)',
+ 'menu.profile': 'Profile',
+ 'menu.profile.basic': 'Basic Profile',
+ 'menu.profile.advanced': 'Advanced Profile',
+ 'menu.result': 'Result',
+ 'menu.result.success': 'Success',
+ 'menu.result.fail': 'Fail',
+ 'menu.exception': 'Exception',
+ 'menu.exception.not-permission': '403',
+ 'menu.exception.not-find': '404',
+ 'menu.exception.server-error': '500',
+ 'menu.exception.trigger': 'Trigger',
+ 'menu.account': 'Account',
+ 'menu.account.center': 'Account Center',
+ 'menu.account.settings': 'Account Settings',
+ 'menu.account.trigger': 'Trigger Error',
+ 'menu.account.logout': 'Logout',
+ 'menu.editor': 'Graphic Editor',
+ 'menu.editor.flow': 'Flow Editor',
+ 'menu.editor.mind': 'Mind Editor',
+ 'menu.editor.koni': 'Koni Editor',
+};
diff --git a/dubbo-admin-ui-antd/src/locales/en-US/pages.ts b/dubbo-admin-ui-antd/src/locales/en-US/pages.ts
new file mode 100644
index 0000000..3596d7a
--- /dev/null
+++ b/dubbo-admin-ui-antd/src/locales/en-US/pages.ts
@@ -0,0 +1,85 @@
+/*
+ * 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 default {
+ 'pages.layouts.userLayout.title':
+ 'Ant Design is the most influential web design specification in Xihu district',
+ 'pages.login.accountLogin.tab': 'Account Login',
+ 'pages.login.accountLogin.successful': 'Login successful!',
+ 'pages.login.accountLogin.error': 'Login failed, please try again!',
+ 'pages.login.accountLogin.errorMessage': 'Incorrect username/password',
+ 'pages.login.username.placeholder': 'Username: admin or user',
+ 'pages.login.username.required': 'Please input your username!',
+ 'pages.login.password.placeholder': 'Default password: root',
+ 'pages.login.password.required': 'Please input your password!',
+ 'pages.login.phoneLogin.tab': 'Phone Login',
+ 'pages.login.phoneLogin.errorMessage': 'Verification Code Error',
+ 'pages.login.phoneNumber.placeholder': 'Phone Number',
+ 'pages.login.phoneNumber.required': 'Please input your phone number!',
+ 'pages.login.phoneNumber.invalid': 'Phone number is invalid!',
+ 'pages.login.captcha.placeholder': 'Verification Code',
+ 'pages.login.captcha.required': 'Please input verification code!',
+ 'pages.login.phoneLogin.getVerificationCode': 'Get Code',
+ 'pages.getCaptchaSecondText': 'sec(s)',
+ 'pages.login.rememberMe': 'Remember me',
+ 'pages.login.forgotPassword': 'Forgot Password ?',
+ 'pages.login.submit': 'Login',
+ 'pages.login.registerAccount': 'Register Account',
+ 'pages.welcome.advancedComponent': 'Advanced Component',
+ 'pages.welcome.link': 'Welcome',
+ 'pages.welcome.advancedLayout': 'Advanced Layout',
+ 'pages.welcome.alertMessage': 'Faster and stronger heavy-duty components have been released.',
+ 'pages.admin.subPage.title': 'This page can only be viewed by Admin',
+ 'pages.admin.subPage.alertMessage':
+ 'Umi ui is now released, welcome to use npm run ui to start the experience.',
+ 'pages.searchTable.createForm.newRule': 'New Rule',
+ 'pages.searchTable.updateForm.ruleConfig': 'Rule configuration',
+ 'pages.searchTable.updateForm.basicConfig': 'Basic Information',
+ 'pages.searchTable.updateForm.ruleName.nameLabel': 'Rule Name',
+ 'pages.searchTable.updateForm.ruleName.nameRules': 'Please enter the rule name!',
+ 'pages.searchTable.updateForm.ruleDesc.descLabel': 'Rule Description',
+ 'pages.searchTable.updateForm.ruleDesc.descPlaceholder': 'Please enter at least five characters',
+ 'pages.searchTable.updateForm.ruleDesc.descRules':
+ 'Please enter a rule description of at least five characters!',
+ 'pages.searchTable.updateForm.ruleProps.title': 'Configure Properties',
+ 'pages.searchTable.updateForm.object': 'Monitoring Object',
+ 'pages.searchTable.updateForm.ruleProps.templateLabel': 'Rule Template',
+ 'pages.searchTable.updateForm.ruleProps.typeLabel': 'Rule Type',
+ 'pages.searchTable.updateForm.schedulingPeriod.title': 'Set Scheduling Period',
+ 'pages.searchTable.updateForm.schedulingPeriod.timeLabel': 'Starting Time',
+ 'pages.searchTable.updateForm.schedulingPeriod.timeRules': 'Please choose a start time!',
+ 'pages.searchTable.titleDesc': 'Description',
+ 'pages.searchTable.ruleName': 'Rule name is required',
+ 'pages.searchTable.titleCallNo': 'Number of Service Calls',
+ 'pages.searchTable.titleStatus': 'Status',
+ 'pages.searchTable.nameStatus.default': 'default',
+ 'pages.searchTable.nameStatus.running': 'running',
+ 'pages.searchTable.nameStatus.online': 'online',
+ 'pages.searchTable.nameStatus.abnormal': 'abnormal',
+ 'pages.searchTable.titleUpdatedAt': 'Last Scheduled at',
+ 'pages.searchTable.exception': 'Please enter the reason for the exception!',
+ 'pages.searchTable.titleOption': 'Option',
+ 'pages.searchTable.config': 'Configuration',
+ 'pages.searchTable.subscribeAlert': 'Subscribe to alerts',
+ 'pages.searchTable.title': 'Enquiry Form',
+ 'pages.searchTable.new': 'New',
+ 'pages.searchTable.chosen': 'chosen',
+ 'pages.searchTable.item': 'item',
+ 'pages.searchTable.totalServiceCalls': 'Total Number of Service Calls',
+ 'pages.searchTable.tenThousand': '0000',
+ 'pages.searchTable.batchDeletion': 'bacth deletion',
+ 'pages.searchTable.batchApproval': 'batch approval',
+};
diff --git a/dubbo-admin-ui-antd/src/locales/en-US/pwa.ts b/dubbo-admin-ui-antd/src/locales/en-US/pwa.ts
new file mode 100644
index 0000000..ed5a925
--- /dev/null
+++ b/dubbo-admin-ui-antd/src/locales/en-US/pwa.ts
@@ -0,0 +1,22 @@
+/*
+ * 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 default {
+ 'app.pwa.offline': 'You are offline now',
+ 'app.pwa.serviceworker.updated': 'New content is available',
+ 'app.pwa.serviceworker.updated.hint': 'Please press the "Refresh" button to reload current page',
+ 'app.pwa.serviceworker.updated.ok': 'Refresh',
+};
diff --git a/dubbo-admin-ui-antd/src/locales/en-US/settingDrawer.ts b/dubbo-admin-ui-antd/src/locales/en-US/settingDrawer.ts
new file mode 100644
index 0000000..4e2401d
--- /dev/null
+++ b/dubbo-admin-ui-antd/src/locales/en-US/settingDrawer.ts
@@ -0,0 +1,47 @@
+/*
+ * 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 default {
+ 'app.setting.pagestyle': 'Page style setting',
+ 'app.setting.pagestyle.dark': 'Dark style',
+ 'app.setting.pagestyle.light': 'Light style',
+ 'app.setting.content-width': 'Content Width',
+ 'app.setting.content-width.fixed': 'Fixed',
+ 'app.setting.content-width.fluid': 'Fluid',
+ 'app.setting.themecolor': 'Theme Color',
+ 'app.setting.themecolor.dust': 'Dust Red',
+ 'app.setting.themecolor.volcano': 'Volcano',
+ 'app.setting.themecolor.sunset': 'Sunset Orange',
+ 'app.setting.themecolor.cyan': 'Cyan',
+ 'app.setting.themecolor.green': 'Polar Green',
+ 'app.setting.themecolor.daybreak': 'Daybreak Blue (default)',
+ 'app.setting.themecolor.geekblue': 'Geek Glue',
+ 'app.setting.themecolor.purple': 'Golden Purple',
+ 'app.setting.navigationmode': 'Navigation Mode',
+ 'app.setting.sidemenu': 'Side Menu Layout',
+ 'app.setting.topmenu': 'Top Menu Layout',
+ 'app.setting.fixedheader': 'Fixed Header',
+ 'app.setting.fixedsidebar': 'Fixed Sidebar',
+ 'app.setting.fixedsidebar.hint': 'Works on Side Menu Layout',
+ 'app.setting.hideheader': 'Hidden Header when scrolling',
+ 'app.setting.hideheader.hint': 'Works when Hidden Header is enabled',
+ 'app.setting.othersettings': 'Other Settings',
+ 'app.setting.weakmode': 'Weak Mode',
+ 'app.setting.copy': 'Copy Setting',
+ 'app.setting.copyinfo': 'copy success,please replace defaultSettings in src/models/setting.js',
+ 'app.setting.production.hint':
+ 'Setting panel shows in development environment only, please manually modify',
+};
diff --git a/dubbo-admin-ui-antd/src/locales/en-US/settings.ts b/dubbo-admin-ui-antd/src/locales/en-US/settings.ts
new file mode 100644
index 0000000..b211bdc
--- /dev/null
+++ b/dubbo-admin-ui-antd/src/locales/en-US/settings.ts
@@ -0,0 +1,76 @@
+/*
+ * 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 default {
+ 'app.settings.menuMap.basic': 'Basic Settings',
+ 'app.settings.menuMap.security': 'Security Settings',
+ 'app.settings.menuMap.binding': 'Account Binding',
+ 'app.settings.menuMap.notification': 'New Message Notification',
+ 'app.settings.basic.avatar': 'Avatar',
+ 'app.settings.basic.change-avatar': 'Change avatar',
+ 'app.settings.basic.email': 'Email',
+ 'app.settings.basic.email-message': 'Please input your email!',
+ 'app.settings.basic.nickname': 'Nickname',
+ 'app.settings.basic.nickname-message': 'Please input your Nickname!',
+ 'app.settings.basic.profile': 'Personal profile',
+ 'app.settings.basic.profile-message': 'Please input your personal profile!',
+ 'app.settings.basic.profile-placeholder': 'Brief introduction to yourself',
+ 'app.settings.basic.country': 'Country/Region',
+ 'app.settings.basic.country-message': 'Please input your country!',
+ 'app.settings.basic.geographic': 'Province or city',
+ 'app.settings.basic.geographic-message': 'Please input your geographic info!',
+ 'app.settings.basic.address': 'Street Address',
+ 'app.settings.basic.address-message': 'Please input your address!',
+ 'app.settings.basic.phone': 'Phone Number',
+ 'app.settings.basic.phone-message': 'Please input your phone!',
+ 'app.settings.basic.update': 'Update Information',
+ 'app.settings.security.strong': 'Strong',
+ 'app.settings.security.medium': 'Medium',
+ 'app.settings.security.weak': 'Weak',
+ 'app.settings.security.password': 'Account Password',
+ 'app.settings.security.password-description': 'Current password strength',
+ 'app.settings.security.phone': 'Security Phone',
+ 'app.settings.security.phone-description': 'Bound phone',
+ 'app.settings.security.question': 'Security Question',
+ 'app.settings.security.question-description':
+ 'The security question is not set, and the security policy can effectively protect the account security',
+ 'app.settings.security.email': 'Backup Email',
+ 'app.settings.security.email-description': 'Bound Email',
+ 'app.settings.security.mfa': 'MFA Device',
+ 'app.settings.security.mfa-description':
+ 'Unbound MFA device, after binding, can be confirmed twice',
+ 'app.settings.security.modify': 'Modify',
+ 'app.settings.security.set': 'Set',
+ 'app.settings.security.bind': 'Bind',
+ 'app.settings.binding.taobao': 'Binding Taobao',
+ 'app.settings.binding.taobao-description': 'Currently unbound Taobao account',
+ 'app.settings.binding.alipay': 'Binding Alipay',
+ 'app.settings.binding.alipay-description': 'Currently unbound Alipay account',
+ 'app.settings.binding.dingding': 'Binding DingTalk',
+ 'app.settings.binding.dingding-description': 'Currently unbound DingTalk account',
+ 'app.settings.binding.bind': 'Bind',
+ 'app.settings.notification.password': 'Account Password',
+ 'app.settings.notification.password-description':
+ 'Messages from other users will be notified in the form of a station letter',
+ 'app.settings.notification.messages': 'System Messages',
+ 'app.settings.notification.messages-description':
+ 'System messages will be notified in the form of a station letter',
+ 'app.settings.notification.todo': 'To-do Notification',
+ 'app.settings.notification.todo-description':
+ 'The to-do list will be notified in the form of a letter from the station',
+ 'app.settings.open': 'Open',
+ 'app.settings.close': 'Close',
+};
diff --git a/dubbo-admin-ui-antd/src/locales/zh-CN.ts b/dubbo-admin-ui-antd/src/locales/zh-CN.ts
new file mode 100644
index 0000000..43b044d
--- /dev/null
+++ b/dubbo-admin-ui-antd/src/locales/zh-CN.ts
@@ -0,0 +1,40 @@
+/*
+ * 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 component from './zh-CN/component';
+import globalHeader from './zh-CN/globalHeader';
+import menu from './zh-CN/menu';
+import pwa from './zh-CN/pwa';
+import settingDrawer from './zh-CN/settingDrawer';
+import settings from './zh-CN/settings';
+import pages from './zh-CN/pages';
+
+export default {
+ 'navBar.lang': '语言',
+ 'layout.user.link.help': '帮助',
+ 'layout.user.link.privacy': '隐私',
+ 'layout.user.link.terms': '条款',
+ 'app.preview.down.block': '下载此页面到本地项目',
+ 'app.welcome.link.fetch-blocks': '获取全部区块',
+ 'app.welcome.link.block-list': '基于 block 开发,快速构建标准页面',
+ ...pages,
+ ...globalHeader,
+ ...menu,
+ ...settingDrawer,
+ ...settings,
+ ...pwa,
+ ...component,
+};
diff --git a/dubbo-admin-ui-antd/src/locales/zh-CN/component.ts b/dubbo-admin-ui-antd/src/locales/zh-CN/component.ts
new file mode 100644
index 0000000..0ddf433
--- /dev/null
+++ b/dubbo-admin-ui-antd/src/locales/zh-CN/component.ts
@@ -0,0 +1,21 @@
+/*
+ * 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 default {
+ 'component.tagSelect.expand': '展开',
+ 'component.tagSelect.collapse': '收起',
+ 'component.tagSelect.all': '全部',
+};
diff --git a/dubbo-admin-ui-antd/src/locales/zh-CN/globalHeader.ts b/dubbo-admin-ui-antd/src/locales/zh-CN/globalHeader.ts
new file mode 100644
index 0000000..b1ce8e9
--- /dev/null
+++ b/dubbo-admin-ui-antd/src/locales/zh-CN/globalHeader.ts
@@ -0,0 +1,33 @@
+/*
+ * 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 default {
+ 'component.globalHeader.search': '站内搜索',
+ 'component.globalHeader.search.example1': '搜索提示一',
+ 'component.globalHeader.search.example2': '搜索提示二',
+ 'component.globalHeader.search.example3': '搜索提示三',
+ 'component.globalHeader.help': '使用文档',
+ 'component.globalHeader.notification': '通知',
+ 'component.globalHeader.notification.empty': '你已查看所有通知',
+ 'component.globalHeader.message': '消息',
+ 'component.globalHeader.message.empty': '您已读完所有消息',
+ 'component.globalHeader.event': '待办',
+ 'component.globalHeader.event.empty': '你已完成所有待办',
+ 'component.noticeIcon.clear': '清空',
+ 'component.noticeIcon.cleared': '清空了',
+ 'component.noticeIcon.empty': '暂无数据',
+ 'component.noticeIcon.view-more': '查看更多',
+};
diff --git a/dubbo-admin-ui-antd/src/locales/zh-CN/menu.ts b/dubbo-admin-ui-antd/src/locales/zh-CN/menu.ts
new file mode 100644
index 0000000..459dfcd
--- /dev/null
+++ b/dubbo-admin-ui-antd/src/locales/zh-CN/menu.ts
@@ -0,0 +1,68 @@
+/*
+ * 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 default {
+ 'menu.welcome': '欢迎',
+ 'menu.more-blocks': '更多区块',
+ 'menu.home': '首页',
+ 'menu.admin': '管理页',
+ 'menu.admin.sub-page': '二级管理页',
+ 'menu.login': '登录',
+ 'menu.register': '注册',
+ 'menu.register.result': '注册结果',
+ 'menu.dashboard': 'Dashboard',
+ 'menu.dashboard.analysis': '分析页',
+ 'menu.dashboard.monitor': '监控页',
+ 'menu.dashboard.workplace': '工作台',
+ 'menu.exception.403': '403',
+ 'menu.exception.404': '404',
+ 'menu.exception.500': '500',
+ 'menu.form': '表单页',
+ 'menu.form.basic-form': '基础表单',
+ 'menu.form.step-form': '分步表单',
+ 'menu.form.step-form.info': '分步表单(填写转账信息)',
+ 'menu.form.step-form.confirm': '分步表单(确认转账信息)',
+ 'menu.form.step-form.result': '分步表单(完成)',
+ 'menu.form.advanced-form': '高级表单',
+ 'menu.list': '列表页',
+ 'menu.list.table-list': '查询表格',
+ 'menu.list.basic-list': '标准列表',
+ 'menu.list.card-list': '卡片列表',
+ 'menu.list.search-list': '搜索列表',
+ 'menu.list.search-list.articles': '搜索列表(文章)',
+ 'menu.list.search-list.projects': '搜索列表(项目)',
+ 'menu.list.search-list.applications': '搜索列表(应用)',
+ 'menu.profile': '详情页',
+ 'menu.profile.basic': '基础详情页',
+ 'menu.profile.advanced': '高级详情页',
+ 'menu.result': '结果页',
+ 'menu.result.success': '成功页',
+ 'menu.result.fail': '失败页',
+ 'menu.exception': '异常页',
+ 'menu.exception.not-permission': '403',
+ 'menu.exception.not-find': '404',
+ 'menu.exception.server-error': '500',
+ 'menu.exception.trigger': '触发错误',
+ 'menu.account': '个人页',
+ 'menu.account.center': '个人中心',
+ 'menu.account.settings': '个人设置',
+ 'menu.account.trigger': '触发报错',
+ 'menu.account.logout': '退出登录',
+ 'menu.editor': '图形编辑器',
+ 'menu.editor.flow': '流程编辑器',
+ 'menu.editor.mind': '脑图编辑器',
+ 'menu.editor.koni': '拓扑编辑器',
+};
diff --git a/dubbo-admin-ui-antd/src/locales/zh-CN/pages.ts b/dubbo-admin-ui-antd/src/locales/zh-CN/pages.ts
new file mode 100644
index 0000000..489cefe
--- /dev/null
+++ b/dubbo-admin-ui-antd/src/locales/zh-CN/pages.ts
@@ -0,0 +1,82 @@
+/*
+ * 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 default {
+ 'pages.layouts.userLayout.title': 'Ant Design 是西湖区最具影响力的 Web 设计规范',
+ 'pages.login.accountLogin.tab': '账户密码登录',
+ 'pages.login.accountLogin.successful': '登录成功!',
+ 'pages.login.accountLogin.error': '登录失败,请重试!',
+ 'pages.login.accountLogin.errorMessage': '账户或密码错误',
+ 'pages.login.username.placeholder': '用户名: admin or user',
+ 'pages.login.username.required': '用户名是必填项!',
+ 'pages.login.password.placeholder': '默认密码: root',
+ 'pages.login.password.required': '密码是必填项!',
+ 'pages.login.phoneLogin.tab': '手机号登录',
+ 'pages.login.phoneLogin.errorMessage': '验证码错误',
+ 'pages.login.phoneNumber.placeholder': '请输入手机号!',
+ 'pages.login.phoneNumber.required': '手机号是必填项!',
+ 'pages.login.phoneNumber.invalid': '不合法的手机号!',
+ 'pages.login.captcha.placeholder': '请输入验证码!',
+ 'pages.login.captcha.required': '验证码是必填项!',
+ 'pages.login.phoneLogin.getVerificationCode': '获取验证码',
+ 'pages.getCaptchaSecondText': '秒后重新获取',
+ 'pages.login.rememberMe': '自动登录',
+ 'pages.login.forgotPassword': '忘记密码 ?',
+ 'pages.login.submit': '登录',
+ 'pages.login.registerAccount': '注册账户',
+ 'pages.welcome.advancedComponent': '高级表格',
+ 'pages.welcome.link': '欢迎使用',
+ 'pages.welcome.advancedLayout': '高级布局',
+ 'pages.welcome.alertMessage': '更快更强的重型组件,已经发布。',
+ 'pages.admin.subPage.title': ' 这个页面只有 admin 权限才能查看',
+ 'pages.admin.subPage.alertMessage': 'umi ui 现已发布,欢迎使用 npm run ui 启动体验。',
+ 'pages.searchTable.createForm.newRule': '新建规则',
+ 'pages.searchTable.updateForm.ruleConfig': '规则配置',
+ 'pages.searchTable.updateForm.basicConfig': '基本信息',
+ 'pages.searchTable.updateForm.ruleName.nameLabel': '规则名称',
+ 'pages.searchTable.updateForm.ruleName.nameRules': '请输入规则名称!',
+ 'pages.searchTable.updateForm.ruleDesc.descLabel': '规则描述',
+ 'pages.searchTable.updateForm.ruleDesc.descPlaceholder': '请输入至少五个字符',
+ 'pages.searchTable.updateForm.ruleDesc.descRules': '请输入至少五个字符的规则描述!',
+ 'pages.searchTable.updateForm.ruleProps.title': '配置规则属性',
+ 'pages.searchTable.updateForm.object': '监控对象',
+ 'pages.searchTable.updateForm.ruleProps.templateLabel': '规则模板',
+ 'pages.searchTable.updateForm.ruleProps.typeLabel': '规则类型',
+ 'pages.searchTable.updateForm.schedulingPeriod.title': '设定调度周期',
+ 'pages.searchTable.updateForm.schedulingPeriod.timeLabel': '开始时间',
+ 'pages.searchTable.updateForm.schedulingPeriod.timeRules': '请选择开始时间!',
+ 'pages.searchTable.titleDesc': '描述',
+ 'pages.searchTable.ruleName': '规则名称为必填项',
+ 'pages.searchTable.titleCallNo': '服务调用次数',
+ 'pages.searchTable.titleStatus': '状态',
+ 'pages.searchTable.nameStatus.default': '关闭',
+ 'pages.searchTable.nameStatus.running': '运行中',
+ 'pages.searchTable.nameStatus.online': '已上线',
+ 'pages.searchTable.nameStatus.abnormal': '异常',
+ 'pages.searchTable.titleUpdatedAt': '上次调度时间',
+ 'pages.searchTable.exception': '请输入异常原因!',
+ 'pages.searchTable.titleOption': '操作',
+ 'pages.searchTable.config': '配置',
+ 'pages.searchTable.subscribeAlert': '订阅警报',
+ 'pages.searchTable.title': '查询表格',
+ 'pages.searchTable.new': '新建',
+ 'pages.searchTable.chosen': '已选择',
+ 'pages.searchTable.item': '项',
+ 'pages.searchTable.totalServiceCalls': '服务调用次数总计',
+ 'pages.searchTable.tenThousand': '万',
+ 'pages.searchTable.batchDeletion': '批量删除',
+ 'pages.searchTable.batchApproval': '批量审批',
+};
diff --git a/dubbo-admin-ui-antd/src/locales/zh-CN/pwa.ts b/dubbo-admin-ui-antd/src/locales/zh-CN/pwa.ts
new file mode 100644
index 0000000..ddc3f0c
--- /dev/null
+++ b/dubbo-admin-ui-antd/src/locales/zh-CN/pwa.ts
@@ -0,0 +1,22 @@
+/*
+ * 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 default {
+ 'app.pwa.offline': '当前处于离线状态',
+ 'app.pwa.serviceworker.updated': '有新内容',
+ 'app.pwa.serviceworker.updated.hint': '请点击“刷新”按钮或者手动刷新页面',
+ 'app.pwa.serviceworker.updated.ok': '刷新',
+};
diff --git a/dubbo-admin-ui-antd/src/locales/zh-CN/settingDrawer.ts b/dubbo-admin-ui-antd/src/locales/zh-CN/settingDrawer.ts
new file mode 100644
index 0000000..ce7d586
--- /dev/null
+++ b/dubbo-admin-ui-antd/src/locales/zh-CN/settingDrawer.ts
@@ -0,0 +1,47 @@
+/*
+ * 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 default {
+ 'app.setting.pagestyle': '整体风格设置',
+ 'app.setting.pagestyle.dark': '暗色菜单风格',
+ 'app.setting.pagestyle.light': '亮色菜单风格',
+ 'app.setting.content-width': '内容区域宽度',
+ 'app.setting.content-width.fixed': '定宽',
+ 'app.setting.content-width.fluid': '流式',
+ 'app.setting.themecolor': '主题色',
+ 'app.setting.themecolor.dust': '薄暮',
+ 'app.setting.themecolor.volcano': '火山',
+ 'app.setting.themecolor.sunset': '日暮',
+ 'app.setting.themecolor.cyan': '明青',
+ 'app.setting.themecolor.green': '极光绿',
+ 'app.setting.themecolor.daybreak': '拂晓蓝(默认)',
+ 'app.setting.themecolor.geekblue': '极客蓝',
+ 'app.setting.themecolor.purple': '酱紫',
+ 'app.setting.navigationmode': '导航模式',
+ 'app.setting.sidemenu': '侧边菜单布局',
+ 'app.setting.topmenu': '顶部菜单布局',
+ 'app.setting.fixedheader': '固定 Header',
+ 'app.setting.fixedsidebar': '固定侧边菜单',
+ 'app.setting.fixedsidebar.hint': '侧边菜单布局时可配置',
+ 'app.setting.hideheader': '下滑时隐藏 Header',
+ 'app.setting.hideheader.hint': '固定 Header 时可配置',
+ 'app.setting.othersettings': '其他设置',
+ 'app.setting.weakmode': '色弱模式',
+ 'app.setting.copy': '拷贝设置',
+ 'app.setting.copyinfo': '拷贝成功,请到 src/defaultSettings.js 中替换默认配置',
+ 'app.setting.production.hint':
+ '配置栏只在开发环境用于预览,生产环境不会展现,请拷贝后手动修改配置文件',
+};
diff --git a/dubbo-admin-ui-antd/src/locales/zh-CN/settings.ts b/dubbo-admin-ui-antd/src/locales/zh-CN/settings.ts
new file mode 100644
index 0000000..9964338
--- /dev/null
+++ b/dubbo-admin-ui-antd/src/locales/zh-CN/settings.ts
@@ -0,0 +1,71 @@
+/*
+ * 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 default {
+ 'app.settings.menuMap.basic': '基本设置',
+ 'app.settings.menuMap.security': '安全设置',
+ 'app.settings.menuMap.binding': '账号绑定',
+ 'app.settings.menuMap.notification': '新消息通知',
+ 'app.settings.basic.avatar': '头像',
+ 'app.settings.basic.change-avatar': '更换头像',
+ 'app.settings.basic.email': '邮箱',
+ 'app.settings.basic.email-message': '请输入您的邮箱!',
+ 'app.settings.basic.nickname': '昵称',
+ 'app.settings.basic.nickname-message': '请输入您的昵称!',
+ 'app.settings.basic.profile': '个人简介',
+ 'app.settings.basic.profile-message': '请输入个人简介!',
+ 'app.settings.basic.profile-placeholder': '个人简介',
+ 'app.settings.basic.country': '国家/地区',
+ 'app.settings.basic.country-message': '请输入您的国家或地区!',
+ 'app.settings.basic.geographic': '所在省市',
+ 'app.settings.basic.geographic-message': '请输入您的所在省市!',
+ 'app.settings.basic.address': '街道地址',
+ 'app.settings.basic.address-message': '请输入您的街道地址!',
+ 'app.settings.basic.phone': '联系电话',
+ 'app.settings.basic.phone-message': '请输入您的联系电话!',
+ 'app.settings.basic.update': '更新基本信息',
+ 'app.settings.security.strong': '强',
+ 'app.settings.security.medium': '中',
+ 'app.settings.security.weak': '弱',
+ 'app.settings.security.password': '账户密码',
+ 'app.settings.security.password-description': '当前密码强度',
+ 'app.settings.security.phone': '密保手机',
+ 'app.settings.security.phone-description': '已绑定手机',
+ 'app.settings.security.question': '密保问题',
+ 'app.settings.security.question-description': '未设置密保问题,密保问题可有效保护账户安全',
+ 'app.settings.security.email': '备用邮箱',
+ 'app.settings.security.email-description': '已绑定邮箱',
+ 'app.settings.security.mfa': 'MFA 设备',
+ 'app.settings.security.mfa-description': '未绑定 MFA 设备,绑定后,可以进行二次确认',
+ 'app.settings.security.modify': '修改',
+ 'app.settings.security.set': '设置',
+ 'app.settings.security.bind': '绑定',
+ 'app.settings.binding.taobao': '绑定淘宝',
+ 'app.settings.binding.taobao-description': '当前未绑定淘宝账号',
+ 'app.settings.binding.alipay': '绑定支付宝',
+ 'app.settings.binding.alipay-description': '当前未绑定支付宝账号',
+ 'app.settings.binding.dingding': '绑定钉钉',
+ 'app.settings.binding.dingding-description': '当前未绑定钉钉账号',
+ 'app.settings.binding.bind': '绑定',
+ 'app.settings.notification.password': '账户密码',
+ 'app.settings.notification.password-description': '其他用户的消息将以站内信的形式通知',
+ 'app.settings.notification.messages': '系统消息',
+ 'app.settings.notification.messages-description': '系统消息将以站内信的形式通知',
+ 'app.settings.notification.todo': '待办任务',
+ 'app.settings.notification.todo-description': '待办任务将以站内信的形式通知',
+ 'app.settings.open': '开',
+ 'app.settings.close': '关',
+};
diff --git a/dubbo-admin-ui-antd/src/manifest.json b/dubbo-admin-ui-antd/src/manifest.json
new file mode 100644
index 0000000..766faf9
--- /dev/null
+++ b/dubbo-admin-ui-antd/src/manifest.json
@@ -0,0 +1,22 @@
+{
+ "name": "Dubbo Admin",
+ "short_name": "Dubbo Admin",
+ "display": "standalone",
+ "start_url": "./?utm_source=homescreen",
+ "theme_color": "#002140",
+ "background_color": "#001529",
+ "icons": [
+ {
+ "src": "icons/icon-192x192.png",
+ "sizes": "192x192"
+ },
+ {
+ "src": "icons/icon-128x128.png",
+ "sizes": "128x128"
+ },
+ {
+ "src": "icons/icon-512x512.png",
+ "sizes": "512x512"
+ }
+ ]
+}
diff --git a/dubbo-admin-ui-antd/src/pages/404.tsx b/dubbo-admin-ui-antd/src/pages/404.tsx
new file mode 100644
index 0000000..105d9bf
--- /dev/null
+++ b/dubbo-admin-ui-antd/src/pages/404.tsx
@@ -0,0 +1,34 @@
+/*
+ * 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, Result } from 'antd';
+import React from 'react';
+import { history } from 'umi';
+
+const NoFoundPage: React.FC = () => (
+ <Result
+ status="404"
+ title="404"
+ subTitle="Sorry, the page you visited does not exist."
+ extra={
+ <Button type="primary" onClick={() => history.push('/')}>
+ Back Home
+ </Button>
+ }
+ />
+);
+
+export default NoFoundPage;
diff --git a/dubbo-admin-ui-antd/src/pages/Admin.tsx b/dubbo-admin-ui-antd/src/pages/Admin.tsx
new file mode 100644
index 0000000..8ffe502
--- /dev/null
+++ b/dubbo-admin-ui-antd/src/pages/Admin.tsx
@@ -0,0 +1,59 @@
+/*
+ * 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 from 'react';
+import { HeartTwoTone, SmileTwoTone } from '@ant-design/icons';
+import { Card, Typography, Alert } from 'antd';
+import { PageHeaderWrapper } from '@ant-design/pro-layout';
+import { useIntl } from 'umi';
+
+export default (): React.ReactNode => {
+ const intl = useIntl();
+ return (
+ <PageHeaderWrapper
+ content={intl.formatMessage({
+ id: 'pages.admin.subPage.title',
+ defaultMessage: ' This page can only be viewed by Admin',
+ })}
+ >
+ <Card>
+ <Alert
+ message={intl.formatMessage({
+ id: 'pages.welcome.alertMessage',
+ defaultMessage: 'Faster and stronger heavy-duty components have been released.',
+ })}
+ type="success"
+ showIcon
+ banner
+ style={{
+ margin: -12,
+ marginBottom: 48,
+ }}
+ />
+ <Typography.Title level={2} style={{ textAlign: 'center' }}>
+ <SmileTwoTone /> Ant Design Pro <HeartTwoTone twoToneColor="#eb2f96" /> You
+ </Typography.Title>
+ </Card>
+ <p style={{ textAlign: 'center', marginTop: 24 }}>
+ Want to add more pages? Please refer to{' '}
+ <a href="https://pro.ant.design/docs/block" target="_blank" rel="noopener noreferrer">
+ use block
+ </a>
+ 。
+ </p>
+ </PageHeaderWrapper>
+ );
+};
diff --git a/dubbo-admin-ui-antd/src/pages/TableList/components/UpdateForm.tsx b/dubbo-admin-ui-antd/src/pages/TableList/components/UpdateForm.tsx
new file mode 100644
index 0000000..3690d6a
--- /dev/null
+++ b/dubbo-admin-ui-antd/src/pages/TableList/components/UpdateForm.tsx
@@ -0,0 +1,225 @@
+/*
+ * 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 from 'react';
+import { Modal } from 'antd';
+import {
+ ProFormSelect,
+ ProFormText,
+ ProFormTextArea,
+ StepsForm,
+ ProFormRadio,
+ ProFormDateTimePicker,
+} from '@ant-design/pro-form';
+import { useIntl, FormattedMessage } from 'umi';
+
+export type FormValueType = {
+ target?: string;
+ template?: string;
+ type?: string;
+ time?: string;
+ frequency?: string;
+} & Partial<API.RuleListItem>;
+
+export type UpdateFormProps = {
+ onCancel: (flag?: boolean, formVals?: FormValueType) => void;
+ onSubmit: (values: FormValueType) => Promise<void>;
+ updateModalVisible: boolean;
+ values: Partial<API.RuleListItem>;
+};
+
+const UpdateForm: React.FC<UpdateFormProps> = (props) => {
+ const intl = useIntl();
+ return (
+ <StepsForm
+ stepsProps={{
+ size: 'small',
+ }}
+ stepsFormRender={(dom, submitter) => {
+ return (
+ <Modal
+ width={640}
+ bodyStyle={{ padding: '32px 40px 48px' }}
+ destroyOnClose
+ title={intl.formatMessage({
+ id: 'pages.searchTable.updateForm.ruleConfig',
+ defaultMessage: 'Rule configuration',
+ })}
+ visible={props.updateModalVisible}
+ footer={submitter}
+ onCancel={() => {
+ props.onCancel();
+ }}
+ >
+ {dom}
+ </Modal>
+ );
+ }}
+ onFinish={props.onSubmit}
+ >
+ <StepsForm.StepForm
+ initialValues={{
+ name: props.values.name,
+ desc: props.values.desc,
+ }}
+ title={intl.formatMessage({
+ id: 'pages.searchTable.updateForm.basicConfig',
+ defaultMessage: 'Basic Information',
+ })}
+ >
+ <ProFormText
+ name="name"
+ label={intl.formatMessage({
+ id: 'pages.searchTable.updateForm.ruleName.nameLabel',
+ defaultMessage: 'Rule Name',
+ })}
+ width="md"
+ rules={[
+ {
+ required: true,
+ message: (
+ <FormattedMessage
+ id="pages.searchTable.updateForm.ruleName.nameRules"
+ defaultMessage="Please enter the rule name!"
+ />
+ ),
+ },
+ ]}
+ />
+ <ProFormTextArea
+ name="desc"
+ width="md"
+ label={intl.formatMessage({
+ id: 'pages.searchTable.updateForm.ruleDesc.descLabel',
+ defaultMessage: 'Rule Description',
+ })}
+ placeholder={intl.formatMessage({
+ id: 'pages.searchTable.updateForm.ruleDesc.descPlaceholder',
+ defaultMessage: 'Please enter at least five characters',
+ })}
+ rules={[
+ {
+ required: true,
+ message: (
+ <FormattedMessage
+ id="pages.searchTable.updateForm.ruleDesc.descRules"
+ defaultMessage="Please enter a rule description of at least five characters!"
+ />
+ ),
+ min: 5,
+ },
+ ]}
+ />
+ </StepsForm.StepForm>
+ <StepsForm.StepForm
+ initialValues={{
+ target: '0',
+ template: '0',
+ }}
+ title={intl.formatMessage({
+ id: 'pages.searchTable.updateForm.ruleProps.title',
+ defaultMessage: 'Configure Properties',
+ })}
+ >
+ <ProFormSelect
+ name="target"
+ width="md"
+ label={intl.formatMessage({
+ id: 'pages.searchTable.updateForm.object',
+ defaultMessage: 'Monitoring Object',
+ })}
+ valueEnum={{
+ 0: '表一',
+ 1: '表二',
+ }}
+ />
+ <ProFormSelect
+ name="template"
+ width="md"
+ label={intl.formatMessage({
+ id: 'pages.searchTable.updateForm.ruleProps.templateLabel',
+ defaultMessage: 'Rule Template',
+ })}
+ valueEnum={{
+ 0: 'Rule Template 1',
+ 1: 'Rule Template 2',
+ }}
+ />
+ <ProFormRadio.Group
+ name="type"
+ label={intl.formatMessage({
+ id: 'pages.searchTable.updateForm.ruleProps.typeLabel',
+ defaultMessage: 'Rule Type',
+ })}
+ options={[
+ {
+ value: '0',
+ label: 'strong',
+ },
+ {
+ value: '1',
+ label: 'weak',
+ },
+ ]}
+ />
+ </StepsForm.StepForm>
+ <StepsForm.StepForm
+ initialValues={{
+ type: '1',
+ frequency: 'month',
+ }}
+ title={intl.formatMessage({
+ id: 'pages.searchTable.updateForm.schedulingPeriod.title',
+ defaultMessage: 'Set Scheduling Period',
+ })}
+ >
+ <ProFormDateTimePicker
+ name="time"
+ width="md"
+ label={intl.formatMessage({
+ id: 'pages.searchTable.updateForm.schedulingPeriod.timeLabel',
+ defaultMessage: 'Starting Time',
+ })}
+ rules={[
+ {
+ required: true,
+ message: (
+ <FormattedMessage
+ id="pages.searchTable.updateForm.schedulingPeriod.timeRules"
+ defaultMessage="Please choose a start time!"
+ />
+ ),
+ },
+ ]}
+ />
+ <ProFormSelect
+ name="frequency"
+ label={intl.formatMessage({
+ id: 'pages.searchTable.updateForm.object',
+ defaultMessage: 'Monitoring Object',
+ })}
+ width="md"
+ valueEnum={{
+ month: 'month',
+ week: 'week',
+ }}
+ />
+ </StepsForm.StepForm>
+ </StepsForm>
+ );
+};
+
+export default UpdateForm;
diff --git a/dubbo-admin-ui-antd/src/pages/TableList/index.tsx b/dubbo-admin-ui-antd/src/pages/TableList/index.tsx
new file mode 100644
index 0000000..6f461d5
--- /dev/null
+++ b/dubbo-admin-ui-antd/src/pages/TableList/index.tsx
@@ -0,0 +1,393 @@
+/*
+ * 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 { PlusOutlined } from '@ant-design/icons';
+import { Button, message, Input, Drawer } from 'antd';
+import React, { useState, useRef } from 'react';
+import { useIntl, FormattedMessage } from 'umi';
+import { PageContainer, FooterToolbar } from '@ant-design/pro-layout';
+import type { ProColumns, ActionType } from '@ant-design/pro-table';
+import ProTable from '@ant-design/pro-table';
+import { ModalForm, ProFormText, ProFormTextArea } from '@ant-design/pro-form';
+import type { ProDescriptionsItemProps } from '@ant-design/pro-descriptions';
+import ProDescriptions from '@ant-design/pro-descriptions';
+import type { FormValueType } from './components/UpdateForm';
+import UpdateForm from './components/UpdateForm';
+import { rule, addRule, updateRule, removeRule } from '@/services/ant-design-pro/rule';
+
+/**
+ * 添加节点
+ *
+ * @param fields
+ */
+const handleAdd = async (fields: API.RuleListItem) => {
+ const hide = message.loading('Adding');
+ try {
+ await addRule({ ...fields });
+ hide();
+ message.success('Added successfully');
+ return true;
+ } catch (error) {
+ hide();
+ message.error('Add failed, please try again!');
+ return false;
+ }
+};
+
+/**
+ * 更新节点
+ *
+ * @param fields
+ */
+const handleUpdate = async (fields: FormValueType) => {
+ const hide = message.loading('Configuring');
+ try {
+ await updateRule({
+ name: fields.name,
+ desc: fields.desc,
+ key: fields.key,
+ });
+ hide();
+
+ message.success('Configuration successful');
+ return true;
+ } catch (error) {
+ hide();
+ message.error('Configuration failed, please try again!');
+ return false;
+ }
+};
+
+/**
+ * 删除节点
+ *
+ * @param selectedRows
+ */
+const handleRemove = async (selectedRows: API.RuleListItem[]) => {
+ const hide = message.loading('Deleting');
+ if (!selectedRows) return true;
+ try {
+ await removeRule({
+ key: selectedRows.map((row) => row.key),
+ });
+ hide();
+ message.success('Successfully deleted, about to refresh');
+ return true;
+ } catch (error) {
+ hide();
+ message.error('Deletion failed. Please try again');
+ return false;
+ }
+};
+
+const TableList: React.FC = () => {
+ /** Pop up window of add window */
+ const [createModalVisible, handleModalVisible] = useState<boolean>(false);
+ /** Pop up window of distributed update window */
+ const [updateModalVisible, handleUpdateModalVisible] = useState<boolean>(false);
+
+ const [showDetail, setShowDetail] = useState<boolean>(false);
+
+ const actionRef = useRef<ActionType>();
+ const [currentRow, setCurrentRow] = useState<API.RuleListItem>();
+ const [selectedRowsState, setSelectedRows] = useState<API.RuleListItem[]>([]);
+
+ /** International configuration */
+ const intl = useIntl();
+
+ const columns: ProColumns<API.RuleListItem>[] = [
+ {
+ title: (
+ <FormattedMessage
+ id="pages.searchTable.updateForm.ruleName.nameLabel"
+ defaultMessage="Rule Name"
+ />
+ ),
+ dataIndex: 'name',
+ tip: 'The rule name is unique key',
+ render: (dom, entity) => {
+ return (
+ <a
+ onClick={() => {
+ setCurrentRow(entity);
+ setShowDetail(true);
+ }}
+ >
+ {dom}
+ </a>
+ );
+ },
+ },
+ {
+ title: <FormattedMessage id="pages.searchTable.titleDesc" defaultMessage="Description" />,
+ dataIndex: 'desc',
+ valueType: 'textarea',
+ },
+ {
+ title: (
+ <FormattedMessage
+ id="pages.searchTable.titleCallNo"
+ defaultMessage="Number of Service Calls"
+ />
+ ),
+ dataIndex: 'callNo',
+ sorter: true,
+ hideInForm: true,
+ renderText: (val: string) =>
+ `${val}${intl.formatMessage({
+ id: 'pages.searchTable.tenThousand',
+ defaultMessage: ' 万 ',
+ })}`,
+ },
+ {
+ title: <FormattedMessage id="pages.searchTable.titleStatus" defaultMessage="Status" />,
+ dataIndex: 'status',
+ hideInForm: true,
+ valueEnum: {
+ 0: {
+ text: (
+ <FormattedMessage id="pages.searchTable.nameStatus.default" defaultMessage="default" />
+ ),
+ status: 'Default',
+ },
+ 1: {
+ text: (
+ <FormattedMessage id="pages.searchTable.nameStatus.running" defaultMessage="running" />
+ ),
+ status: 'Processing',
+ },
+ 2: {
+ text: (
+ <FormattedMessage id="pages.searchTable.nameStatus.online" defaultMessage="online" />
+ ),
+ status: 'Success',
+ },
+ 3: {
+ text: (
+ <FormattedMessage
+ id="pages.searchTable.nameStatus.abnormal"
+ defaultMessage="abnormal"
+ />
+ ),
+ status: 'Error',
+ },
+ },
+ },
+ {
+ title: (
+ <FormattedMessage
+ id="pages.searchTable.titleUpdatedAt"
+ defaultMessage="Last Scheduled at"
+ />
+ ),
+ sorter: true,
+ dataIndex: 'updatedAt',
+ valueType: 'dateTime',
+ renderFormItem: (item, { defaultRender, ...rest }, form) => {
+ const status = form.getFieldValue('status');
+ if (`${status}` === '0') {
+ return false;
+ }
+ if (`${status}` === '3') {
+ return (
+ <Input
+ {...rest}
+ placeholder={intl.formatMessage({
+ id: 'pages.searchTable.exception',
+ defaultMessage: 'Please enter the reason for the exception!',
+ })}
+ />
+ );
+ }
+ return defaultRender(item);
+ },
+ },
+ {
+ title: <FormattedMessage id="pages.searchTable.titleOption" defaultMessage="Option" />,
+ dataIndex: 'option',
+ valueType: 'option',
+ render: (_, record) => [
+ <a
+ key="config"
+ onClick={() => {
+ handleUpdateModalVisible(true);
+ setCurrentRow(record);
+ }}
+ >
+ <FormattedMessage id="pages.searchTable.config" defaultMessage="Configuration" />
+ </a>,
+ <a key="subscribeAlert" href="https://procomponents.ant.design/">
+ <FormattedMessage
+ id="pages.searchTable.subscribeAlert"
+ defaultMessage="Subscribe to alerts"
+ />
+ </a>,
+ ],
+ },
+ ];
+
+ return (
+ <PageContainer>
+ <ProTable<API.RuleListItem, API.PageParams>
+ headerTitle={intl.formatMessage({
+ id: 'pages.searchTable.title',
+ defaultMessage: 'Enquiry Form',
+ })}
+ actionRef={actionRef}
+ rowKey="key"
+ search={{
+ labelWidth: 120,
+ }}
+ toolBarRender={() => [
+ <Button
+ type="primary"
+ key="primary"
+ onClick={() => {
+ handleModalVisible(true);
+ }}
+ >
+ <PlusOutlined /> <FormattedMessage id="pages.searchTable.new" defaultMessage="New" />
+ </Button>,
+ ]}
+ request={rule}
+ columns={columns}
+ rowSelection={{
+ onChange: (_, selectedRows) => {
+ setSelectedRows(selectedRows);
+ },
+ }}
+ />
+ {selectedRowsState?.length > 0 && (
+ <FooterToolbar
+ extra={
+ <div>
+ <FormattedMessage id="pages.searchTable.chosen" defaultMessage="chosen" />{' '}
+ <a style={{ fontWeight: 600 }}>{selectedRowsState.length}</a>{' '}
+ <FormattedMessage id="pages.searchTable.item" defaultMessage="item" />
+
+ <span>
+ <FormattedMessage
+ id="pages.searchTable.totalServiceCalls"
+ defaultMessage="Total Number of Service Calls"
+ />{' '}
+ {selectedRowsState.reduce((pre, item) => pre + item.callNo!, 0)}{' '}
+ <FormattedMessage id="pages.searchTable.tenThousand" defaultMessage="0000" />
+ </span>
+ </div>
+ }
+ >
+ <Button
+ onClick={async () => {
+ await handleRemove(selectedRowsState);
+ setSelectedRows([]);
+ actionRef.current?.reloadAndRest?.();
+ }}
+ >
+ <FormattedMessage
+ id="pages.searchTable.batchDeletion"
+ defaultMessage="bacth deletion"
+ />
+ </Button>
+ <Button type="primary">
+ <FormattedMessage
+ id="pages.searchTable.batchApproval"
+ defaultMessage="batch approval"
+ />
+ </Button>
+ </FooterToolbar>
+ )}
+ <ModalForm
+ title={intl.formatMessage({
+ id: 'pages.searchTable.createForm.newRule',
+ defaultMessage: 'New Rule',
+ })}
+ width="400px"
+ visible={createModalVisible}
+ onVisibleChange={handleModalVisible}
+ onFinish={async (value) => {
+ const success = await handleAdd(value as API.RuleListItem);
+ if (success) {
+ handleModalVisible(false);
+ if (actionRef.current) {
+ actionRef.current.reload();
+ }
+ }
+ }}
+ >
+ <ProFormText
+ rules={[
+ {
+ required: true,
+ message: (
+ <FormattedMessage
+ id="pages.searchTable.ruleName"
+ defaultMessage="Rule name is required"
+ />
+ ),
+ },
+ ]}
+ width="md"
+ name="name"
+ />
+ <ProFormTextArea width="md" name="desc" />
+ </ModalForm>
+ <UpdateForm
+ onSubmit={async (value) => {
+ const success = await handleUpdate(value);
+ if (success) {
+ handleUpdateModalVisible(false);
+ setCurrentRow(undefined);
+ if (actionRef.current) {
+ actionRef.current.reload();
+ }
+ }
+ }}
+ onCancel={() => {
+ handleUpdateModalVisible(false);
+ setCurrentRow(undefined);
+ }}
+ updateModalVisible={updateModalVisible}
+ values={currentRow || {}}
+ />
+
+ <Drawer
+ width={600}
+ visible={showDetail}
+ onClose={() => {
+ setCurrentRow(undefined);
+ setShowDetail(false);
+ }}
+ closable={false}
+ >
+ {currentRow?.name && (
+ <ProDescriptions<API.RuleListItem>
+ column={2}
+ title={currentRow?.name}
+ request={async () => ({
+ data: currentRow || {},
+ })}
+ params={{
+ id: currentRow?.name,
+ }}
+ columns={columns as ProDescriptionsItemProps<API.RuleListItem>[]}
+ />
+ )}
+ </Drawer>
+ </PageContainer>
+ );
+};
+
+export default TableList;
diff --git a/dubbo-admin-ui-antd/src/pages/User/login/index.less b/dubbo-admin-ui-antd/src/pages/User/login/index.less
new file mode 100644
index 0000000..6c267f5
--- /dev/null
+++ b/dubbo-admin-ui-antd/src/pages/User/login/index.less
@@ -0,0 +1,130 @@
+/*
+ * 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 '~antd/es/style/themes/default.less';
+
+.container {
+ display: flex;
+ flex-direction: column;
+ height: 100vh;
+ overflow: auto;
+ background: @layout-body-background;
+}
+
+.lang {
+ width: 100%;
+ height: 40px;
+ line-height: 44px;
+ text-align: right;
+ :global(.ant-dropdown-trigger) {
+ margin-right: 24px;
+ }
+}
+
+.content {
+ flex: 1;
+ padding: 32px 0;
+}
+
+@media (min-width: @screen-md-min) {
+ .container {
+ background-image: url('https://gw.alipayobjects.com/zos/rmsportal/TVYTbAXWheQpRcWDaDMu.svg');
+ background-repeat: no-repeat;
+ background-position: center 110px;
+ background-size: 100%;
+ }
+
+ .content {
+ padding: 32px 0 24px;
+ }
+}
+
+.top {
+ text-align: center;
+}
+
+.header {
+ height: 44px;
+ line-height: 44px;
+ a {
+ text-decoration: none;
+ }
+}
+
+.logo {
+ height: 44px;
+ margin-right: 16px;
+ vertical-align: top;
+}
+
+.title {
+ position: relative;
+ top: 2px;
+ color: @heading-color;
+ font-weight: 600;
+ font-size: 33px;
+ font-family: Avenir, 'Helvetica Neue', Arial, Helvetica, sans-serif;
+}
+
+.desc {
+ margin-top: 12px;
+ margin-bottom: 40px;
+ color: @text-color-secondary;
+ font-size: @font-size-base;
+}
+
+.main {
+ width: 328px;
+ margin: 0 auto;
+ @media screen and (max-width: @screen-sm) {
+ width: 95%;
+ max-width: 328px;
+ }
+
+ :global {
+ .@{ant-prefix}-tabs-nav-list {
+ margin: auto;
+ font-size: 16px;
+ }
+ }
+
+ .icon {
+ margin-left: 16px;
+ color: rgba(0, 0, 0, 0.2);
+ font-size: 24px;
+ vertical-align: middle;
+ cursor: pointer;
+ transition: color 0.3s;
+
+ &:hover {
+ color: @primary-color;
+ }
+ }
+
+ .other {
+ margin-top: 24px;
+ line-height: 22px;
+ text-align: left;
+ .register {
+ float: right;
+ }
+ }
+
+ .prefixIcon {
+ color: @primary-color;
+ font-size: @font-size-base;
+ }
+}
diff --git a/dubbo-admin-ui-antd/src/pages/User/login/index.tsx b/dubbo-admin-ui-antd/src/pages/User/login/index.tsx
new file mode 100644
index 0000000..ff83164
--- /dev/null
+++ b/dubbo-admin-ui-antd/src/pages/User/login/index.tsx
@@ -0,0 +1,212 @@
+/*
+ * 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 { LockOutlined, UserOutlined } from '@ant-design/icons';
+import { Alert, message } from 'antd';
+import React, { useState } from 'react';
+import ProForm, { ProFormCheckbox, ProFormText } from '@ant-design/pro-form';
+import { useIntl, Link, history, FormattedMessage, SelectLang } from 'umi';
+import Footer from '@/components/Footer';
+import { login } from '@/services/ant-design-pro/login';
+
+import styles from './index.less';
+
+const LoginMessage: React.FC<{
+ content: string;
+}> = ({ content }) => (
+ <Alert
+ style={{
+ marginBottom: 24,
+ }}
+ message={content}
+ type="error"
+ showIcon
+ />
+);
+
+/** This method jumps to the position of the redirect parameter */
+const goto = () => {
+ if (!history) return;
+ setTimeout(() => {
+ const { query } = history.location;
+ const { redirect } = query as { redirect: string };
+ history.push(redirect || '/');
+ }, 10);
+};
+
+const Login: React.FC = () => {
+ const [submitting, setSubmitting] = useState(false);
+ const [userLoginState, setUserLoginState] = useState<API.LoginResult>({});
+ const [type] = useState<string>('account');
+
+ const intl = useIntl();
+
+ const handleSubmit = async (values: API.LoginParams) => {
+ setSubmitting(true);
+ try {
+ // login
+ const msg = await login({ ...values, type });
+ if (msg !== '') {
+ message.success(
+ intl.formatMessage({
+ id: 'pages.login.accountLogin.successful',
+ defaultMessage: 'Login successful!',
+ }),
+ );
+ localStorage.setItem('token', msg);
+ localStorage.setItem('username', values.username);
+ goto();
+ return;
+ }
+ // If it fails, set the user error message
+ setUserLoginState(msg);
+ } catch (error) {
+ message.error(
+ intl.formatMessage({
+ id: 'pages.login.accountLogin.error',
+ defaultMessage: 'Login failed, please try again!',
+ }),
+ );
+ }
+ setSubmitting(false);
+ };
+ const { status } = userLoginState;
+
+ return (
+ <div className={styles.container}>
+ <div className={styles.lang} style={{ marginTop: '100px' }}>
+ {SelectLang && <SelectLang />}
+ </div>
+ <div className={styles.content}>
+ <div className={styles.top}>
+ <div className={styles.header}>
+ <Link to="/">
+ <svg
+ xmlns="http://www.w3.org/2000/svg"
+ viewBox="0 0 321.39 78.54"
+ style={{ height: '32px' }}
+ >
+ <title>DUBBO LOGO</title>
+ <path
+ d="M68.46 50.38c0 14.06 11.39 22.11 25.45 22.11s25.45-8.05 25.45-22.11V7.25H68.46zm21.24-28h8.6V31H89.7zm0 22.25h8.6v8.6H89.7zM33.24 7.25H4.06v64H33.24c10.95.0 19.3-7.18 23.29-17.15a45.12 45.12.0 002.38-14.87A45.12 45.12.0 0056.53 24.4C52.84 14.62 44.19 7.25 33.24 7.25zm.43 14.63H30.34a3.44 3.44.0 00-3.44 3.44V53.23a3.44 3.44.0 003.44 3.44h3.33v4.63h-8.3a6.87 6.87.0 01-6.87-6.87V24.12a6.87 6.87.0 016.87-6.87h8.3zM285.51 6.06c-17.05.0-30.88 10.28-30.88 33.21s13.83 33.21 [...]
+ style={{ fill: '#1a8cf7', fillOpacity: 1 }}
+ ></path>
+ </svg>
+ <span className={styles.title}> Admin</span>
+ </Link>
+ </div>
+ </div>
+
+ <div className={styles.main}>
+ <ProForm
+ initialValues={{
+ autoLogin: true,
+ }}
+ submitter={{
+ searchConfig: {
+ submitText: intl.formatMessage({
+ id: 'pages.login.submit',
+ defaultMessage: 'Login',
+ }),
+ },
+ render: (_, dom) => dom.pop(),
+ submitButtonProps: {
+ loading: submitting,
+ size: 'large',
+ style: {
+ width: '100%',
+ },
+ },
+ }}
+ onFinish={async (values) => {
+ handleSubmit(values as API.LoginParams);
+ }}
+ >
+ <div style={{ height: '30px' }}></div>
+
+ {status === 'error' && (
+ <LoginMessage
+ content={intl.formatMessage({
+ id: 'pages.login.accountLogin.errorMessage',
+ defaultMessage: 'Incorrect username/password',
+ })}
+ />
+ )}
+ <>
+ <ProFormText
+ name="username"
+ fieldProps={{
+ size: 'large',
+ prefix: <UserOutlined className={styles.prefixIcon} />,
+ }}
+ placeholder={intl.formatMessage({
+ id: 'pages.login.username.placeholder',
+ defaultMessage: 'Username: admin or user',
+ })}
+ rules={[
+ {
+ required: true,
+ message: (
+ <FormattedMessage
+ id="pages.login.username.required"
+ defaultMessage="Please input your username!"
+ />
+ ),
+ },
+ ]}
+ />
+ <ProFormText.Password
+ name="password"
+ fieldProps={{
+ size: 'large',
+ prefix: <LockOutlined className={styles.prefixIcon} />,
+ }}
+ placeholder={intl.formatMessage({
+ id: 'pages.login.password.placeholder',
+ defaultMessage: 'Default password: root',
+ })}
+ rules={[
+ {
+ required: true,
+ message: (
+ <FormattedMessage
+ id="pages.login.password.required"
+ defaultMessage="Please input your password!"
+ />
+ ),
+ },
+ ]}
+ />
+ </>
+
+ <div
+ style={{
+ marginBottom: 24,
+ }}
+ >
+ <ProFormCheckbox noStyle name="autoLogin">
+ <FormattedMessage id="pages.login.rememberMe" defaultMessage="Remember me" />
+ </ProFormCheckbox>
+ </div>
+ </ProForm>
+ </div>
+ </div>
+ <Footer />
+ </div>
+ );
+};
+
+export default Login;
diff --git a/dubbo-admin-ui-antd/src/pages/Welcome.less b/dubbo-admin-ui-antd/src/pages/Welcome.less
new file mode 100644
index 0000000..ff2e449
--- /dev/null
+++ b/dubbo-admin-ui-antd/src/pages/Welcome.less
@@ -0,0 +1,24 @@
+/*
+ * 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 '~antd/lib/style/themes/default.less';
+
+.pre {
+ margin: 12px 0;
+ padding: 12px 20px;
+ background: @input-bg;
+ box-shadow: @card-shadow;
+}
diff --git a/dubbo-admin-ui-antd/src/pages/Welcome.tsx b/dubbo-admin-ui-antd/src/pages/Welcome.tsx
new file mode 100644
index 0000000..45a20f8
--- /dev/null
+++ b/dubbo-admin-ui-antd/src/pages/Welcome.tsx
@@ -0,0 +1,82 @@
+/*
+ * 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 from 'react';
+import { PageContainer } from '@ant-design/pro-layout';
+import { Card, Alert, Typography } from 'antd';
+import { useIntl, FormattedMessage } from 'umi';
+import styles from './Welcome.less';
+
+const CodePreview: React.FC = ({ children }) => (
+ <pre className={styles.pre}>
+ <code>
+ <Typography.Text copyable>{children}</Typography.Text>
+ </code>
+ </pre>
+);
+
+export default (): React.ReactNode => {
+ const intl = useIntl();
+ return (
+ <PageContainer>
+ <Card>
+ <Alert
+ message={intl.formatMessage({
+ id: 'pages.welcome.alertMessage',
+ defaultMessage: 'Faster and stronger heavy-duty components have been released.',
+ })}
+ type="success"
+ showIcon
+ banner
+ style={{
+ margin: -12,
+ marginBottom: 24,
+ }}
+ />
+ <Typography.Text strong>
+ <FormattedMessage
+ id="pages.welcome.advancedComponent"
+ defaultMessage="Advanced Component"
+ />{' '}
+ <a
+ href="https://procomponents.ant.design/components/table"
+ rel="noopener noreferrer"
+ target="__blank"
+ >
+ <FormattedMessage id="pages.welcome.link" defaultMessage="Welcome" />
+ </a>
+ </Typography.Text>
+ <CodePreview>yarn add @ant-design/pro-table</CodePreview>
+ <Typography.Text
+ strong
+ style={{
+ marginBottom: 12,
+ }}
+ >
+ <FormattedMessage id="pages.welcome.advancedLayout" defaultMessage="Advanced Layout" />{' '}
+ <a
+ href="https://procomponents.ant.design/components/layout"
+ rel="noopener noreferrer"
+ target="__blank"
+ >
+ <FormattedMessage id="pages.welcome.link" defaultMessage="Welcome" />
+ </a>
+ </Typography.Text>
+ <CodePreview>yarn add @ant-design/pro-layout</CodePreview>
+ </Card>
+ </PageContainer>
+ );
+};
diff --git a/dubbo-admin-ui-antd/src/pages/document.ejs b/dubbo-admin-ui-antd/src/pages/document.ejs
new file mode 100644
index 0000000..e20d99c
--- /dev/null
+++ b/dubbo-admin-ui-antd/src/pages/document.ejs
@@ -0,0 +1,208 @@
+<!--
+ ~ 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
+ ~ he 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.
+ -->
+<!DOCTYPE html>
+<html lang="en">
+ <head>
+ <meta charset="UTF-8" />
+ <meta http-equiv="X-UA-Compatible" content="IE=edge" />
+ <meta name="description" content="apache dubbo admin" />
+ <meta
+ name="viewport"
+ content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0"
+ />
+ <title>Ant Design Pro</title>
+ <link rel="icon" href="<%= context.config.publicPath +'favicon.ico'%>" type="image/x-icon" />
+ </head>
+ <body>
+ <noscript>Out-of-the-box mid-stage front/design solution!</noscript>
+ <div id="root">
+ <style>
+ html,
+ body,
+ #root {
+ height: 100%;
+ margin: 0;
+ padding: 0;
+ }
+ #root {
+ background-image: url('<%= context.config.publicPath +"home_bg.png"%>');
+ background-repeat: no-repeat;
+ background-size: 100% auto;
+ }
+ .page-loading-warp {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ padding: 98px;
+ }
+ .ant-spin {
+ position: absolute;
+ display: none;
+ -webkit-box-sizing: border-box;
+ box-sizing: border-box;
+ margin: 0;
+ padding: 0;
+ color: rgba(0, 0, 0, 0.65);
+ color: #1890ff;
+ font-size: 14px;
+ font-variant: tabular-nums;
+ line-height: 1.5;
+ text-align: center;
+ list-style: none;
+ opacity: 0;
+ -webkit-transition: -webkit-transform 0.3s cubic-bezier(0.78, 0.14, 0.15, 0.86);
+ transition: -webkit-transform 0.3s cubic-bezier(0.78, 0.14, 0.15, 0.86);
+ transition: transform 0.3s cubic-bezier(0.78, 0.14, 0.15, 0.86);
+ transition: transform 0.3s cubic-bezier(0.78, 0.14, 0.15, 0.86),
+ -webkit-transform 0.3s cubic-bezier(0.78, 0.14, 0.15, 0.86);
+ -webkit-font-feature-settings: 'tnum';
+ font-feature-settings: 'tnum';
+ }
+
+ .ant-spin-spinning {
+ position: static;
+ display: inline-block;
+ opacity: 1;
+ }
+
+ .ant-spin-dot {
+ position: relative;
+ display: inline-block;
+ width: 20px;
+ height: 20px;
+ font-size: 20px;
+ }
+
+ .ant-spin-dot-item {
+ position: absolute;
+ display: block;
+ width: 9px;
+ height: 9px;
+ background-color: #1890ff;
+ border-radius: 100%;
+ -webkit-transform: scale(0.75);
+ -ms-transform: scale(0.75);
+ transform: scale(0.75);
+ -webkit-transform-origin: 50% 50%;
+ -ms-transform-origin: 50% 50%;
+ transform-origin: 50% 50%;
+ opacity: 0.3;
+ -webkit-animation: antspinmove 1s infinite linear alternate;
+ animation: antSpinMove 1s infinite linear alternate;
+ }
+
+ .ant-spin-dot-item:nth-child(1) {
+ top: 0;
+ left: 0;
+ }
+
+ .ant-spin-dot-item:nth-child(2) {
+ top: 0;
+ right: 0;
+ -webkit-animation-delay: 0.4s;
+ animation-delay: 0.4s;
+ }
+
+ .ant-spin-dot-item:nth-child(3) {
+ right: 0;
+ bottom: 0;
+ -webkit-animation-delay: 0.8s;
+ animation-delay: 0.8s;
+ }
+
+ .ant-spin-dot-item:nth-child(4) {
+ bottom: 0;
+ left: 0;
+ -webkit-animation-delay: 1.2s;
+ animation-delay: 1.2s;
+ }
+
+ .ant-spin-dot-spin {
+ -webkit-transform: rotate(45deg);
+ -ms-transform: rotate(45deg);
+ transform: rotate(45deg);
+ -webkit-animation: antrotate 1.2s infinite linear;
+ animation: antRotate 1.2s infinite linear;
+ }
+
+ .ant-spin-lg .ant-spin-dot {
+ width: 32px;
+ height: 32px;
+ font-size: 32px;
+ }
+
+ .ant-spin-lg .ant-spin-dot i {
+ width: 14px;
+ height: 14px;
+ }
+
+ @media all and (-ms-high-contrast: none), (-ms-high-contrast: active) {
+ .ant-spin-blur {
+ background: #fff;
+ opacity: 0.5;
+ }
+ }
+
+ @-webkit-keyframes antSpinMove {
+ to {
+ opacity: 1;
+ }
+ }
+
+ @keyframes antSpinMove {
+ to {
+ opacity: 1;
+ }
+ }
+
+ @-webkit-keyframes antRotate {
+ to {
+ -webkit-transform: rotate(405deg);
+ transform: rotate(405deg);
+ }
+ }
+
+ @keyframes antRotate {
+ to {
+ -webkit-transform: rotate(405deg);
+ transform: rotate(405deg);
+ }
+ }
+ </style>
+ <div
+ style="
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ height: 100%;
+ min-height: 420px;
+ "
+ >
+ <img src="<%= context.config.publicPath +'pro_icon.svg'%>" alt="logo" width="256" />
+ <div class="page-loading-warp">
+ <div class="ant-spin ant-spin-lg ant-spin-spinning">
+ <span class="ant-spin-dot ant-spin-dot-spin"
+ ><i class="ant-spin-dot-item"></i><i class="ant-spin-dot-item"></i
+ ><i class="ant-spin-dot-item"></i><i class="ant-spin-dot-item"></i
+ ></span>
+ </div>
+ </div>
+ </div>
+ </div>
+ </body>
+</html>
diff --git a/dubbo-admin-ui-antd/src/service-worker.js b/dubbo-admin-ui-antd/src/service-worker.js
new file mode 100644
index 0000000..c2a6205
--- /dev/null
+++ b/dubbo-admin-ui-antd/src/service-worker.js
@@ -0,0 +1,82 @@
+/*
+ * 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 eslint-comments/disable-enable-pair */
+/* eslint-disable no-restricted-globals */
+/* eslint-disable no-underscore-dangle */
+/* globals workbox */
+workbox.core.setCacheNameDetails({
+ prefix: 'antd-pro',
+ suffix: 'v5',
+});
+// Control all opened tabs ASAP
+workbox.clientsClaim();
+
+/**
+ * Use precaching list generated by workbox in build process.
+ * https://developers.google.com/web/tools/workbox/reference-docs/latest/workbox.precaching
+ */
+workbox.precaching.precacheAndRoute(self.__precacheManifest || []);
+
+/**
+ * Register a navigation route.
+ * https://developers.google.com/web/tools/workbox/modules/workbox-routing#how_to_register_a_navigation_route
+ */
+workbox.routing.registerNavigationRoute('/index.html');
+
+/**
+ * Use runtime cache:
+ * https://developers.google.com/web/tools/workbox/reference-docs/latest/workbox.routing#.registerRoute
+ *
+ * Workbox provides all common caching strategies including CacheFirst, NetworkFirst etc.
+ * https://developers.google.com/web/tools/workbox/reference-docs/latest/workbox.strategies
+ */
+
+/** Handle API requests */
+workbox.routing.registerRoute(/\/api\//, workbox.strategies.networkFirst());
+
+/** Handle third party requests */
+workbox.routing.registerRoute(
+ /^https:\/\/gw\.alipayobjects\.com\//,
+ workbox.strategies.networkFirst(),
+);
+workbox.routing.registerRoute(
+ /^https:\/\/cdnjs\.cloudflare\.com\//,
+ workbox.strategies.networkFirst(),
+);
+workbox.routing.registerRoute(/\/color.less/, workbox.strategies.networkFirst());
+
+/** Response to client after skipping waiting with MessageChannel */
+addEventListener('message', (event) => {
+ const replyPort = event.ports[0];
+ const message = event.data;
+ if (replyPort && message && message.type === 'skip-waiting') {
+ event.waitUntil(
+ self.skipWaiting().then(
+ () => {
+ replyPort.postMessage({
+ error: null,
+ });
+ },
+ (error) => {
+ replyPort.postMessage({
+ error,
+ });
+ },
+ ),
+ );
+ }
+});
diff --git a/dubbo-admin-ui-antd/src/services/ant-design-pro/api.ts b/dubbo-admin-ui-antd/src/services/ant-design-pro/api.ts
new file mode 100644
index 0000000..c526ce9
--- /dev/null
+++ b/dubbo-admin-ui-antd/src/services/ant-design-pro/api.ts
@@ -0,0 +1,35 @@
+/*
+ * 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.
+ */
+// @ts-ignore
+/* eslint-disable */
+import { request } from 'umi';
+
+/** Get the current user GET /api/currentUser */
+export async function currentUser(options?: { [key: string]: any }) {
+ return request<API.CurrentUser>('/api/currentUser', {
+ method: 'GET',
+ ...(options || {}),
+ });
+}
+
+/** Get notices GET /api/notices */
+export async function getNotices(options?: { [key: string]: any }) {
+ return request<API.NoticeIconList>('/api/notices', {
+ method: 'GET',
+ ...(options || {}),
+ });
+}
diff --git a/dubbo-admin-ui-antd/src/services/ant-design-pro/index.ts b/dubbo-admin-ui-antd/src/services/ant-design-pro/index.ts
new file mode 100644
index 0000000..1642d8e
--- /dev/null
+++ b/dubbo-admin-ui-antd/src/services/ant-design-pro/index.ts
@@ -0,0 +1,26 @@
+/*
+ * 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.
+ */
+// @ts-ignore
+/* eslint-disable */
+import * as api from './api';
+import * as login from './login';
+import * as rule from './rule';
+export default {
+ api,
+ login,
+ rule,
+};
diff --git a/dubbo-admin-ui-antd/src/services/ant-design-pro/login.ts b/dubbo-admin-ui-antd/src/services/ant-design-pro/login.ts
new file mode 100644
index 0000000..a1bbcee
--- /dev/null
+++ b/dubbo-admin-ui-antd/src/services/ant-design-pro/login.ts
@@ -0,0 +1,37 @@
+/*
+ * 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.
+ */
+// @ts-ignore
+/* eslint-disable */
+import { request } from 'umi';
+
+export async function outLogin(options?: { [key: string]: any }) {
+ return request<Record<string, any>>('/api/login/outLogin', {
+ method: 'GET',
+ ...(options || {}),
+ });
+}
+
+export async function login(body: API.LoginParams, options?: { [key: string]: any }) {
+ return request<API.LoginResult>('/user/login', {
+ method: 'GET',
+ params: {
+ userName: body.username,
+ password: body.password,
+ },
+ ...(options || {}),
+ });
+}
diff --git a/dubbo-admin-ui-antd/src/services/ant-design-pro/rule.ts b/dubbo-admin-ui-antd/src/services/ant-design-pro/rule.ts
new file mode 100644
index 0000000..30af11a
--- /dev/null
+++ b/dubbo-admin-ui-antd/src/services/ant-design-pro/rule.ts
@@ -0,0 +1,63 @@
+/*
+ * 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.
+ */
+// @ts-ignore
+/* eslint-disable */
+import { request } from 'umi';
+
+/** Get rule list GET /api/rule */
+export async function rule(
+ params: {
+ // query
+ /** Current page number */
+ current?: number;
+ /** Page size */
+ pageSize?: number;
+ },
+ options?: { [key: string]: any },
+) {
+ return request<API.RuleList>('/api/rule', {
+ method: 'GET',
+ params: {
+ ...params,
+ },
+ ...(options || {}),
+ });
+}
+
+/** update rule PUT /api/rule */
+export async function updateRule(options?: { [key: string]: any }) {
+ return request<API.RuleListItem>('/api/rule', {
+ method: 'PUT',
+ ...(options || {}),
+ });
+}
+
+/** new rule POST /api/rule */
+export async function addRule(options?: { [key: string]: any }) {
+ return request<API.RuleListItem>('/api/rule', {
+ method: 'POST',
+ ...(options || {}),
+ });
+}
+
+/** delete rule DELETE /api/rule */
+export async function removeRule(options?: { [key: string]: any }) {
+ return request<Record<string, any>>('/api/rule', {
+ method: 'DELETE',
+ ...(options || {}),
+ });
+}
diff --git a/dubbo-admin-ui-antd/src/services/ant-design-pro/typings.d.ts b/dubbo-admin-ui-antd/src/services/ant-design-pro/typings.d.ts
new file mode 100644
index 0000000..614ba78
--- /dev/null
+++ b/dubbo-admin-ui-antd/src/services/ant-design-pro/typings.d.ts
@@ -0,0 +1,117 @@
+/*
+ * 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.
+ */
+// @ts-ignore
+/* eslint-disable */
+
+declare namespace API {
+ type CurrentUser = {
+ name?: string;
+ avatar?: string;
+ userid?: string;
+ email?: string;
+ signature?: string;
+ title?: string;
+ group?: string;
+ tags?: { key?: string; label?: string }[];
+ notifyCount?: number;
+ unreadCount?: number;
+ country?: string;
+ access?: string;
+ geographic?: {
+ province?: { label?: string; key?: string };
+ city?: { label?: string; key?: string };
+ };
+ address?: string;
+ phone?: string;
+ };
+
+ type LoginResult = {
+ status?: string;
+ type?: string;
+ currentAuthority?: string;
+ };
+
+ type PageParams = {
+ current?: number;
+ pageSize?: number;
+ };
+
+ type RuleListItem = {
+ key?: number;
+ disabled?: boolean;
+ href?: string;
+ avatar?: string;
+ name?: string;
+ owner?: string;
+ desc?: string;
+ callNo?: number;
+ status?: number;
+ updatedAt?: string;
+ createdAt?: string;
+ progress?: number;
+ };
+
+ type RuleList = {
+ data?: RuleListItem[];
+ /** The total number of contents in the list */
+ total?: number;
+ success?: boolean;
+ };
+
+ type FakeCaptcha = {
+ code?: number;
+ status?: string;
+ };
+
+ type LoginParams = {
+ username?: string;
+ password?: string;
+ autoLogin?: boolean;
+ type?: string;
+ };
+
+ type ErrorResponse = {
+ /** Error code of business agreement */
+ errorCode: string;
+ /** Business error messages */
+ errorMessage?: string;
+ /** Is the business request successful */
+ success?: boolean;
+ };
+
+ type NoticeIconList = {
+ data?: NoticeIconItem[];
+ /** The total number of contents in the list */
+ total?: number;
+ success?: boolean;
+ };
+
+ type NoticeIconItemType = 'notification' | 'message' | 'event';
+
+ type NoticeIconItem = {
+ id?: string;
+ extra?: string;
+ key?: string;
+ read?: boolean;
+ avatar?: string;
+ title?: string;
+ status?: string;
+ datetime?: string;
+ description?: string;
+ type?: NoticeIconItemType;
+ };
+}
diff --git a/dubbo-admin-ui-antd/src/typings.d.ts b/dubbo-admin-ui-antd/src/typings.d.ts
new file mode 100644
index 0000000..7dfffda
--- /dev/null
+++ b/dubbo-admin-ui-antd/src/typings.d.ts
@@ -0,0 +1,54 @@
+/*
+ * 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.
+ */
+declare module 'slash2';
+declare module '*.css';
+declare module '*.less';
+declare module '*.scss';
+declare module '*.sass';
+declare module '*.svg';
+declare module '*.png';
+declare module '*.jpg';
+declare module '*.jpeg';
+declare module '*.gif';
+declare module '*.bmp';
+declare module '*.tiff';
+declare module 'omit.js';
+
+// google analytics interface
+type GAFieldsObject = {
+ eventCategory: string;
+ eventAction: string;
+ eventLabel?: string;
+ eventValue?: number;
+ nonInteraction?: boolean;
+};
+
+type Window = {
+ ga: (
+ command: 'send',
+ hitType: 'event' | 'pageview',
+ fieldsObject: GAFieldsObject | string,
+ ) => void;
+ reloadAuthorized: () => void;
+};
+
+declare let ga: () => void;
+
+// preview.pro.ant.design only do not use in your production ;
+declare let ANT_DESIGN_PRO_ONLY_DO_NOT_USE_IN_YOUR_PRODUCTION: 'site' | undefined;
+
+declare const REACT_APP_ENV: 'test' | 'dev' | 'pre' | false;
diff --git a/dubbo-admin-ui-antd/src/utils/utils.less b/dubbo-admin-ui-antd/src/utils/utils.less
new file mode 100644
index 0000000..ccb771e
--- /dev/null
+++ b/dubbo-admin-ui-antd/src/utils/utils.less
@@ -0,0 +1,32 @@
+/*
+ * 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.
+ */
+// mixins for clearfix
+// ------------------------
+.clearfix() {
+ zoom: 1;
+ &::before,
+ &::after {
+ display: table;
+ content: ' ';
+ }
+ &::after {
+ clear: both;
+ height: 0;
+ font-size: 0;
+ visibility: hidden;
+ }
+}
diff --git a/dubbo-admin-ui-antd/src/utils/utils.test.ts b/dubbo-admin-ui-antd/src/utils/utils.test.ts
new file mode 100644
index 0000000..fc04836
--- /dev/null
+++ b/dubbo-admin-ui-antd/src/utils/utils.test.ts
@@ -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 { isUrl } from './utils';
+
+describe('isUrl tests', () => {
+ it('should return false for invalid and corner case inputs', () => {
+ expect(isUrl([] as any)).toBeFalsy();
+ expect(isUrl({} as any)).toBeFalsy();
+ expect(isUrl(false as any)).toBeFalsy();
+ expect(isUrl(true as any)).toBeFalsy();
+ expect(isUrl(NaN as any)).toBeFalsy();
+ expect(isUrl(null as any)).toBeFalsy();
+ expect(isUrl(undefined as any)).toBeFalsy();
+ expect(isUrl('')).toBeFalsy();
+ });
+
+ it('should return false for invalid URLs', () => {
+ expect(isUrl('foo')).toBeFalsy();
+ expect(isUrl('bar')).toBeFalsy();
+ expect(isUrl('bar/test')).toBeFalsy();
+ expect(isUrl('http:/example.com/')).toBeFalsy();
+ expect(isUrl('ttp://example.com/')).toBeFalsy();
+ });
+
+ it('should return true for valid URLs', () => {
+ expect(isUrl('http://example.com/')).toBeTruthy();
+ expect(isUrl('https://example.com/')).toBeTruthy();
+ expect(isUrl('http://example.com/test/123')).toBeTruthy();
+ expect(isUrl('https://example.com/test/123')).toBeTruthy();
+ expect(isUrl('http://example.com/test/123?foo=bar')).toBeTruthy();
+ expect(isUrl('https://example.com/test/123?foo=bar')).toBeTruthy();
+ expect(isUrl('http://www.example.com/')).toBeTruthy();
+ expect(isUrl('https://www.example.com/')).toBeTruthy();
+ expect(isUrl('http://www.example.com/test/123')).toBeTruthy();
+ expect(isUrl('https://www.example.com/test/123')).toBeTruthy();
+ expect(isUrl('http://www.example.com/test/123?foo=bar')).toBeTruthy();
+ expect(isUrl('https://www.example.com/test/123?foo=bar')).toBeTruthy();
+ });
+});
diff --git a/dubbo-admin-ui-antd/src/utils/utils.ts b/dubbo-admin-ui-antd/src/utils/utils.ts
new file mode 100644
index 0000000..65129d1
--- /dev/null
+++ b/dubbo-admin-ui-antd/src/utils/utils.ts
@@ -0,0 +1,35 @@
+/*
+ * 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 no-useless-escape:0 import/prefer-default-export:0 */
+const reg = /(((^https?:(?:\/\/)?)(?:[-;:&=\+\$,\w]+@)?[A-Za-z0-9.-]+(?::\d+)?|(?:www.|[-;:&=\+\$,\w]+@)[A-Za-z0-9.-]+)((?:\/[\+~%\/.\w-_]*)?\??(?:[-\+=&;%@.\w_]*)#?(?:[\w]*))?)$/;
+
+export const isUrl = (path: string): boolean => reg.test(path);
+
+export const isAntDesignPro = (): boolean => {
+ if (ANT_DESIGN_PRO_ONLY_DO_NOT_USE_IN_YOUR_PRODUCTION === 'site') {
+ return true;
+ }
+ return window.location.hostname === 'preview.pro.ant.design';
+};
+
+export const isAntDesignProOrDev = (): boolean => {
+ const { NODE_ENV } = process.env;
+ if (NODE_ENV === 'development') {
+ return true;
+ }
+ return isAntDesignPro();
+};
diff --git a/dubbo-admin-ui-antd/tests/PuppeteerEnvironment.js b/dubbo-admin-ui-antd/tests/PuppeteerEnvironment.js
new file mode 100644
index 0000000..6ad5040
--- /dev/null
+++ b/dubbo-admin-ui-antd/tests/PuppeteerEnvironment.js
@@ -0,0 +1,57 @@
+/*
+ * 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-next-line
+const NodeEnvironment = require('jest-environment-node');
+const getBrowser = require('./getBrowser');
+
+class PuppeteerEnvironment extends NodeEnvironment {
+ // Jest is not available here, so we have to reverse engineer
+ // the setTimeout function, see https://github.com/facebook/jest/blob/v23.1.0/packages/jest-runtime/src/index.js#L823
+ setTimeout(timeout) {
+ if (this.global.jasmine) {
+ // eslint-disable-next-line no-underscore-dangle
+ this.global.jasmine.DEFAULT_TIMEOUT_INTERVAL = timeout;
+ } else {
+ this.global[Symbol.for('TEST_TIMEOUT_SYMBOL')] = timeout;
+ }
+ }
+
+ async setup() {
+ const browser = await getBrowser();
+ const page = await browser.newPage();
+ this.global.browser = browser;
+ this.global.page = page;
+ }
+
+ async teardown() {
+ const { page, browser } = this.global;
+
+ if (page) {
+ await page.close();
+ }
+
+ if (browser) {
+ await browser.disconnect();
+ }
+
+ if (browser) {
+ await browser.close();
+ }
+ }
+}
+
+module.exports = PuppeteerEnvironment;
diff --git a/dubbo-admin-ui-antd/tests/beforeTest.js b/dubbo-admin-ui-antd/tests/beforeTest.js
new file mode 100644
index 0000000..e0c0552
--- /dev/null
+++ b/dubbo-admin-ui-antd/tests/beforeTest.js
@@ -0,0 +1,55 @@
+/*
+ * 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 global-require */
+/* eslint-disable import/no-extraneous-dependencies */
+const { execSync } = require('child_process');
+const { join } = require('path');
+const findChrome = require('carlo/lib/find_chrome');
+const detectInstaller = require('detect-installer');
+
+const installPuppeteer = () => {
+ // find can use package manger
+ const packages = detectInstaller(join(__dirname, '../../'));
+ // get installed package manger
+ const packageName = packages.find(detectInstaller.hasPackageCommand) || 'npm';
+ console.log(`🤖 will use ${packageName} install puppeteer`);
+ const command = `${packageName} ${packageName.includes('yarn') ? 'add' : 'i'} puppeteer`;
+ execSync(command, {
+ stdio: 'inherit',
+ });
+};
+
+const initPuppeteer = async () => {
+ try {
+ // eslint-disable-next-line import/no-unresolved
+ const findChromePath = await findChrome({});
+ const { executablePath } = findChromePath;
+ console.log(`🧲 find you browser in ${executablePath}`);
+ return;
+ } catch (error) {
+ console.log('🧲 no find chrome');
+ }
+
+ try {
+ require.resolve('puppeteer');
+ } catch (error) {
+ // need install puppeteer
+ await installPuppeteer();
+ }
+};
+
+initPuppeteer();
diff --git a/dubbo-admin-ui-antd/tests/getBrowser.js b/dubbo-admin-ui-antd/tests/getBrowser.js
new file mode 100644
index 0000000..83bd3e1
--- /dev/null
+++ b/dubbo-admin-ui-antd/tests/getBrowser.js
@@ -0,0 +1,61 @@
+/*
+ * 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 global-require */
+/* eslint-disable import/no-extraneous-dependencies */
+const findChrome = require('carlo/lib/find_chrome');
+
+const getBrowser = async () => {
+ try {
+ // eslint-disable-next-line import/no-unresolved
+ const puppeteer = require('puppeteer');
+ const browser = await puppeteer.launch({
+ args: [
+ '--disable-gpu',
+ '--disable-dev-shm-usage',
+ '--no-first-run',
+ '--no-zygote',
+ '--no-sandbox',
+ ],
+ });
+ return browser;
+ } catch (error) {
+ // console.log(error)
+ }
+
+ try {
+ // eslint-disable-next-line import/no-unresolved
+ const puppeteer = require('puppeteer-core');
+ const findChromePath = await findChrome({});
+ const { executablePath } = findChromePath;
+ const browser = await puppeteer.launch({
+ executablePath,
+ args: [
+ '--disable-gpu',
+ '--disable-dev-shm-usage',
+ '--no-first-run',
+ '--no-zygote',
+ '--no-sandbox',
+ ],
+ });
+ return browser;
+ } catch (error) {
+ console.log('🧲 no find chrome');
+ }
+ throw new Error('no find puppeteer');
+};
+
+module.exports = getBrowser;
diff --git a/dubbo-admin-ui-antd/tests/run-tests.js b/dubbo-admin-ui-antd/tests/run-tests.js
new file mode 100644
index 0000000..3aff026
--- /dev/null
+++ b/dubbo-admin-ui-antd/tests/run-tests.js
@@ -0,0 +1,68 @@
+/*
+ * 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 eslint-comments/disable-enable-pair */
+/* eslint-disable @typescript-eslint/no-var-requires */
+/* eslint-disable eslint-comments/no-unlimited-disable */
+const { spawn } = require('child_process');
+// eslint-disable-next-line import/no-extraneous-dependencies
+const { kill } = require('cross-port-killer');
+
+const env = Object.create(process.env);
+env.BROWSER = 'none';
+env.TEST = true;
+env.UMI_UI = 'none';
+env.PROGRESS = 'none';
+// flag to prevent multiple test
+let once = false;
+
+const startServer = spawn(/^win/.test(process.platform) ? 'npm.cmd' : 'npm', ['start'], {
+ env,
+});
+
+startServer.stderr.on('data', (data) => {
+ // eslint-disable-next-line
+ console.log(data.toString());
+});
+
+startServer.on('exit', () => {
+ kill(process.env.PORT || 8000);
+});
+
+console.log('Starting development server for e2e tests...');
+startServer.stdout.on('data', (data) => {
+ console.log(data.toString());
+ // hack code , wait umi
+ if (
+ (!once && data.toString().indexOf('Compiled successfully') >= 0) ||
+ data.toString().indexOf('Theme generated successfully') >= 0
+ ) {
+ // eslint-disable-next-line
+ once = true;
+ console.log('Development server is started, ready to run tests.');
+ const testCmd = spawn(
+ /^win/.test(process.platform) ? 'npm.cmd' : 'npm',
+ ['test', '--', '--maxWorkers=1', '--runInBand'],
+ {
+ stdio: 'inherit',
+ },
+ );
+ testCmd.on('exit', (code) => {
+ startServer.kill();
+ process.exit(code);
+ });
+ }
+});
diff --git a/dubbo-admin-ui-antd/tests/setupTests.js b/dubbo-admin-ui-antd/tests/setupTests.js
new file mode 100644
index 0000000..784675e
--- /dev/null
+++ b/dubbo-admin-ui-antd/tests/setupTests.js
@@ -0,0 +1,26 @@
+/*
+ * 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.
+ */
+ // do some test init
+
+const localStorageMock = {
+ getItem: jest.fn(),
+ setItem: jest.fn(),
+ removeItem: jest.fn(),
+ clear: jest.fn(),
+};
+
+global.localStorage = localStorageMock;
diff --git a/dubbo-admin-ui-antd/tsconfig.json b/dubbo-admin-ui-antd/tsconfig.json
new file mode 100644
index 0000000..186a435
--- /dev/null
+++ b/dubbo-admin-ui-antd/tsconfig.json
@@ -0,0 +1,40 @@
+{
+ "compilerOptions": {
+ "outDir": "build/dist",
+ "module": "esnext",
+ "target": "esnext",
+ "lib": ["esnext", "dom"],
+ "sourceMap": true,
+ "baseUrl": ".",
+ "jsx": "react-jsx",
+ "allowSyntheticDefaultImports": true,
+ "moduleResolution": "node",
+ "forceConsistentCasingInFileNames": true,
+ "noImplicitReturns": true,
+ "suppressImplicitAnyIndexErrors": true,
+ "noUnusedLocals": true,
+ "allowJs": true,
+ "skipLibCheck": true,
+ "experimentalDecorators": true,
+ "strict": true,
+ "paths": {
+ "@/*": ["./src/*"],
+ "@@/*": ["./src/.umi/*"]
+ }
+ },
+ "include": [
+ "mock/**/*",
+ "src/**/*",
+ "tests/**/*",
+ "test/**/*",
+ "__test__/**/*",
+ "typings/**/*",
+ "config/**/*",
+ ".eslintrc.js",
+ ".stylelintrc.js",
+ ".prettierrc.js",
+ "jest.config.js",
+ "mock/*"
+ ],
+ "exclude": ["node_modules", "build", "dist", "scripts", "src/.umi/*", "webpack", "jest"]
+}