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;

Reply via email to