fix(auth): отобразить роль analyst в UserMenu, расширить Role union в useMe (#1237)
This commit is contained in:
parent
49d26b4696
commit
d8a2ad7854
2 changed files with 19 additions and 5 deletions
|
|
@ -5,7 +5,7 @@
|
||||||
*
|
*
|
||||||
* Avatar-кнопка с инициалом из username + dropdown:
|
* Avatar-кнопка с инициалом из username + dropdown:
|
||||||
* - текущий username
|
* - текущий username
|
||||||
* - role badge («Админ» / «Пилот»)
|
* - role badge («Админ» / «Пилот» / «Аналитик»)
|
||||||
* - кнопка «Выйти» — invalidate Caddy basic_auth cached creds в browser
|
* - кнопка «Выйти» — invalidate Caddy basic_auth cached creds в browser
|
||||||
*
|
*
|
||||||
* Используется в `TopNav.rightSlot`. Если /me грузится или 401 (dev без
|
* Используется в `TopNav.rightSlot`. Если /me грузится или 401 (dev без
|
||||||
|
|
@ -24,7 +24,18 @@ import { useEffect, useRef, useState } from "react";
|
||||||
|
|
||||||
import { LogOut } from "lucide-react";
|
import { LogOut } from "lucide-react";
|
||||||
|
|
||||||
import { useMe } from "@/lib/useMe";
|
import { useMe, type Role } from "@/lib/useMe";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Локализация ролей для badge. Должен покрывать все варианты `Role` из
|
||||||
|
* `lib/useMe.ts` — TypeScript-проверка через `Record<Role, string>`
|
||||||
|
* сломает build, если backend добавит новую роль без обновления map.
|
||||||
|
*/
|
||||||
|
const ROLE_LABELS: Record<Role, string> = {
|
||||||
|
admin: "Админ",
|
||||||
|
pilot: "Пилот",
|
||||||
|
analyst: "Аналитик",
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Logout — invalidate basic_auth cache + reload.
|
* Logout — invalidate basic_auth cache + reload.
|
||||||
|
|
@ -89,7 +100,7 @@ export function UserMenu() {
|
||||||
if (isLoading || error || !data) return null;
|
if (isLoading || error || !data) return null;
|
||||||
|
|
||||||
const initial = data.username[0]?.toUpperCase() ?? "?";
|
const initial = data.username[0]?.toUpperCase() ?? "?";
|
||||||
const roleLabel = data.role === "admin" ? "Админ" : "Пилот";
|
const roleLabel = ROLE_LABELS[data.role];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div ref={containerRef} style={{ position: "relative" }}>
|
<div ref={containerRef} style={{ position: "relative" }}>
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
* `useMe()` — TanStack-хук для GET /api/v1/me.
|
* `useMe()` — TanStack-хук для GET /api/v1/me.
|
||||||
*
|
*
|
||||||
* Backend возвращает `UserScope` (см. `backend/app/core/auth.py`):
|
* Backend возвращает `UserScope` (см. `backend/app/core/auth.py`):
|
||||||
* { username, role: "admin"|"pilot", allowed_paths: string[], deny_paths: string[] }
|
* { username, role: "admin"|"pilot"|"analyst", allowed_paths: string[], deny_paths: string[] }
|
||||||
*
|
*
|
||||||
* Failure modes:
|
* Failure modes:
|
||||||
* - 401 — нет X-Authenticated-User (локально без Caddy basic_auth). Фронт
|
* - 401 — нет X-Authenticated-User (локально без Caddy basic_auth). Фронт
|
||||||
|
|
@ -26,7 +26,10 @@ import { apiFetchWithStatus, HTTPError } from "@/lib/api";
|
||||||
// статус через `error instanceof HTTPError` — это работает в runtime независимо
|
// статус через `error instanceof HTTPError` — это работает в runtime независимо
|
||||||
// от type-level decl.
|
// от type-level decl.
|
||||||
|
|
||||||
export type Role = "admin" | "pilot";
|
// Должен совпадать с `Role` в `backend/app/core/auth.py` (Literal["admin", "pilot", "analyst"]).
|
||||||
|
// Источник правды — `auth/roles.yaml`; при добавлении новой роли расширить тут и
|
||||||
|
// `ROLE_LABELS` в `components/auth/UserMenu.tsx`.
|
||||||
|
export type Role = "admin" | "pilot" | "analyst";
|
||||||
|
|
||||||
export interface UserScope {
|
export interface UserScope {
|
||||||
username: string;
|
username: string;
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue