feat: /audit поле «Пользователь» — typeahead picker из user-cache
Backend: GET /api/v1/admin/users (INTERNAL+ scope) — list cached юзеров из user_display_cache. UserDisplayService.listAll(limit) сортирует по preferred_username, hard-cap 1000. Контроллер: UserDisplayController.list(). Frontend: - queries.ts → useAllUsers() / allUsersQuery (5min stale, 403/404 → []). - components/audit/UserPicker.tsx (новый, ~140 строк) — cmdk-powered combobox: trigger показывает username (или UUID prefix fallback), popover c поиском по preferredUsername/email/UUID. X сбрасывает selection. - routes/audit.tsx — TextInput → UserPicker. UX: раньше юзер вручную копипастил UUID из audit-row'а; теперь поиск по имени/email типа `solov` → находит `solovyev.da`.
This commit is contained in:
@@ -782,6 +782,39 @@ export const useLiveRecord = (dict: string | undefined, businessKey: string | un
|
||||
export const useDictionaries = () => useQuery(dictionariesQuery)
|
||||
export const useDictionaryDetail = (name: string | undefined) =>
|
||||
useQuery({ ...dictionaryDetailQuery(name ?? ''), enabled: Boolean(name) })
|
||||
|
||||
/**
|
||||
* Список всех закэшированных юзеров — для пикеров «Пользователь» в
|
||||
* фильтрах audit/reviews. INTERNAL+ scope; non-INTERNAL получит 403,
|
||||
* fallback на пустой массив (retry: false).
|
||||
*/
|
||||
export type UserListItem = {
|
||||
sub: string
|
||||
preferredUsername?: string | null
|
||||
name?: string | null
|
||||
email?: string | null
|
||||
updatedAt: string
|
||||
}
|
||||
|
||||
export const allUsersQuery = queryOptions({
|
||||
queryKey: ['users', 'all'] as const,
|
||||
staleTime: 5 * 60 * 1000,
|
||||
retry: false,
|
||||
queryFn: async (): Promise<UserListItem[]> => {
|
||||
try {
|
||||
const { data } = await apiClient.get<UserListItem[]>('/admin/users', {
|
||||
params: { limit: 500 },
|
||||
})
|
||||
return data
|
||||
} catch (e: unknown) {
|
||||
const status = (e as { response?: { status?: number } })?.response?.status
|
||||
if (status === 403 || status === 404) return []
|
||||
throw e
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
export const useAllUsers = () => useQuery(allUsersQuery)
|
||||
export const useRecords = (
|
||||
dictionaryName: string,
|
||||
scopeCsv: string,
|
||||
|
||||
Reference in New Issue
Block a user