Serverpuls: Admin-Seite mit Verlauf und Warnungen

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
ClaudeandClaude Opus 5.5 committed 2026-09-30 12:43:13 +00:00
1 parent ae905a5d9b
commit ec740ca970
12 files changed
+749 -3

No files matched your search

+26 -1
View File
@@ -1,4 +1,4 @@
import { useState } from 'react'
import { useEffect, useState } from 'react'
import { Link, useLocation, useNavigate } from 'react-router-dom'
import { useAuth } from '../context/AuthContext'
import {
@@ -7,6 +7,7 @@ import {
IconTargetArrow,
IconReportMoney,
IconScale,
IconActivityHeartbeat,
IconFolders,
IconCalendar,
IconSettings,
@@ -16,6 +17,7 @@ import {
IconExternalLink,
} from '@tabler/icons-react'
import { openProjectAdmin } from '../lib/employeeAdminApi'
import { serverpulsApi } from '../lib/serverpulsApi'
export default function Sidebar() {
const { user, logout, isAdmin } = useAuth()
@@ -23,6 +25,21 @@ export default function Sidebar() {
const location = useLocation()
const [collapsed, setCollapsed] = useState(false)
const [switching, setSwitching] = useState(false)
const [pulseLevel, setPulseLevel] = useState('ok')
// Serverpuls-Punkt: nur Admins, beim Laden und alle 5 Minuten; Fehler bleiben still
useEffect(() => {
if (!isAdmin) { setPulseLevel('ok'); return undefined }
let dead = false
const load = () => {
serverpulsApi.overview()
.then((o) => { if (!dead) setPulseLevel(o?.level || 'ok') })
.catch(() => { if (!dead) setPulseLevel('ok') })
}
load()
const iv = setInterval(load, 5 * 60 * 1000)
return () => { dead = true; clearInterval(iv) }
}, [isAdmin])
const handleProjectAdmin = async () => {
setSwitching(true)
@@ -44,6 +61,7 @@ export default function Sidebar() {
{ label: 'Leads', href: '/leads', icon: <IconTargetArrow />, paused: true },
{ label: 'Finanzen', href: '/finance', icon: <IconReportMoney /> },
{ label: 'Rechtliches', href: '/rechtliches', icon: <IconScale /> },
...(isAdmin ? [{ label: 'Serverpuls', href: '/serverpuls', icon: <IconActivityHeartbeat />, dot: pulseLevel }] : []),
...(isAdmin ? [{ label: 'Admin', href: '/admin', icon: <IconSettings /> }] : []),
]
@@ -81,6 +99,13 @@ export default function Sidebar() {
>
{link.icon}
<span className="side-link-label">{link.label}</span>
{link.dot && link.dot !== 'ok' && (
<span
className={`side-dot side-dot-${link.dot}`}
data-testid="sp-nav-dot"
title={link.dot === 'critical' ? 'Critical-Warnung aktiv' : 'Warnung aktiv'}
/>
)}
</Link>
))}
<button