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 a2b90e33e fix(web): clear the subscription check spinner when a silent 
refresh wins (#5121)
a2b90e33e is described below

commit a2b90e33effe15ebb515798c0eb0d77713d76b3a
Author: 烤化の初雪 <[email protected]>
AuthorDate: Fri Oct 9 17:49:08 2026 +0800

    fix(web): clear the subscription check spinner when a silent refresh wins 
(#5121)
    
    `loadSubscriptions` cleared its loading flag only for non-silent requests, 
so after a background
    refresh the flag stayed false and the subscription table kept showing stale 
rows with no spinner.
    The `!silent` condition is dropped from the `finally`; the request-id check 
still discards
    out-of-order responses.
    
    `ConsumerPage.test.tsx` 44 tests green - including the four import-toast 
assertions added today in
    #5238, whose changes to the same two files this rebases onto - and prettier 
clean.
---
 .../pages/instance/__tests__/ConsumerPage.test.tsx | 63 ++++++++++++++++++++++
 web/src/pages/instance/consumer.tsx                |  9 +++-
 2 files changed, 70 insertions(+), 2 deletions(-)

diff --git a/web/src/pages/instance/__tests__/ConsumerPage.test.tsx 
b/web/src/pages/instance/__tests__/ConsumerPage.test.tsx
index 0c325a116..3fb5bbb65 100644
--- a/web/src/pages/instance/__tests__/ConsumerPage.test.tsx
+++ b/web/src/pages/instance/__tests__/ConsumerPage.test.tsx
@@ -1395,6 +1395,69 @@ describe('Consumer page', () => {
     expect(screen.getByText('全部 2 个订阅配置一致')).toBeInTheDocument();
   });
 
+  it('stops the subscription check spinner when a silent refresh supersedes 
it', async () => {
+    const userRequest =
+      deferred<Awaited<ReturnType<typeof 
consumerService.getConsumerSubscriptions>>>();
+    const silentRequest =
+      deferred<Awaited<ReturnType<typeof 
consumerService.getConsumerSubscriptions>>>();
+    vi.mocked(consumerService.getConsumerSubscriptions)
+      .mockReturnValueOnce(userRequest.promise)
+      .mockReturnValueOnce(silentRequest.promise)
+      .mockResolvedValue([
+        {
+          topic: 'remote-topic',
+          expression: '*',
+          type: 'NORMAL',
+          filterMode: '全量',
+          consistency: 'consistent',
+        },
+      ]);
+
+    const user = userEvent.setup({ pointerEventsCheck: 0 });
+    renderWithProviders(<ConsumerPage />);
+
+    // Opening the modal starts a user-visible check; the modal's 2s 
auto-refresh then starts a
+    // silent one while that check is still in flight.
+    await user.click(await screen.findByRole('button', { name: /详情/ }));
+    const checkButton = await screen.findByRole('button', { name: /重新检查/ });
+    expect(checkButton).toHaveClass('ant-btn-loading');
+    await waitFor(() => 
expect(consumerService.getConsumerSubscriptions).toHaveBeenCalledTimes(2), {
+      timeout: 10000,
+    });
+
+    await act(async () => {
+      silentRequest.resolve([
+        {
+          topic: 'remote-topic',
+          expression: '*',
+          type: 'NORMAL',
+          filterMode: '全量',
+          consistency: 'consistent',
+        },
+      ]);
+      await silentRequest.promise;
+    });
+    await act(async () => {
+      userRequest.resolve([
+        {
+          topic: 'remote-topic',
+          expression: '*',
+          type: 'NORMAL',
+          filterMode: '全量',
+          consistency: 'consistent',
+        },
+      ]);
+      await userRequest.promise;
+    });
+
+    // Neither request clears the flag on the old code: the user-triggered one 
is no longer the
+    // current request and the silent one is skipped by the `!silent` guard, 
so the button kept
+    // spinning forever.
+    await waitFor(() =>
+      expect(screen.getByRole('button', { name: /重新检查/ 
})).not.toHaveClass('ant-btn-loading'),
+    );
+  });
+
   it('keeps unknown consistency values separate from mismatches', async () => {
     vi.mocked(consumerService.getConsumerSubscriptions).mockResolvedValue([
       {
diff --git a/web/src/pages/instance/consumer.tsx 
b/web/src/pages/instance/consumer.tsx
index 790e459a4..01a5577cf 100644
--- a/web/src/pages/instance/consumer.tsx
+++ b/web/src/pages/instance/consumer.tsx
@@ -413,8 +413,13 @@ const ConsumerPageContent = ({
           }
         }
       } finally {
-        if (subscriptionRequestIdRef.current[cacheKey] === requestId && 
!silent) {
-          setSubscriptionLoadingByGroup((prev) => ({ ...prev, [cacheKey]: 
false }));
+        // The loading flag belongs to whichever request is current, not to 
the request that
+        // raised it: the modal's 2s auto-refresh can supersede a user-visible 
check while that
+        // check is still in flight, and then only the silent request is left 
to clear it.
+        if (subscriptionRequestIdRef.current[cacheKey] === requestId) {
+          setSubscriptionLoadingByGroup((prev) =>
+            prev[cacheKey] ? { ...prev, [cacheKey]: false } : prev,
+          );
         }
       }
     },

Reply via email to