Files
webmail/components/offline/kept-files.tsx
T
Linus Rath b001cbf109 feat: show what each account keeps on the device and let it be changed and cleared
The offline section of Settings > Backup & reset now shows, per account, the
space each part takes, the last sync, a first sync's progress with the time
left, the window and attachment choices, and clearing the account. All
conflicts, calendar and contacts too, are listed there and counted in the
banner.

- the organisation's caps beat the user's choice and the desktop default, and
  every path that takes a scope goes through `effectiveScope`
- the desktop app keeps mail without asking, says so once, and stays off for
  an account where the user turned it off
- `navigator.storage.persist()` is asked on turning it on, and a refusal
  warns with a way to ask again; Safari gets the 7-day hint when not installed
- a store the browser deleted is noticed, says what was lost and syncs again
- a full disk says so, with what to do
- those who had offline mode keep it, with the 30 days they had
- Keep offline in the Files app's menu
2026-11-03 08:57:41 +01:00

33 lines
1.7 KiB
TypeScript

'use client';
import { useTranslations } from 'next-intl';
import { Button } from '@/components/ui/button';
import { formatFileSize } from '@/lib/utils';
import { useKeptFiles } from '@/hooks/use-kept-files';
/** The files this account keeps until told otherwise, in Settings > Backup & reset > Offline. */
export function KeptFiles({ account }: { account: string }) {
const t = useTranslations('offlineStorage');
const { pinned, unpin } = useKeptFiles(account);
if (pinned.length === 0) return null;
return (
<div className="border-b border-border py-3 last:border-0" data-testid="offline-kept-files">
<h4 className="text-sm font-medium text-foreground">{t('kept_files_title')}</h4>
<ul className="mt-2 divide-y divide-border rounded-md border border-border" aria-label={t('kept_files_title')}>
{pinned.map((file) => (
<li key={`${file.jmap}:${file.id}`} className="flex flex-col gap-2 px-3 py-2 sm:flex-row sm:items-center sm:justify-between" data-testid="offline-kept-file" data-kept={file.kept}>
<div className="min-w-0 flex-1">
<p className="truncate text-sm text-foreground">{file.name}</p>
<p className="text-xs text-muted-foreground">
{file.size !== null && <>{formatFileSize(file.size)} · </>}
{file.kept ? t('kept_state_kept') : file.error ? t(`kept_error_${file.error}` as 'kept_error_download') : t('kept_state_waiting')}
</p>
</div>
<Button variant="outline" size="sm" className="shrink-0" aria-label={t('unpin_label', { name: file.name })} onClick={() => void unpin(file)}>{t('unpin')}</Button>
</li>
))}
</ul>
</div>
);
}