fix(routing+backends): Pfad-Präfix-Validierung + Warnung bei leerem Backend-Pool (v1.1.141)

- RoutingRules: path_prefix Pattern-Validator (muss mit / beginnen) + destroyOnHidden
- Backends: Alert-Banner wenn aktives Backend 0 Server hat (→ HAProxy 503)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Debian
2026-05-28 21:25:55 +02:00
parent 9dee904169
commit 40414d472b
8 changed files with 31 additions and 5 deletions

View File

@@ -380,6 +380,8 @@
"forceHttp1Hint": "Deaktiviert HTTP/2 (h2) auf der Backend-Verbindung — HAProxy handelt nur noch HTTP/1.1 aus. Nötig für Backends die kein h2 unterstützen (z. B. ältere nginx-Konfigurationen ohne h2-Modul, Legacy-Apps).",
"servers": "Server",
"noServers": "kein Server",
"noServersWarning": "Ein oder mehrere aktive Backends haben keine Server konfiguriert.",
"noServersWarningDesc": "HAProxy liefert für Traffic auf diese Backends 503. Backend öffnen (oranger Tag) und mindestens einen Server hinzufügen.",
"nServers": "{{n}} Server",
"serversIn": "Server in „{{name}}\"",
"serverHintCreate": "Speichern legt nur den Pool an. Server kommen im nächsten Schritt — Pool öffnen → „Server hinzufügen\".",
@@ -415,6 +417,8 @@
"editRule": "Regel bearbeiten",
"domain": "Domain",
"pathPrefix": "Pfad-Präfix",
"pathPrefixHint": "Muss mit / beginnen. HAProxy matcht als Präfix.",
"pathPrefixInvalid": "Pfad muss mit / beginnen und darf nur gültige URL-Zeichen enthalten",
"backend": "Backend",
"priority": "Priorität",
"active": "Aktiv",

View File

@@ -380,6 +380,8 @@
"forceHttp1Hint": "Disables HTTP/2 (h2) on the backend connection — HAProxy negotiates HTTP/1.1 only. Required for backends that don't support h2 (e.g. older nginx configs without the h2 module, legacy apps).",
"servers": "Servers",
"noServers": "no server",
"noServersWarning": "One or more active backends have no servers configured.",
"noServersWarningDesc": "HAProxy will return 503 for any traffic routed to these backends. Open the backend (orange tag) and add at least one server.",
"nServers": "{{n}} servers",
"serversIn": "Servers in “{{name}}”",
"serverHintCreate": "Saving creates the pool only. Add servers in the next step — open the pool and click “Add server”.",
@@ -415,6 +417,8 @@
"editRule": "Edit rule",
"domain": "Domain",
"pathPrefix": "Path prefix",
"pathPrefixHint": "Must start with /. HAProxy uses prefix matching.",
"pathPrefixInvalid": "Path must start with / and contain only valid URL characters",
"backend": "Backend",
"priority": "Priority",
"active": "Active",

View File

@@ -329,6 +329,15 @@ export default function BackendsPage() {
</Tag>
)}
/>
{serverCounts && (data ?? []).some(b => b.active && (serverCounts[b.id] ?? 0) === 0) && (
<Alert
type="warning"
showIcon
className="mb-12"
message={t('backends.noServersWarning')}
description={t('backends.noServersWarningDesc')}
/>
)}
<DataTable
rowKey="id"
loading={isLoading}

View File

@@ -270,6 +270,7 @@ export default function RoutingRulesPage() {
onCancel={() => { setEditing(null); setCreating(false) }}
onOk={() => { void form.submit() }}
confirmLoading={create.isPending || update.isPending}
destroyOnHidden
>
<Form
form={form}
@@ -285,7 +286,15 @@ export default function RoutingRulesPage() {
placeholder={t('routing.selectDomain')}
/>
</Form.Item>
<Form.Item label={t('routing.pathPrefix')} name="path_prefix" rules={[{ required: true }]}>
<Form.Item
label={t('routing.pathPrefix')}
name="path_prefix"
extra={t('routing.pathPrefixHint')}
rules={[
{ required: true },
{ pattern: /^\/[a-zA-Z0-9\-._~!$&'()*+,;=:@/%]*$/, message: t('routing.pathPrefixInvalid') },
]}
>
<Input placeholder="/" />
</Form.Item>
<Form.Item label={t('routing.backend')} name="backend_id" rules={[{ required: true }]}>