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 f674661b Fix isloading never resetting on the exception trigger page 
(#663)
f674661b is described below

commit f674661bf61d063881c94df26cc4f0b1c12fa302
Author: Anay Parwal <[email protected]>
AuthorDate: Sat Sep 26 00:27:57 2026 -0400

    Fix isloading never resetting on the exception trigger page (#663)
    
    * Fix isloading never resetting on the exception trigger page
    
    TriggerException tracked loading in local component state, set it to
    true on click, and never reset it; meanwhile the error model's
    `trigger` reducer dropped the (unused) `isloading` field from state.
    
    Switches the component to the standard `loading.effects["error/query"]`
    pattern already used throughout the codebase (e.g. GlobalHeader,
    BasicLayout, most System/* pages). This is tracked by the dva-loading
    plugin and resets automatically when the effect finishes, including
    on failure, so the spinner can no longer get stuck. Also removes the
    now-dead `isloading` field from the error model's state, since nothing
    referenced it besides the buggy local flag.
    
    Closes #653
    
    * Coerce isloading to boolean; add regression test
    
    Before the first dispatch, dva-loading's `effects` map is empty, so
    `loading.effects["error/query"]` is undefined rather than false.
    Ant Design's Spin treats an undefined `spinning` prop as true, so the
    trigger page showed a loading overlay on initial render before any
    request had been made.
    
    Coerces the mapped value to a boolean with `!!`, and adds a test that
    renders the connected component (via a minimal fake store, following
    the reviewer's own repro) covering the empty-effects, in-flight, and
    finished states.
---
 src/models/error.js                           |  1 -
 src/routes/Exception/triggerException.js      | 26 ++++++------
 src/routes/Exception/triggerException.test.js | 57 +++++++++++++++++++++++++++
 3 files changed, 70 insertions(+), 14 deletions(-)

diff --git a/src/models/error.js b/src/models/error.js
index f994b7df..3af7073c 100644
--- a/src/models/error.js
+++ b/src/models/error.js
@@ -23,7 +23,6 @@ export default {
 
   state: {
     error: "",
-    isloading: false,
   },
 
   effects: {
diff --git a/src/routes/Exception/triggerException.js 
b/src/routes/Exception/triggerException.js
index 96755c67..74c2b27a 100644
--- a/src/routes/Exception/triggerException.js
+++ b/src/routes/Exception/triggerException.js
@@ -18,23 +18,14 @@
 import React, { PureComponent } from "react";
 import { Button, Spin, Card } from "antd";
 import { connect } from "dva";
+import PropTypes from "prop-types";
 import styles from "./style.less";
 
-@connect((state) => ({
-  isloading: state.error.isloading,
+@connect(({ loading }) => ({
+  isloading: !!loading.effects["error/query"],
 }))
 export default class TriggerException extends PureComponent {
-  constructor(props) {
-    super(props);
-    this.state = {
-      isloading: false,
-    };
-  }
-
   triggerError = (code) => {
-    this.setState({
-      isloading: true,
-    });
     const { dispatch } = this.props;
     dispatch({
       type: "error/query",
@@ -45,7 +36,7 @@ export default class TriggerException extends PureComponent {
   };
 
   render() {
-    const { isloading } = this.state;
+    const { isloading } = this.props;
     return (
       <Card>
         <Spin spinning={isloading} wrapperClassName={styles.trigger}>
@@ -66,3 +57,12 @@ export default class TriggerException extends PureComponent {
     );
   }
 }
+
+TriggerException.propTypes = {
+  isloading: PropTypes.bool,
+  dispatch: PropTypes.func.isRequired,
+};
+
+TriggerException.defaultProps = {
+  isloading: false,
+};
diff --git a/src/routes/Exception/triggerException.test.js 
b/src/routes/Exception/triggerException.test.js
new file mode 100644
index 00000000..13c0f9c6
--- /dev/null
+++ b/src/routes/Exception/triggerException.test.js
@@ -0,0 +1,57 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import React from "react";
+import { render } from "@testing-library/react";
+import { Provider } from "react-redux";
+import TriggerException from "./triggerException";
+
+function renderWithStore(state) {
+  const store = {
+    getState: () => state,
+    subscribe: () => () => {},
+    dispatch: () => {},
+  };
+  return render(
+    <Provider store={store}>
+      <TriggerException />
+    </Provider>,
+  );
+}
+
+describe("TriggerException", () => {
+  it("is not spinning on initial render, before any effect has run", () => {
+    // Before the first dispatch, dva-loading's `effects` map is empty, so
+    // `loading.effects["error/query"]` is undefined rather than false.
+    const { container } = renderWithStore({ loading: { effects: {} } });
+    expect(container.querySelector(".ant-spin-spinning")).toBeNull();
+  });
+
+  it("is spinning while the error/query effect is in flight", () => {
+    const { container } = renderWithStore({
+      loading: { effects: { "error/query": true } },
+    });
+    expect(container.querySelector(".ant-spin-spinning")).not.toBeNull();
+  });
+
+  it("is not spinning once the error/query effect has finished", () => {
+    const { container } = renderWithStore({
+      loading: { effects: { "error/query": false } },
+    });
+    expect(container.querySelector(".ant-spin-spinning")).toBeNull();
+  });
+});

Reply via email to