Refactor media asset handling: update ListMediaAssetsQuery to accept an array of statuses, modify MediaEndpoints to handle multiple statuses, and enhance MediaProcessingQueue for improved signal handling. Update frontend components to support new status filtering and improve user experience with asset selection.

This commit is contained in:
Leonid Pershin
2026-07-24 19:22:22 +03:00
parent 8281832e1d
commit 6e7db4a6a9
12 changed files with 303 additions and 66 deletions
@@ -6,11 +6,21 @@ import { HttpError } from '@/shared/api/client'
import type { MediaAssetDto, MediaAssetStatus } from '@/shared/api/types'
import { Badge, type BadgeProps } from '@/shared/ui/badge'
import { Button } from '@/shared/ui/button'
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/shared/ui/select'
import { toast } from '@/shared/ui/toast-store'
import { deleteMedia, listMedia, uploadMedia } from './api'
const PAGE_SIZE = 20
type MediaFilter = 'active' | 'all' | 'Ready' | 'Failed'
const filterStatuses: Record<MediaFilter, MediaAssetStatus[]> = {
active: ['Pending', 'Processing'],
all: [],
Ready: ['Ready'],
Failed: ['Failed'],
}
export function formatDuration(seconds: number | null): string {
if (seconds == null) return '—'
const total = Math.round(seconds)
@@ -35,10 +45,11 @@ export function MediaPanel() {
const [upload, setUpload] = useState<{ current: number; total: number; percent: number } | null>(
null,
)
const [filter, setFilter] = useState<MediaFilter>('active')
const { data, isLoading } = useQuery({
queryKey: ['admin', 'media'],
queryFn: () => listMedia({ page: 1, pageSize: PAGE_SIZE }),
queryKey: ['admin', 'media', filter],
queryFn: () => listMedia({ page: 1, pageSize: PAGE_SIZE, statuses: filterStatuses[filter] }),
// Пока что-то обрабатывается — обновляем чаще, чтобы статус ехал в UI.
refetchInterval: (query) =>
query.state.data?.items.some((a) => a.status === 'Processing' || a.status === 'Pending')
@@ -77,7 +88,20 @@ export function MediaPanel() {
return (
<div className="flex flex-col gap-4">
<div className="flex flex-wrap items-center justify-between gap-2">
<h2 className="crt-glow text-xl font-semibold">{t('admin.media.title')}</h2>
<div className="flex items-center gap-3">
<h2 className="crt-glow text-xl font-semibold">{t('admin.media.title')}</h2>
<Select value={filter} onValueChange={(v) => setFilter(v as MediaFilter)}>
<SelectTrigger className="w-40">
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectItem value="active">{t('admin.media.filterActive')}</SelectItem>
<SelectItem value="all">{t('admin.media.filterAll')}</SelectItem>
<SelectItem value="Ready">{t('admin.media.statuses.Ready')}</SelectItem>
<SelectItem value="Failed">{t('admin.media.statuses.Failed')}</SelectItem>
</SelectContent>
</Select>
</div>
<div className="flex items-center gap-3">
{upload != null && (
<span className="text-sm text-muted-foreground">