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 1e8cc5919 fix(instance): surface the server error reason when creating
or updating an instance (#4241)
1e8cc5919 is described below
commit 1e8cc5919aa5d110f59af60361ffc3a9c4154f9c
Author: 烤化の初雪 <[email protected]>
AuthorDate: Tue Sep 15 21:13:32 2026 +0800
fix(instance): surface the server error reason when creating or updating an
instance (#4241)
(cherry picked from commit efafdda638cb2bd335eccb2eff2b574dd6633490)
Co-authored-by: unbridled-41
<[email protected]>
---
.../pages/instance/__tests__/InstancePage.test.tsx | 45 ++++++++++++++++++++++
web/src/pages/instance/index.tsx | 4 +-
2 files changed, 47 insertions(+), 2 deletions(-)
diff --git a/web/src/pages/instance/__tests__/InstancePage.test.tsx
b/web/src/pages/instance/__tests__/InstancePage.test.tsx
index 2e1cc2b7b..065b3ac90 100644
--- a/web/src/pages/instance/__tests__/InstancePage.test.tsx
+++ b/web/src/pages/instance/__tests__/InstancePage.test.tsx
@@ -440,6 +440,51 @@ describe('InstancePage', () => {
expect(screen.queryByText('请输入接入地址')).not.toBeInTheDocument();
});
+ it('surfaces the server error reason when creating an instance fails', async
() => {
+ const user = userEvent.setup();
+ vi.mocked(instanceService.createInstance).mockRejectedValue({
+ response: { data: { message: 'Instance name already exists: new-proxy' }
},
+ });
+ renderPage();
+
+ expect(await screen.findByText('production-proxy')).toBeInTheDocument();
+ await user.click(screen.getByRole('button', { name: /添加实例/ }));
+ const dialog = await screen.findByRole('dialog');
+ await user.type(within(dialog).getByLabelText('实例 ID'), 'new-proxy');
+ const createTypeSelect = within(dialog).getByRole('combobox');
+ fireEvent.mouseDown(createTypeSelect.parentElement!);
+ const proxyOptions = await screen.findAllByText('Proxy Cluster 模式', {
+ selector: '.ant-select-item-option-content',
+ });
+ await user.click(proxyOptions[proxyOptions.length - 1]);
+ await user.type(within(dialog).getByLabelText('接入地址'), 'proxy-new:8080');
+ await user.click(within(dialog).getByRole('button', { name: /连\s*接/ }));
+
+ expect(await screen.findByText('Instance name already exists:
new-proxy')).toBeInTheDocument();
+ expect(screen.queryByText('添加实例失败,请稍后重试')).not.toBeInTheDocument();
+ });
+
+ it('surfaces the server error reason when updating an instance fails', async
() => {
+ const user = userEvent.setup();
+ vi.mocked(instanceService.updateInstance).mockRejectedValue({
+ response: { data: { message: 'Instance endpoint is not reachable' } },
+ });
+ renderPage();
+
+ expect(await screen.findByText('production-proxy')).toBeInTheDocument();
+ const row = screen.getByRole('row', { name: /production-proxy/ });
+ await user.click(within(row).getByRole('button', { name: /编\s*辑/ }));
+ const dialog = await screen.findByRole('dialog');
+
+ const endpointInput = within(dialog).getByLabelText('接入地址');
+ await user.clear(endpointInput);
+ await user.type(endpointInput, 'namesrv-new:9876');
+ await user.click(within(dialog).getByRole('button', { name: /保\s*存/ }));
+
+ expect(await screen.findByText('Instance endpoint is not
reachable')).toBeInTheDocument();
+ expect(screen.queryByText('更新实例失败,请稍后重试')).not.toBeInTheDocument();
+ });
+
it('reloads the latest filters after a pending instance deletion completes',
async () => {
const user = userEvent.setup();
const pendingDelete = deferred<void>();
diff --git a/web/src/pages/instance/index.tsx b/web/src/pages/instance/index.tsx
index 23eb74185..146013c65 100644
--- a/web/src/pages/instance/index.tsx
+++ b/web/src/pages/instance/index.tsx
@@ -375,7 +375,7 @@ const InstancePage = () => {
if (error && typeof error === 'object' && 'errorFields' in error) {
return; // validation failure; antd already shows field-level errors
}
- message.error(t('instance.createFailed'));
+ message.error(describeApiError(error, t('instance.createFailed')));
} finally {
mutationInFlightRef.current = false;
setSubmitting(false);
@@ -459,7 +459,7 @@ const InstancePage = () => {
if (error && typeof error === 'object' && 'errorFields' in error) {
return; // validation failure; antd already shows field-level errors
}
- message.error(t('instance.updateFailed'));
+ message.error(describeApiError(error, t('instance.updateFailed')));
} finally {
mutationInFlightRef.current = false;
setSubmitting(false);