window.open(`${API}/assets/${detail.id}/label`, '_blank')}
- >
-
-
Asset-Label drucken
-
QR-Code Label als PDF ΓΆffnen
+
+
+
π·οΈ
+
+
Asset-Label drucken
+
Format wΓ€hlen und als PDF ΓΆffnen
+
+
+
+ {[
+ { key: 'small', label: 'Klein (50Γ25mm)' },
+ { key: 'medium', label: 'Mittel (80Γ40mm)' },
+ { key: 'large', label: 'GroΓ (A5)' },
+ { key: 'ptouch12', label: 'P-Touch 700 (12mm)' },
+ ].map(f => (
+
+ ))}
{detail.status === 'zugewiesen' && (
diff --git a/frontend/src/pages/MonitoringPage.jsx b/frontend/src/pages/MonitoringPage.jsx
index 4c005ea..27e52e0 100644
--- a/frontend/src/pages/MonitoringPage.jsx
+++ b/frontend/src/pages/MonitoringPage.jsx
@@ -748,6 +748,7 @@ const MonitoringPage = () => {
const [agentFilter, setAgentFilter] = useState('all');
const [expandedAgents, setExpandedAgents] = useState(new Set());
const [expandedHosts, setExpandedHosts] = useState(new Set());
+ const [agentSort, setAgentSort] = useState('cpu');
const [hostFilter, setHostFilter] = useState('all');
const [hostSearch, setHostSearch] = useState('');
const [proxmoxData, setProxmoxData] = useState(null);
@@ -1186,6 +1187,11 @@ const MonitoringPage = () => {
// βββ Tab: Agents ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
const renderAgents = () => {
+ const isAgentOffline = (a) => {
+ if (!a.last_checkin) return true;
+ return Date.now() - new Date(a.last_checkin).getTime() > 5 * 60 * 1000;
+ };
+
const filtered = agents.filter(a => {
if (agentSearch && !a.hostname.toLowerCase().includes(agentSearch.toLowerCase()) && !(a.ip_address || '').includes(agentSearch)) return false;
if (agentFilter === 'online' && a.status !== 'online') return false;
@@ -1193,6 +1199,27 @@ const MonitoringPage = () => {
if (agentFilter === 'warn' && warnings(a).length === 0) return false;
return true;
});
+
+ const sorted = [...filtered].sort((a, b) => {
+ const aOffline = isAgentOffline(a);
+ const bOffline = isAgentOffline(b);
+ // Offline immer ans Ende
+ if (aOffline !== bOffline) return aOffline ? 1 : -1;
+ if (agentSort === 'cpu') {
+ const av = a.cpu_usage_percent ?? (a.ram_total_gb > 0 ? (a.ram_used_gb / a.ram_total_gb) * 100 : 0);
+ const bv = b.cpu_usage_percent ?? (b.ram_total_gb > 0 ? (b.ram_used_gb / b.ram_total_gb) * 100 : 0);
+ return bv - av;
+ }
+ if (agentSort === 'ram') {
+ const av = a.ram_total_gb > 0 ? (a.ram_used_gb / a.ram_total_gb) * 100 : 0;
+ const bv = b.ram_total_gb > 0 ? (b.ram_used_gb / b.ram_total_gb) * 100 : 0;
+ return bv - av;
+ }
+ if (agentSort === 'name') return (a.hostname || '').localeCompare(b.hostname || '');
+ if (agentSort === 'seen') return new Date(b.last_checkin || 0) - new Date(a.last_checkin || 0);
+ return 0;
+ });
+
return (
<>
@@ -1203,10 +1230,16 @@ const MonitoringPage = () => {
{pill(agentFilter === 'offline', () => setAgentFilter('offline'), 'OFFLINE')}
{pill(agentFilter === 'warn', () => setAgentFilter('warn'), 'WARNUNG')}
-
{filtered.length} EintrΓ€ge
+
+
{sorted.length} EintrΓ€ge
- {filtered.length === 0
+ {sorted.length === 0
?
: (
/* Checkmk-style service table */
@@ -1221,7 +1254,7 @@ const MonitoringPage = () => {