import { InfoIcon } from 'lucide-react'; import { AppTile } from '#/components/atoms/app-tile.jsx'; import { Card } from '#/components/atoms/card.jsx'; import { Chip } from '#/components/atoms/chip.jsx'; import { Dialog } from '#/components/molecules/dialog.jsx'; import { ErrorNotice } from '#/components/molecules/error-notice.jsx'; import { StorageBar } from '#/components/molecules/storage-bar.jsx'; import { TextLink } from '#/components/molecules/text-link.jsx'; import { post } from '#/lib/api.js'; import { KIND_META, KIND_ORDER } from '#/lib/file-kinds.js'; import { bytes, num } from '#/lib/format.js'; import { useApiMutation } from '#/lib/query.js'; import { cn } from '#/lib/utils.js'; /** The Newest/Largest toggle with its how-it-works explainer. */ function SortControls({ sort, filters, hrefFor, onNavigate }) { return ( <> {['newest', 'largest'].map((order) => ( {order === 'newest' ? 'Newest' : 'Largest'} ))} } >

Newest lists files by when their content was made. The date comes from the record that uses the file, so it stays accurate even if your account moves between hosts.

Some records carry no date of their own. Those files are listed by when they reached this server instead, and their dates read “Stored”.

Largest lists files by size, biggest first.

); } /** The bar plus every filter control; the chip rows double as the legend. */ export function FilesHeader({ facets, filters, hrefFor, onNavigate }) { const sort = filters.sort === 'largest' ? 'largest' : 'newest'; const kinds = KIND_ORDER.map((kind) => facets.kinds.find((facet) => facet.kind === kind), ).filter(Boolean); // Rebuilds blob usage from record content, for repos that arrived by // import, where usage undercounts until the links are rebuilt. const relink = useApiMutation([['blobs']]); return (

{num(facets.total.count)}{' '} {facets.total.count === 1 ? 'file' : 'files'}, using{' '} {bytes(facets.total.bytes)} of storage.

relink.run(() => post('/blobs/relink'))} disabled={relink.busy} title="Re-read every record to rebuild which files are used. Useful after moving to this server." > {relink.busy ? 'Rechecking…' : 'Recheck usage'}
{/* On a phone this row scrolls sideways, so sort leads at the left edge, always in view; the kinds trail off, hinting at the scroll. On wider screens sort moves to its usual place at the right. */}
{kinds.map((facet) => ( {KIND_META[facet.kind].label} {num(facet.count)} ))} {facets.unused.count > 0 && ( Not used {num(facets.unused.count)} )}
{facets.apps.length > 0 && (
{facets.apps.map((app) => ( {app.domain} {bytes(app.bytes)} ))}
)}
); }