Finish the MCP auth labels, the plural forms and the skeleton's status role

Three things the UI pass started but did not carry all the way.

The MCP server dialog's Basic Authentication branch was fixed to use the
label keys for its labels and the placeholder keys for its placeholders,
but the API Key and Bearer Token branches above it in the same
renderAuthFields were left reading placeholders.apiKey and
placeholders.bearerToken as their <Label>. Both fields showed the
placeholder text twice over: the label above the input read "Your secret
API key" where the input already hinted it. authTypes.apiKey and
authTypes.bearer already held "API Key" and "Bearer Token". (Note that
the Basic branch that prompted all this is unreachable — `basic` is
commented out of the authTypes list, so that form cannot be opened.)

Dropped a dead `t(...) || 'Scopes (comma separated)'` fallback in the same
file while there. t() returns the key string when a key is missing, never
a falsy value, so the right-hand side could not run; the branch would
render the raw key rather than the English it looks like it guards.

The plural fix covered English only. resultSummary, view_more,
actionsFound and needsSetup all took _one/_other in en.json, but de, es
and ru kept a single form, so "1 Chunks abgerufen", "1 fragmentos
recuperados" and "ещё 1 источников" still rendered — the exact bug the
change set out to remove, in every language but the one it was tested in.
Added _one/_other for de and es, and _one/_few/_many/_other for ru, which
needs the three-way split (1 источник, 2 источника, 5 источников).
Translated needsSetup while there; it was still English in all three.
jp, zh and zh-TW have a single plural category, so their base form is
already correct and stays as it is.

Replacing Spinner with a skeleton dropped the role="status" that Spinner
carried, and the skeleton divs announce nothing, so a screen reader got
no signal at all between navigating to Agents and the list appearing.
Put it on SkeletonLoader itself rather than at the call sites, so every
variant gets it. It is sr-only, which is position: absolute, so it never
becomes a flex or grid item in the containers these render into.
This commit is contained in:
Alex committed 2026-09-22 10:02:56 +01:00
1 parent 327055b5f2
commit c2e04fa7bf
9 files changed
+55 -17

No files matched your search

+13 -1
View File
@@ -1,4 +1,5 @@
import { useState, useEffect } from 'react';
import { useTranslation } from 'react-i18next';
interface SkeletonLoaderProps {
count?: number;
@@ -22,6 +23,7 @@ const SkeletonLoader: React.FC<SkeletonLoaderProps> = ({
count = 1,
component = 'default',
}) => {
const { t } = useTranslation();
const [skeletonCount, setSkeletonCount] = useState(count);
useEffect(() => {
@@ -353,7 +355,17 @@ const SkeletonLoader: React.FC<SkeletonLoaderProps> = ({
const render = componentMap[component] || componentMap.default;
return <>{render()}</>;
// The Spinner this replaces carried role="status"; without it a screen
// reader gets no signal at all while a section loads. Absolutely
// positioned by `sr-only`, so it never becomes a flex/grid item.
return (
<>
<span className="sr-only" role="status">
{t('loading')}
</span>
{render()}
</>
);
};
export default SkeletonLoader;
+9 -4
View File
@@ -7,6 +7,7 @@
"tagline": "DocsGPT verwendet GenAI, bitte überprüfe kritische Informationen anhand der Quellen.",
"sourceDocs": "Quelle",
"none": "Keine",
"loading": "Wird geladen...",
"cancel": "Abbrechen",
"help": "Hilfe",
"emailUs": "E-Mail senden",
@@ -197,7 +198,8 @@
"queryPlaceholder": "Frage etwas, das diese Quelle beantworten sollte...",
"run": "Ausführen",
"notSavedHint": "Diese Einstellungen gelten nur für diesen Test – sie werden nicht in der Quelle gespeichert. Ändere sie in den Quelleneinstellungen, um sie dauerhaft zu übernehmen.",
"resultSummary": "{{count}} Chunks abgerufen · {{retriever}}",
"resultSummary_one": "{{count}} Chunk abgerufen · {{retriever}}",
"resultSummary_other": "{{count}} Chunks abgerufen · {{retriever}}",
"latency": "{{ms}} ms",
"empty": "Keine Chunks für diese Anfrage abgerufen.",
"emptyWithThreshold": "Keine Chunks haben den Score-Schwellenwert ({{threshold}}) erreicht. Senke ihn, um knappe Treffer zu sehen.",
@@ -1137,7 +1139,8 @@
"parseError": "Spezifikation konnte nicht geparst werden. Bitte Dateiformat prüfen.",
"version": "Version",
"baseUrl": "Basis-URL",
"actionsFound": "{{count}} Aktionen gefunden",
"actionsFound_one": "{{count}} Aktion gefunden",
"actionsFound_other": "{{count}} Aktionen gefunden",
"selectAll": "Alle auswählen",
"deselectAll": "Alle abwählen",
"cancel": "Abbrechen",
@@ -1211,7 +1214,8 @@
"title": "Quellen",
"text": "Wähle deine Quellen",
"link": "Quellen-Link",
"view_more": "{{count}} weitere Quellen",
"view_more_one": "{{count}} weitere Quelle",
"view_more_other": "{{count}} weitere Quellen",
"noSourcesAvailable": "Keine Quellen verfügbar",
"selectedCount": "{{count}} Quellen ausgewählt",
"groupOwn": "Deine Quellen",
@@ -1466,7 +1470,8 @@
"confidence": "Confidence threshold",
"confidenceHint": "The judge must both flag the content and be at least this confident (default: 0.7)",
"activeCount": "{{count}} active",
"needsSetup": "{{count}} need setup",
"needsSetup_one": "{{count}} benötigt Einrichtung",
"needsSetup_other": "{{count}} benötigen Einrichtung",
"setupRequired": "Fill in this check's settings before saving.",
"pickAtLeastOne": "Pick at least one — the check cannot run with none selected.",
"remove": "Remove",
+1
View File
@@ -7,6 +7,7 @@
"tagline": "DocsGPT uses GenAI, please review critical information using sources.",
"sourceDocs": "Source",
"none": "None",
"loading": "Loading...",
"cancel": "Cancel",
"errorBoundary": {
"message": "Something went wrong displaying this content.",
+9 -4
View File
@@ -7,6 +7,7 @@
"tagline": "DocsGPT utiliza GenAI, por favor revisa información crítica utilizando fuentes.",
"sourceDocs": "Fuente",
"none": "Ninguno",
"loading": "Cargando...",
"cancel": "Cancelar",
"help": "Asistencia",
"emailUs": "Envíanos un correo",
@@ -197,7 +198,8 @@
"queryPlaceholder": "Pregunta algo que esta fuente debería responder...",
"run": "Ejecutar",
"notSavedHint": "Estos ajustes solo se usan para esta prueba — no se guardan en la fuente. Cámbialos en Configuración de la fuente para hacerlos permanentes.",
"resultSummary": "{{count}} fragmentos recuperados · {{retriever}}",
"resultSummary_one": "{{count}} fragmento recuperado · {{retriever}}",
"resultSummary_other": "{{count}} fragmentos recuperados · {{retriever}}",
"latency": "{{ms}} ms",
"empty": "No se recuperaron fragmentos para esta consulta.",
"emptyWithThreshold": "Ningún fragmento alcanzó el umbral de puntuación ({{threshold}}). Bájalo para ver los que estuvieron cerca.",
@@ -1137,7 +1139,8 @@
"parseError": "No se pudo analizar la especificación. Verifica el formato del archivo.",
"version": "Versión",
"baseUrl": "URL base",
"actionsFound": "{{count}} acciones encontradas",
"actionsFound_one": "{{count}} acción encontrada",
"actionsFound_other": "{{count}} acciones encontradas",
"selectAll": "Seleccionar todo",
"deselectAll": "Deseleccionar todo",
"cancel": "Cancelar",
@@ -1211,7 +1214,8 @@
"title": "Fuentes",
"text": "Elegir tus fuentes",
"link": "Enlace fuente",
"view_more": "Ver {{count}} más fuentes",
"view_more_one": "Ver {{count}} fuente más",
"view_more_other": "Ver {{count}} fuentes más",
"noSourcesAvailable": "No hay fuentes disponibles",
"selectedCount": "{{count}} fuentes seleccionadas",
"groupOwn": "Tus fuentes",
@@ -1466,7 +1470,8 @@
"confidence": "Confidence threshold",
"confidenceHint": "The judge must both flag the content and be at least this confident (default: 0.7)",
"activeCount": "{{count}} active",
"needsSetup": "{{count}} need setup",
"needsSetup_one": "{{count}} necesita configuración",
"needsSetup_other": "{{count}} necesitan configuración",
"setupRequired": "Fill in this check's settings before saving.",
"pickAtLeastOne": "Pick at least one — the check cannot run with none selected.",
"remove": "Remove",
+1
View File
@@ -7,6 +7,7 @@
"tagline": "DocsGPTはGenAIを使用しています。重要な情報はソースで確認してください。",
"sourceDocs": "ソース",
"none": "なし",
"loading": "読み込み中...",
"cancel": "キャンセル",
"help": "ヘルプ",
"emailUs": "メールを送る",
+17 -4
View File
@@ -7,6 +7,7 @@
"tagline": "DocsGPT использует GenAI, пожалуйста, проверьте важную информацию, используя источники.",
"sourceDocs": "Источник",
"none": "Нет",
"loading": "Загрузка...",
"cancel": "Отмена",
"help": "Помощь",
"emailUs": "Напишите нам",
@@ -207,7 +208,10 @@
"queryPlaceholder": "Спросите что-нибудь, на что этот источник должен ответить...",
"run": "Запустить",
"notSavedHint": "Эти настройки используются только для этого теста — они не сохраняются в источнике. Чтобы сделать их постоянными, измените их в настройках источника.",
"resultSummary": "Извлечено фрагментов: {{count}} · {{retriever}}",
"resultSummary_one": "Извлечён {{count}} фрагмент · {{retriever}}",
"resultSummary_few": "Извлечено {{count}} фрагмента · {{retriever}}",
"resultSummary_many": "Извлечено фрагментов: {{count}} · {{retriever}}",
"resultSummary_other": "Извлечено фрагментов: {{count}} · {{retriever}}",
"latency": "{{ms}} мс",
"empty": "По этому запросу фрагменты не извлечены.",
"emptyWithThreshold": "Ни один фрагмент не набрал оценку не ниже порога ({{threshold}}). Понизьте порог, чтобы увидеть близкие результаты.",
@@ -1167,7 +1171,10 @@
"parseError": "Не удалось разобрать спецификацию. Проверьте формат файла.",
"version": "Версия",
"baseUrl": "Базовый URL",
"actionsFound": "{{count}} действий найдено",
"actionsFound_one": "найдено {{count}} действие",
"actionsFound_few": "найдено {{count}} действия",
"actionsFound_many": "найдено {{count}} действий",
"actionsFound_other": "найдено {{count}} действий",
"selectAll": "Выбрать все",
"deselectAll": "Снять выделение со всех",
"cancel": "Отмена",
@@ -1241,7 +1248,10 @@
"title": "Источники",
"text": "Выберите ваши источники",
"link": "Ссылка на источник",
"view_more": "ещё {{count}} источников",
"view_more_one": "ещё {{count}} источник",
"view_more_few": "ещё {{count}} источника",
"view_more_many": "ещё {{count}} источников",
"view_more_other": "ещё {{count}} источников",
"noSourcesAvailable": "Нет доступных источников",
"selectedCount": "Выбрано источников: {{count}}",
"groupOwn": "Ваши источники",
@@ -1496,7 +1506,10 @@
"confidence": "Confidence threshold",
"confidenceHint": "The judge must both flag the content and be at least this confident (default: 0.7)",
"activeCount": "{{count}} active",
"needsSetup": "{{count}} need setup",
"needsSetup_one": "{{count}} требует настройки",
"needsSetup_few": "{{count}} требуют настройки",
"needsSetup_many": "{{count}} требуют настройки",
"needsSetup_other": "{{count}} требуют настройки",
"setupRequired": "Fill in this check's settings before saving.",
"pickAtLeastOne": "Pick at least one — the check cannot run with none selected.",
"remove": "Remove",
+1
View File
@@ -7,6 +7,7 @@
"tagline": "DocsGPT 使用生成式 AI,請使用原始資料來源審閱重要資訊。",
"sourceDocs": "原始文件",
"none": "無",
"loading": "載入中...",
"cancel": "取消",
"help": "幫助",
"emailUs": "給我們發電郵",
+1
View File
@@ -7,6 +7,7 @@
"tagline": "DocsGPT 使用 GenAI, 请使用来源审核关键信息.",
"sourceDocs": "源",
"none": "无",
"loading": "加载中...",
"cancel": "取消",
"help": "帮助",
"emailUs": "给我们发邮件",
+3 -4
View File
@@ -455,7 +455,7 @@ export default function MCPServerModal({
<div className="flex flex-col gap-4">
<div className="flex flex-col gap-1.5">
<Label htmlFor="api_key">
{t('settings.tools.mcp.placeholders.apiKey')}
{t('settings.tools.mcp.authTypes.apiKey')}
<span className="text-red-500">*</span>
</Label>
<Input
@@ -492,7 +492,7 @@ export default function MCPServerModal({
return (
<div className="flex flex-col gap-1.5">
<Label htmlFor="bearer_token">
{t('settings.tools.mcp.placeholders.bearerToken')}
{t('settings.tools.mcp.authTypes.bearer')}
<span className="text-red-500">*</span>
</Label>
<Input
@@ -556,8 +556,7 @@ export default function MCPServerModal({
return (
<div className="flex flex-col gap-1.5">
<Label htmlFor="oauth_scopes">
{t('settings.tools.mcp.placeholders.oauthScopes') ||
'Scopes (comma separated)'}
{t('settings.tools.mcp.placeholders.oauthScopes')}
</Label>
<Input
id="oauth_scopes"