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 649bd45b fix(auth): preserve AppAuth filters during reload (#705)
649bd45b is described below
commit 649bd45bd0a1609b09d4b32c9c90b85544515a72
Author: Kazi Rezoanur Rahman <[email protected]>
AuthorDate: Tue Oct 13 08:16:50 2026 +0200
fix(auth): preserve AppAuth filters during reload (#705)
* fix(auth): preserve AppAuth filters during reload
Reload now forwards `appKey` and `phone` with the active page size.
Mutation refreshes use the model reload as the single fetch path.
Removed the hardcoded 20-row page size and added regression coverage.
`npm test` and `npm run lint` pass.
Closes #624
* fix(auth): guard optional callbacks in auth effects
---
src/models/auth.js | 44 ++++++++---
src/routes/System/AppAuth/index.js | 92 +++++++++--------------
src/routes/System/AppAuth/index.test.js | 126 ++++++++++++++++++++++++++++++++
3 files changed, 191 insertions(+), 71 deletions(-)
diff --git a/src/models/auth.js b/src/models/auth.js
index 243b87f8..864b98b0 100644
--- a/src/models/auth.js
+++ b/src/models/auth.js
@@ -65,7 +65,9 @@ export default {
const json = yield call(findAuthData, payload);
if (json.code === 200) {
const auth = json.data;
- callback(auth);
+ if (typeof callback === "function") {
+ callback(auth);
+ }
}
},
*fetchItemDel(params, { call }) {
@@ -73,7 +75,9 @@ export default {
const json = yield call(findAuthDataDel, payload);
if (json.code === 200) {
const auth = json.data;
- callback({ auth });
+ if (typeof callback === "function") {
+ callback({ auth });
+ }
}
},
*fetchMeta(params, { call }) {
@@ -89,14 +93,18 @@ export default {
};
return item;
});
- callback({ dataList });
+ if (typeof callback === "function") {
+ callback({ dataList });
+ }
}
},
*fetchMetaGroup(params, { call }) {
const { payload, callback } = params;
const json = yield call(getfetchMetaGroup, payload);
if (json.code === 200) {
- callback(json.data);
+ if (typeof callback === "function") {
+ callback(json.data);
+ }
}
},
*add(params, { call, put }) {
@@ -104,7 +112,9 @@ export default {
const json = yield call(addAuthData, payload);
if (json.code === 200) {
message.success(getIntlContent("SHENYU.COMMON.RESPONSE.ADD.SUCCESS"));
- callback();
+ if (typeof callback === "function") {
+ callback();
+ }
yield put({ type: "reload", fetchValue });
} else {
message.warn(json.message);
@@ -118,7 +128,9 @@ export default {
message.success(
getIntlContent("SHENYU.COMMON.RESPONSE.DELETE.SUCCESS"),
);
- callback();
+ if (typeof callback === "function") {
+ callback();
+ }
yield put({ type: "reload", fetchValue });
} else {
message.warn(json.message);
@@ -132,7 +144,9 @@ export default {
message.success(
getIntlContent("SHENYU.COMMON.RESPONSE.UPDATE.SUCCESS"),
);
- callback();
+ if (typeof callback === "function") {
+ callback();
+ }
yield put({ type: "reload", fetchValue });
} else {
message.warn(json.message);
@@ -145,7 +159,9 @@ export default {
message.success(
getIntlContent("SHENYU.COMMON.RESPONSE.UPDATE.SUCCESS"),
);
- callback();
+ if (typeof callback === "function") {
+ callback();
+ }
yield put({ type: "reload", fetchValue });
} else {
message.warn(json.message);
@@ -153,8 +169,8 @@ export default {
},
*reload(params, { put }) {
const { fetchValue } = params;
- const { name, currentPage, pageSize, namespaceId } = fetchValue;
- const payload = { name, currentPage, pageSize, namespaceId };
+ const { appKey, phone, currentPage, pageSize, namespaceId } = fetchValue;
+ const payload = { appKey, phone, currentPage, pageSize, namespaceId };
yield put({ type: "fetch", payload });
},
*updateEn(params, { call, put }) {
@@ -164,7 +180,9 @@ export default {
message.success(
getIntlContent("SHENYU.COMMON.RESPONSE.UPDATE.SUCCESS"),
);
- callback();
+ if (typeof callback === "function") {
+ callback();
+ }
yield put({ type: "reload", fetchValue });
} else {
message.warn(json.message);
@@ -177,7 +195,9 @@ export default {
message.success(
getIntlContent("SHENYU.COMMON.RESPONSE.UPDATE.SUCCESS"),
);
- callback();
+ if (typeof callback === "function") {
+ callback();
+ }
yield put({ type: "reload", fetchValue });
} else {
message.warn(json.message);
diff --git a/src/routes/System/AppAuth/index.js
b/src/routes/System/AppAuth/index.js
index 343c9199..6f4c4e77 100644
--- a/src/routes/System/AppAuth/index.js
+++ b/src/routes/System/AppAuth/index.js
@@ -83,34 +83,32 @@ export default class Auth extends Component {
this.setState({ selectedRowKeys }, this.query);
};
+ currentQueryPayload = (currentPage = this.state.currentPage) => {
+ const { currentNamespaceId } = this.props;
+ const { appKey, phone, pageSize } = this.state;
+ return {
+ appKey,
+ phone,
+ currentPage,
+ pageSize,
+ namespaceId: currentNamespaceId,
+ };
+ };
+
query = () => {
- const { dispatch, currentNamespaceId } = this.props;
- const { appKey, phone, currentPage, pageSize } = this.state;
+ const { dispatch } = this.props;
dispatch({
type: "auth/fetch",
- payload: {
- appKey,
- phone,
- currentPage,
- pageSize,
- namespaceId: currentNamespaceId,
- },
+ payload: this.currentQueryPayload(),
});
};
// eslint-disable-next-line react/no-unused-class-component-methods
getAllAuths = (page) => {
- const { dispatch, currentNamespaceId } = this.props;
- const { appKey, phone, pageSize } = this.state;
+ const { dispatch } = this.props;
dispatch({
type: "auth/fetch",
- payload: {
- appKey,
- phone,
- currentPage: page,
- pageSize,
- namespaceId: currentNamespaceId,
- },
+ payload: this.currentQueryPayload(page),
});
};
@@ -122,10 +120,7 @@ export default class Auth extends Component {
this.setState({ currentPage: 1, pageSize }, this.query);
};
- closeModal = (refresh) => {
- if (refresh) {
- this.setState({ popup: "" }, this.query);
- }
+ closeModal = () => {
this.setState({ popup: "" });
};
@@ -150,13 +145,9 @@ export default class Auth extends Component {
...values,
namespaceId: currentNamespaceId,
},
- fetchValue: {
- currentPage,
- pageSize: 20,
- namespaceId: currentNamespaceId,
- },
+ fetchValue: this.currentQueryPayload(currentPage),
callback: () => {
- this.closeModal(true);
+ this.closeModal();
},
});
}}
@@ -172,7 +163,7 @@ export default class Auth extends Component {
editClickMeta = (record) => {
const { currentPage } = this.state;
- const { dispatch, currentNamespaceId } = this.props;
+ const { dispatch } = this.props;
dispatch({
type: "auth/fetchItemDel",
payload: {
@@ -205,13 +196,9 @@ export default class Auth extends Component {
dispatch({
type: "auth/updateDel",
payload: values,
- fetchValue: {
- currentPage,
- pageSize: 20,
- namespaceId: currentNamespaceId,
- },
+ fetchValue: this.currentQueryPayload(currentPage),
callback: () => {
- this.closeModal(true);
+ this.closeModal();
},
});
}}
@@ -232,7 +219,7 @@ export default class Auth extends Component {
};
deleteClick = () => {
- const { dispatch, currentNamespaceId } = this.props;
+ const { dispatch } = this.props;
const { selectedRowKeys } = this.state;
if (selectedRowKeys && selectedRowKeys.length > 0) {
dispatch({
@@ -240,11 +227,9 @@ export default class Auth extends Component {
payload: {
list: selectedRowKeys,
},
- fetchValue: {
- namespaceId: currentNamespaceId,
- },
+ fetchValue: this.currentQueryPayload(1),
callback: () => {
- this.setState({ selectedRowKeys: [], currentPage: 1 }, this.query);
+ this.setState({ selectedRowKeys: [], currentPage: 1 });
},
});
} else {
@@ -256,7 +241,6 @@ export default class Auth extends Component {
// 添加表格数据事件
addClick = () => {
- const { currentPage } = this.state;
const { dispatch, currentNamespaceId } = this.props;
dispatch({
type: "auth/fetchMetaGroup",
@@ -270,14 +254,10 @@ export default class Auth extends Component {
dispatch({
type: "auth/add",
payload: { ...values, namespaceId: currentNamespaceId },
- fetchValue: {
- currentPage,
- pageSize: 20,
- namespaceId: currentNamespaceId,
- },
+ fetchValue: this.currentQueryPayload(1),
callback: () => {
this.setState({ selectedRowKeys: [], currentPage: 1 });
- this.closeModal(true);
+ this.closeModal();
},
});
}}
@@ -292,16 +272,14 @@ export default class Auth extends Component {
};
openSwitch = ({ list, enabled, callback }) => {
- const { dispatch, currentNamespaceId } = this.props;
+ const { dispatch } = this.props;
dispatch({
type: "auth/updateOp",
payload: {
list,
enabled,
},
- fetchValue: {
- namespaceId: currentNamespaceId,
- },
+ fetchValue: this.currentQueryPayload(),
callback,
});
};
@@ -320,7 +298,7 @@ export default class Auth extends Component {
list: selectedRowKeys,
enabled: !user.open,
callback: () => {
- this.setState({ selectedRowKeys: [] }, this.query);
+ this.setState({ selectedRowKeys: [] });
},
});
},
@@ -332,16 +310,14 @@ export default class Auth extends Component {
};
statusSwitch = ({ list, enabled, callback }) => {
- const { dispatch, currentNamespaceId } = this.props;
+ const { dispatch } = this.props;
dispatch({
type: "auth/updateEn",
payload: {
list,
enabled,
},
- fetchValue: {
- namespaceId: currentNamespaceId,
- },
+ fetchValue: this.currentQueryPayload(),
callback,
});
};
@@ -360,7 +336,7 @@ export default class Auth extends Component {
list: selectedRowKeys,
enabled: !user.enabled,
callback: () => {
- this.setState({ selectedRowKeys: [] }, this.query);
+ this.setState({ selectedRowKeys: [] });
},
});
},
@@ -453,7 +429,6 @@ export default class Auth extends Component {
this.openSwitch({
list: [row.id],
enabled: checked,
- callback: this.query,
});
}}
/>
@@ -490,7 +465,6 @@ export default class Auth extends Component {
this.statusSwitch({
list: [row.id],
enabled: checked,
- callback: this.query,
});
}}
/>
diff --git a/src/routes/System/AppAuth/index.test.js
b/src/routes/System/AppAuth/index.test.js
new file mode 100644
index 00000000..87993702
--- /dev/null
+++ b/src/routes/System/AppAuth/index.test.js
@@ -0,0 +1,126 @@
+/*
+ * 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 ConnectedAuth from "./index";
+import model from "../../../models/auth";
+
+jest.mock("./AddModal", () => () => null);
+jest.mock("./AddTable", () => () => null);
+jest.mock("./RelateMetadata", () => () => null);
+jest.mock("./SearchContent", () => () => null);
+jest.mock(
+ "../../../utils/AuthButton",
+ () =>
+ ({ children }) =>
+ children,
+);
+jest.mock("../../../utils/IntlUtils", () => ({
+ getCurrentLocale: jest.fn(),
+ getIntlContent: (key) => key,
+}));
+jest.mock("../../../services/api", () => ({
+ addAuthData: jest.fn(),
+ deleteAuths: jest.fn(),
+ findAuthData: jest.fn(),
+ findAuthDataDel: jest.fn(),
+ getAllAuths: jest.fn(),
+ getAllMetadata: jest.fn(),
+ getAllMetadatas: jest.fn(),
+ getfetchMetaGroup: jest.fn(),
+ syncAuthsData: jest.fn(),
+ updateAuthData: jest.fn(),
+ updateAuthDel: jest.fn(),
+ updateAuthEnabled: jest.fn(),
+ updateAuthOpened: jest.fn(),
+}));
+
+const Auth = ConnectedAuth.WrappedComponent;
+const put = (action) => ({ type: "put", action });
+
+const makeComponent = (dispatch) => {
+ const component = new Auth({
+ currentNamespaceId: "namespace-1",
+ dispatch,
+ });
+ component.setState = (update, callback) => {
+ const nextState =
+ typeof update === "function"
+ ? update(component.state, component.props)
+ : update;
+ component.state = { ...component.state, ...nextState };
+ if (callback) {
+ callback();
+ }
+ };
+ return component;
+};
+
+it("reloads auths with the active filters and page size", () => {
+ const fetchValue = {
+ appKey: "app-key",
+ phone: "13800000000",
+ currentPage: 2,
+ pageSize: 12,
+ namespaceId: "namespace-1",
+ };
+ const generator = model.effects.reload({ fetchValue }, { put });
+
+ expect(generator.next().value).toEqual(
+ put({
+ type: "fetch",
+ payload: fetchValue,
+ }),
+ );
+ expect(generator.next().done).toBe(true);
+});
+
+it("passes the current query to update without issuing a second fetch", () => {
+ const dispatch = jest.fn((action) => {
+ if (action.type === "auth/fetchItem") {
+ action.callback({ id: "auth-1" });
+ }
+ });
+ const component = makeComponent(dispatch);
+ component.state = {
+ ...component.state,
+ appKey: "app-key",
+ phone: "13800000000",
+ currentPage: 2,
+ pageSize: 12,
+ };
+
+ component.editClick({ id: "auth-1" });
+ component.state.popup.props.handleOk({ appKey: "updated-app-key" });
+
+ const updateCall = dispatch.mock.calls.find(
+ ([action]) => action.type === "auth/update",
+ );
+ expect(updateCall).toBeDefined();
+ const [updateAction] = updateCall;
+ expect(updateAction.fetchValue).toEqual({
+ appKey: "app-key",
+ phone: "13800000000",
+ currentPage: 2,
+ pageSize: 12,
+ namespaceId: "namespace-1",
+ });
+
+ updateAction.callback();
+ expect(
+ dispatch.mock.calls.filter(([action]) => action.type === "auth/fetch"),
+ ).toHaveLength(0);
+});