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 ed7c5b63c fix(instance): recover from malformed route encoding (#2357)
ed7c5b63c is described below

commit ed7c5b63c06e6718f77a9f2725196c5c37c04597
Author: yyqdbngt <[email protected]>
AuthorDate: Fri Aug 21 17:03:55 2026 +0800

    fix(instance): recover from malformed route encoding (#2357)
---
 web/src/hooks/useInstanceFilter.test.tsx | 28 ++++++++++++++++++++++++++++
 web/src/hooks/useInstanceFilter.ts       | 11 ++++++++++-
 2 files changed, 38 insertions(+), 1 deletion(-)

diff --git a/web/src/hooks/useInstanceFilter.test.tsx 
b/web/src/hooks/useInstanceFilter.test.tsx
index 461b7f0e1..b73abc2dd 100644
--- a/web/src/hooks/useInstanceFilter.test.tsx
+++ b/web/src/hooks/useInstanceFilter.test.tsx
@@ -60,4 +60,32 @@ describe('useInstanceFilter', () => {
       
expect(screen.getByText('/instance/instance-a/topic|instance-a')).toBeInTheDocument();
     });
   });
+
+  it('recovers from a malformed encoded instance id', async () => {
+    instanceServiceMocks.listInstances.mockResolvedValue([
+      {
+        id: 7,
+        name: 'instance-a',
+        remark: '',
+        type: 'PROXY',
+        endpoint: '127.0.0.1:8080',
+        topicCount: 0,
+        consumerGroupCount: 0,
+        gmtCreate: '2026-01-01T00:00:00Z',
+        gmtModified: '2026-01-01T00:00:00Z',
+      },
+    ]);
+
+    render(
+      <MemoryRouter initialEntries={['/instance/%E0%A4%A/topic']}>
+        <Routes>
+          <Route path="/instance/:instanceId/topic" 
element={<InstanceRouteProbe />} />
+        </Routes>
+      </MemoryRouter>,
+    );
+
+    await waitFor(() => {
+      
expect(screen.getByText('/instance/instance-a/topic|instance-a')).toBeInTheDocument();
+    });
+  });
 });
diff --git a/web/src/hooks/useInstanceFilter.ts 
b/web/src/hooks/useInstanceFilter.ts
index 6c70aded9..2d9e63a84 100644
--- a/web/src/hooks/useInstanceFilter.ts
+++ b/web/src/hooks/useInstanceFilter.ts
@@ -23,6 +23,15 @@ import type { Instance } from '../api/instance';
 const INSTANCE_SCOPED_PATH = 
/^\/instance\/([^/]+)\/(topic|consumer|message|acl|dlq)$/;
 const STATIC_SECTION_PATH = /^\/instance\/(topic|consumer|message|acl|dlq)$/;
 
+function decodeRouteSegment(segment: string | undefined) {
+  if (segment === undefined) return undefined;
+  try {
+    return decodeURIComponent(segment);
+  } catch {
+    return undefined;
+  }
+}
+
 /**
  * 实例维度页面的公共筛选逻辑:从 /instance/:instanceId/<section> 路由解析当前实例,
  * 无实例参数时重定向到第一个实例;实例列表加载失败时降级为不过滤。
@@ -33,7 +42,7 @@ export function useInstanceFilter() {
 
   const scopedMatch = pathname.match(INSTANCE_SCOPED_PATH);
   const staticMatch = pathname.match(STATIC_SECTION_PATH);
-  const routeInstanceId = scopedMatch ? decodeURIComponent(scopedMatch[1]) : 
undefined;
+  const routeInstanceId = decodeRouteSegment(scopedMatch?.[1]);
   const section = scopedMatch?.[2] ?? staticMatch?.[1] ?? 'topic';
 
   const [instances, setInstances] = useState<Instance[]>([]);

Reply via email to