/// Device management view — list devices with revoke actions. import { setState, sendMessage, navigate, escapeHtml } from '../popup'; import type { Device } from '../../shared/types'; function relativeTime(unixSec: number): string { const now = Math.floor(Date.now() / 1000); const diff = now - unixSec; if (diff < 60) return 'just now'; if (diff < 3600) return `${Math.floor(diff / 60)}m ago`; if (diff < 86400) return `${Math.floor(diff / 3600)}h ago`; if (diff < 2592000) return `${Math.floor(diff / 86400)}d ago`; return `${Math.floor(diff / 2592000)}mo ago`; } export function teardown(): void { // No cleanup needed } export async function renderDevices(app: HTMLElement): Promise { // Get current device name from local storage const stored = await chrome.storage.local.get(['device_name']); const currentDeviceName: string | undefined = stored.device_name as string | undefined; // Fetch device list const resp = await sendMessage({ type: 'list_devices' }); if (!resp.ok) { app.innerHTML = `

Failed to load devices

`; return; } const devices = (resp.data as { devices: Device[] }).devices; const isRegistered = currentDeviceName && devices.some((d) => d.name === currentDeviceName); app.innerHTML = `

devices

${!isRegistered ? `
⚠ This device is not registered
` : ''} ${devices.length === 0 ? `

No devices registered

` : devices.map((d) => { const isCurrentDevice = d.name === currentDeviceName; return `
${escapeHtml(d.name)}${isCurrentDevice ? ' ← you' : ''} added ${relativeTime(d.added_at)}
${isCurrentDevice ? '' : ``}
`; }).join('')}
`; // Wire handlers document.getElementById('back-btn')?.addEventListener('click', () => navigate('list')); document.getElementById('register-btn')?.addEventListener('click', async () => { // Generate keypair and register // This would need WASM access - for now, redirect to a registration flow // The full implementation happens in Task 12 (setup wizard integration) setState({ error: 'Device registration from here is not yet implemented. Use setup wizard.' }); }); document.querySelectorAll('[data-revoke]').forEach((btn) => { btn.addEventListener('click', async () => { const name = btn.dataset.revoke; if (!name) return; if (!confirm(`Revoke ${name}? This device will no longer be authorized.`)) return; btn.disabled = true; btn.textContent = '...'; const result = await sendMessage({ type: 'revoke_device', name }); if (result.ok) { await sendMessage({ type: 'sync' }); renderDevices(app); } else { setState({ error: result.error }); } }); }); }