This is an automated email from the ASF dual-hosted git repository. xiaoyu 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 794dde9d [Bugfix] namespace plugin batch enable (#512) 794dde9d is described below commit 794dde9d65583b57b94d7b7796a12f1372bbff8c Author: aias00 <rok...@163.com> AuthorDate: Tue Dec 3 11:04:23 2024 +0800 [Bugfix] namespace plugin batch enable (#512) * fix namespace plugin batch enable * fix get alert receviers * fix namespace plugin get selector * fix ns plugin selector bug * fix namespace detail restful * fix namespace plugin restful * fix data permission ns bug * support copy selector from other ns * support rule copy from other ns --- src/models/global.js | 22 +++++++++++++ src/routes/Plugin/Common/RuleCopy.js | 49 +++++++++++++++++++++++++-- src/routes/Plugin/Common/SelectorCopy.js | 52 ++++++++++++++++++++++++++--- src/routes/Plugin/Common/index.js | 21 +++++++----- src/routes/System/Alert/index.js | 6 ++-- src/routes/System/NamespacePlugin/index.js | 6 ++-- src/routes/System/User/DataPermModal.js | 53 +++++++++++++++++++----------- src/services/api.js | 26 +++++++++------ 8 files changed, 183 insertions(+), 52 deletions(-) diff --git a/src/models/global.js b/src/models/global.js index 64ca7cb6..0d2357d7 100644 --- a/src/models/global.js +++ b/src/models/global.js @@ -86,6 +86,28 @@ export default { }); } }, + *fetchPluginsByNamespace({ payload }, { call, put }) { + const { callback, namespaceId } = payload ?? {}; + const params = { + namespaceId, + currentPage: 1, + pageSize: 50, + }; + const json = yield call(getPluginsByNamespace, params); + if (json.code === 200) { + let { dataList } = json.data; + + if (callback) { + callback(dataList); + } + yield put({ + type: "savePlugins", + payload: { + dataList, + }, + }); + } + }, *asyncPlugin(params, { call }) { const { payload } = params; const json = yield call(asyncByPluginAndNamespace, payload); diff --git a/src/routes/Plugin/Common/RuleCopy.js b/src/routes/Plugin/Common/RuleCopy.js index d79b5ed6..27417207 100644 --- a/src/routes/Plugin/Common/RuleCopy.js +++ b/src/routes/Plugin/Common/RuleCopy.js @@ -16,7 +16,7 @@ */ import React, { Component } from "react"; -import { Modal, TreeSelect } from "antd"; +import { Modal, TreeSelect, Dropdown, Menu, Button, Icon } from "antd"; import { connect } from "dva"; import { getPluginDropDownListByNamespace, @@ -25,9 +25,11 @@ import { findRule, } from "../../../services/api"; import { getIntlContent } from "../../../utils/IntlUtils"; +import { defaultNamespaceId } from "../../../components/_utils/utils"; @connect(({ global }) => ({ currentNamespaceId: global.currentNamespaceId, + namespaces: global.namespaces, })) class RuleCopy extends Component { constructor(props) { @@ -36,6 +38,7 @@ class RuleCopy extends Component { ruleTree: [], value: undefined, loading: false, + currentNamespaceId: defaultNamespaceId, }; } @@ -43,6 +46,12 @@ class RuleCopy extends Component { this.getAllRule(); } + handleNamespacesValueChange = (value) => { + this.setState({ currentNamespaceId: value.key }, () => { + this.getAllRule(); + }); + }; + getAllRule = async () => { const { currentNamespaceId } = this.props; const { code: pluginCode, data: pluginList = [] } = @@ -133,8 +142,8 @@ class RuleCopy extends Component { }; render() { - const { visible = false } = this.props; - const { ruleTree, value, loading } = this.state; + const { visible = false, namespaces } = this.props; + const { ruleTree, value, loading, currentNamespaceId } = this.state; return ( <Modal visible={visible} @@ -144,6 +153,40 @@ class RuleCopy extends Component { onOk={this.handleOk} confirmLoading={loading} > + <Dropdown + placement="bottomCenter" + overlay={ + <Menu onClick={this.handleNamespacesValueChange}> + {namespaces.map((namespace) => { + let isCurrentNamespace = + currentNamespaceId === namespace.namespaceId; + return ( + <Menu.Item + key={namespace.namespaceId} + disabled={isCurrentNamespace} + > + <span>{namespace.name}</span> + </Menu.Item> + ); + })} + </Menu> + } + > + <Button> + <a + className="ant-dropdown-link" + style={{ fontWeight: "bold" }} + onClick={(e) => e.preventDefault()} + > + {`${getIntlContent("SHENYU.SYSTEM.NAMESPACE")} / ${ + namespaces.find( + (namespace) => currentNamespaceId === namespace.namespaceId, + )?.name + } `} + </a> + <Icon type="down" /> + </Button> + </Dropdown> <TreeSelect style={{ width: "100%" }} showSearch diff --git a/src/routes/Plugin/Common/SelectorCopy.js b/src/routes/Plugin/Common/SelectorCopy.js index 959efa91..9ca62fa0 100644 --- a/src/routes/Plugin/Common/SelectorCopy.js +++ b/src/routes/Plugin/Common/SelectorCopy.js @@ -16,7 +16,7 @@ */ import React, { Component } from "react"; -import { Modal, TreeSelect } from "antd"; +import { Modal, TreeSelect, Dropdown, Menu, Button, Icon } from "antd"; import { connect } from "dva"; import { getPluginDropDownListByNamespace, @@ -24,9 +24,10 @@ import { findSelector, } from "../../../services/api"; import { getIntlContent } from "../../../utils/IntlUtils"; +import { defaultNamespaceId } from "../../../components/_utils/utils"; @connect(({ global }) => ({ - currentNamespaceId: global.currentNamespaceId, + namespaces: global.namespaces, })) class SelectorCopy extends Component { constructor(props) { @@ -35,6 +36,7 @@ class SelectorCopy extends Component { selectorTree: [], value: undefined, loading: false, + currentNamespaceId: defaultNamespaceId, }; } @@ -42,8 +44,14 @@ class SelectorCopy extends Component { this.getAllSelectors(); } + handleNamespacesValueChange = (value) => { + this.setState({ currentNamespaceId: value.key }, () => { + this.getAllSelectors(); + }); + }; + getAllSelectors = async () => { - const { currentNamespaceId } = this.props; + const { currentNamespaceId } = this.state; const { code: pluginCode, data: pluginList = [] } = await getPluginDropDownListByNamespace({ namespace: currentNamespaceId, @@ -113,8 +121,8 @@ class SelectorCopy extends Component { }; render() { - const { visible = false } = this.props; - const { selectorTree, value, loading } = this.state; + const { visible = false, namespaces } = this.props; + const { selectorTree, value, loading, currentNamespaceId } = this.state; return ( <Modal visible={visible} @@ -124,6 +132,40 @@ class SelectorCopy extends Component { onOk={this.handleOk} confirmLoading={loading} > + <Dropdown + placement="bottomCenter" + overlay={ + <Menu onClick={this.handleNamespacesValueChange}> + {namespaces.map((namespace) => { + let isCurrentNamespace = + currentNamespaceId === namespace.namespaceId; + return ( + <Menu.Item + key={namespace.namespaceId} + disabled={isCurrentNamespace} + > + <span>{namespace.name}</span> + </Menu.Item> + ); + })} + </Menu> + } + > + <Button> + <a + className="ant-dropdown-link" + style={{ fontWeight: "bold" }} + onClick={(e) => e.preventDefault()} + > + {`${getIntlContent("SHENYU.SYSTEM.NAMESPACE")} / ${ + namespaces.find( + (namespace) => currentNamespaceId === namespace.namespaceId, + )?.name + } `} + </a> + <Icon type="down" /> + </Button> + </Dropdown> <TreeSelect style={{ width: "100%" }} showSearch diff --git a/src/routes/Plugin/Common/index.js b/src/routes/Plugin/Common/index.js index 37b85ecb..a7d351e0 100755 --- a/src/routes/Plugin/Common/index.js +++ b/src/routes/Plugin/Common/index.js @@ -123,7 +123,7 @@ export default class Common extends Component { const { selectorName } = this.state; let name = this.props.match.params ? this.props.match.params.id : ""; const tempPlugin = this.getPlugin(plugins, name); - const tempPluginId = tempPlugin?.id; + const tempPluginId = tempPlugin?.pluginId; const enabled = tempPlugin?.enabled ?? false; this.setState({ pluginId: tempPluginId, isPluginEnabled: enabled }); dispatch({ @@ -168,7 +168,7 @@ export default class Common extends Component { getPluginId = (plugins, name) => { let plugin = this.getPlugin(plugins, name); if (plugin) { - return plugin.id; + return plugin.pluginId; } else { return ""; } @@ -210,7 +210,7 @@ export default class Common extends Component { const { dispatch, plugins, currentNamespaceId } = this.props; let name = this.props.match.params ? this.props.match.params.id : ""; const plugin = this.getPlugin(plugins, name); - const { id: pluginId, config } = plugin; + const { pluginId, config } = plugin; const multiSelectorHandle = this.getPluginConfigField(config, "multiSelectorHandle") === "1"; const isDiscovery = this.isDiscovery(pluginId); @@ -379,7 +379,7 @@ export default class Common extends Component { const plugin = this.getPlugin(plugins, pluginName); const enabled = !this.state.isPluginEnabled; updateNamespacePluginsEnabledByNamespace({ - list: [plugin.id], + list: [plugin.pluginId], namespaceId: this.props.currentNamespaceId, enabled, dispatch, @@ -398,7 +398,7 @@ export default class Common extends Component { : ""; const plugin = this.getPlugin(plugins, pluginName); getUpdateModal({ - pluginId: plugin.id, + pluginId: plugin.pluginId, dispatch, callback: (popup) => { this.setState({ popup }); @@ -504,7 +504,7 @@ export default class Common extends Component { const { selectorPage, selectorPageSize } = this.state; let name = this.props.match.params ? this.props.match.params.id : ""; const plugin = this.getPlugin(plugins, name); - const { id: pluginId, config } = plugin; + const { pluginId, config } = plugin; const multiSelectorHandle = this.getPluginConfigField(config, "multiSelectorHandle") === "1"; const isDiscovery = this.isDiscovery(pluginId); @@ -670,7 +670,7 @@ export default class Common extends Component { const { selectorPage, selectorPageSize } = this.state; let name = this.props.match.params ? this.props.match.params.id : ""; const plugin = this.getPlugin(plugins, name); - const { id: pluginId } = plugin; + const { pluginId } = plugin; dispatch({ type: "common/enableSelector", payload: { @@ -887,17 +887,20 @@ export default class Common extends Component { pageSize: rulePageSize, namespaceId: currentNamespaceId, }, + callback: () => { + this.setState({ ruleSelectedRowKeys: [] }); + }, }); }; asyncClick = () => { const { dispatch, plugins, currentNamespaceId } = this.props; let name = this.props.match.params ? this.props.match.params.id : ""; - const id = this.getPluginId(plugins, name); + const pluginId = this.getPluginId(plugins, name); dispatch({ type: "global/asyncPlugin", payload: { - id, + pluginId, namespaceId: currentNamespaceId, }, }); diff --git a/src/routes/System/Alert/index.js b/src/routes/System/Alert/index.js index a6304e31..47138529 100644 --- a/src/routes/System/Alert/index.js +++ b/src/routes/System/Alert/index.js @@ -26,9 +26,10 @@ import { Type } from "./globalData"; const DEFAULT_ALERT_TYPE = 1; -@connect(({ alert, loading }) => ({ +@connect(({ alert, loading, global }) => ({ alert, loading: loading.effects["alert/fetch"], + currentNamespaceId: global.currentNamespaceId, })) export default class Alert extends Component { constructor(props) { @@ -49,13 +50,14 @@ export default class Alert extends Component { }; getAllAlerts = () => { - const { dispatch } = this.props; + const { dispatch, currentNamespaceId } = this.props; const { currentPage, pageSize } = this.state; dispatch({ type: "alert/fetch", payload: { currentPage, pageSize, + namespaceId: currentNamespaceId, }, }); }; diff --git a/src/routes/System/NamespacePlugin/index.js b/src/routes/System/NamespacePlugin/index.js index 060f991d..ab77458a 100644 --- a/src/routes/System/NamespacePlugin/index.js +++ b/src/routes/System/NamespacePlugin/index.js @@ -216,11 +216,11 @@ export default class NamespacePlugin extends Component { if (selectedRowKeys && selectedRowKeys.length > 0) { dispatch({ type: "namespacePlugin/fetchItem", - payload: { id: selectedRowKeys[0] }, - callback: (user) => { + payload: { id: selectedRowKeys[0], namespaceId: currentNamespaceId }, + callback: (plugin) => { this.statusSwitch({ list: selectedRowKeys, - enabled: !user.enabled, + enabled: !plugin.enabled, namespaceId: currentNamespaceId, callback: () => { this.setState({ selectedRowKeys: [] }); diff --git a/src/routes/System/User/DataPermModal.js b/src/routes/System/User/DataPermModal.js index 827da468..ed1ac63a 100644 --- a/src/routes/System/User/DataPermModal.js +++ b/src/routes/System/User/DataPermModal.js @@ -69,11 +69,15 @@ export default class DataPermModal extends Component { getPluginTreeData = () => { const { dispatch } = this.props; + const { currentNamespaceId } = this.state; dispatch({ type: "resource/fetchMenuTree", }); dispatch({ - type: "global/fetchPlugins", + type: "global/fetchPluginsByNamespace", + payload: { + namespaceId: currentNamespaceId, + }, }); }; @@ -241,28 +245,30 @@ export default class DataPermModal extends Component { return; } const currentPluginInfo = plugins.find((v) => v.name === plugin.name); - let currentCategory = treeData.find( - (tree) => tree.title === currentPluginInfo.role, - ); - if (!currentCategory) { - treeData.push({ - title: currentPluginInfo.role, - key: currentPluginInfo.role, - selectable: false, - icon: "unordered-list", + if (currentPluginInfo) { + let currentCategory = treeData.find( + (tree) => tree.title === currentPluginInfo.role, + ); + if (!currentCategory) { + treeData.push({ + title: currentPluginInfo.role, + key: currentPluginInfo.role, + selectable: false, + icon: "unordered-list", + sort: plugin.sort, + children: [], + }); + currentCategory = treeData[treeData.length - 1]; + } + currentCategory.children.push({ + key: currentPluginInfo.pluginId, + title: titleCase(currentPluginInfo.name), + selectable: true, sort: plugin.sort, - children: [], + icon: plugin.meta.icon, + pluginId: currentPluginInfo.pluginId, }); - currentCategory = treeData[treeData.length - 1]; } - currentCategory.children.push({ - key: currentPluginInfo.id, - title: titleCase(currentPluginInfo.name), - selectable: true, - sort: plugin.sort, - icon: plugin.meta.icon, - pluginId: currentPluginInfo.id, - }); }); pluginMenuList = treeData; @@ -424,11 +430,18 @@ export default class DataPermModal extends Component { handleNamespacesValueChange = (value) => { const { currentPlugin } = this.state; + const { dispatch } = this.props; this.setState({ currentNamespaceId: value.key }, () => { if (currentPlugin) { this.setState({ selectorExpandedRowKeys: [] }); this.getPermissionSelectorList(1); } + dispatch({ + type: "global/fetchPluginsByNamespace", + payload: { + namespaceId: value.key, + }, + }); }); }; diff --git a/src/services/api.js b/src/services/api.js index b014028f..fe1e346e 100644 --- a/src/services/api.js +++ b/src/services/api.js @@ -198,7 +198,7 @@ export async function addPlugin(params) { /* generatePlugin */ export async function generatePlugin({ pluginId, namespaceId }) { return request(`${baseUrl}/namespace-plugin/${namespaceId}/${pluginId}`, { - method: `PUT`, + method: `POST`, }); } @@ -594,7 +594,7 @@ export async function asyncOnePlugin(params) { // sync by plugin and namespace export async function asyncByPluginAndNamespace(params) { return request( - `${baseUrl}/namespace-plugin/syncPluginData?id=${params.id}&namespaceId=${params.namespaceId}`, + `${baseUrl}/namespace-plugin/syncPluginData?pluginId=${params.pluginId}&namespaceId=${params.namespaceId}`, { method: `PUT`, }, @@ -611,7 +611,7 @@ export async function getPluginDropDownList() { // get plugin dropdown list by namespace export async function getPluginDropDownListByNamespace(params) { return request( - `${baseUrl}/plugin-template/listByNamespace?namespace=${params.namespace}`, + `${baseUrl}/namespace-plugin/listByNamespace?namespace=${params.namespace}`, { method: `GET`, }, @@ -1294,9 +1294,12 @@ export async function deleteNamespace(params) { /* findNamespacePlugin */ export async function findNamespacePlugin(params) { - return request(`${baseUrl}/namespace-plugin/detail?${stringify(params)}`, { - method: `GET`, - }); + return request( + `${baseUrl}/namespace-plugin/${params.namespaceId}/${params.id}`, + { + method: `GET`, + }, + ); } /* getAllNamespacePlugins */ @@ -1331,10 +1334,13 @@ export async function updateNamespacePluginEnabledByNamespace(params) { /* updateNamespacePlugin */ export async function updateNamespacePlugin(params) { - return request(`${baseUrl}/namespace-plugin`, { - method: `POST`, - body: params, - }); + return request( + `${baseUrl}/namespace-plugin/${params.namespaceId}/${params.pluginId}`, + { + method: `PUT`, + body: params, + }, + ); } /* deletePlugin */