This is an automated email from the ASF dual-hosted git repository.

dengliming pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/shenyu-dashboard.git


The following commit(s) were added to refs/heads/master by this push:
     new c3946cf2 [type:feat]Add namespace management interface and plugin 
management interface adaptation and transformation (#459)
c3946cf2 is described below

commit c3946cf20d0f0dbb77493b342de2a4ed02fefd0b
Author: xcsnx <1192709...@qq.com>
AuthorDate: Thu Jul 18 12:50:53 2024 +0800

    [type:feat]Add namespace management interface and plugin management 
interface adaptation and transformation (#459)
    
    * namespace module
    
    * fix
    
    * fix code checkstyle
    
    * move namespace position and fix bug
    
    * fix cr
    
    * rename pluginNamespace to namespacePlugin
    
    * fix
    
    * fix cr
    
    * update
    
    * fix
    
    * fix
    
    ---------
    
    Co-authored-by: ‘xcsnx’ <‘1192709...@qq.com’>
---
 src/common/menu.js                                 |  10 +
 src/common/router.js                               |  23 +-
 src/locales/en-US.json                             |  14 +-
 src/locales/zh-CN.json                             |  14 +-
 src/models/namespace.js                            | 133 ++++++++
 src/models/namespacePlugin.js                      | 182 +++++++++++
 src/routes/System/Namespace/AddModal.js            | 132 ++++++++
 src/routes/System/{Plugin => Namespace}/index.js   | 361 ++++++---------------
 src/routes/System/NamespacePlugin/AddModal.js      | 242 ++++++++++++++
 .../System/{Plugin => NamespacePlugin}/index.js    | 121 +++----
 src/routes/System/Plugin/index.js                  |  18 -
 src/services/api.js                                |  98 ++++++
 src/utils/namespacePlugin.js                       | 103 ++++++
 13 files changed, 1090 insertions(+), 361 deletions(-)

diff --git a/src/common/menu.js b/src/common/menu.js
index fbb29507..1f092a69 100644
--- a/src/common/menu.js
+++ b/src/common/menu.js
@@ -65,6 +65,16 @@ export const menuData = [
         path: "plugin",
         locale: "SHENYU.MENU.SYSTEM.MANAGMENT.PLUGIN",
       },
+      {
+        name: getIntlContent("SHENYU.MENU.SYSTEM.MANAGMENT.NAMESPACEPLUGIN"),
+        path: "namespacePlugin",
+        locale: "SHENYU.MENU.SYSTEM.MANAGMENT.NAMESPACEPLUGIN",
+      },
+      {
+        name: getIntlContent("SHENYU.MENU.SYSTEM.MANAGMENT.NAMESPACE"),
+        path: "namespace",
+        locale: "SHENYU.MENU.SYSTEM.MANAGMENT.NAMESPACE",
+      },
       {
         name: getIntlContent("SHENYU.PLUGIN.PLUGINHANDLE"),
         path: "pluginhandle",
diff --git a/src/common/router.js b/src/common/router.js
index 328f54dc..53b78a53 100644
--- a/src/common/router.js
+++ b/src/common/router.js
@@ -113,7 +113,6 @@ export const getRouterData = (app) => {
       ),
     },
     "/system/role": {
-      // 角色管理
       component: dynamicWrapper(
         app,
         ["role"],
@@ -121,7 +120,6 @@ export const getRouterData = (app) => {
       ),
     },
     "/system/manage": {
-      // 用户管理
       component: dynamicWrapper(
         app,
         ["manage", "dataPermission"],
@@ -129,7 +127,6 @@ export const getRouterData = (app) => {
       ),
     },
     "/system/resource": {
-      // 资源管理
       component: dynamicWrapper(
         app,
         ["resource"],
@@ -137,15 +134,20 @@ export const getRouterData = (app) => {
       ),
     },
     "/system/alert": {
-      // 告警管理
       component: dynamicWrapper(
         app,
         ["alert"],
         () => import("../routes/System/Alert"),
       ),
     },
+    "/config/namespace": {
+      component: dynamicWrapper(
+        app,
+        ["namespace"],
+        () => import("../routes/System/Namespace"),
+      ),
+    },
     "/config/metadata": {
-      // 元数据管理
       component: dynamicWrapper(
         app,
         ["metadata"],
@@ -153,15 +155,20 @@ export const getRouterData = (app) => {
       ),
     },
     "/config/plugin": {
-      // 插件管理
       component: dynamicWrapper(
         app,
         ["plugin"],
         () => import("../routes/System/Plugin"),
       ),
     },
+    "/config/namespacePlugin": {
+      component: dynamicWrapper(
+        app,
+        ["namespacePlugin"],
+        () => import("../routes/System/NamespacePlugin"),
+      ),
+    },
     "/config/pluginhandle": {
-      // 插件处理管理
       component: dynamicWrapper(
         app,
         ["pluginHandle"],
@@ -169,7 +176,6 @@ export const getRouterData = (app) => {
       ),
     },
     "/config/auth": {
-      // 认证管理
       component: dynamicWrapper(
         app,
         ["auth"],
@@ -177,7 +183,6 @@ export const getRouterData = (app) => {
       ),
     },
     "/config/dict": {
-      // 字典管理
       component: dynamicWrapper(
         app,
         ["shenyuDict"],
diff --git a/src/locales/en-US.json b/src/locales/en-US.json
index e99a8125..7e2a7779 100644
--- a/src/locales/en-US.json
+++ b/src/locales/en-US.json
@@ -69,11 +69,12 @@
   "SHENYU.MENU.SYSTEM.MANAGMENT.USER": "User",
   "SHENYU.MENU.SYSTEM.MANAGMENT.RESOURCE": "Resource",
   "SHENYU.MENU.SYSTEM.MANAGMENT.ALERT": "Alert",
-  "SHENYU.MENU.SYSTEM.MANAGMENT.PLUGIN": "Plugin",
+  "SHENYU.MENU.SYSTEM.MANAGMENT.PLUGIN": "PluginTemplate",
   "SHENYU.MENU.SYSTEM.MANAGMENT.PLUGINHANDLE": "PluginHandle",
   "SHENYU.MENU.SYSTEM.MANAGMENT.AUTHEN": "Authentication",
   "SHENYU.MENU.SYSTEM.MANAGMENT.METADATA": "Metadata",
   "SHENYU.MENU.SYSTEM.MANAGMENT.DICTIONARY": "Dictionary",
+  "SHENYU.MENU.SYSTEM.MANAGMENT.NAMESPACE": "Namespace",
   "SHENYU.MENU.CONFIG.MANAGMENT": "BasicConfig",
   "SHENYU.PLUGIN.SELECTOR.LIST.TITLE": "SelectorList",
   "SHENYU.PLUGIN.SELECTOR.LIST.ADD": "Add",
@@ -430,5 +431,14 @@
   "SHENYU.DISCOVERY.SELECTOR.CONFIG.IMPORT.CONFIRM": "Configuration Import 
Confirmation",
   "SHENYU.DISCOVERY.SELECTOR.DELETE.CONFIRM": "Are you sure to delete this 
selector?",
   "SHENYU.DISCOVERY.SELECTOR.CONFIG.IMPORT.SURE": "Import",
-  "SHENYU.COMMON.REFRESH": "Refresh"
+  "SHENYU.COMMON.REFRESH": "Refresh",
+  "SHENYU.SYSTEM.NAMESPACE": "Namespace",
+  "SHENYU.SYSTEM.NAMESPACE.NAMESPACEID": "namespaceId",
+  "SHENYU.SYSTEM.NAMESPACE.NAME": "name",
+  "SHENYU.SYSTEM.NAMESPACE.DESC": "description",
+  "SHENYU.NAMESPACE.INPUTNAME":"namespaceName",
+  "SHENYU.NAMESPACE.INPUTDESC":"description",
+  "SHENYU.NAMESPACE.INPUTNAMESPACEID":"namespaceId",
+  "SHENYU.NAMESPACE.ALERTNAMESPACEID":"Automatically generated namespaceId",
+  "SHENYU.MENU.SYSTEM.MANAGMENT.NAMESPACEPLUGIN":"Plugin"
 }
diff --git a/src/locales/zh-CN.json b/src/locales/zh-CN.json
index ee6e6500..d71cf9c3 100644
--- a/src/locales/zh-CN.json
+++ b/src/locales/zh-CN.json
@@ -70,12 +70,13 @@
   "SHENYU.MENU.SYSTEM.MANAGMENT.USER": "用户管理",
   "SHENYU.MENU.SYSTEM.MANAGMENT.RESOURCE": "资源管理",
   "SHENYU.MENU.SYSTEM.MANAGMENT.ALERT": "告警管理",
-  "SHENYU.MENU.SYSTEM.MANAGMENT.PLUGIN": "插件管理",
+  "SHENYU.MENU.SYSTEM.MANAGMENT.PLUGIN": "插件模板管理",
   "SHENYU.MENU.SYSTEM.MANAGMENT.PLUGINHANDLE": "插件处理管理",
   "SHENYU.MENU.SYSTEM.MANAGMENT.AUTHEN": "认证管理",
   "SHENYU.MENU.SYSTEM.MANAGMENT.METADATA": "元数据管理",
   "SHENYU.MENU.SYSTEM.MANAGMENT.DICTIONARY": "字典管理",
   "SHENYU.MENU.CONFIG.MANAGMENT": "基础配置",
+  "SHENYU.MENU.SYSTEM.MANAGMENT.NAMESPACE": "命名空间管理",
   "SHENYU.PLUGIN.SELECTOR.LIST.TITLE": "选择器列表",
   "SHENYU.PLUGIN.SELECTOR.LIST.ADD": "添加选择器",
   "SHENYU.PLUGIN.SELECTOR.BATCH.OPENED": "批量开启",
@@ -436,5 +437,14 @@
   "SHENYU.DISCOVERY.SELECTOR.CONFIG.IMPORT.CONFIRM": "后台配置导入确认",
   "SHENYU.DISCOVERY.SELECTOR.CONFIG.IMPORT.SURE": "导入",
   "SHENYU.DISCOVERY.SELECTOR.DELETE.CONFIRM": "确定删除该选择器吗?",
-  "SHENYU.COMMON.REFRESH": "刷新"
+  "SHENYU.COMMON.REFRESH": "刷新",
+  "SHENYU.SYSTEM.NAMESPACE": "命名空间",
+  "SHENYU.SYSTEM.NAMESPACE.NAMESPACEID": "namespaceId",
+  "SHENYU.SYSTEM.NAMESPACE.NAME": "名称",
+  "SHENYU.SYSTEM.NAMESPACE.DESC": "描述",
+  "SHENYU.NAMESPACE.INPUTNAME":"请输入命名空间名称",
+  "SHENYU.NAMESPACE.INPUTDESC":"请输入命名空间描述",
+  "SHENYU.NAMESPACE.INPUTNAMESPACEID":"请输入namespaceId",
+  "SHENYU.NAMESPACE.ALERTNAMESPACEID":"系统自动生成namespaceId",
+  "SHENYU.MENU.SYSTEM.MANAGMENT.NAMESPACEPLUGIN":"插件管理"
 }
diff --git a/src/models/namespace.js b/src/models/namespace.js
new file mode 100644
index 00000000..13864c6d
--- /dev/null
+++ b/src/models/namespace.js
@@ -0,0 +1,133 @@
+/*
+ * 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 { message } from "antd";
+import {
+  getAllNamespaces,
+  findNamespace,
+  insertOrUpdateNamespace,
+  deleteNamespace,
+} from "../services/api";
+import { getIntlContent } from "../utils/IntlUtils";
+
+export default {
+  namespace: "namespace",
+
+  state: {
+    namespaceList: [],
+    total: 0,
+  },
+
+  effects: {
+    *fetch(params, { call, put }) {
+      const { payload } = params;
+      const json = yield call(getAllNamespaces, payload);
+      if (json.code === 200) {
+        let { page, dataList } = json.data;
+        dataList = dataList.map((item) => {
+          item.key = item.id;
+          return item;
+        });
+        yield put({
+          type: "saveNamespaces",
+          payload: {
+            total: page.totalCount,
+            dataList,
+          },
+        });
+      }
+    },
+    *fetchItem(params, { call }) {
+      const { payload, callback } = params;
+      const json = yield call(findNamespace, payload);
+      if (json.code === 200) {
+        const plugin = json.data;
+        callback(plugin);
+      }
+    },
+    *add(params, { call, put }) {
+      const { payload, callback, fetchValue } = params;
+      const json = yield call(insertOrUpdateNamespace, payload);
+      if (json.code === 200) {
+        message.success(getIntlContent("SHENYU.COMMON.RESPONSE.ADD.SUCCESS"));
+        callback();
+        yield put({ type: "reload", fetchValue });
+      } else {
+        message.warn(json.message);
+      }
+    },
+    *delete(params, { call, put }) {
+      const { payload, fetchValue, callback } = params;
+      const { list } = payload;
+      const json = yield call(deleteNamespace, { list });
+      if (json.code === 200) {
+        message.success(
+          getIntlContent("SHENYU.COMMON.RESPONSE.DELETE.SUCCESS"),
+        );
+        callback();
+        yield put({ type: "reload", fetchValue });
+      } else {
+        message.warn(json.message);
+      }
+    },
+    *update(params, { call, put }) {
+      const { payload, callback, fetchValue } = params;
+      const json = yield call(insertOrUpdateNamespace, payload);
+      if (json.code === 200) {
+        message.success(
+          getIntlContent("SHENYU.COMMON.RESPONSE.UPDATE.SUCCESS"),
+        );
+        callback();
+        if (fetchValue) {
+          yield put({ type: "reload", fetchValue });
+        }
+      } else {
+        message.warn(json.message);
+      }
+    },
+
+    *reload(params, { put }) {
+      const { fetchValue } = params;
+      const { name, currentPage, enabled, pageSize } = fetchValue;
+      const payload = { name, enabled, currentPage, pageSize };
+      yield put({ type: "fetch", payload });
+    },
+  },
+
+  reducers: {
+    saveNamespaces(state, { payload }) {
+      return {
+        ...state,
+        namespaceList: payload.dataList,
+        total: payload.total,
+      };
+    },
+    updatePlugins(state, { payload }) {
+      let pluginList = state.pluginList;
+      pluginList = pluginList.map((item) => {
+        if (item.id === payload.id) {
+          item.enabled = payload.enabled;
+        }
+        return item;
+      });
+      return {
+        ...state,
+        pluginList,
+      };
+    },
+  },
+};
diff --git a/src/models/namespacePlugin.js b/src/models/namespacePlugin.js
new file mode 100644
index 00000000..ad8fc328
--- /dev/null
+++ b/src/models/namespacePlugin.js
@@ -0,0 +1,182 @@
+/*
+ * 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 { message } from "antd";
+import {
+  addPlugin,
+  fetchPluginHandleByPluginId,
+  addPluginResource,
+  findNamespacePlugin,
+  getAllNamespacePlugins,
+  updateNamespacePluginEnabled,
+  updateNamespacePlugin,
+  deleteNamespacePlugin,
+  asyncNamespacePlugin,
+} from "../services/api";
+import { getIntlContent } from "../utils/IntlUtils";
+
+export default {
+  namespace: "namespacePlugin",
+
+  state: {
+    namespacePluginList: [],
+    total: 0,
+  },
+
+  effects: {
+    *fetch(params, { call, put }) {
+      const { payload } = params;
+      const json = yield call(getAllNamespacePlugins, payload);
+      if (json.code === 200) {
+        let { page, dataList } = json.data;
+        dataList = dataList.map((item) => {
+          item.key = item.id;
+          return item;
+        });
+        yield put({
+          type: "savePlugins",
+          payload: {
+            total: page.totalCount,
+            dataList,
+          },
+        });
+      }
+    },
+    *fetchItem(params, { call }) {
+      const { payload, callback } = params;
+      const json = yield call(findNamespacePlugin, payload);
+      if (json.code === 200) {
+        const plugin = json.data;
+        callback(plugin);
+      }
+    },
+    *add(params, { call, put }) {
+      const { payload, callback, fetchValue } = params;
+      const json = yield call(addPlugin, payload);
+      if (json.code === 200) {
+        message.success(getIntlContent("SHENYU.COMMON.RESPONSE.ADD.SUCCESS"));
+        callback();
+        yield put({ type: "reload", fetchValue });
+      } else {
+        message.warn(json.message);
+      }
+    },
+    *delete(params, { call, put }) {
+      const { payload, fetchValue, callback } = params;
+      // const { list } = payload;
+      const json = yield call(deleteNamespacePlugin, payload);
+      if (json.code === 200) {
+        message.success(
+          getIntlContent("SHENYU.COMMON.RESPONSE.DELETE.SUCCESS"),
+        );
+        callback();
+        yield put({ type: "reload", fetchValue });
+      } else {
+        message.warn(json.message);
+      }
+    },
+    *update(params, { call, put }) {
+      const { payload, callback, fetchValue } = params;
+      const json = yield call(updateNamespacePlugin, payload);
+      if (json.code === 200) {
+        message.success(
+          getIntlContent("SHENYU.COMMON.RESPONSE.UPDATE.SUCCESS"),
+        );
+        callback();
+        if (fetchValue) {
+          yield put({ type: "reload", fetchValue });
+        }
+      } else {
+        message.warn(json.message);
+      }
+    },
+    *updateEn(params, { call, put }) {
+      const { payload, fetchValue, callback } = params;
+      const json = yield call(updateNamespacePluginEnabled, payload);
+
+      if (json.code === 200) {
+        message.success(
+          getIntlContent("SHENYU.COMMON.RESPONSE.UPDATE.SUCCESS"),
+        );
+        callback();
+        if (fetchValue) {
+          yield put({ type: "reload", fetchValue });
+        }
+      } else {
+        message.warn(json.message);
+      }
+    },
+
+    *reload(params, { put }) {
+      const { fetchValue } = params;
+      const { name, currentPage, enabled, pageSize } = fetchValue;
+      const payload = { name, enabled, currentPage, pageSize };
+      yield put({ type: "fetch", payload });
+    },
+
+    *asyncAll(_, { call }) {
+      const json = yield call(asyncNamespacePlugin);
+      if (json.code === 200) {
+        message.success(getIntlContent("SHENYU.COMMON.RESPONSE.SYNC.SUCCESS"));
+      } else {
+        message.warn(json.message);
+      }
+    },
+
+    *fetchByPluginId(params, { call }) {
+      const { payload, callback } = params;
+      const json = yield call(fetchPluginHandleByPluginId, payload);
+      if (json.code === 200) {
+        callback(json);
+      }
+    },
+
+    *createPluginResource(params, { call }) {
+      const { payload, callback } = params;
+      const json = yield call(addPluginResource, payload);
+      if (json.code === 200) {
+        message.success(getIntlContent("SHENYU.COMMON.RESPONSE.ADD.SUCCESS"));
+        callback();
+      } else {
+        message.warn(json.message);
+      }
+    },
+  },
+
+  reducers: {
+    savePlugins(state, { payload }) {
+      return {
+        ...state,
+        namespacePluginList: payload.dataList,
+        total: payload.total,
+      };
+    },
+    updatePlugins(state, { payload }) {
+      let pluginList = state.pluginList;
+      pluginList = pluginList.map((item) => {
+        if (item.id === payload.id) {
+          item.enabled = payload.enabled;
+        }
+        return item;
+      });
+      return {
+        ...state,
+        pluginList,
+      };
+    },
+  },
+};
diff --git a/src/routes/System/Namespace/AddModal.js 
b/src/routes/System/Namespace/AddModal.js
new file mode 100644
index 00000000..852adfc9
--- /dev/null
+++ b/src/routes/System/Namespace/AddModal.js
@@ -0,0 +1,132 @@
+/*
+ * 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, { Component } from "react";
+import { Modal, Form, Input } from "antd";
+import { getIntlContent } from "../../../utils/IntlUtils";
+
+const FormItem = Form.Item;
+
+class AddModal extends Component {
+  handleSubmit = (e) => {
+    const { form, handleOk, id = "" } = this.props;
+    e.preventDefault();
+    form.validateFieldsAndScroll((err, values) => {
+      if (!err) {
+        handleOk({ ...values, id });
+      }
+    });
+  };
+
+  render() {
+    let {
+      handleCancel,
+      form,
+      name = "",
+      description = "",
+      namespaceId = "",
+    } = this.props;
+
+    const { getFieldDecorator } = form;
+    const formItemLayout = {
+      labelCol: {
+        sm: { span: 6 },
+      },
+      wrapperCol: {
+        sm: { span: 18 },
+      },
+    };
+    return (
+      <Modal
+        width={450}
+        centered
+        title={getIntlContent("SHENYU.SYSTEM.NAMESPACE")}
+        visible
+        okText={getIntlContent("SHENYU.COMMON.SURE")}
+        cancelText={getIntlContent("SHENYU.COMMON.CALCEL")}
+        onOk={this.handleSubmit}
+        onCancel={handleCancel}
+      >
+        <Form onSubmit={this.handleSubmit} className="login-form">
+          <FormItem
+            label={getIntlContent("SHENYU.SYSTEM.NAMESPACE.NAME")}
+            {...formItemLayout}
+          >
+            {getFieldDecorator("name", {
+              rules: [
+                {
+                  required: true,
+                  message: getIntlContent("SHENYU.NAMESPACE.INPUTNAME"),
+                },
+              ],
+              initialValue: name,
+            })(
+              <Input
+                allowClear
+                placeholder={getIntlContent("SHENYU.NAMESPACE.INPUTNAME")}
+              />,
+            )}
+          </FormItem>
+          <FormItem
+            label={getIntlContent("SHENYU.SYSTEM.NAMESPACE.DESC")}
+            {...formItemLayout}
+          >
+            {getFieldDecorator("description", {
+              rules: [
+                {
+                  required: false,
+                  message: getIntlContent("SHENYU.NAMESPACE.INPUTDESC"),
+                },
+              ],
+              initialValue: description,
+            })(
+              <Input.TextArea
+                autoSize
+                allowClear
+                placeholder={getIntlContent("SHENYU.NAMESPACE.INPUTDESC")}
+              />,
+            )}
+          </FormItem>
+          <FormItem
+            label={getIntlContent("SHENYU.SYSTEM.NAMESPACE.NAMESPACEID")}
+            {...formItemLayout}
+          >
+            {getFieldDecorator("namespaceId", {
+              rules: [
+                {
+                  required: false,
+                  message: getIntlContent("SHENYU.NAMESPACE.ALERTNAMESPACEID"),
+                },
+              ],
+              initialValue: namespaceId,
+            })(
+              <Input
+                allowClear
+                disabled={true}
+                placeholder={getIntlContent(
+                  "SHENYU.NAMESPACE.ALERTNAMESPACEID",
+                )}
+              />,
+            )}
+          </FormItem>
+        </Form>
+      </Modal>
+    );
+  }
+}
+
+export default Form.create()(AddModal);
diff --git a/src/routes/System/Plugin/index.js 
b/src/routes/System/Namespace/index.js
similarity index 51%
copy from src/routes/System/Plugin/index.js
copy to src/routes/System/Namespace/index.js
index ea442965..3cdda422 100644
--- a/src/routes/System/Plugin/index.js
+++ b/src/routes/System/Namespace/index.js
@@ -16,38 +16,21 @@
  */
 
 import React, { Component } from "react";
-import {
-  Table,
-  Input,
-  Button,
-  message,
-  Popconfirm,
-  Select,
-  Popover,
-  Tag,
-  Typography,
-  Switch,
-} from "antd";
+import { Table, Input, Button, message, Popconfirm } from "antd";
 import { connect } from "dva";
-import { Link } from "dva/router";
 import { resizableComponents } from "../../../utils/resizable";
 import AddModal from "./AddModal";
 import { getCurrentLocale, getIntlContent } from "../../../utils/IntlUtils";
 import AuthButton from "../../../utils/AuthButton";
 import { refreshAuthMenus } from "../../../utils/AuthRoute";
-import { getUpdateModal, updatePluginsEnabled } from "../../../utils/plugin";
 
-const { Text } = Typography;
-
-const { Option } = Select;
-
-@connect(({ plugin, resource, loading, global }) => ({
-  plugin,
+@connect(({ namespace, resource, loading, global }) => ({
+  namespace,
   authMenu: resource.authMenu,
   language: global.language,
-  loading: loading.effects["plugin/fetch"],
+  loading: loading.effects["namespace/fetch"],
 }))
-export default class Plugin extends Component {
+export default class Namespace extends Component {
   components = resizableComponents;
 
   constructor(props) {
@@ -57,6 +40,8 @@ export default class Plugin extends Component {
       pageSize: 12,
       selectedRowKeys: [],
       name: "",
+      namespaceId: "",
+      // eslint-disable-next-line react/no-unused-state
       enabled: null,
       popup: "",
       localeName: window.sessionStorage.getItem("locale")
@@ -68,14 +53,14 @@ export default class Plugin extends Component {
 
   componentDidMount() {
     this.query();
-    this.initPluginColumns();
+    this.initNamespaceColumns();
   }
 
   componentDidUpdate() {
     const { language } = this.props;
     const { localeName } = this.state;
     if (language !== localeName) {
-      this.initPluginColumns();
+      this.initNamespaceColumns();
       this.changeLocale(language);
     }
   }
@@ -98,10 +83,10 @@ export default class Plugin extends Component {
   };
 
   currentQueryPayload = (override) => {
-    const { name, enabled, currentPage, pageSize } = this.state;
+    const { name, namespaceId, currentPage, pageSize } = this.state;
     return {
       name,
-      enabled,
+      namespaceId,
       currentPage,
       pageSize,
       ...override,
@@ -111,7 +96,7 @@ export default class Plugin extends Component {
   query = () => {
     const { dispatch } = this.props;
     dispatch({
-      type: "plugin/fetch",
+      type: "namespace/fetch",
       payload: this.currentQueryPayload(),
     });
   };
@@ -134,39 +119,39 @@ export default class Plugin extends Component {
 
   editClick = (record) => {
     const { dispatch } = this.props;
-    getUpdateModal({
-      pluginId: record.id,
-      dispatch,
-      fetchValue: this.currentQueryPayload(),
-      callback: (popup) => {
-        this.setState({ popup });
-      },
-      updatedCallback: () => {
-        this.setState({ selectedRowKeys: [] });
-        this.closeModal(true);
-      },
-      canceledCallback: () => {
-        this.closeModal();
-      },
-    });
-  };
 
-  resourceClick = (record) => {
-    // code here...
-    const { dispatch } = this.props;
-    const { name, role, sort, config, id, enabled } = record;
     dispatch({
-      type: "plugin/createPluginResource",
+      type: "namespace/fetchItem",
       payload: {
-        name,
-        role,
-        sort,
-        config,
-        id,
-        enabled,
+        id: record.namespaceId,
       },
-      callback: () => {
-        refreshAuthMenus({ dispatch });
+      callback: (namespace) => {
+        this.setState({
+          popup: (
+            <AddModal
+              {...namespace}
+              handleOk={(values) => {
+                const { name, description } = values;
+                dispatch({
+                  type: "namespace/update",
+                  payload: {
+                    id: record.id,
+                    name,
+                    description,
+                    namespaceId: record.namespaceId,
+                  },
+                  fetchValue: this.currentQueryPayload(),
+                  callback: () => {
+                    this.closeModal();
+                  },
+                });
+              }}
+              handleCancel={() => {
+                this.closeModal();
+              }}
+            />
+          ),
+        });
       },
     });
   };
@@ -175,8 +160,8 @@ export default class Plugin extends Component {
     this.setState({ name: e.target.value }, this.query);
   };
 
-  enabledOnchange = (e) => {
-    this.setState({ enabled: e }, this.query);
+  searchNamespaceIdOnchange = (e) => {
+    this.setState({ namespaceId: e.target.value }, this.query);
   };
 
   searchClick = () => {
@@ -188,7 +173,7 @@ export default class Plugin extends Component {
     const { selectedRowKeys } = this.state;
     if (selectedRowKeys && selectedRowKeys.length > 0) {
       dispatch({
-        type: "plugin/delete",
+        type: "namespace/delete",
         payload: {
           list: selectedRowKeys,
         },
@@ -213,16 +198,12 @@ export default class Plugin extends Component {
           disabled={false}
           handleOk={(values) => {
             const { dispatch } = this.props;
-            const { name, enabled, role, config, sort, file } = values;
+            const { name, description } = values;
             dispatch({
-              type: "plugin/add",
+              type: "namespace/add",
               payload: {
                 name,
-                config,
-                role,
-                enabled,
-                sort,
-                file,
+                description,
               },
               fetchValue: this.currentQueryPayload(),
               callback: () => {
@@ -239,52 +220,6 @@ export default class Plugin extends Component {
     });
   };
 
-  // 数据状态切换
-  statusSwitch = ({ list, enabled, callback }) => {
-    const { dispatch } = this.props;
-    updatePluginsEnabled({
-      list,
-      dispatch,
-      callback,
-      enabled,
-      fetchValue: this.currentQueryPayload(),
-    });
-  };
-
-  // 批量启用或禁用
-  enableClick = () => {
-    const { dispatch } = this.props;
-    const { selectedRowKeys } = this.state;
-    if (selectedRowKeys && selectedRowKeys.length > 0) {
-      dispatch({
-        type: "plugin/fetchItem",
-        payload: {
-          id: selectedRowKeys[0],
-        },
-        callback: (user) => {
-          this.statusSwitch({
-            list: selectedRowKeys,
-            enabled: !user.enabled,
-            callback: () => {
-              this.setState({ selectedRowKeys: [] });
-            },
-          });
-        },
-      });
-    } else {
-      message.destroy();
-      message.warn("Please select data");
-    }
-  };
-
-  // 同步插件数据
-  syncAllClick = () => {
-    const { dispatch } = this.props;
-    dispatch({
-      type: "plugin/asyncAll",
-    });
-  };
-
   changeLocale(locale) {
     this.setState({
       localeName: locale,
@@ -292,134 +227,41 @@ export default class Plugin extends Component {
     getCurrentLocale(this.state.localeName);
   }
 
-  initPluginColumns() {
+  initNamespaceColumns() {
     this.setState({
       columns: [
         {
           align: "center",
-          title: getIntlContent("SHENYU.PLUGIN.PLUGIN.NAME"),
-          dataIndex: "name",
-          key: "name",
+          title: getIntlContent("SHENYU.SYSTEM.NAMESPACE.NAMESPACEID"),
+          dataIndex: "namespaceId",
+          key: "namespaceId",
           ellipsis: true,
-          width: 120,
-          render: (text, record) => {
-            return record.url ? (
-              <Link to={record.url}>
-                <div
-                  style={{
-                    color: "#1890ff",
-                    fontWeight: "bold",
-                    textDecorationLine: "underline",
-                  }}
-                >
-                  {text || "----"}
-                </div>
-              </Link>
-            ) : (
-              <div style={{ color: "#260033", fontWeight: "bold" }}>
-                {text || "----"}
-              </div>
-            );
+          width: 300,
+          render: (text) => {
+            return <div style={{ color: "#1f640a" }}>{text || "----"}</div>;
           },
         },
         {
           align: "center",
-          title: getIntlContent("SHENYU.SYSTEM.ROLE"),
-          dataIndex: "role",
+          title: getIntlContent("SHENYU.SYSTEM.NAMESPACE.NAME"),
+          dataIndex: "name",
           ellipsis: true,
-          key: "role",
-          width: 120,
-          sorter: (a, b) => (a.role > b.role ? 1 : -1),
+          key: "name",
+          width: 240,
           render: (text) => {
             return <div style={{ color: "#1f640a" }}>{text || "----"}</div>;
           },
         },
         {
           align: "center",
-          title: getIntlContent("SHENYU.PLUGIN.SORT"),
-          dataIndex: "sort",
+          title: getIntlContent("SHENYU.SYSTEM.NAMESPACE.DESC"),
+          dataIndex: "description",
           ellipsis: true,
-          key: "sort",
-          width: 120,
-          sorter: (a, b) => (a.role > b.role ? 1 : -1),
+          key: "desc",
           render: (text) => {
             return <div style={{ color: "#014955" }}>{text}</div>;
           },
         },
-        {
-          align: "center",
-          title: getIntlContent("SHENYU.COMMON.SETTING"),
-          dataIndex: "config",
-          key: "config",
-          ellipsis: true,
-          render: (text, record) => {
-            const tag = (
-              <div>
-                <Tag color="#9dd3a8">{record.name}</Tag>
-                <Tag color="#CCCC99">{record.role}</Tag>
-                <Tag color="#3b9a9c">{record.sort}</Tag>
-              </div>
-            );
-            const t = JSON.stringify(
-              JSON.parse(text !== null && text.length > 0 ? text : "{}"),
-              null,
-              4,
-            );
-            const content = (
-              <div>
-                <Text 
type="secondary">{`${getIntlContent("SHENYU.SYSTEM.CREATETIME")}: 
${record.dateCreated}`}</Text>
-                <br />
-                <Text 
type="secondary">{`${getIntlContent("SHENYU.SYSTEM.UPDATETIME")}: 
${record.dateUpdated}`}</Text>
-                <hr />
-                <div style={{ fontWeight: "bold" }}>
-                  <pre>
-                    <code>{t}</code>
-                  </pre>
-                </div>
-              </div>
-            );
-            return (
-              <Popover content={content} title={tag}>
-                <div>{text || "----"}</div>
-              </Popover>
-            );
-          },
-        },
-        {
-          align: "center",
-          title: getIntlContent("SHENYU.SYSTEM.STATUS"),
-          dataIndex: "enabled",
-          key: "enabled",
-          ellipsis: true,
-          width: 80,
-          sorter: (a, b) =>
-            (a.enabled || "-1") > (b.enabled || "-1") ? 1 : -1,
-          render: (text, row) => (
-            <AuthButton
-              perms="system:plugin:disable"
-              noAuth={
-                text ? (
-                  <div className="open">
-                    {getIntlContent("SHENYU.COMMON.OPEN")}
-                  </div>
-                ) : (
-                  <div className="close">
-                    {getIntlContent("SHENYU.COMMON.CLOSE")}
-                  </div>
-                )
-              }
-            >
-              <Switch
-                checkedChildren={getIntlContent("SHENYU.COMMON.OPEN")}
-                unCheckedChildren={getIntlContent("SHENYU.COMMON.CLOSE")}
-                checked={text}
-                onChange={(checked) => {
-                  this.statusSwitch({ list: [row.id], enabled: checked });
-                }}
-              />
-            </AuthButton>
-          ),
-        },
         {
           align: "center",
           title: getIntlContent("SHENYU.COMMON.OPERAT"),
@@ -429,9 +271,12 @@ export default class Plugin extends Component {
           width: 160,
           fixed: "right",
           render: (text, record) => {
-            return (
+            return record.namespaceId ===
+              "649330b6-c2d7-4edc-be8e-8a54df9eb385" ? (
+              ""
+            ) : (
               <div className="optionParts">
-                <AuthButton perms="system:plugin:edit">
+                <AuthButton perms="system:namespace:edit">
                   <div
                     className="edit"
                     onClick={() => {
@@ -441,15 +286,29 @@ export default class Plugin extends Component {
                     {getIntlContent("SHENYU.SYSTEM.EDITOR")}
                   </div>
                 </AuthButton>
-                <AuthButton perms="system:plugin:resource">
-                  <div
-                    className="edit"
-                    onClick={() => {
-                      this.resourceClick(record);
+                <AuthButton perms="system:namespace:delete">
+                  <Popconfirm
+                    title={getIntlContent("SHENYU.COMMON.DELETE")}
+                    placement="bottom"
+                    onCancel={(e) => {
+                      e.stopPropagation();
+                    }}
+                    onConfirm={(e) => {
+                      e.stopPropagation();
+                      this.deleteClick(record);
                     }}
+                    okText={getIntlContent("SHENYU.COMMON.SURE")}
+                    cancelText={getIntlContent("SHENYU.COMMON.CALCEL")}
                   >
-                    {getIntlContent("SHENYU.BUTTON.SYSTEM.RESOURCE")}
-                  </div>
+                    <span
+                      className="edit"
+                      onClick={(e) => {
+                        e.stopPropagation();
+                      }}
+                    >
+                      {getIntlContent("SHENYU.COMMON.DELETE.NAME")}
+                    </span>
+                  </Popconfirm>
                 </AuthButton>
               </div>
             );
@@ -460,9 +319,9 @@ export default class Plugin extends Component {
   }
 
   render() {
-    const { plugin, loading, authMenu } = this.props;
-    const { pluginList, total } = plugin;
-    const { currentPage, pageSize, selectedRowKeys, name, enabled, popup } =
+    const { namespace, loading, authMenu } = this.props;
+    const { namespaceList, total } = namespace;
+    const { currentPage, pageSize, selectedRowKeys, name, namespaceId, popup } 
=
       this.state;
     const columns = this.state.columns.map((col, index) => ({
       ...col,
@@ -487,7 +346,7 @@ export default class Plugin extends Component {
     };
     const flatAuthMenu = flatList({}, authMenu);
 
-    pluginList.forEach((p) => {
+    namespaceList.forEach((p) => {
       p.url = (flatAuthMenu[p.id] ?? {}).path;
     });
 
@@ -498,19 +357,16 @@ export default class Plugin extends Component {
             allowClear
             value={name}
             onChange={this.searchOnchange}
-            placeholder={getIntlContent("SHENYU.PLUGIN.INPUTNAME")}
+            placeholder={getIntlContent("SHENYU.NAMESPACE.INPUTNAME")}
             style={{ width: 240 }}
           />
-          <Select
-            value={enabled != null ? enabled : undefined}
-            onChange={this.enabledOnchange}
-            placeholder={getIntlContent("SHENYU.PLUGIN.SELECT.STATUS")}
-            style={{ width: 150, marginLeft: 20 }}
+          <Input
             allowClear
-          >
-            <Option value="0">{getIntlContent("SHENYU.COMMON.CLOSE")}</Option>
-            <Option value="1">{getIntlContent("SHENYU.COMMON.OPEN")}</Option>
-          </Select>
+            value={namespaceId}
+            onChange={this.searchNamespaceIdOnchange}
+            placeholder={getIntlContent("SHENYU.NAMESPACE.INPUTNAMESPACEID")}
+            style={{ width: 300, marginLeft: 20 }}
+          />
           <AuthButton perms="system:plugin:list">
             <Button
               type="primary"
@@ -544,25 +400,6 @@ export default class Plugin extends Component {
               {getIntlContent("SHENYU.SYSTEM.ADDDATA")}
             </Button>
           </AuthButton>
-          <AuthButton perms="system:plugin:modify">
-            <Button
-              style={{ marginLeft: 20 }}
-              icon="reload"
-              type="primary"
-              onClick={this.syncAllClick}
-            >
-              {getIntlContent("SHENYU.PLUGIN.SYNCALLDATA")}
-            </Button>
-          </AuthButton>
-          <AuthButton perms="system:plugin:disable">
-            <Button
-              style={{ marginLeft: 20 }}
-              type="primary"
-              onClick={this.enableClick}
-            >
-              {getIntlContent("SHENYU.PLUGIN.BATCH")}
-            </Button>
-          </AuthButton>
         </div>
 
         <Table
@@ -572,7 +409,7 @@ export default class Plugin extends Component {
           bordered
           loading={loading}
           columns={columns}
-          dataSource={pluginList}
+          dataSource={namespaceList}
           rowSelection={rowSelection}
           pagination={{
             total,
diff --git a/src/routes/System/NamespacePlugin/AddModal.js 
b/src/routes/System/NamespacePlugin/AddModal.js
new file mode 100644
index 00000000..b6e83867
--- /dev/null
+++ b/src/routes/System/NamespacePlugin/AddModal.js
@@ -0,0 +1,242 @@
+/*
+ * 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, { Component, Fragment } from "react";
+import { Modal, Form, Switch, Input, Select, Divider, InputNumber } from 
"antd";
+import { connect } from "dva";
+import { getIntlContent } from "../../../utils/IntlUtils";
+
+const { Option } = Select;
+const FormItem = Form.Item;
+
+@connect(({ global }) => ({
+  platform: global.platform,
+}))
+class AddModal extends Component {
+  handleSubmit = (e) => {
+    const { form, handleOk, id = "", data } = this.props;
+    e.preventDefault();
+    form.validateFieldsAndScroll((err, values) => {
+      if (!err) {
+        let { name, enabled, config, sort } = values;
+        if (data && data.length > 0) {
+          config = {};
+          data.forEach((item) => {
+            let fieldName = `__${item.field}__`;
+            if (values[fieldName]) {
+              config[item.field] = values[fieldName];
+            }
+          });
+          config = JSON.stringify(config);
+          if (config === "{}") {
+            config = "";
+          }
+        }
+        handleOk({ name, enabled, config, id, sort });
+      }
+    });
+  };
+
+  render() {
+    let {
+      handleCancel,
+      form,
+      config,
+      name,
+      enabled = true,
+      id,
+      data,
+      sort,
+    } = this.props;
+    let disable = id !== undefined;
+    const { getFieldDecorator } = form;
+    const formItemLayout = {
+      labelCol: {
+        sm: { span: 7 },
+      },
+      wrapperCol: {
+        sm: { span: 17 },
+      },
+    };
+    if (config) {
+      config = JSON.parse(config);
+    }
+    return (
+      <Modal
+        width={520}
+        centered
+        title={getIntlContent("SHENYU.PLUGIN")}
+        visible
+        okText={getIntlContent("SHENYU.COMMON.SURE")}
+        cancelText={getIntlContent("SHENYU.COMMON.CALCEL")}
+        onOk={this.handleSubmit}
+        onCancel={handleCancel}
+      >
+        <Form onSubmit={this.handleSubmit} className="login-form">
+          <FormItem label={getIntlContent("SHENYU.PLUGIN")} 
{...formItemLayout}>
+            {getFieldDecorator("name", {
+              rules: [
+                {
+                  required: true,
+                  message: getIntlContent("SHENYU.PLUGIN.SELECT"),
+                },
+              ],
+              initialValue: name,
+            })(
+              <Input
+                allowClear
+                placeholder={getIntlContent("SHENYU.PLUGIN.PLUGIN.NAME")}
+                disabled={disable}
+              />,
+            )}
+          </FormItem>
+          {data && data.length > 0 && (
+            <>
+              <Divider>
+                {name} {getIntlContent("SHENYU.COMMON.SETTING")}
+              </Divider>
+              {data.map((eachField, index) => {
+                let fieldInitialValue = config
+                  ? config[eachField.field]
+                  : undefined;
+                // Add prefixes to prevent naming conflicts
+                let fieldName = `__${eachField.field}__`;
+                let dataType = eachField.dataType;
+                let required = "";
+                let checkRule;
+                if (eachField.extObj) {
+                  let extObj = JSON.parse(eachField.extObj);
+                  required = extObj.required === "0" ? "" : extObj.required;
+                  if (!fieldInitialValue) {
+                    fieldInitialValue = extObj.defaultValue;
+                  }
+                  if (extObj.rule) {
+                    checkRule = extObj.rule;
+                  }
+                }
+                let rules = [];
+                if (required) {
+                  rules.push({
+                    required: { required },
+                    message: getIntlContent("SHENYU.COMMON.PLEASEINPUT"),
+                  });
+                }
+                if (checkRule) {
+                  rules.push({
+                    // eslint-disable-next-line no-eval
+                    pattern: eval(checkRule),
+                    message: `${getIntlContent(
+                      "SHENYU.PLUGIN.RULE.INVALID",
+                    )}:(${checkRule})`,
+                  });
+                }
+                if (dataType === 1) {
+                  return (
+                    <FormItem
+                      label={eachField.label}
+                      name={fieldName}
+                      {...formItemLayout}
+                      key={index}
+                    >
+                      {getFieldDecorator(fieldName, {
+                        rules,
+                        initialValue: fieldInitialValue,
+                      })(
+                        <InputNumber
+                          precision={0}
+                          placeholder={eachField.label}
+                        />,
+                      )}
+                    </FormItem>
+                  );
+                } else if (dataType === 3 && eachField.dictOptions) {
+                  return (
+                    <FormItem
+                      label={eachField.label}
+                      name={fieldName}
+                      {...formItemLayout}
+                      key={index}
+                    >
+                      {getFieldDecorator(fieldName, {
+                        rules,
+                        initialValue: fieldInitialValue,
+                      })(
+                        <Select placeholder={eachField.label}>
+                          {eachField.dictOptions.map((option) => {
+                            return (
+                              <Option
+                                key={option.dictValue}
+                                value={option.dictValue}
+                              >
+                                {option.dictName} ({eachField.label})
+                              </Option>
+                            );
+                          })}
+                        </Select>,
+                      )}
+                    </FormItem>
+                  );
+                } else {
+                  return (
+                    <FormItem
+                      label={eachField.label}
+                      name={fieldName}
+                      {...formItemLayout}
+                      key={index}
+                    >
+                      {getFieldDecorator(fieldName, {
+                        rules,
+                        initialValue: fieldInitialValue,
+                      })(<Input allowClear placeholder={eachField.label} />)}
+                    </FormItem>
+                  );
+                }
+              })}
+              <Divider />
+            </>
+          )}
+          <FormItem
+            label={getIntlContent("SHENYU.PLUGIN.SORT")}
+            {...formItemLayout}
+          >
+            {getFieldDecorator("sort", {
+              rules: [
+                {
+                  required: true,
+                  message: getIntlContent("SHENYU.PLUGIN.INPUTSORT"),
+                },
+              ],
+              initialValue: sort,
+            })(<InputNumber precision={0} style={{ width: "100%" }} />)}
+          </FormItem>
+
+          <FormItem
+            {...formItemLayout}
+            label={getIntlContent("SHENYU.SYSTEM.STATUS")}
+          >
+            {getFieldDecorator("enabled", {
+              initialValue: enabled,
+              valuePropName: "checked",
+            })(<Switch />)}
+          </FormItem>
+        </Form>
+      </Modal>
+    );
+  }
+}
+
+export default Form.create()(AddModal);
diff --git a/src/routes/System/Plugin/index.js 
b/src/routes/System/NamespacePlugin/index.js
similarity index 85%
copy from src/routes/System/Plugin/index.js
copy to src/routes/System/NamespacePlugin/index.js
index ea442965..5543517f 100644
--- a/src/routes/System/Plugin/index.js
+++ b/src/routes/System/NamespacePlugin/index.js
@@ -31,23 +31,25 @@ import {
 import { connect } from "dva";
 import { Link } from "dva/router";
 import { resizableComponents } from "../../../utils/resizable";
-import AddModal from "./AddModal";
 import { getCurrentLocale, getIntlContent } from "../../../utils/IntlUtils";
 import AuthButton from "../../../utils/AuthButton";
 import { refreshAuthMenus } from "../../../utils/AuthRoute";
-import { getUpdateModal, updatePluginsEnabled } from "../../../utils/plugin";
+import {
+  getUpdateModal,
+  updateNamespacePluginsEnabled,
+} from "../../../utils/namespacePlugin";
 
 const { Text } = Typography;
 
 const { Option } = Select;
 
-@connect(({ plugin, resource, loading, global }) => ({
-  plugin,
+@connect(({ namespacePlugin, resource, loading, global }) => ({
+  namespacePlugin,
   authMenu: resource.authMenu,
   language: global.language,
-  loading: loading.effects["plugin/fetch"],
+  loading: loading.effects["namespacePlugin/fetch"],
 }))
-export default class Plugin extends Component {
+export default class NamespacePlugin extends Component {
   components = resizableComponents;
 
   constructor(props) {
@@ -55,6 +57,8 @@ export default class Plugin extends Component {
     this.state = {
       currentPage: 1,
       pageSize: 12,
+      // todo:[To be refactored with namespace] Temporarily hardcode
+      namespaceId: "649330b6-c2d7-4edc-be8e-8a54df9eb385",
       selectedRowKeys: [],
       name: "",
       enabled: null,
@@ -68,14 +72,14 @@ export default class Plugin extends Component {
 
   componentDidMount() {
     this.query();
-    this.initPluginColumns();
+    this.initNamespacePluginColumns();
   }
 
   componentDidUpdate() {
     const { language } = this.props;
     const { localeName } = this.state;
     if (language !== localeName) {
-      this.initPluginColumns();
+      this.initNamespacePluginColumns();
       this.changeLocale(language);
     }
   }
@@ -98,10 +102,11 @@ export default class Plugin extends Component {
   };
 
   currentQueryPayload = (override) => {
-    const { name, enabled, currentPage, pageSize } = this.state;
+    const { name, enabled, currentPage, pageSize, namespaceId } = this.state;
     return {
       name,
       enabled,
+      namespaceId,
       currentPage,
       pageSize,
       ...override,
@@ -111,7 +116,7 @@ export default class Plugin extends Component {
   query = () => {
     const { dispatch } = this.props;
     dispatch({
-      type: "plugin/fetch",
+      type: "namespacePlugin/fetch",
       payload: this.currentQueryPayload(),
     });
   };
@@ -135,7 +140,9 @@ export default class Plugin extends Component {
   editClick = (record) => {
     const { dispatch } = this.props;
     getUpdateModal({
-      pluginId: record.id,
+      id: record.id,
+      // todo:[To be refactored with namespace] Temporarily hardcode
+      namespaceId: "649330b6-c2d7-4edc-be8e-8a54df9eb385",
       dispatch,
       fetchValue: this.currentQueryPayload(),
       callback: (popup) => {
@@ -154,7 +161,7 @@ export default class Plugin extends Component {
   resourceClick = (record) => {
     // code here...
     const { dispatch } = this.props;
-    const { name, role, sort, config, id, enabled } = record;
+    const { name, role, sort, config, pluginId, enabled } = record;
     dispatch({
       type: "plugin/createPluginResource",
       payload: {
@@ -162,7 +169,7 @@ export default class Plugin extends Component {
         role,
         sort,
         config,
-        id,
+        id: pluginId,
         enabled,
       },
       callback: () => {
@@ -188,9 +195,11 @@ export default class Plugin extends Component {
     const { selectedRowKeys } = this.state;
     if (selectedRowKeys && selectedRowKeys.length > 0) {
       dispatch({
-        type: "plugin/delete",
+        type: "namespacePlugin/delete",
         payload: {
           list: selectedRowKeys,
+          // todo:[To be refactored with namespace] Temporarily hardcode
+          namespaceId: "649330b6-c2d7-4edc-be8e-8a54df9eb385",
         },
         fetchValue: this.currentQueryPayload({
           pageSize: 12,
@@ -206,47 +215,15 @@ export default class Plugin extends Component {
     }
   };
 
-  addClick = () => {
-    this.setState({
-      popup: (
-        <AddModal
-          disabled={false}
-          handleOk={(values) => {
-            const { dispatch } = this.props;
-            const { name, enabled, role, config, sort, file } = values;
-            dispatch({
-              type: "plugin/add",
-              payload: {
-                name,
-                config,
-                role,
-                enabled,
-                sort,
-                file,
-              },
-              fetchValue: this.currentQueryPayload(),
-              callback: () => {
-                this.closeModal(true);
-                refreshAuthMenus({ dispatch });
-              },
-            });
-          }}
-          handleCancel={() => {
-            this.closeModal();
-          }}
-        />
-      ),
-    });
-  };
-
   // 数据状态切换
-  statusSwitch = ({ list, enabled, callback }) => {
+  statusSwitch = ({ list, enabled, namespaceId, callback }) => {
     const { dispatch } = this.props;
-    updatePluginsEnabled({
+    updateNamespacePluginsEnabled({
       list,
       dispatch,
       callback,
       enabled,
+      namespaceId,
       fetchValue: this.currentQueryPayload(),
     });
   };
@@ -257,14 +234,18 @@ export default class Plugin extends Component {
     const { selectedRowKeys } = this.state;
     if (selectedRowKeys && selectedRowKeys.length > 0) {
       dispatch({
-        type: "plugin/fetchItem",
+        type: "namespacePlugin/fetchItem",
         payload: {
           id: selectedRowKeys[0],
+          // todo:[To be refactored with namespace] Temporarily hardcode
+          namespaceId: "649330b6-c2d7-4edc-be8e-8a54df9eb385",
         },
         callback: (user) => {
           this.statusSwitch({
             list: selectedRowKeys,
             enabled: !user.enabled,
+            // todo:[To be refactored with namespace] Temporarily hardcode
+            namespaceId: "649330b6-c2d7-4edc-be8e-8a54df9eb385",
             callback: () => {
               this.setState({ selectedRowKeys: [] });
             },
@@ -281,7 +262,7 @@ export default class Plugin extends Component {
   syncAllClick = () => {
     const { dispatch } = this.props;
     dispatch({
-      type: "plugin/asyncAll",
+      type: "namespacePlugin/asyncAll",
     });
   };
 
@@ -292,7 +273,7 @@ export default class Plugin extends Component {
     getCurrentLocale(this.state.localeName);
   }
 
-  initPluginColumns() {
+  initNamespacePluginColumns() {
     this.setState({
       columns: [
         {
@@ -414,7 +395,11 @@ export default class Plugin extends Component {
                 unCheckedChildren={getIntlContent("SHENYU.COMMON.CLOSE")}
                 checked={text}
                 onChange={(checked) => {
-                  this.statusSwitch({ list: [row.id], enabled: checked });
+                  this.statusSwitch({
+                    list: [row.id],
+                    enabled: checked,
+                    namespaceId: row.namespaceId,
+                  });
                 }}
               />
             </AuthButton>
@@ -431,7 +416,7 @@ export default class Plugin extends Component {
           render: (text, record) => {
             return (
               <div className="optionParts">
-                <AuthButton perms="system:plugin:edit">
+                <AuthButton perms="system:namespacePlugin:edit">
                   <div
                     className="edit"
                     onClick={() => {
@@ -441,7 +426,7 @@ export default class Plugin extends Component {
                     {getIntlContent("SHENYU.SYSTEM.EDITOR")}
                   </div>
                 </AuthButton>
-                <AuthButton perms="system:plugin:resource">
+                <AuthButton perms="system:namespacePlugin:resource">
                   <div
                     className="edit"
                     onClick={() => {
@@ -460,8 +445,8 @@ export default class Plugin extends Component {
   }
 
   render() {
-    const { plugin, loading, authMenu } = this.props;
-    const { pluginList, total } = plugin;
+    const { namespacePlugin, loading, authMenu } = this.props;
+    const { namespacePluginList, total } = namespacePlugin;
     const { currentPage, pageSize, selectedRowKeys, name, enabled, popup } =
       this.state;
     const columns = this.state.columns.map((col, index) => ({
@@ -487,7 +472,7 @@ export default class Plugin extends Component {
     };
     const flatAuthMenu = flatList({}, authMenu);
 
-    pluginList.forEach((p) => {
+    namespacePluginList.forEach((p) => {
       p.url = (flatAuthMenu[p.id] ?? {}).path;
     });
 
@@ -535,15 +520,15 @@ export default class Plugin extends Component {
               </Button>
             </Popconfirm>
           </AuthButton>
-          <AuthButton perms="system:plugin:add">
-            <Button
-              style={{ marginLeft: 20 }}
-              type="primary"
-              onClick={this.addClick}
-            >
-              {getIntlContent("SHENYU.SYSTEM.ADDDATA")}
-            </Button>
-          </AuthButton>
+          {/* <AuthButton perms="system:plugin:add"> */}
+          {/*  <Button */}
+          {/*    style={{ marginLeft: 20 }} */}
+          {/*    type="primary" */}
+          {/*    onClick={this.addClick} */}
+          {/*  > */}
+          {/*    {getIntlContent("SHENYU.SYSTEM.ADDDATA")} */}
+          {/*  </Button> */}
+          {/* </AuthButton> */}
           <AuthButton perms="system:plugin:modify">
             <Button
               style={{ marginLeft: 20 }}
@@ -572,7 +557,7 @@ export default class Plugin extends Component {
           bordered
           loading={loading}
           columns={columns}
-          dataSource={pluginList}
+          dataSource={namespacePluginList}
           rowSelection={rowSelection}
           pagination={{
             total,
diff --git a/src/routes/System/Plugin/index.js 
b/src/routes/System/Plugin/index.js
index ea442965..08539917 100644
--- a/src/routes/System/Plugin/index.js
+++ b/src/routes/System/Plugin/index.js
@@ -277,14 +277,6 @@ export default class Plugin extends Component {
     }
   };
 
-  // 同步插件数据
-  syncAllClick = () => {
-    const { dispatch } = this.props;
-    dispatch({
-      type: "plugin/asyncAll",
-    });
-  };
-
   changeLocale(locale) {
     this.setState({
       localeName: locale,
@@ -544,16 +536,6 @@ export default class Plugin extends Component {
               {getIntlContent("SHENYU.SYSTEM.ADDDATA")}
             </Button>
           </AuthButton>
-          <AuthButton perms="system:plugin:modify">
-            <Button
-              style={{ marginLeft: 20 }}
-              icon="reload"
-              type="primary"
-              onClick={this.syncAllClick}
-            >
-              {getIntlContent("SHENYU.PLUGIN.SYNCALLDATA")}
-            </Button>
-          </AuthButton>
           <AuthButton perms="system:plugin:disable">
             <Button
               style={{ marginLeft: 20 }}
diff --git a/src/services/api.js b/src/services/api.js
index f9682cce..c793896d 100644
--- a/src/services/api.js
+++ b/src/services/api.js
@@ -1137,3 +1137,101 @@ export function 
updateDiscoveryUpstream(discoveryHandlerId, upstreams) {
     body: upstreams,
   });
 }
+
+/* getAllNamespaces */
+export async function getAllNamespaces(params) {
+  return request(`${baseUrl}/namespace/findPageByQuery?${stringify(params)}`, {
+    method: `GET`,
+  });
+}
+/* insertOrUpdateNamespace */
+export async function insertOrUpdateNamespace(params) {
+  return request(`${baseUrl}/namespace/insertOrUpdate`, {
+    method: `POST`,
+    body: {
+      ...params,
+    },
+  });
+}
+
+/* findNamespace */
+export async function findNamespace(params) {
+  return request(`${baseUrl}/namespace/${params.id}`, {
+    method: `GET`,
+  });
+}
+
+/* deleteNamespace */
+export async function deleteNamespace(params) {
+  return request(`${baseUrl}/namespace/batch`, {
+    method: `DELETE`,
+    body: [...params.list],
+  });
+}
+
+/* findNamespacePlugin */
+export async function findNamespacePlugin(params) {
+  return request(
+    
`${baseUrl}/namespacePlugin/id=${params.id}&namespaceId=${params.namespaceId}`,
+    {
+      method: `GET`,
+    },
+  );
+}
+
+/* getAllNamespacePlugins */
+export async function getAllNamespacePlugins(params) {
+  // todo:[To be refactored with namespace] Temporarily hardcode
+  params.namespaceId = "649330b6-c2d7-4edc-be8e-8a54df9eb385";
+  return request(`${baseUrl}/namespacePlugin?${stringify(params)}`, {
+    method: `GET`,
+  });
+}
+
+/* updatepluginEnabled */
+export async function updateNamespacePluginEnabled(params) {
+  return request(`${baseUrl}/namespacePlugin/enabled`, {
+    method: `POST`,
+    body: {
+      ids: params.list,
+      enabled: params.enabled,
+      namespaceId: params.namespaceId,
+    },
+  });
+}
+
+/* updateNamespacePlugin */
+export async function updateNamespacePlugin(params) {
+  const formData = new FormData();
+  formData.append("pluginId", params.pluginId);
+  if (params.config) formData.append("config", params.config);
+  formData.append("sort", params.sort);
+  formData.append("enabled", params.enabled);
+  formData.append("name", params.name);
+  formData.append("namespaceId", params.namespaceId);
+  return request(
+    
`${baseUrl}/namespacePlugin/pluginId=${params.pluginId}&namespaceId=${params.namespaceId}`,
+    {
+      method: `PUT`,
+      body: formData,
+    },
+  );
+}
+
+/* deletePlugin */
+export async function deleteNamespacePlugin(params) {
+  return request(`${baseUrl}/namespacePlugin/batch`, {
+    method: `DELETE`,
+    body: {
+      ids: [...params.list],
+      namespaceId: params.namespaceId,
+    },
+  });
+}
+
+// sync all plugin
+export async function asyncNamespacePlugin() {
+  return request(`${baseUrl}/namespacePlugin/syncPluginAll`, {
+    method: `POST`,
+  });
+}
diff --git a/src/utils/namespacePlugin.js b/src/utils/namespacePlugin.js
new file mode 100644
index 00000000..e45c4c3b
--- /dev/null
+++ b/src/utils/namespacePlugin.js
@@ -0,0 +1,103 @@
+/*
+ * 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 { refreshAuthMenus } from "./AuthRoute";
+import AddModal from "../routes/System/NamespacePlugin/AddModal";
+
+export function getUpdateModal({
+  id,
+  namespaceId,
+  dispatch,
+  fetchValue,
+  callback,
+  updatedCallback,
+  canceledCallback,
+}) {
+  dispatch({
+    type: "namespacePlugin/fetchItem",
+    payload: {
+      id,
+      namespaceId,
+    },
+    callback: (plugin) => {
+      dispatch({
+        type: "namespacePlugin/fetchByPluginId",
+        payload: {
+          pluginId: plugin.pluginId,
+          type: "3",
+        },
+        callback: (pluginConfigList) => {
+          callback(
+            <AddModal
+              disabled={true}
+              {...plugin}
+              {...pluginConfigList}
+              handleOk={(values) => {
+                const { enabled, name, config, sort } = values;
+                dispatch({
+                  type: "namespacePlugin/update",
+                  payload: {
+                    config,
+                    pluginId: plugin.pluginId,
+                    enabled,
+                    namespaceId,
+                    sort,
+                    name,
+                  },
+                  fetchValue,
+                  callback: () => {
+                    if (updatedCallback) {
+                      updatedCallback(values);
+                    }
+                    refreshAuthMenus({ dispatch });
+                  },
+                });
+              }}
+              handleCancel={canceledCallback}
+            />,
+          );
+        },
+      });
+    },
+  });
+}
+
+export function updateNamespacePluginsEnabled({
+  list,
+  enabled,
+  namespaceId,
+  dispatch,
+  fetchValue,
+  callback,
+}) {
+  dispatch({
+    type: "namespacePlugin/updateEn",
+    payload: {
+      list,
+      enabled,
+      namespaceId,
+    },
+    fetchValue,
+    callback: () => {
+      if (callback) {
+        callback();
+      }
+      refreshAuthMenus({ dispatch });
+    },
+  });
+}

Reply via email to