chore: Decouple UI from API by adding mock data

Co-authored-by: aider (gemini/gemini-2.5-pro) <aider@aider.chat>
This commit is contained in:
Chris Frankland-Wright 2025-08-07 23:47:46 +01:00
parent f0ac2ed3d4
commit 8636ed4ec4

View file

@ -1,4 +1,39 @@
document.addEventListener('DOMContentLoaded', () => { document.addEventListener('DOMContentLoaded', () => {
const mockApiData = {
status: {
ltc_status: 'LOCK',
ltc_timecode: '10:20:30:00',
frame_rate: '25.00',
lock_ratio: 99.5,
system_clock: '10:20:30.500',
system_date: '2025-08-07',
ntp_active: true,
sync_status: 'IN SYNC',
timecode_delta_ms: 5,
timecode_delta_frames: 0.125,
jitter_status: 'GOOD',
interfaces: ['192.168.1.100 (eth0)', '10.0.0.5 (wlan0)'],
},
config: {
hardwareOffsetMs: 10,
autoSyncEnabled: true,
defaultNudgeMs: 2,
timeturnerOffset: {
hours: 1,
minutes: 2,
seconds: 3,
frames: 4,
milliseconds: 50
},
},
logs: [
'2025-08-07 10:20:30 [INFO] Starting up...',
'2025-08-07 10:20:31 [INFO] Found serial device on /dev/ttyACM0.',
'2025-08-07 10:20:32 [INFO] LTC LOCK detected. Frame rate: 25.00fps.',
'2025-08-07 10:20:35 [INFO] Initial sync complete. Clock adjusted by -15ms.',
]
};
let lastApiData = null; let lastApiData = null;
let lastApiFetchTime = null; let lastApiFetchTime = null;
@ -147,36 +182,24 @@ document.addEventListener('DOMContentLoaded', () => {
} }
async function fetchStatus() { async function fetchStatus() {
try { // Mock implementation to allow UI development without a running backend.
const response = await fetch('/api/status'); const data = mockApiData.status;
if (!response.ok) throw new Error('Failed to fetch status'); updateStatus(data);
const data = await response.json(); lastApiData = data;
updateStatus(data); lastApiFetchTime = new Date();
lastApiData = data;
lastApiFetchTime = new Date();
} catch (error) {
console.error('Error fetching status:', error);
lastApiData = null;
lastApiFetchTime = null;
}
} }
async function fetchConfig() { async function fetchConfig() {
try { // Mock implementation
const response = await fetch('/api/config'); const data = mockApiData.config;
if (!response.ok) throw new Error('Failed to fetch config'); hwOffsetInput.value = data.hardwareOffsetMs;
const data = await response.json(); autoSyncCheckbox.checked = data.autoSyncEnabled;
hwOffsetInput.value = data.hardwareOffsetMs; offsetInputs.h.value = data.timeturnerOffset.hours;
autoSyncCheckbox.checked = data.autoSyncEnabled; offsetInputs.m.value = data.timeturnerOffset.minutes;
offsetInputs.h.value = data.timeturnerOffset.hours; offsetInputs.s.value = data.timeturnerOffset.seconds;
offsetInputs.m.value = data.timeturnerOffset.minutes; offsetInputs.f.value = data.timeturnerOffset.frames;
offsetInputs.s.value = data.timeturnerOffset.seconds; offsetInputs.ms.value = data.timeturnerOffset.milliseconds || 0;
offsetInputs.f.value = data.timeturnerOffset.frames; nudgeValueInput.value = data.defaultNudgeMs;
offsetInputs.ms.value = data.timeturnerOffset.milliseconds || 0;
nudgeValueInput.value = data.defaultNudgeMs;
} catch (error) {
console.error('Error fetching config:', error);
}
} }
async function saveConfig() { async function saveConfig() {
@ -193,69 +216,34 @@ document.addEventListener('DOMContentLoaded', () => {
} }
}; };
try { // Mock implementation
const response = await fetch('/api/config', { console.log('Saving mock config:', config);
method: 'POST', alert('Configuration saved (mock).');
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(config),
});
if (!response.ok) throw new Error('Failed to save config');
alert('Configuration saved.');
} catch (error) {
console.error('Error saving config:', error);
alert('Error saving configuration.');
}
} }
async function fetchLogs() { async function fetchLogs() {
try { // Mock implementation
const response = await fetch('/api/logs'); const logs = mockApiData.logs;
if (!response.ok) throw new Error('Failed to fetch logs'); statusElements.logs.textContent = logs.join('\n');
const logs = await response.json(); // Auto-scroll to the bottom
statusElements.logs.textContent = logs.join('\n'); statusElements.logs.scrollTop = statusElements.logs.scrollHeight;
// Auto-scroll to the bottom
statusElements.logs.scrollTop = statusElements.logs.scrollHeight;
} catch (error) {
console.error('Error fetching logs:', error);
statusElements.logs.textContent = 'Error fetching logs.';
}
} }
async function triggerManualSync() { async function triggerManualSync() {
syncMessage.textContent = 'Issuing sync command...'; syncMessage.textContent = 'Issuing sync command...';
try { // Mock implementation
const response = await fetch('/api/sync', { method: 'POST' }); setTimeout(() => {
const data = await response.json(); syncMessage.textContent = 'Success: Manual sync triggered (mock).';
if (response.ok) { }, 1000);
syncMessage.textContent = `Success: ${data.message}`;
} else {
syncMessage.textContent = `Error: ${data.message}`;
}
} catch (error) {
console.error('Error triggering sync:', error);
syncMessage.textContent = 'Failed to send sync command.';
}
setTimeout(() => { syncMessage.textContent = ''; }, 5000); setTimeout(() => { syncMessage.textContent = ''; }, 5000);
} }
async function nudgeClock(ms) { async function nudgeClock(ms) {
nudgeMessage.textContent = 'Nudging clock...'; nudgeMessage.textContent = 'Nudging clock...';
try { // Mock implementation
const response = await fetch('/api/nudge_clock', { setTimeout(() => {
method: 'POST', nudgeMessage.textContent = `Success: Clock nudged by ${ms}ms (mock).`;
headers: { 'Content-Type': 'application/json' }, }, 500);
body: JSON.stringify({ microseconds: ms * 1000 }),
});
const data = await response.json();
if (response.ok) {
nudgeMessage.textContent = `Success: ${data.message}`;
} else {
nudgeMessage.textContent = `Error: ${data.message}`;
}
} catch (error) {
console.error('Error nudging clock:', error);
nudgeMessage.textContent = 'Failed to send nudge command.';
}
setTimeout(() => { nudgeMessage.textContent = ''; }, 3000); setTimeout(() => { nudgeMessage.textContent = ''; }, 3000);
} }
@ -267,24 +255,15 @@ document.addEventListener('DOMContentLoaded', () => {
} }
dateMessage.textContent = 'Setting date...'; dateMessage.textContent = 'Setting date...';
try { // Mock implementation
const response = await fetch('/api/set_date', { setTimeout(() => {
method: 'POST', dateMessage.textContent = `Success: Date set to ${date} (mock).`;
headers: { 'Content-Type': 'application/json' }, // To make it look real, we can update the system date display
body: JSON.stringify({ date: date }), if (lastApiData) {
}); mockApiData.status.system_date = date;
const data = await response.json();
if (response.ok) {
dateMessage.textContent = `Success: ${data.message}`;
// Fetch status again to update the displayed date immediately
fetchStatus(); fetchStatus();
} else {
dateMessage.textContent = `Error: ${data.message}`;
} }
} catch (error) { }, 1000);
console.error('Error setting date:', error);
dateMessage.textContent = 'Failed to send date command.';
}
setTimeout(() => { dateMessage.textContent = ''; }, 5000); setTimeout(() => { dateMessage.textContent = ''; }, 5000);
} }
@ -305,8 +284,8 @@ document.addEventListener('DOMContentLoaded', () => {
fetchConfig(); fetchConfig();
fetchLogs(); fetchLogs();
// Refresh data every 2 seconds // Refresh data every 2 seconds - MOCKED
setInterval(fetchStatus, 2000); // setInterval(fetchStatus, 2000);
setInterval(fetchLogs, 2000); // setInterval(fetchLogs, 2000);
setInterval(animateClocks, 50); // High-frequency clock animation setInterval(animateClocks, 50); // High-frequency clock animation
}); });