Skip to content

Commit 64f1812

Browse files
os-zhuangclaude
andcommitted
fix(list,i18n): a 400 from the server no longer reads as "check your connection"
classifyLoadError exists because a 403 rendered the same "check your connection and try again" panel as a genuine outage — its own doc comment says users "were told to debug their network when the server had (correctly) denied them access." It made that distinction for 401 and 403, then sent everything else, 4xx included, to the network branch. A 400 is the server saying it understood the request and will never accept it. Retrying resends the identical bad request, so the connection copy is advice that cannot work — the same mistake the function exists to prevent, one status code over. Reachable from ordinary stored metadata since objectstack#4121: a `$filter` array that is not a filter AST is now rejected at the protocol with 400 INVALID_FILTER, where it previously reached a driver (and, for a lone ['and'], silently returned every row). A view saved with such a filter now answers 400 on every load. Adds a fourth classification, `rejected`, for status 400 and the server's 400-class codes (INVALID_FILTER, UNSUPPORTED_QUERY_PARAM, INVALID_QUERY). Its copy points at the filter rather than the network and says who can fix it when the view is saved that way. 403/401 keep priority so a permission denial can never read as a bad request — pinned by a test. The two strings go into ALL TEN locale packs, not just en: the neighbouring panels are translated and fallbackLng would have rendered this one in English beside them. all-locales-key-parity.test.ts caught the pack I missed. 5 new tests (numeric status, code without status, status in message text, 403/401 ordering); reverting the branch fails four. plugin-list + i18n: 403 tests / 29 files green. Refs objectstack-ai/objectstack#4121, #2945 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
1 parent 2b5e95b commit 64f1812

13 files changed

Lines changed: 131 additions & 4 deletions

File tree

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
---
2+
"@object-ui/plugin-list": minor
3+
"@object-ui/i18n": minor
4+
---
5+
6+
fix(list,i18n): a 400 from the server no longer reads as "check your connection"
7+
8+
`classifyLoadError` was written because a 403 rendered the same
9+
"check your connection and try again" panel as a genuine outage — its own doc
10+
comment says users "were told to debug their network when the server had
11+
(correctly) denied them access." It made that distinction for 401 and 403 and
12+
then sent **everything else**, including 4xx, to the network branch.
13+
14+
A **400** is the server saying it understood the request and will never accept
15+
it. Retrying resends the identical bad request, so "check your connection and
16+
try again" is advice that cannot work — the same mistake the function exists to
17+
prevent, one status code over.
18+
19+
This became reachable from ordinary stored metadata with
20+
objectstack-ai/objectstack#4121: a `$filter` array that is not a filter AST is
21+
now rejected at the protocol with `400 INVALID_FILTER`, where it previously
22+
reached a driver (and, for a lone `['and']`, silently returned every row). A
23+
view saved with such a filter now answers 400 on every load.
24+
25+
Adds a fourth classification, `rejected`, for `status === 400` and for the
26+
server's 400-class codes (`INVALID_FILTER`, `UNSUPPORTED_QUERY_PARAM`,
27+
`INVALID_QUERY`). Its copy points at the filter rather than the network, and
28+
says who can fix it when the view is saved that way. 403/401 keep priority, so a
29+
permission denial can never read as a bad request — pinned by a test.
30+
31+
The two new strings are added to **all ten locale packs**, not just `en`: the
32+
neighbouring panels are translated, and `fallbackLng: 'en'` would have rendered
33+
this one in English beside them. The full-parity gate
34+
(`all-locales-key-parity.test.ts`) caught the pack I missed.
35+
36+
Verified: 5 new tests — numeric status, error code without a status, a status
37+
embedded in the message text, and the 403/401 ordering guard. Reverting the
38+
branch fails four of them. `plugin-list` + `i18n`: **403 tests across 29 files**,
39+
green.

packages/i18n/src/locales/ar.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -457,6 +457,8 @@ const ar = {
457457
loadErrorForbiddenMessage: "ليس لديك إذن لعرض هذه السجلات. تواصل مع المسؤول إذا كنت تعتقد أنه يجب أن يكون لديك وصول.",
458458
loadErrorUnauthorizedTitle: "يلزم تسجيل الدخول",
459459
loadErrorUnauthorizedMessage: "انتهت صلاحية جلستك أو تم تسجيل خروجك. سجّل الدخول مرة أخرى لعرض هذه السجلات.",
460+
loadErrorRejectedTitle: "تم رفض استعلام طريقة العرض هذه",
461+
loadErrorRejectedMessage: "تعذّر على الخادم معالجة عامل التصفية أو خيارات الاستعلام لطريقة العرض هذه. مسح عوامل التصفية يحل المشكلة عادةً؛ وإذا كانت طريقة العرض محفوظة بهذا الشكل، فيجب على المسؤول تصحيحها.",
460462
retry: "إعادة المحاولة",
461463
managedBy: {
462464
system: {

packages/i18n/src/locales/de.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -457,6 +457,8 @@ const de = {
457457
loadErrorForbiddenMessage: "Sie haben keine Berechtigung, diese Datensätze anzuzeigen. Wenden Sie sich an Ihren Administrator, wenn Sie Zugriff benötigen.",
458458
loadErrorUnauthorizedTitle: "Anmeldung erforderlich",
459459
loadErrorUnauthorizedMessage: "Ihre Sitzung ist abgelaufen oder Sie sind abgemeldet. Melden Sie sich erneut an, um diese Datensätze anzuzeigen.",
460+
loadErrorRejectedTitle: "Die Abfrage dieser Ansicht wurde abgelehnt",
461+
loadErrorRejectedMessage: "Der Server konnte den Filter oder die Abfrageoptionen dieser Ansicht nicht verarbeiten. Das Zurücksetzen der Filter behebt das meist; ist die Ansicht so gespeichert, muss ein Administrator sie korrigieren.",
460462
retry: "Erneut versuchen",
461463
managedBy: {
462464
system: {

packages/i18n/src/locales/en.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -486,6 +486,8 @@ const en = {
486486
loadErrorForbiddenMessage: 'You don\u2019t have permission to view these records. Contact your administrator if you think you should have access.',
487487
loadErrorUnauthorizedTitle: 'Sign in required',
488488
loadErrorUnauthorizedMessage: 'Your session has expired or you are signed out. Sign in again to view these records.',
489+
loadErrorRejectedTitle: 'This view’s query was rejected',
490+
loadErrorRejectedMessage: 'The server could not process this view’s filter or query options. Clearing the filters usually fixes it; if the view is saved this way, an administrator needs to correct it.',
489491
retry: 'Retry',
490492
managedBy: {
491493
system: {

packages/i18n/src/locales/es.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -457,6 +457,8 @@ const es = {
457457
loadErrorForbiddenMessage: "No tiene permiso para ver estos registros. Contacte a su administrador si cree que debería tener acceso.",
458458
loadErrorUnauthorizedTitle: "Se requiere iniciar sesión",
459459
loadErrorUnauthorizedMessage: "Su sesión ha expirado o ha cerrado sesión. Inicie sesión de nuevo para ver estos registros.",
460+
loadErrorRejectedTitle: "La consulta de esta vista fue rechazada",
461+
loadErrorRejectedMessage: "El servidor no pudo procesar el filtro ni las opciones de consulta de esta vista. Borrar los filtros suele resolverlo; si la vista está guardada así, un administrador debe corregirla.",
460462
retry: "Reintentar",
461463
managedBy: {
462464
system: {

packages/i18n/src/locales/fr.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -457,6 +457,8 @@ const fr = {
457457
loadErrorForbiddenMessage: "Vous n'avez pas la permission de consulter ces enregistrements. Contactez votre administrateur si vous pensez devoir y accéder.",
458458
loadErrorUnauthorizedTitle: "Connexion requise",
459459
loadErrorUnauthorizedMessage: "Votre session a expiré ou vous êtes déconnecté. Reconnectez-vous pour consulter ces enregistrements.",
460+
loadErrorRejectedTitle: "La requête de cette vue a été rejetée",
461+
loadErrorRejectedMessage: "Le serveur n’a pas pu traiter le filtre ou les options de requête de cette vue. Effacer les filtres suffit généralement ; si la vue est enregistrée ainsi, un administrateur doit la corriger.",
460462
retry: "Réessayer",
461463
managedBy: {
462464
system: {

packages/i18n/src/locales/ja.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -457,6 +457,8 @@ const ja = {
457457
loadErrorForbiddenMessage: "これらのレコードを表示する権限がありません。必要な場合は管理者にお問い合わせください。",
458458
loadErrorUnauthorizedTitle: "サインインが必要です",
459459
loadErrorUnauthorizedMessage: "セッションの有効期限が切れたか、サインアウトしています。再度サインインしてください。",
460+
loadErrorRejectedTitle: "このビューのクエリは拒否されました",
461+
loadErrorRejectedMessage: "サーバーはこのビューのフィルターまたはクエリ設定を処理できませんでした。フィルターを解除すると解消することがほとんどです。ビューがこの状態で保存されている場合は、管理者による修正が必要です。",
460462
retry: "再試行",
461463
managedBy: {
462464
system: {

packages/i18n/src/locales/ko.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -457,6 +457,8 @@ const ko = {
457457
loadErrorForbiddenMessage: "이 레코드를 볼 권한이 없습니다. 접근이 필요하면 관리자에게 문의하세요.",
458458
loadErrorUnauthorizedTitle: "로그인이 필요합니다",
459459
loadErrorUnauthorizedMessage: "세션이 만료되었거나 로그아웃되었습니다. 다시 로그인한 후 확인하세요.",
460+
loadErrorRejectedTitle: "이 뷰의 쿼리가 거부되었습니다",
461+
loadErrorRejectedMessage: "서버가 이 뷰의 필터 또는 쿼리 옵션을 처리하지 못했습니다. 필터를 지우면 대부분 해결됩니다. 뷰가 이 상태로 저장되어 있다면 관리자가 수정해야 합니다.",
460462
retry: "다시 시도",
461463
managedBy: {
462464
system: {

packages/i18n/src/locales/pt.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -457,6 +457,8 @@ const pt = {
457457
loadErrorForbiddenMessage: "Você não tem permissão para ver estes registros. Contate seu administrador se acha que deveria ter acesso.",
458458
loadErrorUnauthorizedTitle: "É necessário entrar",
459459
loadErrorUnauthorizedMessage: "Sua sessão expirou ou você saiu. Entre novamente para ver estes registros.",
460+
loadErrorRejectedTitle: "A consulta desta visualização foi rejeitada",
461+
loadErrorRejectedMessage: "O servidor não conseguiu processar o filtro ou as opções de consulta desta visualização. Limpar os filtros costuma resolver; se a visualização estiver salva assim, um administrador precisa corrigi-la.",
460462
retry: "Tentar novamente",
461463
managedBy: {
462464
system: {

packages/i18n/src/locales/ru.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -457,6 +457,8 @@ const ru = {
457457
loadErrorForbiddenMessage: "У вас нет прав на просмотр этих записей. Обратитесь к администратору, если считаете, что доступ вам нужен.",
458458
loadErrorUnauthorizedTitle: "Требуется вход",
459459
loadErrorUnauthorizedMessage: "Сессия истекла или вы вышли из системы. Войдите снова, чтобы просмотреть эти записи.",
460+
loadErrorRejectedTitle: "Запрос этого представления отклонён",
461+
loadErrorRejectedMessage: "Сервер не смог обработать фильтр или параметры запроса этого представления. Обычно помогает сброс фильтров; если представление сохранено в таком виде, исправить его должен администратор.",
460462
retry: "Повторить",
461463
managedBy: {
462464
system: {

0 commit comments

Comments
 (0)