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 c44dd9ced fix(message): preserve unknown queue metadata in query 
history (#5143)
c44dd9ced is described below

commit c44dd9ced2e857bf3b8cc2a289a7a6f7425634e5
Author: Wang1rrr <[email protected]>
AuthorDate: Thu Oct 1 17:31:16 2026 +0800

    fix(message): preserve unknown queue metadata in query history (#5143)
    
    * fix(message): preserve unknown queue metadata in query history
    
    * fix(web): align saved message queue metadata with nullable API values
---
 .../instance/message/QueryHistoryService.java      |  4 +-
 .../instance/message/QueryHistoryServiceTest.java  | 47 ++++++++++++++++++++++
 web/src/api/messageHistory.test.ts                 | 30 ++++++++++++++
 web/src/api/messageHistory.ts                      |  4 +-
 4 files changed, 81 insertions(+), 4 deletions(-)

diff --git 
a/server/src/main/java/org/apache/rocketmq/studio/instance/message/QueryHistoryService.java
 
b/server/src/main/java/org/apache/rocketmq/studio/instance/message/QueryHistoryService.java
index 98055144c..b7c18fa7c 100644
--- 
a/server/src/main/java/org/apache/rocketmq/studio/instance/message/QueryHistoryService.java
+++ 
b/server/src/main/java/org/apache/rocketmq/studio/instance/message/QueryHistoryService.java
@@ -114,8 +114,8 @@ public class QueryHistoryService {
                 m.put("tag", r.getTag() == null ? "" : r.getTag());
                 m.put("key", r.getKey() == null ? "" : r.getKey());
                 m.put("brokerName", r.getBrokerName() == null ? "" : 
r.getBrokerName());
-                m.put("queueId", r.getQueueId() == null ? 0 : r.getQueueId());
-                m.put("queueOffset", r.getQueueOffset() == null ? 0L : 
r.getQueueOffset());
+                m.put("queueId", r.getQueueId());
+                m.put("queueOffset", r.getQueueOffset());
                 m.put("storeTime", r.getStoreTime());
                 m.put("bornHost", r.getBornHost() == null ? "" : 
r.getBornHost());
                 m.put("storeHost", r.getStoreHost() == null ? "" : 
r.getStoreHost());
diff --git 
a/server/src/test/java/org/apache/rocketmq/studio/instance/message/QueryHistoryServiceTest.java
 
b/server/src/test/java/org/apache/rocketmq/studio/instance/message/QueryHistoryServiceTest.java
index 3d52d789d..9213fda28 100644
--- 
a/server/src/test/java/org/apache/rocketmq/studio/instance/message/QueryHistoryServiceTest.java
+++ 
b/server/src/test/java/org/apache/rocketmq/studio/instance/message/QueryHistoryServiceTest.java
@@ -36,6 +36,7 @@ import java.time.Instant;
 import java.time.LocalDateTime;
 import java.time.ZoneOffset;
 import java.util.List;
+import java.util.Map;
 
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.assertThatThrownBy;
@@ -244,6 +245,50 @@ class QueryHistoryServiceTest {
         
assertThat(queryCaptor.getValue().getCustomSqlSegment()).contains("queried_by");
     }
 
+    @Test
+    void savedMessageSnapshotsPreserveNullableQueueMetadataTest() {
+        AuthenticatedUserContext.setUsername("alice");
+        List<MessageRecordVO> messages = List.of(
+                
MessageRecordVO.builder().msgId("cloud-message").topic("orders").build(),
+                
MessageRecordVO.builder().msgId("first-message").topic("orders")
+                        .queueId(0).queueOffset(0L).build(),
+                
MessageRecordVO.builder().msgId("later-message").topic("orders")
+                        .queueId(7).queueOffset(12345678901L).build());
+        RmqMessageQuery entity = new RmqMessageQuery();
+        entity.setId(9L);
+        entity.setQueriedBy("alice");
+        entity.setResultSnapshot(service.buildResultSnapshot(messages));
+        when(messageQueryMapper.selectOne(any())).thenReturn(entity);
+
+        List<MessageRecordVO> restored = service.getMessageQueryResults(9L);
+
+        assertThat(restored).hasSize(messages.size());
+        for (int index = 0; index < messages.size(); index++) {
+            assertThat(restored.get(index).getQueueId())
+                    .as("queue ID for %s", messages.get(index).getMsgId())
+                    .isEqualTo(messages.get(index).getQueueId());
+            assertThat(restored.get(index).getQueueOffset())
+                    .as("queue offset for %s", messages.get(index).getMsgId())
+                    .isEqualTo(messages.get(index).getQueueOffset());
+        }
+    }
+
+    @Test
+    void savedMessageSnapshotsExcludeBodiesAndUserPropertiesTest() throws 
Exception {
+        MessageRecordVO message = MessageRecordVO.builder()
+                .msgId("message-with-payload").topic("orders")
+                .body("private message body")
+                .properties(Map.of("private-property", "private value"))
+                .build();
+
+        String snapshot = service.buildResultSnapshot(List.of(message));
+
+        var savedMessage = new ObjectMapper().readTree(snapshot).get(0);
+        
assertThat(savedMessage.path("msgId").asText()).isEqualTo("message-with-payload");
+        assertThat(savedMessage.has("body")).isFalse();
+        assertThat(savedMessage.has("properties")).isFalse();
+    }
+
     @Test
     void loadsResultSnapshotOnlyForTheAuthenticatedOperatorTest() {
         AuthenticatedUserContext.setUsername("alice");
@@ -258,6 +303,8 @@ class QueryHistoryServiceTest {
         assertThat(results).singleElement().satisfies(result -> {
             assertThat(result.getMsgId()).isEqualTo("msg-9");
             assertThat(result.getTopic()).isEqualTo("orders");
+            assertThat(result.getQueueId()).isNull();
+            assertThat(result.getQueueOffset()).isNull();
         });
         ArgumentCaptor<QueryWrapper<RmqMessageQuery>> queryCaptor = 
ArgumentCaptor.forClass(QueryWrapper.class);
         verify(messageQueryMapper).selectOne(queryCaptor.capture());
diff --git a/web/src/api/messageHistory.test.ts 
b/web/src/api/messageHistory.test.ts
index 540c7b0c4..7391685a9 100644
--- a/web/src/api/messageHistory.test.ts
+++ b/web/src/api/messageHistory.test.ts
@@ -8,9 +8,11 @@ import MockAdapter from 'axios-mock-adapter';
 import { afterEach, beforeEach, describe, expect, it } from 'vitest';
 import client from './client';
 import {
+  getMessageQueryResults,
   getQueryHistorySummary,
   listMessageQueryHistory,
   listTraceQueryHistory,
+  type MessageResultSnapshot,
 } from './messageHistory';
 
 const mock = new MockAdapter(client);
@@ -19,6 +21,34 @@ describe('message query history API', () => {
   beforeEach(() => mock.reset());
   afterEach(() => mock.reset());
 
+  it('preserves unknown and zero queue positions in saved message results', 
async () => {
+    const unknown: MessageResultSnapshot = {
+      msgId: 'cloud-message',
+      topic: 'orders',
+      tag: '',
+      key: '',
+      brokerName: '',
+      queueId: null,
+      queueOffset: null,
+      storeTime: 1,
+      bornHost: '',
+      storeHost: '',
+      size: 1,
+    };
+    const firstMessage: MessageResultSnapshot = {
+      ...unknown,
+      msgId: 'first-message',
+      queueId: 0,
+      queueOffset: 0,
+    };
+    mock.onGet('/query-history/messages/9/results').reply(200, {
+      code: 200,
+      data: [unknown, firstMessage],
+    });
+
+    await expect(getMessageQueryResults(9)).resolves.toEqual([unknown, 
firstMessage]);
+  });
+
   it('forwards filters and pagination for message history', async () => {
     mock.onGet('/query-history/messages').reply((config) => {
       expect(config.params).toEqual({
diff --git a/web/src/api/messageHistory.ts b/web/src/api/messageHistory.ts
index 2c63a1063..5bad05bfe 100644
--- a/web/src/api/messageHistory.ts
+++ b/web/src/api/messageHistory.ts
@@ -87,8 +87,8 @@ export interface MessageResultSnapshot {
   tag: string;
   key: string;
   brokerName: string;
-  queueId: number;
-  queueOffset: number;
+  queueId: number | null;
+  queueOffset: number | null;
   storeTime: number;
   bornHost: string;
   storeHost: string;

Reply via email to