mirror of
https://github.com/jkingsman/Remote-Terminal-for-MeshCore.git
synced 2026-08-12 11:43:03 +02:00
Fix repeater clock drift-drift on nav-away-come-back
This commit is contained in:
@@ -16,8 +16,8 @@ export function NodeInfoPane({
|
||||
}) {
|
||||
const clockDrift = useMemo(() => {
|
||||
if (!data?.clock_utc) return null;
|
||||
return formatClockDrift(data.clock_utc);
|
||||
}, [data?.clock_utc]);
|
||||
return formatClockDrift(data.clock_utc, state.fetched_at ?? undefined);
|
||||
}, [data?.clock_utc, state.fetched_at]);
|
||||
|
||||
return (
|
||||
<RepeaterPane title="Node Info" state={state} onRefresh={onRefresh} disabled={disabled}>
|
||||
|
||||
@@ -39,7 +39,10 @@ export function formatDuration(seconds: number): string {
|
||||
return `${mins}m`;
|
||||
}
|
||||
|
||||
export function formatClockDrift(clockUtc: string): { text: string; isLarge: boolean } {
|
||||
export function formatClockDrift(
|
||||
clockUtc: string,
|
||||
referenceTimeMs: number = Date.now()
|
||||
): { text: string; isLarge: boolean } {
|
||||
// Firmware format: "HH:MM - D/M/YYYY UTC" or "HH:MM:SS - D/M/YYYY UTC"
|
||||
// Also handle ISO-like: "YYYY-MM-DD HH:MM:SS"
|
||||
let parsed: Date;
|
||||
@@ -56,7 +59,7 @@ export function formatClockDrift(clockUtc: string): { text: string; isLarge: boo
|
||||
}
|
||||
if (isNaN(parsed.getTime())) return { text: '(invalid)', isLarge: false };
|
||||
|
||||
const driftMs = Math.abs(Date.now() - parsed.getTime());
|
||||
const driftMs = Math.abs(referenceTimeMs - parsed.getTime());
|
||||
const driftSec = Math.floor(driftMs / 1000);
|
||||
|
||||
if (driftSec >= 86400) return { text: '>24 hours!', isLarge: true };
|
||||
|
||||
@@ -401,6 +401,40 @@ describe('RepeaterDashboard', () => {
|
||||
expect(screen.getByText(/Fetched .*Just now/)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('keeps repeater clock drift anchored to fetch time across remounts', () => {
|
||||
vi.useFakeTimers();
|
||||
try {
|
||||
const fetchedAt = Date.UTC(2024, 0, 1, 12, 0, 0);
|
||||
vi.setSystemTime(fetchedAt);
|
||||
|
||||
mockHook.loggedIn = true;
|
||||
mockHook.paneData.nodeInfo = {
|
||||
name: 'TestRepeater',
|
||||
lat: null,
|
||||
lon: null,
|
||||
clock_utc: '11:59:30 - 1/1/2024 UTC',
|
||||
};
|
||||
mockHook.paneStates.nodeInfo = {
|
||||
loading: false,
|
||||
attempt: 1,
|
||||
error: null,
|
||||
fetched_at: fetchedAt,
|
||||
};
|
||||
|
||||
const firstRender = render(<RepeaterDashboard {...defaultProps} />);
|
||||
expect(screen.getByText(/\(drift: 30s\)/)).toBeInTheDocument();
|
||||
|
||||
vi.setSystemTime(fetchedAt + 10 * 60 * 1000);
|
||||
firstRender.unmount();
|
||||
|
||||
render(<RepeaterDashboard {...defaultProps} />);
|
||||
expect(screen.getByText(/\(drift: 30s\)/)).toBeInTheDocument();
|
||||
expect(screen.queryByText(/\(drift: 10m30s\)/)).not.toBeInTheDocument();
|
||||
} finally {
|
||||
vi.useRealTimers();
|
||||
}
|
||||
});
|
||||
|
||||
it('renders action buttons', () => {
|
||||
mockHook.loggedIn = true;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user