import React, { useEffect, useState } from 'react'; import { api } from '../api.js'; import { formatLastSeen } from '../utils/format.js'; const STATUS_LABELS = { online: 'В сети', recent: 'Недавно', offline: 'Не в сети', }; function Tooltip({ children }) { return {children}; } function TextMorph({ from, to }) { const anchor = from.length >= to.length ? from : to; return ; } export function DevicesPanel({ open, panelRef, closeRef, onClose }) { const [snapshot, setSnapshot] = useState(null); const [status, setStatus] = useState('idle'); const [error, setError] = useState(null); const [editingId, setEditingId] = useState(''); const [alias, setAlias] = useState(''); const [savingId, setSavingId] = useState(''); async function load(quiet = false) { if (!quiet) setStatus(snapshot ? 'refreshing' : 'loading'); try { const next = await api.devices.list(); setSnapshot((current) => !current || next.revision >= current.revision ? next : current); setError(null); setStatus('ready'); } catch (requestError) { setError(requestError); setStatus('error'); } } useEffect(() => { if (!open) return undefined; load(); const timer = setInterval(() => load(true), 15_000); return () => clearInterval(timer); }, [open]); async function updateDevice(device, patch) { setSavingId(device.id); try { const next = await api.devices.update(device.id, patch, snapshot.revision); setSnapshot((current) => !current || next.revision >= current.revision ? next : current); setError(null); return true; } catch (requestError) { if (requestError.code === 'STATE_CONFLICT') await load(true); setError(requestError); return false; } finally { setSavingId(''); } } async function saveAlias(event, device) { event.preventDefault(); if (!await updateDevice(device, { alias })) return; setEditingId(''); } const devices = snapshot?.devices || []; return ( ); }