fix(admin-ui): UserPicker — TextInput fallback когда cache пустой
Если /api/v1/admin/users возвращает [] (cache пустой / writer только-что рестартован / у юзера нет INTERNAL scope → 403 → catch → []), picker показывал «Пользователи не найдены» и фильтр становился недоступен. До MR !263 здесь был обычный TextInput, не лишаем юзера возможности вписать UUID руками. При isLoading=false, isError=false, data.length===0 — рендерим TextInput с подсказкой «Список юзеров пуст — введите вручную». Backend cache прогреется по мере того как юзеры будут делать authenticated requests (JwtUserCaptureFilter перепишет user_display_cache); тогда picker включится автоматически.
This commit is contained in:
@@ -2,7 +2,7 @@ import * as React from 'react'
|
||||
import { useMemo, useState } from 'react'
|
||||
import { CaretDownIcon, MagnifyingGlassIcon, UserIcon, XIcon } from '@phosphor-icons/react'
|
||||
import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList } from 'cmdk'
|
||||
import { Popover, PopoverTrigger, PopoverContent, FieldLabel } from '@/ui'
|
||||
import { Popover, PopoverTrigger, PopoverContent, FieldLabel, TextInput } from '@/ui'
|
||||
import { useAllUsers, type UserListItem } from '@/api/queries'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
@@ -38,11 +38,32 @@ export function UserPicker({ value, onChange, label, placeholder, disabled }: Us
|
||||
const [open, setOpen] = useState(false)
|
||||
const usersQ = useAllUsers()
|
||||
|
||||
// Fallback на TextInput если cache пустой или endpoint вернул 403/404 (юзер
|
||||
// без INTERNAL scope, либо writer был только-что рестартован и cache не
|
||||
// прогрелся). Без этого user-фильтр становится недоступен — раньше тут был
|
||||
// TextInput, не лишаем юзера возможности вписать UUID руками.
|
||||
const usersList = usersQ.data ?? []
|
||||
const fallbackToTextInput =
|
||||
!usersQ.isLoading && !usersQ.isError && usersList.length === 0
|
||||
|
||||
const usersBySub = useMemo(() => {
|
||||
const m = new Map<string, UserListItem>()
|
||||
for (const u of usersQ.data ?? []) m.set(u.sub, u)
|
||||
for (const u of usersList) m.set(u.sub, u)
|
||||
return m
|
||||
}, [usersQ.data])
|
||||
}, [usersList])
|
||||
|
||||
if (fallbackToTextInput) {
|
||||
return (
|
||||
<TextInput
|
||||
label={label}
|
||||
value={value ?? ''}
|
||||
onChange={(e) => onChange(e.target.value || undefined)}
|
||||
placeholder="UUID или username"
|
||||
hint="Список юзеров пуст — введите вручную"
|
||||
disabled={disabled}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
const selected = value ? usersBySub.get(value) : undefined
|
||||
const triggerLabel = useMemo(() => {
|
||||
|
||||
Reference in New Issue
Block a user