feat(admin-ui): shadcn primitives + @/ui barrel (Stage 2.1)

This commit is contained in:
Александр Зимин
2026-05-10 21:47:24 +00:00
parent c11a70128c
commit 5d12c89c4f
36 changed files with 2826 additions and 28 deletions
+17 -2
View File
@@ -25,14 +25,29 @@ export function TokenSync() {
const redirecting = useRef(false)
// 1) Token sync — single update path к accessToken holder в client.ts.
// ВАЖНО: пропускаем токен ТОЛЬКО когда user реально authenticated AND token
// не expired. Раньше передавали raw {@code auth.user?.access_token} — это
// включало случаи когда oidc-client-ts вернул user object с уже expired
// token'ом (silent renew failed но user object всё ещё в state). axios
// отправлял Bearer expired_token → backend (с permissive=false для guest
// anyway re-validates JWT через oauth2ResourceServer) → 401 → catalog UI
// показывал «Не удалось загрузить данные» вместо PUBLIC dicts.
//
// user.expired property из oidc-client-ts: true если access_token expiry
// прошла. Дополнительно проверяем isAuthenticated — react-oidc-context
// обновляет это в реальном времени.
useEffect(() => {
setAccessToken(auth.user?.access_token ?? null)
const liveToken =
auth.isAuthenticated && auth.user && !auth.user.expired
? auth.user.access_token
: null
setAccessToken(liveToken ?? null)
// Cleanup legacy localStorage key (was used до fix #12 + #2/3/13 cascade).
// Идемпотентный no-op если ключа нет.
if (typeof window !== 'undefined') {
window.localStorage.removeItem(LEGACY_TOKEN_STORAGE_KEY)
}
}, [auth.user?.access_token])
}, [auth.isAuthenticated, auth.user, auth.user?.access_token, auth.user?.expired])
// 2) 401 handler — registered once на app mount, делегирует silent renew /
// redirect на Keycloak. Guard'ы: