diff --git a/frontend/src/features/admin/media/MediaPanel.tsx b/frontend/src/features/admin/media/MediaPanel.tsx index 612a444..995875a 100644 --- a/frontend/src/features/admin/media/MediaPanel.tsx +++ b/frontend/src/features/admin/media/MediaPanel.tsx @@ -1,5 +1,5 @@ import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query' -import { useRef, useState } from 'react' +import { useEffect, useRef, useState } from 'react' import { useTranslation } from 'react-i18next' import { FolderInput, ListPlus, Upload } from 'lucide-react' import { HttpError } from '@/shared/api/client' @@ -62,7 +62,7 @@ export function MediaPanel() { toggle(key) } - const { data, isLoading } = useQuery({ + const { data, isLoading, refetch } = useQuery({ queryKey: ['admin', 'media', filter, page, sort.key, sort.desc], queryFn: () => listMedia({ @@ -87,6 +87,20 @@ export function MediaPanel() { (query.state.data?.queued ?? 0) + (query.state.data?.processing ?? 0) > 0 ? 4000 : 15000, }) + /** + * Сводка очереди опрашивается всегда, и она же служит датчиком: изменилась пара + * «в очереди / в обработке» — значит какая-то запись сменила статус, и список пора перечитать. + * Без этого список обновлялся бы, только пока активные записи видны на текущей странице: при + * фильтре «Готовые» или пустом списке опрос выключался, и новый файл из inbox не появлялся. + */ + const activity = `${stats?.queued ?? 0}:${stats?.processing ?? 0}` + const lastActivity = useRef(activity) + useEffect(() => { + if (lastActivity.current === activity) return + lastActivity.current = activity + void refetch() + }, [activity, refetch]) + const invalidate = () => queryClient.invalidateQueries({ queryKey: ['admin', 'media'] }) const onError = (error: unknown) => toast.error(error instanceof HttpError ? error.detail : t('common.error'))