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[]>([]);