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

lizhimins pushed a commit to branch rocketmq-studio
in repository https://gitbox.apache.org/repos/asf/rocketmq-dashboard.git


The following commit(s) were added to refs/heads/rocketmq-studio by this push:
     new 3a78b1824 fix(alerts): reset list state when the alerts domain route 
switches (#4004)
3a78b1824 is described below

commit 3a78b1824b8ee349b8963371148509c4337650d7
Author: 烤化の初雪 <[email protected]>
AuthorDate: Mon Sep 7 18:22:51 2026 +0800

    fix(alerts): reset list state when the alerts domain route switches (#4004)
    
    /ops/alerts and /ops/business-alerts render the same AlertsPage
    instance, so React preserved page, search and status-filter state when
    navigating between the two menu entries. Paging to page 2 and then
    switching domains fetched the other domain with the retained page and
    showed an empty table (rc-pagination clamps the displayed page to 1),
    and a retained search silently narrowed the other domain's rule list.
    
    Drop the previous domain's list state during render when the domain
    prop changes, so each domain loads from a clean page 1 with no filters.
    
    Co-authored-by: unbridled-41 
<[email protected]>
---
 web/src/pages/ops/__tests__/AlertsPage.test.tsx | 48 +++++++++++++++++++++++++
 web/src/pages/ops/alerts.tsx                    | 17 +++++++++
 2 files changed, 65 insertions(+)

diff --git a/web/src/pages/ops/__tests__/AlertsPage.test.tsx 
b/web/src/pages/ops/__tests__/AlertsPage.test.tsx
index e9c1f7a39..77abe6db6 100644
--- a/web/src/pages/ops/__tests__/AlertsPage.test.tsx
+++ b/web/src/pages/ops/__tests__/AlertsPage.test.tsx
@@ -315,6 +315,54 @@ describe('AlertsPage', () => {
     expect(screen.getByText('21')).toBeInTheDocument();
   });
 
+  it('resets page, search and status filters when the domain switches', async 
() => {
+    vi.mocked(listAlertRulesPage).mockClear();
+    vi.mocked(listAlertRulesPage).mockResolvedValue({
+      items: [cloneRule(alertRules[0])],
+      total: 21,
+      page: 2,
+      size: 20,
+    });
+    const user = userEvent.setup();
+    const { rerender } = renderPage();
+
+    await screen.findByText('Broker disk usage');
+    await user.type(screen.getByPlaceholderText('搜索规则名称或指标'), 'disk');
+    await waitFor(() =>
+      expect(listAlertRulesPage).toHaveBeenLastCalledWith(
+        'CLUSTER',
+        expect.objectContaining({ search: 'disk' }),
+      ),
+    );
+    const secondPage = document.querySelector('.ant-pagination-item-2') as 
HTMLElement | null;
+    if (!secondPage) throw new Error('Pagination page 2 not found');
+    await user.click(secondPage);
+    await waitFor(() =>
+      expect(listAlertRulesPage).toHaveBeenLastCalledWith(
+        'CLUSTER',
+        expect.objectContaining({ page: 2 }),
+      ),
+    );
+
+    rerender(
+      <App>
+        <LangProvider>
+          <AlertsPage domain="BUSINESS" />
+        </LangProvider>
+      </App>,
+    );
+
+    await waitFor(() =>
+      expect(listAlertRulesPage).toHaveBeenLastCalledWith('BUSINESS', {
+        enabled: undefined,
+        page: 1,
+        pageSize: 20,
+        search: undefined,
+      }),
+    );
+    expect(screen.getByPlaceholderText('搜索规则名称或指标')).toHaveValue('');
+  });
+
   it('uses the business rule API and loads only business metrics for the 
selected instance', async () => {
     vi.mocked(listNativeAlertMetrics).mockResolvedValue([
       {
diff --git a/web/src/pages/ops/alerts.tsx b/web/src/pages/ops/alerts.tsx
index 242d257d4..3280abedb 100644
--- a/web/src/pages/ops/alerts.tsx
+++ b/web/src/pages/ops/alerts.tsx
@@ -172,6 +172,23 @@ const AlertsPage = ({ domain = 'CLUSTER' }: 
AlertsPageProps) => {
   const [selectedRuleIds, setSelectedRuleIds] = useState<Key[]>([]);
   const [bulkAction, setBulkAction] = useState<'enable' | 'disable' | 'delete' 
| null>(null);
   const [form] = Form.useForm();
+  // The same component instance serves /ops/alerts and /ops/business-alerts, 
so the
+  // list state from the previous domain must be dropped when the route 
switches
+  // (React's documented "adjust state when a prop changes" pattern). Clear 
the loaded
+  // rows/total/runtime and re-enter the loading state as well, otherwise the 
previous
+  // domain's rules stay visible with loading=false until the new page 
resolves.
+  const [renderedDomain, setRenderedDomain] = useState(domain);
+  if (renderedDomain !== domain) {
+    setRenderedDomain(domain);
+    setPage(1);
+    setSearch('');
+    setEnabledFilter(undefined);
+    setSelectedRuleIds([]);
+    setRules([]);
+    setTotalRules(0);
+    setRuntime([]);
+    setLoading(true);
+  }
   const selectedMetric = Form.useWatch('metric', form);
   const selectedOperator = Form.useWatch('operator', form);
   const selectedThresholdUnit = Form.useWatch('thresholdUnit', form);

Reply via email to