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,
+ );
}
}
},