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();
+  });
 });

Reply via email to