fix(users): show password rules in form + match FE check to BE (#1303)

Create/Edit User modal previously had no hint about backend password
  complexity, and the FE pre-check was only length>=6 — so any weak
  password got bounced as a bare "HTTP 422" toast after the round-trip.

  - New checkPasswordComplexity util mirroring backend's validator order
  - Helper text under password inputs in both modals
  - Submit disabled until every rule passes
  - client.ts 422 parser falls back to JSON.stringify(detail) when the
    mapped array is empty, so a bare status code never masks the real
    Pydantic detail again
  - i18n keys added in all 8 locales (EN/DE fully translated, others
    per project's English-seed convention)
  - 7 unit tests pinning the validator contract, including the
    reporter's "12345678" input
This commit is contained in:
maziggy
2026-05-13 09:50:42 +02:00
parent db308aa80b
commit d08183278f
15 changed files with 602 additions and 461 deletions
+16 -5
View File
@@ -104,11 +104,22 @@ async function request<T>(
if (!response.ok) {
const error = await response.json().catch(() => ({}));
const detail = error.detail;
const message = typeof detail === 'string'
? detail
: Array.isArray(detail)
? detail.map((e: { msg?: string }) => (e.msg ?? '').replace(/^Value error,\s*/i, '')).filter(Boolean).join('; ')
: `HTTP ${response.status}`;
let message: string;
if (typeof detail === 'string') {
message = detail;
} else if (Array.isArray(detail)) {
// FastAPI 422 shape: each entry has `msg` like "Value error, <real msg>".
// Strip the prefix and join. Fall back to raw JSON if every entry has an
// empty msg (defensive — shouldn't happen with stock Pydantic, but the
// previous fallback masked the real cause as a bare "HTTP 422" toast).
const joined = detail
.map((e: { msg?: string }) => (e.msg ?? '').replace(/^Value error,\s*/i, ''))
.filter(Boolean)
.join('; ');
message = joined || JSON.stringify(detail) || `HTTP ${response.status}`;
} else {
message = `HTTP ${response.status}`;
}
// Handle 401 Unauthorized - only clear token if it's actually invalid
// Don't clear on "Authentication required" which might be a timing issue