mirror of
https://github.com/jkingsman/Remote-Terminal-for-MeshCore.git
synced 2026-08-07 17:23:05 +02:00
Don't change historical migrations (cruft from rebasing) and don't overwrite data
This commit is contained in:
+1
-1
@@ -808,7 +808,7 @@ class AppSettings(BaseModel):
|
|||||||
default_factory=list, description="List of favorited conversations"
|
default_factory=list, description="List of favorited conversations"
|
||||||
)
|
)
|
||||||
auto_decrypt_dm_on_advert: bool = Field(
|
auto_decrypt_dm_on_advert: bool = Field(
|
||||||
default=False,
|
default=True,
|
||||||
description="Whether to attempt historical DM decryption on new contact advertisement",
|
description="Whether to attempt historical DM decryption on new contact advertisement",
|
||||||
)
|
)
|
||||||
sidebar_sort_order: Literal["recent", "alpha"] = Field(
|
sidebar_sort_order: Literal["recent", "alpha"] = Field(
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { useState, useEffect } from 'react';
|
import { useEffect, useRef, useState } from 'react';
|
||||||
|
|
||||||
import { api } from '../api';
|
import { api } from '../api';
|
||||||
import { toast } from './ui/sonner';
|
import { toast } from './ui/sonner';
|
||||||
@@ -100,20 +100,34 @@ export function RepeaterDashboard({
|
|||||||
|
|
||||||
// Telemetry history: preload from stored data, refresh from live status
|
// Telemetry history: preload from stored data, refresh from live status
|
||||||
const [telemetryHistory, setTelemetryHistory] = useState<TelemetryHistoryEntry[]>([]);
|
const [telemetryHistory, setTelemetryHistory] = useState<TelemetryHistoryEntry[]>([]);
|
||||||
|
const telemetryHistorySourceRef = useRef<'none' | 'preload' | 'live'>('none');
|
||||||
|
const telemetryHistoryRequestRef = useRef(0);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
telemetryHistoryRequestRef.current += 1;
|
||||||
|
telemetryHistorySourceRef.current = 'none';
|
||||||
|
setTelemetryHistory([]);
|
||||||
|
|
||||||
if (!loggedIn) return;
|
if (!loggedIn) return;
|
||||||
|
|
||||||
|
const requestId = telemetryHistoryRequestRef.current;
|
||||||
api
|
api
|
||||||
.repeaterTelemetryHistory(conversation.id)
|
.repeaterTelemetryHistory(conversation.id)
|
||||||
.then(setTelemetryHistory)
|
.then((history) => {
|
||||||
|
if (telemetryHistoryRequestRef.current !== requestId) return;
|
||||||
|
if (telemetryHistorySourceRef.current === 'live') return;
|
||||||
|
telemetryHistorySourceRef.current = 'preload';
|
||||||
|
setTelemetryHistory(history);
|
||||||
|
})
|
||||||
.catch(() => {});
|
.catch(() => {});
|
||||||
}, [loggedIn, conversation.id]);
|
}, [loggedIn, conversation.id]);
|
||||||
|
|
||||||
// When a live status fetch returns embedded telemetry_history, replace local state
|
// When a live status fetch returns embedded telemetry_history, replace local state
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const liveHistory = paneData.status?.telemetry_history;
|
const liveHistory = paneData.status?.telemetry_history;
|
||||||
if (liveHistory && liveHistory.length > 0) {
|
if (!liveHistory) return;
|
||||||
setTelemetryHistory(liveHistory);
|
telemetryHistorySourceRef.current = 'live';
|
||||||
}
|
setTelemetryHistory(liveHistory);
|
||||||
}, [paneData.status?.telemetry_history]);
|
}, [paneData.status?.telemetry_history]);
|
||||||
|
|
||||||
const isFav = isFavorite(favorites, 'contact', conversation.id);
|
const isFav = isFavorite(favorites, 'contact', conversation.id);
|
||||||
|
|||||||
@@ -126,6 +126,16 @@ const defaultProps = {
|
|||||||
onDeleteContact: vi.fn(),
|
onDeleteContact: vi.fn(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function createDeferred<T>() {
|
||||||
|
let resolve!: (value: T) => void;
|
||||||
|
let reject!: (reason?: unknown) => void;
|
||||||
|
const promise = new Promise<T>((res, rej) => {
|
||||||
|
resolve = res;
|
||||||
|
reject = rej;
|
||||||
|
});
|
||||||
|
return { promise, resolve, reject };
|
||||||
|
}
|
||||||
|
|
||||||
describe('RepeaterDashboard', () => {
|
describe('RepeaterDashboard', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
vi.clearAllMocks();
|
vi.clearAllMocks();
|
||||||
@@ -645,6 +655,11 @@ describe('RepeaterDashboard', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('telemetry history', () => {
|
describe('telemetry history', () => {
|
||||||
|
beforeEach(async () => {
|
||||||
|
const { api } = await import('../api');
|
||||||
|
vi.mocked(api.repeaterTelemetryHistory).mockResolvedValue([]);
|
||||||
|
});
|
||||||
|
|
||||||
it('loads telemetry history on mount when logged in', async () => {
|
it('loads telemetry history on mount when logged in', async () => {
|
||||||
const { api } = await import('../api');
|
const { api } = await import('../api');
|
||||||
mockHook.loggedIn = true;
|
mockHook.loggedIn = true;
|
||||||
@@ -699,5 +714,45 @@ describe('RepeaterDashboard', () => {
|
|||||||
expect(screen.getByText('1 samples')).toBeInTheDocument();
|
expect(screen.getByText('1 samples')).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('does not let an older preload overwrite newer live status history', async () => {
|
||||||
|
const { api } = await import('../api');
|
||||||
|
const historySpy = vi.mocked(api.repeaterTelemetryHistory);
|
||||||
|
const deferred = createDeferred<{ timestamp: number; data: { battery_volts: number } }[]>();
|
||||||
|
historySpy.mockReturnValue(deferred.promise);
|
||||||
|
|
||||||
|
mockHook.loggedIn = true;
|
||||||
|
mockHook.paneData.status = {
|
||||||
|
battery_volts: 4.2,
|
||||||
|
tx_queue_len: 0,
|
||||||
|
noise_floor_dbm: -120,
|
||||||
|
last_rssi_dbm: -85,
|
||||||
|
last_snr_db: 7.5,
|
||||||
|
packets_received: 100,
|
||||||
|
packets_sent: 50,
|
||||||
|
airtime_seconds: 600,
|
||||||
|
rx_airtime_seconds: 1200,
|
||||||
|
uptime_seconds: 86400,
|
||||||
|
sent_flood: 10,
|
||||||
|
sent_direct: 40,
|
||||||
|
recv_flood: 30,
|
||||||
|
recv_direct: 70,
|
||||||
|
flood_dups: 1,
|
||||||
|
direct_dups: 0,
|
||||||
|
full_events: 0,
|
||||||
|
telemetry_history: [{ timestamp: 1700000000, data: { battery_volts: 4.2 } }],
|
||||||
|
};
|
||||||
|
|
||||||
|
render(<RepeaterDashboard {...defaultProps} />);
|
||||||
|
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(screen.getByText('1 samples')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
deferred.resolve([{ timestamp: 1690000000, data: { battery_volts: 3.9 } }]);
|
||||||
|
await deferred.promise;
|
||||||
|
|
||||||
|
expect(screen.getByText('1 samples')).toBeInTheDocument();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user