+
+ {tab === 'software' ? (
+
+ ) :
}
+
setSearches({ ...searches, [tab]: v })} />
+
+
+ {tab === 'general' && (
+ <>
+ {showRows(infoRows)}
+
+ {!editing ? (
+ <>
+ {showRows(manualRows)}
+ {q && showRows(infoRows).length + showRows(manualRows).length === 0 &&
{t('common_search_no_results')}
}
+
+ >
+ ) : (
+ <>
+
+ setForm({ ...form, status: v })}
+ />
+
+
+ setForm({ ...form, assignedUserId: v })} />
+
+
+ setForm({ ...form, departmentId: v })} />
+
+
+
+
+
+
+
+ >
+ )}
+ >
+ )}
+
+ {tab === 'hardware' && (
+ <>
+ {showRows(hwRows)}
+ {hwSection(t('eq_memories'), memories, [
+ { key: 'slot', label: t('eq_slot') }, { key: 'capacity_mb', label: t('eq_capacity'), render: (r) => gb(r.capacity_mb) },
+ { key: 'type', label: t('eq_type') }, { key: 'speed', label: t('eq_speed') }, { key: 'manufacturer', label: t('eq_manufacturer') },
+ ])}
+ {hwSection(t('eq_disks'), disks, [
+ { key: 'model', label: t('eq_model') }, { key: 'type', label: t('eq_type') },
+ { key: 'size_mb', label: t('eq_capacity'), render: (r) => gb(r.size_mb) }, { key: 'serial', label: t('eq_serial') },
+ ])}
+ {hwSection(t('eq_volumes'), volumes, [
+ { key: 'mount', label: t('eq_mount') }, { key: 'filesystem', label: t('eq_fs') },
+ { key: 'total_mb', label: t('eq_capacity'), render: (r) => gb(r.total_mb) }, { key: 'free_mb', label: t('eq_free'), render: (r) => gb(r.free_mb) },
+ ])}
+ {hwSection(t('eq_monitors'), monitors, [
+ { key: 'manufacturer', label: t('eq_manufacturer') }, { key: 'model', label: t('eq_model') }, { key: 'serial', label: t('eq_serial') },
+ ])}
+ {q && showRows(hwRows).length + memories.length + disks.length + volumes.length + monitors.length === 0 &&
{t('common_search_no_results')}
}
+ >
+ )}
+
+ {tab === 'network' && (
+
+ )}
+
+ {tab === 'software' && (
+
+ )}
+
+ {tab === 'history' && (
+
fmtDate(r.created_at) },
+ { key: 'change_type', label: t('eq_change'), render: (r) => t(`eq_change_${r.change_type}`) },
+ { key: 'field', label: t('eq_field') },
+ { key: 'old_value', label: t('eq_before') }, { key: 'new_value', label: t('eq_after') },
+ ]} />
+ )}
+
+ >
+ );
+}
+
+function SummaryTab() {
+ const { t } = useUi();
+ const { data: kpis } = useAsync(getDevicesDashboard, []);
+ if (!kpis) return
+ {[['eq_by_os', kpis.byOs, (l) => l], ['eq_by_kind', kpis.byKind, (l) => t(`eq_kind_${l}`)], ['eq_top_software', kpis.topSoftware, (l) => l]].map(([title, rows, fmt]) => (
+
+
{t(title)}
+ {rows.length === 0 &&
{t('common_empty')}
}
+ {rows.map((r) => (
+
+ {fmt(r.label)}{r.value}
+
+ ))}
+
+ ))}
+
+ >
+ );
+}
+
+function DevicesTab() {
+ const { t } = useUi();
+ const [search, setSearch] = useState('');
+ const [kind, setKind] = useState('');
+ const [status, setStatus] = useState('active');
+ const [selected, setSelected] = useState(null); // { id, view: 'info' }
+ const { data: devices, reload } = useAsync(() => listDevices({ kind, status }), [kind, status]);
+
+ const kindOptions = [{ value: '', label: t('common_all') }, ...KINDS.map((k) => ({ value: k, label: t(`eq_kind_${k}`) }))];
+ const statusOptions = [
+ { value: 'active', label: t('eq_status_active') }, { value: 'retired', label: t('eq_status_retired') }, { value: '', label: t('common_all') },
+ ];
+
+ const columns = [
+ { key: 'hostname', label: t('eq_hostname'), render: (r) =>