fix(mqtt): reset messages to the newest entry

This commit is contained in:
Melody Ruch
2026-09-18 17:33:55 +08:00
committed by GitHub
parent ec356293aa
commit 985d55ba85
2 changed files with 30 additions and 2 deletions
@@ -1,5 +1,5 @@
<script setup lang="ts">
import { ref, computed, onMounted, onUnmounted, watch } from "vue";
import { ref, computed, onMounted, onUnmounted, watch, nextTick } from "vue";
import { useI18n } from "vue-i18n";
import { mqttGetBrokerInfo, mqttListTopics, mqttListSavedTopicConfigs, mqttGetMessages, mqttSubscribe, mqttUnsubscribe, mqttSaveTopicConfig, mqttDeleteTopicConfig, mqttClearMessages } from "@/lib/backend/api";
import type { MqttBrokerInfo, MqttSavedTopic, MqttTopicNode, MqttMessage, MqttQoS } from "@/types/mqtt";
@@ -45,6 +45,7 @@ const selectedTopic = ref<string>(restoredUiState.selectedTopic ?? props.initial
const loading = ref(true);
const error = ref<string | null>(null);
const pollingTimer = ref<ReturnType<typeof setInterval> | null>(null);
const messageListRef = ref<HTMLElement | null>(null);
const messagesPaused = ref(restoredUiState.messagesPaused ?? false);
const displayEncoding = ref<PayloadEncoding>(restoredUiState.displayEncoding ?? "plaintext");
const topicSearch = ref(restoredUiState.topicSearch ?? "");
@@ -126,6 +127,9 @@ async function refreshData() {
savedTopics.value = configs.map((config) => ({ ...config, enabled: config.enabled !== false, noLocal: config.noLocal === true }));
messages.value = msgs;
error.value = null;
void nextTick(() => {
if (messageListRef.value) messageListRef.value.scrollTop = 0;
});
} catch (e) {
error.value = String(e);
} finally {
@@ -412,7 +416,7 @@ onUnmounted(stopPolling);
</Button>
</div>
</div>
<div class="flex min-h-0 flex-1 flex-col overflow-auto">
<div ref="messageListRef" data-testid="mqtt-message-list" class="flex min-h-0 flex-1 flex-col overflow-auto">
<div v-if="messages.length === 0" class="p-4 text-center text-xs text-muted-foreground">{{ t("connection.mqttNoMessages") }}</div>
<div v-else-if="filteredMessages.length === 0" data-testid="mqtt-no-matching-messages" class="p-4 text-center text-xs text-muted-foreground">{{ t("connection.mqttNoMatchingMessages") }}</div>
<div
@@ -127,6 +127,30 @@ describe("MQTT 控制台消息暂停自动滚动 (issue #5615)", () => {
});
});
describe("MQTT 消息列表刷新后自动回到最新消息 (issue #9373)", () => {
it("刷新消息列表后,消息容器的 scrollTop 被重置为 0", async () => {
const container = await mountConsole();
await Promise.resolve();
await Promise.resolve();
await nextTick();
const messageList = container.querySelector('[data-testid="mqtt-message-list"]') as HTMLElement | null;
expect(messageList).toBeTruthy();
messageList!.scrollTop = 120;
expect(messageList!.scrollTop).toBe(120);
mqttGetMessagesMock.mockResolvedValueOnce([messageAt(1)]);
const refreshButton = Array.from(container.querySelectorAll("button")).find((button) => button.textContent?.includes("刷新"));
expect(refreshButton).toBeTruthy();
refreshButton?.dispatchEvent(new MouseEvent("click", { bubbles: true }));
await Promise.resolve();
await Promise.resolve();
await nextTick();
expect(messageList!.scrollTop).toBe(0);
});
});
describe("MQTT 控制台暂停后选择消息 (issue #8353)", () => {
it("点击暂停后的消息内容时不会重新获取并替换消息", async () => {
mqttGetMessagesMock.mockResolvedValue([messageAt(0, "device/other")]);