web: a folder is chosen by picking one — the backup row names it and opens the picker, and restore always asks which backup
RESTORE was dead on a machine that had never written a backup: the button was `disabled` while no folder was remembered, and nothing in the handler could ever pick one, so the reader who had carried a copy over on a stick had no way to point at it. The button now stands, and the folder it restores from is whatever the reader picks in the dialog that opens — which is the whole of the choice there is, because a backup is a folder of rows and tiles. The folder on the other disk, the one made before the edit: the folder is the version. BACK UP asked for a folder only the first time one was ever chosen. After that it wrote into it in silence, and after a restart — when the browser takes the permission back, since a permission outlives the tab only while the tab does — it wrote nothing and said so, which is a backup that quietly stops happening. It now picks whenever it cannot write, and the picker is the only thing that can hand a remembered folder its permission back; a permission asked for with no picker behind it is one the browser may refuse. The run that follows a scan is untouched: it is guarded by the permission it would be asking for. And the folder is a control, not a caption. The line that names it — with the frames in it and when they were written — is what tells one backup from another, and pressing it is how a folder is picked, a name given, a permission handed back. It keeps the hint's own look through five lines of CSS, so the row still reads as a caption and not as a third button. What the line says is now read out of the folder rather than out of this browser's memory of it. `pickBackupFolder` reads the catalogue file inside the folder just picked and takes its count and its date as the row's own; a folder with no catalogue of its own has none, and the row says so instead of showing the numbers of the folder next door. That is also what the confirm names before a restore — the frames and the time in the folder just picked, which is the thing about to be restored. `restoreNow` already read that file; this reads its header first. Checked on the running bundle with the picker stubbed, since the dialog is one a probe cannot press: with nothing remembered, RESTORE now opens the picker where it did nothing at all, the row names the folder the picker returned, and a folder without a catalogue of its own is refused with a line saying so rather than restored as an empty catalogue. BACK UP opens it too, from the same fresh state. The line computes to a button with no border, no background, the page's own font and the hint's own 12px dim grey — a caption that happens to be pressable. The wall, the strip, the grid, the deep link and the phone's recipes all pass their checks.
This commit is contained in:
@@ -145,8 +145,26 @@ export async function backupStatus(): Promise<BackupStatus> {
|
||||
};
|
||||
}
|
||||
|
||||
// The catalogue's own header, read out of the file and not out of this browser's
|
||||
// memory of it. A folder the reader is pointing at may be a copy carried over on
|
||||
// a stick, written by another machine, at another time: it is its own catalogue
|
||||
// that says which backup it is, and its own count and date that the screen has
|
||||
// to show before anything is written to it or read from it.
|
||||
async function head(root: FileSystemDirectoryHandle): Promise<Meta | null> {
|
||||
try {
|
||||
const text = await (await (await root.getFileHandle(CATALOGUE)).getFile()).text();
|
||||
const cat = JSON.parse(text) as { at?: number; photos?: unknown[] };
|
||||
return { id: 'meta', at: cat.at ?? 0, photos: (cat.photos ?? []).length, wrote: 0 };
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// The picker's own dialog, the same way a folder of frames is picked — a second
|
||||
// `id` so the browser remembers this folder apart from the library's.
|
||||
// `id` so the browser remembers this folder apart from the library's. It is the
|
||||
// only way a folder is ever chosen, and the only thing that hands a remembered
|
||||
// one its permission back: the browser takes that away when the tab closes, and
|
||||
// a permission asked for without a picker behind it is one it may refuse.
|
||||
export async function pickBackupFolder(): Promise<string> {
|
||||
if (!('showDirectoryPicker' in window)) throw new Error('no-folder-picker');
|
||||
const handle = await (
|
||||
@@ -159,7 +177,14 @@ export async function pickBackupFolder(): Promise<string> {
|
||||
// A folder that is not the one the last run wrote into starts empty, and the
|
||||
// list of tiles already written is about that folder — kept, it would say every
|
||||
// tile is there and the new folder would come out with none of them.
|
||||
if (before?.name !== handle.name) await ask(WRITTEN, 'readwrite', (s) => s.clear());
|
||||
if (before?.name !== handle.name) {
|
||||
await ask(WRITTEN, 'readwrite', (s) => s.clear());
|
||||
// And the row goes back to saying what this folder holds rather than what
|
||||
// the last one did: a count and a date from the folder next door is a count
|
||||
// and a date about a backup the reader is not looking at.
|
||||
const meta = await head(handle);
|
||||
await ask<Meta | undefined>(WHERE, 'readwrite', (s) => (meta ? s.put(meta) : s.delete('meta')));
|
||||
}
|
||||
return handle.name;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user