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 2945fba5e fix(topic): scope topic page state to the selected instance
(#4490)
2945fba5e is described below
commit 2945fba5e27fddcc68e4792a59cfa1fb3c48142e
Author: zmuxuny <[email protected]>
AuthorDate: Mon Sep 21 12:09:29 2026 +0800
fix(topic): scope topic page state to the selected instance (#4490)
Split TopicPage into a thin shell plus TopicPageContent and key the content
by the
selected instance id, the same shape the consumer page already uses.
Every piece of page state — search term, type filter, pagination, row
selection,
open dialogs and their form values, in-flight request ids — is now reset
when the
operator switches instance, so an edit dialog opened on instance A can no
longer
stay mounted and submit A's values against B's id.
---
.../pages/instance/__tests__/TopicPage.test.tsx | 32 ++++++++++++++++++++++
web/src/pages/instance/topic.tsx | 29 ++++++++++++++------
2 files changed, 52 insertions(+), 9 deletions(-)
diff --git a/web/src/pages/instance/__tests__/TopicPage.test.tsx
b/web/src/pages/instance/__tests__/TopicPage.test.tsx
index e7d4c27c3..a4f27af07 100644
--- a/web/src/pages/instance/__tests__/TopicPage.test.tsx
+++ b/web/src/pages/instance/__tests__/TopicPage.test.tsx
@@ -318,6 +318,38 @@ describe('TopicPage', () => {
expect(await screen.findByText(/更新成功/)).toBeInTheDocument();
});
+ it('invalidates an open Topic edit when the selected instance changes',
async () => {
+ const user = userEvent.setup();
+ const topicA = { ...buildTopics(1)[0], name: 'topic-a', instanceId:
'instance-a' };
+ const topicB = { ...buildTopics(1)[0], name: 'topic-b', instanceId:
'instance-b' };
+ instanceServiceMocks.listInstances.mockResolvedValue([
+ { ...selectedInstance, id: 1, name: 'instance-a', endpoint:
'127.0.0.1:9876' },
+ { ...selectedInstance, id: 2, name: 'instance-b', endpoint:
'127.0.0.2:9876' },
+ ]);
+ topicServiceMocks.listTopicsPage.mockImplementation(async (params) => ({
+ items: [params?.instanceId === 'instance-b' ? topicB : topicA],
+ total: 1,
+ page: 1,
+ size: 20,
+ }));
+ renderWithProviders('/instance/instance-a/topic');
+
+ expect(await screen.findByText('topic-a')).toBeInTheDocument();
+ const row = within(getTableBody()).getByText('topic-a').closest('tr') as
HTMLElement;
+ await user.click(within(row).getByRole('button', { name: /配\s*置/ }));
+ const editDialog = await screen.findByRole('dialog');
+ expect(within(editDialog).getByText('编辑 Topic')).toBeInTheDocument();
+
+ await user.click(screen.getAllByRole('combobox')[0]);
+ await user.click(
+ await screen.findByText('instance-b', { selector:
'.ant-select-item-option-content' }),
+ );
+
+ expect(await screen.findByText('topic-b')).toBeInTheDocument();
+ await waitFor(() => expect(screen.queryByText('编辑
Topic')).not.toBeInTheDocument());
+ expect(topicServiceMocks.updateTopic).not.toHaveBeenCalled();
+ });
+
it('edits cloud topics without the broker-only fields', async () => {
instanceServiceMocks.listInstances.mockResolvedValue([
{ ...selectedInstance, vendor: 'ALIYUN' },
diff --git a/web/src/pages/instance/topic.tsx b/web/src/pages/instance/topic.tsx
index 4252332cb..4f6e8c4cb 100644
--- a/web/src/pages/instance/topic.tsx
+++ b/web/src/pages/instance/topic.tsx
@@ -336,17 +336,18 @@ const PAYLOAD_ISSUE_COLOR:
Record<MessagePayloadIssue['severity'], string> = {
};
// ═══════════════════════════════════════════════════════════════════
-const TopicPage = () => {
+type TopicPageContentProps = ReturnType<typeof useInstanceFilter>;
+
+const TopicPageContent = ({
+ selectedInstanceId,
+ selectedInstance,
+ selectInstance,
+ instanceOptions,
+ instancesLoading,
+ instances,
+}: TopicPageContentProps) => {
const { t } = useLang();
const navigate = useNavigate();
- const {
- selectedInstanceId,
- selectedInstance,
- selectInstance,
- instanceOptions,
- instancesLoading,
- instances,
- } = useInstanceFilter();
const isCloudInstance =
selectedInstance?.vendor === 'ALIYUN' || selectedInstance?.vendor ===
'TENCENT';
const hasSelectedInstance = Boolean(selectedInstanceId);
@@ -2091,4 +2092,14 @@ const TopicPage = () => {
);
};
+const TopicPage = () => {
+ const instanceFilter = useInstanceFilter();
+ return (
+ <TopicPageContent
+ key={instanceFilter.selectedInstanceId || 'no-selected-instance'}
+ {...instanceFilter}
+ />
+ );
+};
+
export default TopicPage;