feat(dashboard): resolve eg_backend_<id> → friendly name in HAProxy card
The HAProxy stats card now shows the configured backend name (e.g.
"My Backend/web1") instead of the internal HAProxy name
("eg_backend_1/web1"). Also surfaces the socket error message when
HAProxy is unreachable (⚠ HAProxy socket: <error>) instead of the
generic "no backends" empty state — operators immediately see whether
the box is unconfigured or the socket is down. v1.1.114.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -6,7 +6,7 @@ import {
|
||||
} from '@ant-design/icons'
|
||||
import { Link } from 'react-router-dom'
|
||||
import { useQuery } from '@tanstack/react-query'
|
||||
import { useEffect, useRef, useState } from 'react'
|
||||
import { useEffect, useMemo, useRef, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
|
||||
import apiClient, { isEnvelope } from '../../api/client'
|
||||
@@ -201,9 +201,9 @@ export default function DashboardPage() {
|
||||
try {
|
||||
const r = await apiClient.get('/haproxy/stats')
|
||||
if (!isEnvelope(r.data)) return { backends: [] as HAProxyBackend[], frontends: [] as HAProxyFrontend[] }
|
||||
const d = r.data.data as { backends?: HAProxyBackend[]; frontends?: HAProxyFrontend[] }
|
||||
return { backends: d.backends ?? [], frontends: d.frontends ?? [] }
|
||||
} catch { return { backends: [] as HAProxyBackend[], frontends: [] as HAProxyFrontend[] } }
|
||||
const d = r.data.data as { backends?: HAProxyBackend[]; frontends?: HAProxyFrontend[]; error?: string }
|
||||
return { backends: d.backends ?? [], frontends: d.frontends ?? [], error: d.error }
|
||||
} catch { return { backends: [] as HAProxyBackend[], frontends: [] as HAProxyFrontend[], error: undefined } }
|
||||
},
|
||||
refetchInterval: 10_000,
|
||||
})
|
||||
@@ -267,6 +267,18 @@ export default function DashboardPage() {
|
||||
const now = Date.now()
|
||||
const maintenanceDomains = (domains.data ?? []).filter(d => d.maintenance_mode)
|
||||
|
||||
// eg_backend_<id> → friendly name lookup for HAProxy stats display.
|
||||
const backendIdToName = useMemo(() => {
|
||||
const m = new Map<number, string>()
|
||||
for (const b of backends.data ?? []) m.set(b.id, b.name)
|
||||
return m
|
||||
}, [backends.data])
|
||||
const resolveHAName = (haName: string): string => {
|
||||
const match = /^eg_backend_(\d+)$/.exec(haName)
|
||||
const id = match ? Number(match[1]) : null
|
||||
return id != null ? (backendIdToName.get(id) ?? haName) : haName
|
||||
}
|
||||
|
||||
// Backends die komplett DOWN sind (mind. 1 Server mit echtem Check,
|
||||
// aber kein einziger UP) — liefert friendly Backend-Namen.
|
||||
const downBackends = (() => {
|
||||
@@ -486,13 +498,19 @@ export default function DashboardPage() {
|
||||
</div>
|
||||
)}
|
||||
{(haproxyBackends.data ?? []).length === 0 ? (
|
||||
<Text type="secondary">{t('dashboard.haproxyCard.empty')}</Text>
|
||||
haproxyStats.data?.error ? (
|
||||
<Text type="secondary" style={{ fontSize: 12 }}>
|
||||
⚠ HAProxy socket: <code style={{ fontSize: 11 }}>{haproxyStats.data.error}</code>
|
||||
</Text>
|
||||
) : (
|
||||
<Text type="secondary">{t('dashboard.haproxyCard.empty')}</Text>
|
||||
)
|
||||
) : (
|
||||
<Space direction="vertical" style={{ width: '100%' }} size={2}>
|
||||
{(haproxyBackends.data ?? []).map((b, i) => (
|
||||
<div key={i} style={{ fontSize: 12, color: '#334155', borderBottom: '1px solid #F1F5F9', padding: '4px 0' }}>
|
||||
<Space size={6} wrap>
|
||||
<code style={{ fontSize: 11 }}>{b.backend}/{b.server}</code>
|
||||
<code style={{ fontSize: 11 }}>{resolveHAName(b.backend)}/{b.server}</code>
|
||||
<Tag
|
||||
color={b.status === 'UP' ? 'green' : b.status === 'no check' ? 'default' : 'red'}
|
||||
style={{ margin: 0, fontSize: 10 }}
|
||||
|
||||
Reference in New Issue
Block a user