Sort packages by availability and tidy availability-related displays

- Make the Verfügbarkeit column sortable from fully online through partial and unchecked down to fully offline, reversing on the second click
- Show partially available packages in the warning color as soon as one link is online and one is offline
- Switch the package order instantly on column sorts instead of sliding rows
- Keep offline links out of the package status error count
- Show queue volumes of one terabyte or more as grouped gigabytes with one decimal per language

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MxAH7rSv8MgfKEPwMkR8N2
This commit is contained in:
Sucukdeluxe
2026-09-04 00:19:37 +02:00
co-authored by Claude Fable 5.1
parent 65084bd6d2
commit 558d6ca4f4
11 changed files with 264 additions and 41 deletions
@@ -1,4 +1,4 @@
import type { DownloadItem, DownloadStatus, PackageEntry } from "../../../shared/types";
import type { AppLanguage, DownloadItem, DownloadStatus, PackageEntry } from "../../../shared/types";
import { extractHoster, humanSize } from "../../download-format";
import { DOWNLOAD_FILE_ROW_HEIGHT, DOWNLOAD_PACKAGE_ROW_HEIGHT, type DownloadVirtualRowInput } from "./download-virtualizer";
@@ -147,9 +147,14 @@ export function getDownloadQueueStatusMetrics(items: readonly DownloadItem[]): {
};
}
export function formatRemainingDownloadBytes(summary: { bytes: number; unknownItems: number }): string {
const largeQueueGigabyteFormatters: Record<AppLanguage, Intl.NumberFormat> = {
de: new Intl.NumberFormat("de-DE", { minimumFractionDigits: 1, maximumFractionDigits: 1 }),
en: new Intl.NumberFormat("en-US", { minimumFractionDigits: 1, maximumFractionDigits: 1 })
};
export function formatRemainingDownloadBytes(summary: { bytes: number; unknownItems: number }, language: AppLanguage = "de"): string {
const value = summary.bytes >= 1024 ** 4
? `${(summary.bytes / 1024 ** 4).toFixed(5)} TB`
? `${largeQueueGigabyteFormatters[language].format(summary.bytes / 1024 ** 3)} GB`
: humanSize(summary.bytes);
if (summary.unknownItems <= 0) return value;
return summary.bytes > 0 ? `${value}` : "Unbekannt";