Merge branch 'fix/user-picker-hooks-order' into 'main'

fix(admin-ui): UserPicker — порядок хуков (rules-of-hooks)

See merge request 2-6/2-6-4/terravault/ordinis!265
This commit is contained in:
Александр Зимин
2026-05-25 15:15:20 +00:00
@@ -46,11 +46,23 @@ export function UserPicker({ value, onChange, label, placeholder, disabled }: Us
const fallbackToTextInput =
!usersQ.isLoading && !usersQ.isError && usersList.length === 0
// Все хуки ДО любого early-return — иначе rules-of-hooks нарушится при
// переходе loading→empty (loading rendered ВСЕ хуки → empty возвращает
// TextInput минуя последующие useMemo). React в production падает на
// "rendered fewer hooks than expected" → error boundary → "Что-то пошло
// не так". Reproduce: loading=true первый рендер, loading=false data=[]
// второй.
const usersBySub = useMemo(() => {
const m = new Map<string, UserListItem>()
for (const u of usersList) m.set(u.sub, u)
return m
}, [usersList])
const selected = value ? usersBySub.get(value) : undefined
const triggerLabel = useMemo(() => {
if (!value) return placeholder ?? 'Любой'
if (selected) return labelFor(selected)
return `${value.slice(0, 8)}`
}, [value, selected, placeholder])
if (fallbackToTextInput) {
return (
@@ -65,14 +77,6 @@ export function UserPicker({ value, onChange, label, placeholder, disabled }: Us
)
}
const selected = value ? usersBySub.get(value) : undefined
const triggerLabel = useMemo(() => {
if (!value) return placeholder ?? 'Любой'
if (selected) return labelFor(selected)
// Value есть, но юзера нет в кеше — показываем UUID prefix.
return `${value.slice(0, 8)}`
}, [value, selected, placeholder])
// Поиск: substring по preferredUsername / name / email / sub. cmdk
// делает client-side фильтрацию по value атрибуту CommandItem'а;
// концатенируем все поля в один searchable string.