diff --git a/docker/frontend/src/Library.tsx b/docker/frontend/src/Library.tsx index c587118..774be3d 100644 --- a/docker/frontend/src/Library.tsx +++ b/docker/frontend/src/Library.tsx @@ -1648,12 +1648,12 @@ function Catalogue() { // would be the same row for the whole of an afternoon while // the work went on somewhere the reader cannot see — together // with every folder above it, so a branch folded shut still - // shows the work going on under it. The roll's own row is - // never one of them: it is the head of everything below it, - // and a head that says all of a tree is being read says - // nothing about the folder the reading is actually in. The - // frames that sit in the roll's own folder are the one case - // left bare, and the toolbar's line is what carries them. + // shows the work going on under it. The roll's own row wears + // it too, and for two reasons: the frames that sit in the + // roll's own folder have no row but this one, and a reading + // kept to one folder leaves its branch folded or its folder + // off the column, which would otherwise be a whole reading + // reported by the toolbar's line alone. const isScanFolderMatch = !!(live && folder && normPath(live.folder) === normPath(folder.name)); const scanAt = live?.progress.at ? normPath(live.progress.at) : ''; // The row's own path under its own roll, spelled the way the @@ -1668,21 +1668,20 @@ function Catalogue() { : n.key.slice(normFolder.length + 1); const scanning = isScanFolderMatch && - n.depth > 0 && - nodeRel !== '' && - (scanAt === nodeRel || scanAt.startsWith(`${nodeRel}/`)); + (n.depth === 0 || (nodeRel !== '' && (scanAt === nodeRel || scanAt.startsWith(`${nodeRel}/`)))); // What is waiting its turn is waiting on the row it was asked // of, and on every row above it: a request under a folded // branch still says the roll has work queued. The roll's own - // row says nothing, for the reason it says nothing of the - // reading — and a request belongs to the roll it was asked - // of, so another roll's queue is not this row's news. + // row carries it for the same reason it carries the reading — + // and a request belongs to the roll it was asked of, so + // another roll's queue is not this row's news. const waiting = !scanning && - n.depth > 0 && - nodeRel !== '' && + (n.depth === 0 || nodeRel !== '') && scanQueue().some( - (j) => j.folder === folder?.name && (j.rel === `${nodeRel}/` || j.rel.startsWith(`${nodeRel}/`)) + (j) => + j.folder === folder?.name && + (n.depth === 0 || j.rel === `${nodeRel}/` || j.rel.startsWith(`${nodeRel}/`)) ); const under = parents.has(n.key); return ( diff --git a/docker/frontend/src/engine/library.ts b/docker/frontend/src/engine/library.ts index e9b32d8..a3a2213 100644 --- a/docker/frontend/src/engine/library.ts +++ b/docker/frontend/src/engine/library.ts @@ -786,28 +786,28 @@ export async function scanFolder( progress.written ??= 0; progress.at ??= ''; const found = new Set(progress.dirs.map((d) => d.id)); - const counts: Record = progress.counts; - // Count the frame the moment the scan gets to it, before it knows whether the - // frame is new: the rows say how far the reading has come, not what it kept. - const count = (rel: string) => { + const normRoot = normPath(folder.name); + // The rows are counted from what the catalogue already holds, and the reading + // only adds to them. A number that started at nothing would sit under the + // catalogue's own for as long as the reading took to pass it, and the screen + // shows the larger of the two — so an update, where the reading is mostly + // frames the catalogue has, is a number that stands still and then jumps. What + // the reading adds is the frames it found that the catalogue does not hold yet: + // the number climbs for news alone, and ends on the true total. + const counts: Record = {}; + const count = (rel: string, n = 1) => { const relNorm = rel.replace(/\\/g, '/'); const cut = relNorm.lastIndexOf('/'); - const normRoot = normPath(folder.name); - // A reading kept to one folder says nothing about the roll it sits in: the - // roll's own row counts every frame of the roll, and a number that counted - // one branch of it would count the roll down to that branch. Its own frames - // are outside the reading anyway — a bounded walk starts at `from`, so every - // frame it reaches is under it, and the roll's row keeps the catalogue's - // number until the reading is through and the catalogue is read back. - if (!bounded) counts[normRoot] = (counts[normRoot] ?? 0) + 1; + counts[normRoot] = (counts[normRoot] ?? 0) + n; let path = ''; for (const part of (cut < 0 ? '' : relNorm.slice(0, cut)).split('/')) { if (!part) continue; path = path ? `${path}/${part}` : part; const key = `${normRoot}/${path}`; - counts[key] = (counts[key] ?? 0) + 1; + counts[key] = (counts[key] ?? 0) + n; } }; + for (const id of known.keys()) count(id.startsWith(`${normRoot}/`) ? id.slice(normRoot.length + 1) : id); // The frames the catalogue already holds of the folder being read, which is // what the reading is measured against: a roll of a hundred thousand that has // been read once before is a reading of a hundred thousand frames even while @@ -984,7 +984,12 @@ export async function scanFolder( addedAt: seen?.addedAt ?? Date.now(), }; batch.push(row); - if (!seen) added.push(row); + if (!seen) { + added.push(row); + // A frame the catalogue did not hold is news the rows have to show: it is + // the one thing an update adds to a number the catalogue already set. + count(rel); + } progress.added++; inHand = inHand.filter((r) => r !== rel); if (batch.length >= BATCH) await flush(); @@ -1013,7 +1018,6 @@ export async function scanFolder( const at = rel.lastIndexOf('/'); progress.at = at < 0 ? '' : rel.slice(0, at); progress.done++; - count(rel); const read = readOne(handle, rel); const lane = read .catch(() => undefined)