diff --git a/spotizerr-ui/src/routes/history.tsx b/spotizerr-ui/src/routes/history.tsx index 8d02a07..bd042ec 100644 --- a/spotizerr-ui/src/routes/history.tsx +++ b/spotizerr-ui/src/routes/history.tsx @@ -343,55 +343,59 @@ export const History = () => {

Download History

)} - {/* Filter Controls */} + {/* Filter Controls - Responsive */} {!parentTaskId && ( -
- - - - +
+ {/* Mobile: Stacked filters */} +
+ + + + +
)} - {/* Table */} -
+ {/* Desktop Table */} +
{table.getHeaderGroups().map((headerGroup) => ( @@ -455,39 +459,149 @@ export const History = () => {
- {/* Pagination Controls */} -
- - - Page{" "} - - {table.getState().pagination.pageIndex + 1} of {table.getPageCount()} - - - - + {/* Mobile Card Layout */} +
+ {isLoading ? ( +
+ Loading... +
+ ) : table.getRowModel().rows.length === 0 ? ( +
+ No history entries found. +
+ ) : ( + table.getRowModel().rows.map((row) => { + const entry = row.original; + const isParent = !entry.parent_task_id && (entry.download_type === "album" || entry.download_type === "playlist"); + const isChild = !!entry.parent_task_id; + const status = entry.parent_task_id ? entry.track_status : entry.status_final; + const statusKey = (status || "").toUpperCase(); + const statusClass = { + COMPLETED: "text-success", + SUCCESSFUL: "text-success", + ERROR: "text-error", + FAILED: "text-error", + CANCELLED: "text-content-muted dark:text-content-muted-dark", + SKIPPED: "text-warning", + }[statusKey] || "text-gray-500"; + + let cardClass = "bg-surface dark:bg-surface-secondary-dark rounded-lg border border-border dark:border-border-dark p-4"; + if (isParent) { + cardClass += " border-l-4 border-l-primary"; + } else if (isChild) { + cardClass += " ml-4 border-l-2 border-l-content-muted dark:border-l-content-muted-dark"; + } + + return ( +
+ {/* Header */} +
+
+

+ {isChild ? `└─ ${entry.item_name}` : entry.item_name} +

+

+ {entry.item_artist} +

+
+ + {status} + +
+ + {/* Details Grid */} +
+
+ Type: + + {entry.download_type} + +
+
+ Source: + + {getDownloadSource(entry)} + +
+
+ Quality: + + {formatQuality(entry)} + +
+
+ Completed: + + {new Date(entry.timestamp_completed * 1000).toLocaleString()} + +
+
+ + {/* Actions for parent entries */} + {!parentTaskId && isParent && ( + entry.total_successful || entry.total_skipped || entry.total_failed + ) ? ( +
+
+ {entry.total_successful ?? 0} ✓ + {entry.total_skipped ?? 0} ⊘ + {entry.total_failed ?? 0} ✗ +
+ +
+ ) : null} +
+ ); + }) + )} +
+ + {/* Pagination Controls - Responsive */} +
+ {/* Mobile: Stacked layout */} +
+
+ + +
+ +
+ + Page{" "} + + {table.getState().pagination.pageIndex + 1} of {table.getPageCount()} + + + +
+
);