feat: cycle availability sorting with part-count tie breakers
This commit is contained in:
+16
-6
@@ -39,7 +39,7 @@ import {
|
||||
getProviderDailyUsageBytes,
|
||||
getProviderUsageDayKey
|
||||
} from "../shared/provider-daily-limits";
|
||||
import { preservePackageOrderForDisplay, sortPackageOrderByAvailability, sortPackageOrderByName } from "./package-order";
|
||||
import { createAvailabilitySortCycle, preservePackageOrderForDisplay, sortPackageOrderByAvailability, sortPackageOrderByName } from "./package-order";
|
||||
import { createPackageOrderState } from "./package-order-state";
|
||||
import { getPackagesWithOfflineLinks } from "../shared/offline-packages";
|
||||
import type { OfflineSkipScope } from "../shared/types";
|
||||
@@ -1894,7 +1894,8 @@ export function App(): ReactElement {
|
||||
const [downloadDisplayMode, setDownloadDisplayMode] = useState<DownloadDisplayMode>("packages");
|
||||
const [downloadFilter, setDownloadFilter] = useState<DownloadSidebarFilter>("all");
|
||||
const [downloadProviderFilter, setDownloadProviderFilter] = useState("all");
|
||||
const [downloadsSortColumn, setDownloadsSortColumn] = useState<DownloadSortColumn>("name");
|
||||
const [downloadsSortColumn, setDownloadsSortColumn] = useState<DownloadSortColumn | undefined>("name");
|
||||
const availabilitySortCycleRef = useRef(createAvailabilitySortCycle());
|
||||
const [downloadsSortRevision, setDownloadsSortRevision] = useState(0);
|
||||
const [downloadsSortDescending, setDownloadsSortDescending] = useState(false);
|
||||
const [showAllPackages, setShowAllPackages] = useState(false);
|
||||
@@ -5271,11 +5272,22 @@ export function App(): ReactElement {
|
||||
}, [snapshot.packageSpeedBps]);
|
||||
|
||||
const sortDownloadsByColumn = useCallback((column: DownloadSortColumn): void => {
|
||||
const baseOrder = packageOrderRef.current.length > 0 ? packageOrderRef.current : snapshot.session.packageOrder;
|
||||
if (column === "availability") {
|
||||
const step = availabilitySortCycleRef.current.next(baseOrder);
|
||||
setDownloadsSortColumn(step.descending === null ? undefined : column);
|
||||
setDownloadsSortDescending(step.descending === false);
|
||||
setDownloadsSortRevision((revision) => revision + 1);
|
||||
commitPackageOrder(step.descending === null ? step.order : sortPackageOrderByAvailability(
|
||||
step.order, snapshot.session.packages, snapshot.session.items, step.descending
|
||||
));
|
||||
return;
|
||||
}
|
||||
availabilitySortCycleRef.current.reset();
|
||||
const nextDescending = downloadsSortColumn === column ? !downloadsSortDescending : false;
|
||||
setDownloadsSortColumn(column);
|
||||
setDownloadsSortDescending(nextDescending);
|
||||
setDownloadsSortRevision((revision) => revision + 1);
|
||||
const baseOrder = packageOrderRef.current.length > 0 ? packageOrderRef.current : snapshot.session.packageOrder;
|
||||
const sorted = column === "progress"
|
||||
? sortPackageOrderByProgress(baseOrder, snapshot.session.packages, snapshot.session.items, nextDescending)
|
||||
: column === "size"
|
||||
@@ -5290,9 +5302,7 @@ export function App(): ReactElement {
|
||||
nextDescending,
|
||||
Object.fromEntries(downloadsViewCore.packageRows.map((row) => [row.package.id, row.items]))
|
||||
)
|
||||
: column === "availability"
|
||||
? sortPackageOrderByAvailability(baseOrder, snapshot.session.packages, snapshot.session.items, nextDescending)
|
||||
: sortPackageOrderByName(baseOrder, snapshot.session.packages, nextDescending);
|
||||
: sortPackageOrderByName(baseOrder, snapshot.session.packages, nextDescending);
|
||||
commitPackageOrder(sorted);
|
||||
}, [commitPackageOrder, downloadsSortColumn, downloadsSortDescending, downloadsViewCore.packageRows, snapshot.session.items, snapshot.session.packageOrder, snapshot.session.packages]);
|
||||
|
||||
|
||||
@@ -37,7 +37,9 @@ export function sortPackageOrderByAvailability(
|
||||
}));
|
||||
const sorted = [...order];
|
||||
sorted.sort((a, b) => {
|
||||
const cmp = compareAvailabilitySummaries(summaries.get(a)!, summaries.get(b)!);
|
||||
const summaryA = summaries.get(a)!;
|
||||
const summaryB = summaries.get(b)!;
|
||||
const cmp = compareAvailabilitySummaries(summaryA, summaryB) || summaryB.total - summaryA.total;
|
||||
return descending ? -cmp : cmp;
|
||||
});
|
||||
return sorted;
|
||||
@@ -46,3 +48,31 @@ export function sortPackageOrderByAvailability(
|
||||
export function preservePackageOrderForDisplay(packages: PackageEntry[]): PackageEntry[] {
|
||||
return packages;
|
||||
}
|
||||
|
||||
export function createAvailabilitySortCycle() {
|
||||
let phase: "off" | "online" | "offline" = "off";
|
||||
let originalOrder: string[] = [];
|
||||
return {
|
||||
reset(): void {
|
||||
phase = "off";
|
||||
originalOrder = [];
|
||||
},
|
||||
next(currentOrder: string[]): { descending: boolean | null; order: string[] } {
|
||||
if (phase === "off") {
|
||||
originalOrder = [...currentOrder];
|
||||
phase = "online";
|
||||
return { descending: false, order: currentOrder };
|
||||
}
|
||||
if (phase === "online") {
|
||||
phase = "offline";
|
||||
return { descending: true, order: currentOrder };
|
||||
}
|
||||
phase = "off";
|
||||
const available = new Set(currentOrder);
|
||||
const order = originalOrder.filter((id) => available.delete(id));
|
||||
order.push(...available);
|
||||
originalOrder = [];
|
||||
return { descending: null, order };
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -551,7 +551,7 @@ export interface DownloadsTableHeaderProps {
|
||||
actions: DownloadsTableActions;
|
||||
columnOrder: readonly string[];
|
||||
gridTemplate: string;
|
||||
sortColumn: DownloadSortColumn;
|
||||
sortColumn?: DownloadSortColumn;
|
||||
sortDirection: "asc" | "desc";
|
||||
selectedCount: number;
|
||||
visibleIds: string[];
|
||||
|
||||
@@ -260,7 +260,7 @@ export function DownloadsContent({ actions, model }: { actions: DownloadsViewAct
|
||||
return (
|
||||
<main className="downloads-content">
|
||||
<div className="downloads-table" role="table" aria-label="Downloads">
|
||||
<DownloadsTableHeader actions={actions} columnOrder={model.columnOrder} gridTemplate={model.gridTemplate} selectedCount={model.actionableSelectedIds.length} sortColumn={model.sortColumn ?? "name"} sortDirection={model.sortDirection ?? "asc"} visibleIds={model.visibleRowIds} />
|
||||
<DownloadsTableHeader actions={actions} columnOrder={model.columnOrder} gridTemplate={model.gridTemplate} selectedCount={model.actionableSelectedIds.length} sortColumn={model.sortColumn} sortDirection={model.sortDirection ?? "asc"} visibleIds={model.visibleRowIds} />
|
||||
<VirtualizedDownloadsBody actions={actions} model={model} state={state} />
|
||||
</div>
|
||||
</main>
|
||||
|
||||
Reference in New Issue
Block a user