diff --git a/client/src/Pages/Settings/index.tsx b/client/src/Pages/Settings/index.tsx index c5cd8f7c2..c8fccfd3f 100644 --- a/client/src/Pages/Settings/index.tsx +++ b/client/src/Pages/Settings/index.tsx @@ -58,8 +58,6 @@ const SETTINGS_TABS = [ type SettingsTabKey = (typeof SETTINGS_TABS)[number]["key"]; -// Maps a validation error back to the tab holding it, so a failed save can -// reveal the offending field instead of naming one on a hidden tab. const FIELD_TAB: Record = { checkTTL: "monitoring", globalThresholds: "monitoring", @@ -74,10 +72,6 @@ const tabForField = (field: string): SettingsTabKey => ? "email" : (FIELD_TAB[field.split(".")[0]] ?? "general"); -// Error rows named the raw schema key ("systemEmailRejectUnauthorized"). Each -// field already owns a translated label, so reuse those rather than adding -// strings. Labels that append an explanation after a dash are trimmed to the -// name itself. const FIELD_LABEL_KEY: Record = { checkTTL: "pages.settings.form.retention.option.days.label", "globalThresholds.cpu": "pages.settings.form.thresholds.option.cpu.label", @@ -104,10 +98,6 @@ const FIELD_LABEL_KEY: Record = { "pages.settings.form.email.option.rejectUnauthorized.label", }; -// react-hook-form nests errors by path, so a grouped field arrives as -// { globalThresholds: { cpu: { message } } }. Iterating the top level alone -// yields an entry whose own message is undefined, which renders as a bare -// "globalThresholds" naming none of the four sliders. Walk to the leaves. type FieldErrorLeaf = { path: string; message?: string }; const flattenFieldErrors = (errors: unknown, prefix = ""): FieldErrorLeaf[] => { @@ -115,6 +105,9 @@ const flattenFieldErrors = (errors: unknown, prefix = ""): FieldErrorLeaf[] => { return []; } return Object.entries(errors).flatMap(([key, value]) => { + if (key === "ref") { + return []; + } const path = prefix ? `${prefix}.${key}` : key; if (typeof value !== "object" || value === null) { return []; @@ -141,11 +134,7 @@ export const SettingsPage = () => { [isAdmin] ); - // An unknown tab, or an admin tab requested by a non-admin, falls back to the - // first tab the current user can actually see. const requestedTab = searchParams.get("tab"); - // visibleTabs always contains "general" today; the constant fallback keeps a - // future gating change from throwing on an empty list. const firstVisibleTab: SettingsTabKey = visibleTabs[0]?.key ?? SETTINGS_TABS[0].key; const activeTab: SettingsTabKey = visibleTabs.find((tab) => tab.key === requestedTab)?.key ?? firstVisibleTab; @@ -160,16 +149,19 @@ export const SettingsPage = () => { setSearchParams(updated, { replace: true }); }; - // A "tab" that does not resolve -- an unknown key, or an admin tab followed by - // a non-admin -- leaves the URL claiming a tab the page is not showing. Drop it - // so the address bar matches what is rendered. + // Drop a "tab" param that does not resolve to a rendered tab, or that names + // the first tab, which is addressed with no param at all. useEffect(() => { - if (requestedTab !== null && requestedTab !== activeTab) { - const updated = new URLSearchParams(searchParams); - updated.delete("tab"); - setSearchParams(updated, { replace: true }); + if (requestedTab === null) { + return; } - }, [requestedTab, activeTab, searchParams, setSearchParams]); + if (requestedTab === activeTab && activeTab !== firstVisibleTab) { + return; + } + const updated = new URLSearchParams(searchParams); + updated.delete("tab"); + setSearchParams(updated, { replace: true }); + }, [requestedTab, activeTab, firstVisibleTab, searchParams, setSearchParams]); // Local state for demo monitors dialog const [isDemoMonitorsDialogOpen, setIsDemoMonitorsDialogOpen] = useState(false); @@ -418,10 +410,6 @@ export const SettingsPage = () => { logger.debug("Form validation errors", errors); }; - // The save bar lists errors by field name, and the offending field may sit on - // a tab that is not open. Submitting cannot reveal it -- the button is - // disabled while the form is invalid -- so each listed field switches to its - // own tab instead. const revealField = (field: string) => { const target = tabForField(field); if (visibleTabs.some((tab) => tab.key === target)) { diff --git a/client/src/locales/ar.json b/client/src/locales/ar.json index 55f34650d..f1153737f 100644 --- a/client/src/locales/ar.json +++ b/client/src/locales/ar.json @@ -1141,6 +1141,13 @@ } }, "settings": { + "tabs": { + "general": "عام", + "monitoring": "المراقبة", + "email": "البريد الإلكتروني", + "integrations": "التكاملات", + "data": "البيانات" + }, "form": { "timezone": { "title": "المنطقة الزمنية للعرض", diff --git a/client/src/locales/ca.json b/client/src/locales/ca.json index 7e39eca86..5ac20610e 100644 --- a/client/src/locales/ca.json +++ b/client/src/locales/ca.json @@ -1141,6 +1141,13 @@ } }, "settings": { + "tabs": { + "general": "General", + "monitoring": "Monitoratge", + "email": "Correu electrònic", + "integrations": "Integracions", + "data": "Dades" + }, "form": { "timezone": { "title": "Zona horària de visualització", diff --git a/client/src/locales/cs.json b/client/src/locales/cs.json index d04b9b23b..2896413fa 100644 --- a/client/src/locales/cs.json +++ b/client/src/locales/cs.json @@ -1141,6 +1141,13 @@ } }, "settings": { + "tabs": { + "general": "Obecné", + "monitoring": "Monitorování", + "email": "E-mail", + "integrations": "Integrace", + "data": "Data" + }, "form": { "timezone": { "title": "Zobrazované časové pásmo", diff --git a/client/src/locales/de.json b/client/src/locales/de.json index d43d5d52a..de517b57c 100644 --- a/client/src/locales/de.json +++ b/client/src/locales/de.json @@ -1141,6 +1141,13 @@ } }, "settings": { + "tabs": { + "general": "Allgemein", + "monitoring": "Überwachung", + "email": "E-Mail", + "integrations": "Integrationen", + "data": "Daten" + }, "form": { "timezone": { "title": "Anzeigesprache Zeitzone", diff --git a/client/src/locales/es.json b/client/src/locales/es.json index 589399a83..24fd69302 100644 --- a/client/src/locales/es.json +++ b/client/src/locales/es.json @@ -1141,6 +1141,13 @@ } }, "settings": { + "tabs": { + "general": "General", + "monitoring": "Monitorización", + "email": "Correo electrónico", + "integrations": "Integraciones", + "data": "Datos" + }, "form": { "timezone": { "title": "Zona horaria de visualización", diff --git a/client/src/locales/fi.json b/client/src/locales/fi.json index 030698d44..3ffb1acc3 100644 --- a/client/src/locales/fi.json +++ b/client/src/locales/fi.json @@ -1141,6 +1141,13 @@ } }, "settings": { + "tabs": { + "general": "Yleiset", + "monitoring": "Valvonta", + "email": "Sähköposti", + "integrations": "Integraatiot", + "data": "Tiedot" + }, "form": { "timezone": { "title": "Näytettävä aikavyöhyke", diff --git a/client/src/locales/fr.json b/client/src/locales/fr.json index 1e0a6b096..94f723074 100644 --- a/client/src/locales/fr.json +++ b/client/src/locales/fr.json @@ -1141,6 +1141,13 @@ } }, "settings": { + "tabs": { + "general": "Général", + "monitoring": "Surveillance", + "email": "E-mail", + "integrations": "Intégrations", + "data": "Données" + }, "form": { "timezone": { "title": "Fuseau horaire d'affichage", diff --git a/client/src/locales/it.json b/client/src/locales/it.json index 3d6d1ea16..af743e7d2 100644 --- a/client/src/locales/it.json +++ b/client/src/locales/it.json @@ -1237,6 +1237,13 @@ } }, "settings": { + "tabs": { + "general": "Generale", + "monitoring": "Monitoraggio", + "email": "Email", + "integrations": "Integrazioni", + "data": "Dati" + }, "form": { "timezone": { "title": "Fuso orario di visualizzazione", diff --git a/client/src/locales/ja.json b/client/src/locales/ja.json index 16e2ec641..617d06fdf 100644 --- a/client/src/locales/ja.json +++ b/client/src/locales/ja.json @@ -1141,6 +1141,13 @@ } }, "settings": { + "tabs": { + "general": "一般", + "monitoring": "監視", + "email": "メール", + "integrations": "連携", + "data": "データ" + }, "form": { "timezone": { "title": "表示タイムゾーン", diff --git a/client/src/locales/pl.json b/client/src/locales/pl.json index 81509ee6f..2298ea96c 100644 --- a/client/src/locales/pl.json +++ b/client/src/locales/pl.json @@ -1207,6 +1207,13 @@ } }, "settings": { + "tabs": { + "general": "Ogólne", + "monitoring": "Monitorowanie", + "email": "E-mail", + "integrations": "Integracje", + "data": "Dane" + }, "form": { "about": { "developedBy": "Opracowane przez Bluewave Labs", diff --git a/client/src/locales/pt-BR.json b/client/src/locales/pt-BR.json index c75ead3ef..7b85a43d4 100644 --- a/client/src/locales/pt-BR.json +++ b/client/src/locales/pt-BR.json @@ -1141,6 +1141,13 @@ } }, "settings": { + "tabs": { + "general": "Geral", + "monitoring": "Monitoramento", + "email": "E-mail", + "integrations": "Integrações", + "data": "Dados" + }, "form": { "timezone": { "title": "Fuso horário de exibição", diff --git a/client/src/locales/ru.json b/client/src/locales/ru.json index cf5e486f7..7f1824793 100644 --- a/client/src/locales/ru.json +++ b/client/src/locales/ru.json @@ -1141,6 +1141,13 @@ } }, "settings": { + "tabs": { + "general": "Общие", + "monitoring": "Мониторинг", + "email": "Электронная почта", + "integrations": "Интеграции", + "data": "Данные" + }, "form": { "timezone": { "title": "Часовой пояс отображения", diff --git a/client/src/locales/th.json b/client/src/locales/th.json index 66d354adc..f3b535f86 100644 --- a/client/src/locales/th.json +++ b/client/src/locales/th.json @@ -1141,6 +1141,13 @@ } }, "settings": { + "tabs": { + "general": "ทั่วไป", + "monitoring": "การตรวจสอบ", + "email": "อีเมล", + "integrations": "การเชื่อมต่อ", + "data": "ข้อมูล" + }, "form": { "timezone": { "title": "เขตเวลาที่แสดง", diff --git a/client/src/locales/tr.json b/client/src/locales/tr.json index 26f8aace0..f70f18511 100644 --- a/client/src/locales/tr.json +++ b/client/src/locales/tr.json @@ -1141,6 +1141,13 @@ } }, "settings": { + "tabs": { + "general": "Genel", + "monitoring": "İzleme", + "email": "E-posta", + "integrations": "Entegrasyonlar", + "data": "Veri" + }, "form": { "timezone": { "title": "Görüntüleme saat dilimi", diff --git a/client/src/locales/uk.json b/client/src/locales/uk.json index d1cb983d1..73b10decc 100644 --- a/client/src/locales/uk.json +++ b/client/src/locales/uk.json @@ -1141,6 +1141,13 @@ } }, "settings": { + "tabs": { + "general": "Загальні", + "monitoring": "Моніторинг", + "email": "Електронна пошта", + "integrations": "Інтеграції", + "data": "Дані" + }, "form": { "timezone": { "title": "Часовий пояс відображення", diff --git a/client/src/locales/vi.json b/client/src/locales/vi.json index 81da1c6fc..b04b5de1e 100644 --- a/client/src/locales/vi.json +++ b/client/src/locales/vi.json @@ -1141,6 +1141,13 @@ } }, "settings": { + "tabs": { + "general": "Chung", + "monitoring": "Giám sát", + "email": "Email", + "integrations": "Tích hợp", + "data": "Dữ liệu" + }, "form": { "timezone": { "title": "Múi giờ hiển thị", diff --git a/client/src/locales/zh-CN.json b/client/src/locales/zh-CN.json index 1a455d41c..e93707729 100644 --- a/client/src/locales/zh-CN.json +++ b/client/src/locales/zh-CN.json @@ -1142,6 +1142,13 @@ } }, "settings": { + "tabs": { + "general": "常规", + "monitoring": "监控", + "email": "邮件", + "integrations": "集成", + "data": "数据" + }, "form": { "timezone": { "title": "显示时区", diff --git a/client/src/locales/zh-TW.json b/client/src/locales/zh-TW.json index a15a2a2bb..a7da9b80b 100644 --- a/client/src/locales/zh-TW.json +++ b/client/src/locales/zh-TW.json @@ -1141,6 +1141,13 @@ } }, "settings": { + "tabs": { + "general": "一般", + "monitoring": "監控", + "email": "郵件", + "integrations": "整合", + "data": "資料" + }, "form": { "timezone": { "title": "顯示時區",