fix(ui): WCAG light-theme accent, overflow-safe audit page, formal address
Some checks are pending
Security / Security check (push) Waiting to run

Accessibility/responsive audit pass with two new permanent test
gates (test/a11y_test.dart: WCAG text contrast + labeled tap
targets on every page in both themes; test/responsive_test.dart:
no layout overflow at 800/960/1280/1920 px). Findings fixed:

- Light theme primary/tertiary sky-500 → sky-700: white text on
  the lighter accent only reached 2.8:1 (welcome CTA, active
  sidebar label); sky-700 clears WCAG AA at ~5.9:1. Dark theme
  unchanged (already compliant). FABs now follow the same accent
  instead of Material 3's washed-out tonal default.
- Audit page: filter chips collapse into a checkmark popup menu
  below 900 px window width (app bar overflowed); the live-status
  bar's left text is now Expanded with ellipsis so the row can
  shrink, and the disconnected state's copyable error gets the
  full remaining width.
- German strings now use formal address consistently (~20 strings
  still used du-forms next to Sie-forms on welcome/setup), the
  audit event-type chip "Step" is "Schritt", and the doctor
  page's event count pluralises correctly in both languages.

flutter analyze clean, 64 tests green. Screenshot pass light+dark
via the guide-shots harness (verified parity, no overflows).

Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
This commit is contained in:
flemming-it 2026-07-15 04:34:19 +02:00
parent efaa089454
commit da58125f20
9 changed files with 339 additions and 95 deletions

View file

@ -54,13 +54,13 @@
"errOutputTooLarge": "Step-Output hat die Größenbegrenzung überschritten.",
"errOutputTooLargeHint": "Entweder Output kürzen (Text truncaten, Bytes komprimieren) oder `max_output_size_mb` in der Operator-Config erhöhen.",
"errServiceUnavailableForStep": "Host-Service nicht konfiguriert.",
"errServiceUnavailableForStepHint": "Das Modul braucht einen Service (z.B. ollama, playwright), den der Operator nicht deklariert hat. Trage ihn unter `services:` in ~/.chain/config.yaml ein.",
"errServiceUnavailableForStepHint": "Das Modul braucht einen Service (z.B. ollama, playwright), den der Operator nicht deklariert hat. Tragen Sie ihn unter `services:` in ~/.chain/config.yaml ein.",
"errMissingValue": "Pflichtwert fehlt.",
"errMissingValueHint": "Der Step erwartet eine Eingabe, die nicht verdrahtet ist — entweder zur Laufzeit liefern oder den vorgelagerten `$ref` korrigieren.",
"errMcpUnreachable": "MCP-Endpunkt nicht erreichbar.",
"errMcpUnreachableHint": "Der MCP-Server hat nicht geantwortet. Endpunkt in Einstellungen → Integrationen prüfen und sicherstellen, dass er läuft.",
"errCapabilityNotInstalled": "Benötigte Capability nicht installiert.",
"errCapabilityNotInstalledHint": "Im Text-Tab des Flows klickst du auf den Fix-Button — der installiert die Capability, sofern sie im Store ist.",
"errCapabilityNotInstalledHint": "Im Text-Tab des Flows klicken Sie auf den Fix-Button — der installiert die Capability, sofern sie im Store ist.",
"welcomeDocClose": "Schließen",
"welcomeDocFailedToLoad": "Doku konnte nicht geladen werden: {error}",
"@welcomeDocFailedToLoad": {
@ -172,7 +172,7 @@
"systemAiOff": "aus",
"systemAiEdit": "Bearbeiten…",
"systemAiConfigure": "Konfigurieren…",
"systemAiOffBlurb": "Aus — Fehlererklärungen auf der Protokoll-Seite sind deaktiviert. Klicke Konfigurieren…, um einen Provider zu wählen (Ollama / OpenAI / LM Studio / vLLM / Eigene). Die Operator-Konfig wird direkt überschrieben; kein Daemon-Neustart nötig.",
"systemAiOffBlurb": "Aus — Fehlererklärungen auf der Protokoll-Seite sind deaktiviert. Klicken Sie auf Konfigurieren…, um einen Provider zu wählen (Ollama / OpenAI / LM Studio / vLLM / Eigene). Die Operator-Konfig wird direkt überschrieben; kein Daemon-Neustart nötig.",
"mcpServersCount": "{n} {n, plural, =1{Server} other{Server}}",
"@mcpServersCount": {
"placeholders": {
@ -286,7 +286,7 @@
"storeAskAi": "KI fragen",
"storeAskClear": "Frage zurücksetzen",
"storeAskAiThinking": "Module werden durchsucht…",
"storeAskAiUnavailable": "Konfiguriere eine System-AI in den Einstellungen, um Fragen in normaler Sprache zu stellen.",
"storeAskAiUnavailable": "Konfigurieren Sie eine System-AI in den Einstellungen, um Fragen in normaler Sprache zu stellen.",
"storeAskNoMatches": "Keine Treffer — Frage verfeinern oder im Grid unten stöbern.",
"storeAskAnswerLabel": "KI-Vorschlag",
"storeAskAnswerWhy": "Warum es passt",
@ -479,7 +479,7 @@
"storeOpenRepoButton": "Repository im Browser öffnen",
"storeDocsErrorNotFound": "Dieses Modul ist nicht im Store-Index des Hubs enthalten.",
"storeDocsErrorNoDocs": "Für dieses Modul ist keine Repository-URL hinterlegt.",
"storeDocsErrorAuth": "Die Registry erfordert Authentifizierung, um dieses README zu laden. Setze CHAIN_REGISTRY_TOKEN in der Umgebung des Daemons und starte den Hub neu.",
"storeDocsErrorAuth": "Die Registry erfordert Authentifizierung, um dieses README zu laden. Setzen Sie CHAIN_REGISTRY_TOKEN in der Umgebung des Daemons und starten Sie den Hub neu.",
"storeDocsErrorNetwork": "Netzwerkfehler beim Laden des README. {detail}",
"@storeDocsErrorNetwork": {
"placeholders": {
@ -529,7 +529,7 @@
}
}
},
"storeProviderAddedZeroToast": "{name} ist eingetragen, aber der Server hat noch keine Fähigkeiten geliefert. Öffne Einstellungen → MCP-Clients, um Discovery erneut zu versuchen oder den Server zu prüfen.",
"storeProviderAddedZeroToast": "{name} ist eingetragen, aber der Server hat noch keine Fähigkeiten geliefert. Öffnen Sie Einstellungen → MCP-Clients, um Discovery erneut zu versuchen oder den Server zu prüfen.",
"@storeProviderAddedZeroToast": {
"placeholders": {
"name": {
@ -550,11 +550,12 @@
},
"auditTitle": "Protokoll",
"auditNoEvents": "Noch keine Ereignisse",
"auditNoEventsHint": "Starte einen Flow, um den Audit-Stream zu füllen.\nEreignisse erscheinen innerhalb von Sekunden.",
"auditNoEventsHint": "Starten Sie einen Flow, um den Audit-Stream zu füllen.\nEreignisse erscheinen innerhalb von Sekunden.",
"auditFilterAll": "alle",
"auditFilterFlow": "Flow",
"auditFilterStep": "Step",
"auditFilterStep": "Schritt",
"auditFilterModule": "Modul",
"auditFilterTooltip": "Ereignisse filtern",
"auditClearLogTooltip": "Protokoll löschen (nur local/dev Kanal)",
"auditClearedToast": "{n} Ereignisse auf Kanal „{channel}\" gelöscht. Kette mit Marker neu geseedet.",
"@auditClearedToast": {
@ -880,7 +881,7 @@
},
"storeAdvisoryVersionTooltip": "Föderierter Upstream-Dienst — Version ist Richtwert; der Upstream kann ohne Versionsanhebung Kompatibilität brechen.",
"uninstallVersionPickerTitle": "Version zum Entfernen wählen",
"uninstallVersionPickerBody": "Mehrere Versionen von `{module}` sind parallel installiert. Wähle genau die Version aus, die entfernt werden soll — die anderen bleiben bestehen.",
"uninstallVersionPickerBody": "Mehrere Versionen von `{module}` sind parallel installiert. Wählen Sie genau die Version aus, die entfernt werden soll — die anderen bleiben bestehen.",
"@uninstallVersionPickerBody": {
"placeholders": {
"module": {
@ -1070,7 +1071,7 @@
"approvalsPayloadPreview": "ZU PRÜFENDE DATEN",
"approvalsNoPayload": "Keine Daten zum Prüfen angehängt. Der system.approval-Schritt des Flows bestimmt über sein \"show:\"-Feld, was angezeigt wird — setze es, um die Daten hinter dieser Entscheidung sichtbar zu machen.",
"approvalsNoDataConfirmTitle": "Ohne Prüfdaten freigeben?",
"approvalsNoDataConfirmBody": "Dieser Flow hat bewusst keine Prüfdaten hinterlegt (kein \"show:\" am Freigabe-Schritt). Du kannst trotzdem freigeben — entscheidest dann aber, ohne die Daten hinter dieser Entscheidung gesehen zu haben.",
"approvalsNoDataConfirmBody": "Dieser Flow hat bewusst keine Prüfdaten hinterlegt (kein \"show:\" am Freigabe-Schritt). Sie können trotzdem freigeben — entscheiden dann aber, ohne die Daten hinter dieser Entscheidung gesehen zu haben.",
"approvalsNoDataConfirmAction": "Trotzdem freigeben",
"approvalsRequestFallback": "Freigabe für diesen Schritt erforderlich",
"approvalsFlowStepMeta": "Flow: {flow} · Schritt: {step}",
@ -1196,7 +1197,7 @@
"doctorDaemonFilesSection": "Daemon-Dateien",
"doctorDaemonControlSection": "Daemon-Steuerung",
"doctorChainIntact": "Hash-Kette intakt",
"doctorChainIntactDetail": "{n} Ereignisse · prev_event_sha256 lückenlos verifiziert",
"doctorChainIntactDetail": "{n} {n, plural, =1{Ereignis} other{Ereignisse}} · prev_event_sha256 lückenlos verifiziert",
"@doctorChainIntactDetail": {
"placeholders": {
"n": {
@ -1499,9 +1500,9 @@
"flowEditorRefresh": "Datei-Liste neu laden",
"flowEditorRunOutput": "LAUF-ERGEBNIS",
"flowEditorEmptyTitle": "Kein Flow geöffnet",
"flowEditorEmptyBody": "Wähle links einen aus oder klicke Neuer Flow um einen neuen anzulegen.",
"flowEditorEmptyBody": "Wählen Sie links einen aus oder klicken Sie auf Neuer Flow, um einen neuen anzulegen.",
"flowEditorListEmptyTitle": "Keine gespeicherten Flows",
"flowEditorListEmptyBody": "Klicke Neuer Flow um aus einer Vorlage zu starten.",
"flowEditorListEmptyBody": "Klicken Sie auf Neuer Flow, um aus einer Vorlage zu starten.",
"flowEditorDiscardTitle": "Ungespeicherte Änderungen verwerfen?",
"flowEditorDiscardBody": "Beim Wechsel der Datei gehen alle noch nicht gespeicherten Änderungen verloren.",
"flowEditorDiscardKeep": "Weiterbearbeiten",
@ -1584,9 +1585,9 @@
}
},
"addSourceField": "URL oder Pfad zum .chain-Bundle",
"addSourceHint": "https://git.flemming.ai/deine-org/dein-modul/releases/download/v0.1.0/foo-0.1.0.chain",
"addSourceHint": "https://git.flemming.ai/ihre-org/ihr-modul/releases/download/v0.1.0/foo-0.1.0.chain",
"addSourceHowItWorksTitle": "Wie private Module funktionieren",
"addSourceHowItWorksBody": "Ein Modul ist ein Verzeichnis mit module.yaml + WASM-Artefakt. Zum Teilen: `chain pack <verzeichnis>` baut ein `.chain`-Bundle, das du beliebig hosten kannst (eigene Forgejo / GitHub / S3). Der Hub installiert per URL und prüft die Signatur gegen seinen Trust-Store.\n\nLokal entwickeln? Nimm das CLI — Studio installiert (noch) nicht aus einem unverpackten Verzeichnis:",
"addSourceHowItWorksBody": "Ein Modul ist ein Verzeichnis mit module.yaml + WASM-Artefakt. Zum Teilen: `chain pack <verzeichnis>` baut ein `.chain`-Bundle, das Sie beliebig hosten können (eigene Forgejo / GitHub / S3). Der Hub installiert per URL und prüft die Signatur gegen seinen Trust-Store.\n\nLokal entwickeln? Nimm das CLI — Studio installiert (noch) nicht aus einem unverpackten Verzeichnis:",
"addSourceCliExample": "chain install --link /pfad/zum/modul",
"addSourceInstallButton": "Installieren",
"addSourceCancel": "Abbrechen",
@ -1597,7 +1598,7 @@
}
},
"welcomeHubDownTitle": "Der Hub läuft noch nicht",
"welcomeHubDownBody": "Studio spricht mit einem lokalen Hub — der Engine, die Module lädt und Flows ausführt. Sie ist gerade nicht erreichbar. Starte sie, um loszulegen.",
"welcomeHubDownBody": "Studio spricht mit einem lokalen Hub — der Engine, die Module lädt und Flows ausführt. Sie ist gerade nicht erreichbar. Starten Sie die Engine, um loszulegen.",
"welcomeHubDownStart": "Hub starten",
"welcomeHubDownStarting": "Wird gestartet …",
"welcomeHubDownDocsLink": "Klappt der Start nicht? Zur Erste-Schritte-Anleitung",
@ -1615,7 +1616,7 @@
}
},
"chainBinaryNotFound": "Das Programm `chain` wurde auf diesem Rechner nicht gefunden.",
"chainBinaryNotFoundHint": "Installiere die Ch∆In-Plattform oder verweise Studio auf eine vorhandene `chain`-Datei.",
"chainBinaryNotFoundHint": "Installieren Sie die Ch∆In-Plattform oder verweisen Sie Studio auf eine vorhandene `chain`-Datei.",
"chainBinaryLocateButton": "`chain`-Programm suchen …",
"chainBinaryInstallDocsButton": "Installationsanleitung öffnen",
"chainBinaryPickerTitle": "`chain`-Programm auswählen",
@ -1633,9 +1634,9 @@
}
},
"sysAiFixDisabled": "Richte die System-KI in den Einstellungen (Cmd+,) → Bereich System-KI ein.",
"sysAiFixEnvMissing": "Die Umgebungsvariable für den API-Schlüssel ist leer. Setze sie in deiner Shell und starte den Daemon neu.",
"sysAiFixEnvMissing": "Die Umgebungsvariable für den API-Schlüssel ist leer. Setzen Sie sie in Ihrer Shell und starten Sie den Daemon neu.",
"sysAiFixNetwork": "Der Hub erreicht den konfigurierten Endpunkt nicht. Läuft dein Anbieter?",
"sysAiFixHttp": "Der Anbieter hat einen Status außerhalb 2xx geliefert. Prüfe Endpunkt, Modellname und API-Schlüssel.",
"sysAiFixHttp": "Der Anbieter hat einen Status außerhalb 2xx geliefert. Prüfen Sie Endpunkt, Modellnamen und API-Schlüssel.",
"sysAiFixEmptyResponse": "Der Anbieter hat keinen Inhalt geliefert. Probiere ein anderes Modell oder formuliere den Prompt um.",
"channelSwitchOk": "Aktiver Kanal auf \"{name}\" umgeschaltet. Daemon neu gestartet.",
"@channelSwitchOk": {
@ -1649,9 +1650,9 @@
"detail": {"type": "String"}
}
},
"providerDescOllama": "Lokales `ollama serve`. Die Modelle bleiben auf deinem Rechner. Kein API-Schlüssel nötig.",
"providerDescOpenai": "Gehostete OpenAI-API. Erfordert einen API-Schlüssel. Daten verlassen deinen Rechner.",
"providerDescLmstudio": "Lokaler LM-Studio-Server. Die Modelle bleiben auf deinem Rechner. Kein API-Schlüssel nötig.",
"providerDescOllama": "Lokales `ollama serve`. Die Modelle bleiben auf Ihrem Rechner. Kein API-Schlüssel nötig.",
"providerDescOpenai": "Gehostete OpenAI-API. Erfordert einen API-Schlüssel. Daten verlassen Ihren Rechner.",
"providerDescLmstudio": "Lokaler LM-Studio-Server. Die Modelle bleiben auf Ihrem Rechner. Kein API-Schlüssel nötig.",
"providerDescVllm": "Selbst gehostetes vLLM oder ein anderer OpenAI-kompatibler Server. Endpunkt erforderlich.",
"providerDescCustom": "Alles andere, das die OpenAI-kompatible Chat-Completions-Schnittstelle spricht (LiteLLM-Proxy, interner Spiegel, …).",
"welcomeDocLoadFailedBody": "Die mitgelieferte Doku \"{slug}\" ({locale}) konnte nicht geladen werden.\nVersucht: {attempted}\nUrsache: {underlying}\nMeist ist der installierte Studio-Build älter als das Doku-Bundle. Baue Studio neu oder öffne die Online-Kopie.",
@ -1675,7 +1676,7 @@
"federationReloadTooltip": "Satelliten neu laden",
"federationAddSatellite": "Satellit hinzufügen",
"federationEmptyTitle": "Keine Satelliten verbunden",
"federationEmptyHint": "Verbinde einen weiteren Hub als Satellit, um Capabilities dort auszuführen. Stelle dazu ein Enrollment-Token aus.",
"federationEmptyHint": "Verbinden Sie einen weiteren Hub als Satellit, um Capabilities dort auszuführen. Stellen Sie dazu ein Enrollment-Token aus.",
"federationPillConnected": "verbunden",
"federationRegionNone": "keine Region",
"federationCapabilities": "{count} angebotene Capabilities",