Remove downloads management features: delete DownloadsEndpoints and related API logic, remove associated frontend components and routes, and update documentation to reflect the removal of the downloads directory from the application structure.

This commit is contained in:
Leonid Pershin
2026-07-24 18:18:22 +03:00
parent 44d10f667c
commit 7309a25764
18 changed files with 6 additions and 382 deletions
@@ -1,112 +0,0 @@
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'
import { useTranslation } from 'react-i18next'
import { ExternalLink, RotateCw } from 'lucide-react'
import { HttpError } from '@/shared/api/client'
import { Button } from '@/shared/ui/button'
import { toast } from '@/shared/ui/toast-store'
import { importDownload, listDownloads } from './api'
function formatBytes(bytes: number): string {
if (bytes < 1024) return `${bytes} B`
const units = ['KB', 'MB', 'GB', 'TB']
let value = bytes / 1024
let i = 0
while (value >= 1024 && i < units.length - 1) {
value /= 1024
i++
}
return `${value.toFixed(1)} ${units[i]}`
}
export function DownloadsPanel() {
const { t } = useTranslation()
const queryClient = useQueryClient()
const { data, isLoading, refetch, isFetching } = useQuery({
queryKey: ['admin', 'downloads'],
queryFn: listDownloads,
refetchInterval: 15_000,
})
const onError = (error: unknown) =>
toast.error(error instanceof HttpError ? error.detail : t('common.error'))
const importMutation = useMutation({
mutationFn: importDownload,
onSuccess: () => {
toast.success(t('admin.downloads.imported'))
void queryClient.invalidateQueries({ queryKey: ['admin', 'media'] })
},
onError,
})
const clientUrl =
typeof window !== 'undefined' ? `${window.location.protocol}//${window.location.hostname}:8090` : '#'
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.downloads.title')}</h2>
<div className="flex items-center gap-2">
<Button size="sm" variant="outline" asChild>
<a href={clientUrl} target="_blank" rel="noreferrer">
<ExternalLink className="h-4 w-4" />
{t('admin.downloads.openClient')}
</a>
</Button>
<Button size="sm" variant="outline" disabled={isFetching} onClick={() => void refetch()}>
<RotateCw className="h-4 w-4" />
{t('admin.downloads.refresh')}
</Button>
</div>
</div>
<p className="text-sm text-muted-foreground">{t('admin.downloads.hint')}</p>
<div className="crt-panel overflow-x-auto rounded-md">
<table className="w-full text-sm">
<thead className="border-b border-border text-left text-muted-foreground">
<tr>
<th className="px-4 py-2 font-medium">{t('admin.downloads.path')}</th>
<th className="px-4 py-2 font-medium">{t('admin.downloads.size')}</th>
<th className="px-4 py-2 font-medium">{t('common.actions')}</th>
</tr>
</thead>
<tbody>
{isLoading && (
<tr>
<td className="px-4 py-3 text-muted-foreground" colSpan={3}>
{t('common.loading')}
</td>
</tr>
)}
{data?.map((file) => (
<tr key={file.relativePath} className="border-b border-border last:border-0">
<td className="px-4 py-2" title={file.relativePath}>
{file.relativePath}
</td>
<td className="px-4 py-2 text-muted-foreground">{formatBytes(file.sizeBytes)}</td>
<td className="px-4 py-2">
<Button
size="sm"
disabled={importMutation.isPending}
onClick={() => importMutation.mutate(file.relativePath)}
>
{t('admin.downloads.import')}
</Button>
</td>
</tr>
))}
{data && data.length === 0 && !isLoading && (
<tr>
<td className="px-4 py-3 text-muted-foreground" colSpan={3}>
{t('admin.downloads.empty')}
</td>
</tr>
)}
</tbody>
</table>
</div>
</div>
)
}
@@ -1,13 +0,0 @@
import { apiRequest } from '@/shared/api/client'
import type { CreatedIdResponse, DownloadFileDto } from '@/shared/api/types'
export function listDownloads() {
return apiRequest<DownloadFileDto[]>('/admin/downloads')
}
export function importDownload(relativePath: string) {
return apiRequest<CreatedIdResponse>('/admin/downloads/import', {
method: 'POST',
body: { relativePath },
})
}