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 4180a4d9 fix: preserve alert namespace on reload (#680)
4180a4d9 is described below

commit 4180a4d9b8fff9ddf49537daaa490e0c481bc547
Author: Carlos Acosta <[email protected]>
AuthorDate: Sun Sep 27 00:32:00 2026 -0500

    fix: preserve alert namespace on reload (#680)
    
    Co-authored-by: Aeontra <aeontra@localhost>
---
 src/models/alert.js                   |  4 +-
 src/models/alert.test.js              | 49 ++++++++++++++++++++++++
 src/routes/System/Alert/index.js      | 45 +++++++++++++++++-----
 src/routes/System/Alert/index.test.js | 71 +++++++++++++++++++++++++++++++++++
 4 files changed, 158 insertions(+), 11 deletions(-)

diff --git a/src/models/alert.js b/src/models/alert.js
index 51332f22..02b818cd 100644
--- a/src/models/alert.js
+++ b/src/models/alert.js
@@ -96,8 +96,8 @@ export default {
     },
     *reload(params, { put }) {
       const { fetchValue } = params;
-      const { userName, currentPage, pageSize } = fetchValue;
-      const payload = { userName, currentPage, pageSize };
+      const { currentPage, pageSize, namespaceId } = fetchValue;
+      const payload = { currentPage, pageSize, namespaceId };
       yield put({ type: "fetch", payload });
     },
   },
diff --git a/src/models/alert.test.js b/src/models/alert.test.js
new file mode 100644
index 00000000..5a002628
--- /dev/null
+++ b/src/models/alert.test.js
@@ -0,0 +1,49 @@
+/*
+ * 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 model from "./alert";
+
+jest.mock("../services/api", () => ({
+  addAlertReceiver: jest.fn(),
+  deleteAlertReceivers: jest.fn(),
+  fetchAlertReport: jest.fn(),
+  getAlertReceiverDetail: jest.fn(),
+  getAlertReceivers: jest.fn(),
+  updateAlertReceiver: jest.fn(),
+}));
+jest.mock("../utils/IntlUtils", () => ({
+  getIntlContent: (key) => key,
+}));
+
+const put = (action) => ({ type: "put", action });
+
+it("reloads alert receivers with the active namespace", () => {
+  const fetchValue = {
+    currentPage: 2,
+    pageSize: 20,
+    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);
+});
diff --git a/src/routes/System/Alert/index.js b/src/routes/System/Alert/index.js
index 7a8d9d3b..cb5d48ea 100644
--- a/src/routes/System/Alert/index.js
+++ b/src/routes/System/Alert/index.js
@@ -26,12 +26,20 @@ import { Type } from "./globalData";
 
 const DEFAULT_ALERT_TYPE = 1;
 
-@connect(({ alert, loading, global }) => ({
-  alert,
-  loading: loading.effects["alert/fetch"],
-  currentNamespaceId: global.currentNamespaceId,
-}))
-export default class Alert extends Component {
+export const getAlertPageAfterDelete = (
+  total,
+  deletedCount,
+  currentPage,
+  pageSize,
+) => {
+  const remainingPages = Math.max(
+    1,
+    Math.ceil((total - deletedCount) / pageSize),
+  );
+  return Math.min(currentPage, remainingPages);
+};
+
+export class AlertComponent extends Component {
   constructor(props) {
     super(props);
     this.state = {
@@ -123,20 +131,31 @@ export default class Alert extends Component {
   };
 
   deleteClick = () => {
-    const { dispatch } = this.props;
+    const {
+      dispatch,
+      currentNamespaceId,
+      alert: { total },
+    } = this.props;
     const { currentPage, pageSize, selectedRowKeys } = this.state;
     if (selectedRowKeys && selectedRowKeys.length > 0) {
+      const nextPage = getAlertPageAfterDelete(
+        total,
+        selectedRowKeys.length,
+        currentPage,
+        pageSize,
+      );
       dispatch({
         type: "alert/delete",
         payload: {
           list: selectedRowKeys,
         },
         fetchValue: {
-          currentPage,
+          currentPage: nextPage,
           pageSize,
+          namespaceId: currentNamespaceId,
         },
         callback: () => {
-          this.setState({ selectedRowKeys: [] });
+          this.setState({ selectedRowKeys: [], currentPage: nextPage });
         },
       });
     } else {
@@ -350,3 +369,11 @@ export default class Alert extends Component {
     );
   }
 }
+
+const ConnectedAlert = connect(({ alert, loading, global }) => ({
+  alert,
+  loading: loading.effects["alert/fetch"],
+  currentNamespaceId: global.currentNamespaceId,
+}))(AlertComponent);
+
+export default ConnectedAlert;
diff --git a/src/routes/System/Alert/index.test.js 
b/src/routes/System/Alert/index.test.js
new file mode 100644
index 00000000..fa1020a5
--- /dev/null
+++ b/src/routes/System/Alert/index.test.js
@@ -0,0 +1,71 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { AlertComponent, getAlertPageAfterDelete } from "./index";
+
+jest.mock("./AddModal", () => () => null);
+jest.mock(
+  "../../../utils/AuthButton",
+  () =>
+    ({ children }) =>
+      children,
+);
+jest.mock("../../../utils/IntlUtils", () => ({
+  getCurrentLocale: jest.fn(),
+  getIntlContent: (key) => key,
+}));
+
+it("moves back when deleting the final row on a later page", () => {
+  expect(getAlertPageAfterDelete(13, 1, 2, 12)).toBe(1);
+  expect(getAlertPageAfterDelete(25, 1, 3, 12)).toBe(2);
+  expect(getAlertPageAfterDelete(30, 1, 2, 12)).toBe(2);
+});
+
+it("passes namespace and the existing page to the delete reload", () => {
+  const dispatch = jest.fn();
+  const component = new AlertComponent({
+    dispatch,
+    currentNamespaceId: "namespace-1",
+    alert: {
+      alertList: [{ id: "receiver-13" }],
+      total: 13,
+    },
+  });
+  component.state = {
+    ...component.state,
+    currentPage: 2,
+    pageSize: 12,
+    selectedRowKeys: ["receiver-13"],
+  };
+  component.setState = (update) => {
+    component.state = { ...component.state, ...update };
+  };
+
+  component.deleteClick();
+
+  const action = dispatch.mock.calls[0][0];
+  expect(action.type).toBe("alert/delete");
+  expect(action.fetchValue).toEqual({
+    currentPage: 1,
+    pageSize: 12,
+    namespaceId: "namespace-1",
+  });
+
+  action.callback();
+  expect(component.state.currentPage).toBe(1);
+  expect(component.state.selectedRowKeys).toEqual([]);
+});

Reply via email to