import { useEffect, useState, type ChangeEvent, type MouseEvent, type ReactElement } from "react"; import { DataTable, DataTableBody, DataTableEmpty, DataTableHeader } from "../../ui/DataTable"; import { Toolbar, ToolbarGroup, ToolbarSearch } from "../../ui/Toolbar"; import { SlidingSelection } from "../../ui/SlidingSelection"; import { paginateHistoryRows, type HistoryFilter, type HistoryPage, type HistoryRow, type HistoryViewModel } from "./history-model"; import "./history.css"; export interface HistoryViewActions { onFilterChange: (filter: HistoryFilter) => void; onQueryChange: (value: string) => void; onToggleSelection: (entryId: string) => void; onToggleSelectAll: (visibleIds: string[]) => void; onToggleExpansion: (entryId: string) => void; onRestore: (entryIds: string[]) => void; onReveal: (entryId: string) => void; onRemove: (entryIds: string[]) => void; onClearSelection: () => void; onClearHistory: () => void; onContextMenu: (entryId: string, x: number, y: number) => void; } export interface HistoryViewProps { model: HistoryViewModel; actions: HistoryViewActions; } const filterItems: Array<{ id: HistoryFilter; label: string }> = [ { id: "all", label: "Alle Einträge" }, { id: "today", label: "Heute" }, { id: "week", label: "Letzte 7 Tage" }, { id: "older", label: "Älter" }, { id: "completed", label: "Fertig" }, { id: "deleted", label: "Gelöscht" }, { id: "failed", label: "Fehlgeschlagen" } ]; function HistoryRowDetails({ row }: { row: HistoryRow }): ReactElement { return (
Provider
{row.providerLabel}
Dateien
{row.fileCount}
Dauer
{row.durationLabel}
Durchschnitt
{row.averageSpeedLabel}
Zielordner
{row.outputDir || "—"}
URLs
{row.urls?.length ? row.urls.join("\n") : "—"}
); } export function HistorySidebar({ model, actions }: HistoryViewProps): ReactElement { return (
Verlauf {filterItems.map((item) => ( ))}
); } export function HistoryToolbar({ model, actions }: HistoryViewProps): ReactElement { const selectedIds = model.selectedIds; const selectedSet = new Set(selectedIds); const restorable = model.rows.some((row) => selectedSet.has(row.id) && (row.urls?.length ?? 0) > 0); return ( ) => actions.onQueryChange(event.target.value)} placeholder="Name, Pfad, Hoster oder Provider" value={model.query} /> ); } export function historyPageStatusLabel(page: HistoryPage): string { return `Seite ${page.page} von ${page.totalPages}`; } export function HistoryPagination({ page, onPageChange }: { page: HistoryPage; onPageChange: (page: number) => void; }): ReactElement { return ( ); } interface HistoryContentPageProps extends HistoryViewProps { page: HistoryPage; onPageChange: (page: number) => void; } export function HistoryContentPage({ model, actions, page, onPageChange }: HistoryContentPageProps): ReactElement { const selected = new Set(model.selectedIds); const expanded = new Set(model.expandedIds); const visibleIds = page.rows.map((row) => row.id); const allVisibleSelected = visibleIds.length > 0 && visibleIds.every((id) => selected.has(id)); const showEmpty = !model.loading && !model.error && model.rows.length === 0; const emptyTitle = model.totalCount === 0 && !model.query && model.filter === "all" ? "Noch kein Verlauf" : "Keine passenden Einträge"; const announcement = model.loading ? { role: "status" as const, live: "polite" as const, message: "Verlauf wird geladen. Die gespeicherten Einträge werden geladen." } : model.error ? { role: "alert" as const, live: "assertive" as const, message: `${model.error}. Öffne die Ansicht erneut, um es noch einmal zu versuchen.` } : null; return (

Verlauf

actions.onToggleSelectAll(visibleIds)} type="checkbox" /> Paket / Datei Status Größe Hoster Gestartet Beendet Aktion
{model.loading ? ( ) : model.error ? ( ) : showEmpty ? ( ) : ( page.rows.map((row) => { const isSelected = selected.has(row.id); const isExpanded = expanded.has(row.id); const onContextMenu = (event: MouseEvent): void => { event.preventDefault(); event.stopPropagation(); event.currentTarget.querySelector(".history-row-action button")?.focus({ preventScroll: true }); actions.onContextMenu(row.id, event.clientX, event.clientY); }; return (
actions.onToggleSelection(row.id)} type="checkbox" /> {row.name} {row.statusLabel} {row.sizeLabel} {row.hoster} {row.startedLabel} {row.completedLabel}
{isExpanded ? : null}
); }) )}
{announcement ? (
{announcement.message}
) : null}
); } function PaginatedHistoryContent({ model, actions }: HistoryViewProps): ReactElement { const [requestedPage, setRequestedPage] = useState(1); const page = paginateHistoryRows(model.rows, requestedPage); useEffect(() => { setRequestedPage((current) => current === page.page ? current : page.page); }, [page.page]); return ( ); } export function HistoryContent({ model, actions }: HistoryViewProps): ReactElement { return ; } export function HistoryFooter(_props: Pick): null { return null; } export function HistoryView({ model, actions }: HistoryViewProps): ReactElement { return (
); }