Files
mdm-ordinis/ordinis-admin-ui/src/lib/useUserDisplay.tsx
T
Zimin A.N. e6294ce79c fix(ui): shared UserCell для display UUID actor'ов везде
Browser QA на staging показал что UUID actor'а render'ится raw во многих
местах кроме drawer (MR !158 — там был inline fix):
- /reviews Records tab — column AUTHOR
- /reviews Schemas tab — column AUTHOR
- /audit log — column USER

77ec2cc8-98e3-4d70-8037-94038fcbde67 — нечитаемо для оператора. Тот же
паттерн что я делал в MR !158, теперь shared helper:

src/lib/useUserDisplay.tsx:
- useUserDisplay(uuid) hook — returns { display, isMe, fullId }
- UserCell component — readonly cell с title=fullId tooltip
- Match current user (JWT sub claim) → 'Я • <preferred_username>'
- Other user → short UUID (8 chars) + full в title
- null/undefined → 'anonymous'

Применено:
- reviews.tsx:334,625 — records + schemas table AUTHOR cells
- audit.tsx:476 — USER cell
- SchemaDraftDrawer.tsx — refactor (был inline в MR !158 → теперь shared)

TODO Phase 1d: backend endpoint /admin/users/{sub}/display чтобы и для
не-current-user отображать username.
2026-05-13 11:43:04 +03:00

63 lines
2.2 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { useAuth } from 'react-oidc-context'
/**
* Resolve UUID sub claim (Keycloak {@code sub} → makerId / userId) к
* human-friendly display string.
*
* <p>Cases:
* <ul>
* <li><b>uuid matches current user</b> → {@code "Я • <preferred_username>"}
* (или just {@code "Я"} если profile неполный).</li>
* <li><b>different user</b> → first 8 chars of UUID. Full ID в {@code fullId}
* чтобы consumer мог положить в {@code title=...} для tooltip.</li>
* <li><b>null/undefined uuid</b> → {@code "anonymous"}.</li>
* </ul>
*
* <p>TODO Phase 1d: для не-current-user backend endpoint
* {@code /admin/users/{sub}/display} → resolve в username. Пока best-effort:
* current user resolved через JWT profile claim, остальные — UUID prefix
* (achievable via JWT alone).
*
* <p>Используется везде где UI показывает actor: AUTHOR в таблицах
* /reviews (record + schema), USER в /audit log, AUTHOR в schema draft
* drawer.
*/
export function useUserDisplay(uuid: string | null | undefined): {
display: string
isMe: boolean
fullId: string
} {
const auth = useAuth()
const fullId = uuid ?? ''
if (!fullId) {
return { display: 'anonymous', isMe: false, fullId: '' }
}
const currentSub = auth.user?.profile?.sub
const isMe = Boolean(currentSub) && currentSub === fullId
if (isMe) {
const me =
auth.user?.profile?.preferred_username ||
auth.user?.profile?.name ||
auth.user?.profile?.email
return { display: me ? `Я • ${me}` : 'Я', isMe, fullId }
}
return { display: fullId.substring(0, 8), isMe, fullId }
}
/**
* UserCell — convenience component для тех мест где нужен readonly displaу
* с tooltip. Используется в таблицах.
*/
export function UserCell({ uuid }: { uuid: string | null | undefined }) {
const { display, isMe, fullId } = useUserDisplay(uuid)
if (!fullId) return <span className="text-mute italic">anonymous</span>
return (
<span
className={isMe ? 'text-ink' : 'font-mono text-ink-2'}
title={fullId}
>
{display}
</span>
)
}