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 b922a8b9 feat: support topic-only producer connection queries (#742)
b922a8b9 is described below
commit b922a8b94d54aad61920cbc22a87d56e19ce6641
Author: yx9o <[email protected]>
AuthorDate: Mon Aug 3 11:17:19 2026 +0800
feat: support topic-only producer connection queries (#742)
---
web/src/api/producer.test.ts | 11 +++++++++
web/src/api/producer.ts | 7 +++---
web/src/pages/studio/Producer.tsx | 10 +++-----
web/src/pages/studio/__tests__/Producer.test.tsx | 31 ++++++++++++++++++++++--
4 files changed, 47 insertions(+), 12 deletions(-)
diff --git a/web/src/api/producer.test.ts b/web/src/api/producer.test.ts
index b5b3f31c..07bffaea 100644
--- a/web/src/api/producer.test.ts
+++ b/web/src/api/producer.test.ts
@@ -85,6 +85,17 @@ describe('Producer API', () => {
expect(result[0].clientId).toBe('producer-1');
});
+ it('queries producer connections by topic without a group', async () => {
+ mock.onGet('/producer/connection').reply((config) => {
+ expect(config.params).toEqual({ topic: 'order-events' });
+ expect(config.params).not.toHaveProperty('producerGroup');
+ return [200, { connectionSet: [] }];
+ });
+
+ const result = await queryProducerConnection('order-events');
+ expect(result).toEqual([]);
+ });
+
it('handles empty producer connections', async () => {
mock.onGet('/producer/connection').reply(200, { connectionSet: [] });
diff --git a/web/src/api/producer.ts b/web/src/api/producer.ts
index 26c31aba..c7e93928 100644
--- a/web/src/api/producer.ts
+++ b/web/src/api/producer.ts
@@ -43,13 +43,14 @@ export async function fetchTopicList(): Promise<string[]> {
return topics.sort();
}
-/** Query producer connections by topic and group */
+/** Query producer connections by topic and an optional group */
export async function queryProducerConnection(
topic: string,
- producerGroup: string,
+ producerGroup?: string,
): Promise<ProducerConnection[]> {
+ const params = producerGroup ? { topic, producerGroup } : { topic };
const res = await client.get<{ connectionSet: ProducerConnection[]
}>('/producer/connection', {
- params: { topic, producerGroup },
+ params,
});
return res.data?.connectionSet ?? [];
}
diff --git a/web/src/pages/studio/Producer.tsx
b/web/src/pages/studio/Producer.tsx
index f88b8197..8dba66ea 100644
--- a/web/src/pages/studio/Producer.tsx
+++ b/web/src/pages/studio/Producer.tsx
@@ -57,7 +57,7 @@ const ProducerPage = () => {
};
}, [fetchTopicFailedMessage, message]);
- const onFinish = async (values: { selectedTopic: string; producerGroup:
string }) => {
+ const onFinish = async (values: { selectedTopic: string; producerGroup?:
string }) => {
setLoading(true);
try {
const connections = await queryProducerConnection(values.selectedTopic,
values.producerGroup);
@@ -122,12 +122,8 @@ const ProducerPage = () => {
options={topicList.map((topic) => ({ value: topic, label: topic
}))}
/>
</Form.Item>
- <Form.Item
- label="PRODUCER GROUP"
- name="producerGroup"
- rules={[{ required: true, message: t('producer.inputGroup') }]}
- >
- <Input style={{ width: 300 }} />
+ <Form.Item label="PRODUCER GROUP" name="producerGroup">
+ <Input placeholder={t('producer.inputGroup')} style={{ width: 300
}} />
</Form.Item>
<Form.Item>
<Button
diff --git a/web/src/pages/studio/__tests__/Producer.test.tsx
b/web/src/pages/studio/__tests__/Producer.test.tsx
index b4dbb091..b44ed70f 100644
--- a/web/src/pages/studio/__tests__/Producer.test.tsx
+++ b/web/src/pages/studio/__tests__/Producer.test.tsx
@@ -16,12 +16,12 @@
*/
import { beforeAll, beforeEach, describe, expect, it, vi } from 'vitest';
-import { render, screen, waitFor } from '@testing-library/react';
+import { fireEvent, render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { App } from 'antd';
import { LangProvider } from '../../../i18n/LangContext';
import ProducerPage from '../Producer';
-import { fetchTopicList } from '../../../api/producer';
+import { fetchTopicList, queryProducerConnection } from
'../../../api/producer';
vi.mock('../../../api/producer', () => ({
fetchTopicList: vi.fn(),
@@ -56,6 +56,7 @@ describe('ProducerPage', () => {
beforeEach(() => {
vi.clearAllMocks();
vi.mocked(fetchTopicList).mockResolvedValue(['order-events',
'payment-events']);
+ vi.mocked(queryProducerConnection).mockResolvedValue([]);
});
it('loads topic options after mount', async () => {
@@ -78,4 +79,30 @@ describe('ProducerPage', () => {
await screen.findByRole('option', { name: 'order-events' });
expect(await screen.findByRole('option', { name: 'payment-events'
})).toBeInTheDocument();
});
+
+ it('queries all producer connections for a topic without requiring a group',
async () => {
+ const user = userEvent.setup();
+ vi.mocked(queryProducerConnection).mockResolvedValue([
+ {
+ clientId: 'producer-1',
+ clientAddr: '192.168.1.10',
+ language: 'JAVA',
+ versionDesc: '5.1.0',
+ },
+ ]);
+ renderWithProviders(<ProducerPage />);
+
+ await waitFor(() => expect(fetchTopicList).toHaveBeenCalledTimes(1));
+ const topicSelect = screen.getByRole('combobox');
+ fireEvent.mouseDown(topicSelect.parentElement!);
+ await user.click(
+ await screen.findByText('order-events', { selector:
'.ant-select-item-option-content' }),
+ );
+ await user.click(screen.getByRole('button', { name: /搜索/ }));
+
+ await waitFor(() => {
+ expect(queryProducerConnection).toHaveBeenCalledWith('order-events',
undefined);
+ });
+ expect(await screen.findByText('producer-1')).toBeInTheDocument();
+ });
});