fix: drop the add-anyway override from the upload tray
Storing the same bytes twice splits reading progress and shelves across two records that can never converge. The skipped row still names the book that holds the file; allow_duplicates stays on the API for a wrong verdict.
This commit is contained in:
@@ -118,7 +118,13 @@
|
||||
{job.error}
|
||||
</span>
|
||||
{:else if duplicates.length > 0}
|
||||
<span class="flex min-w-0 items-baseline gap-2 text-[10px] text-muted-foreground">
|
||||
<!--
|
||||
Reported, with no offer to override. Storing the same bytes twice
|
||||
splits reading progress and shelves across two records that can
|
||||
never converge, and there is no version of that the reader wants.
|
||||
`allow_duplicates` stays on the API for when the match is wrong.
|
||||
-->
|
||||
<span class="block min-w-0 text-[10px] text-muted-foreground">
|
||||
{#if target}
|
||||
<a
|
||||
href={resolve('/(root)/(library)/book/[bookId]', { bookId: String(target) })}
|
||||
@@ -129,23 +135,6 @@
|
||||
{:else}
|
||||
<span class="truncate">{duplicateNote(duplicates)}</span>
|
||||
{/if}
|
||||
|
||||
<!-- The hash reads a sample of the file, so a match is strong
|
||||
evidence rather than proof. Someone who knows better needs a
|
||||
way to overrule it.
|
||||
|
||||
Only for a book that was skipped whole: sending a partly-new
|
||||
folder again would build a second book holding both the file
|
||||
that just went in and the one that was already here. -->
|
||||
{#if job.status === 'skipped' && !queue.active}
|
||||
<button
|
||||
type="button"
|
||||
class="shrink-0 underline underline-offset-2 hover:text-foreground"
|
||||
onclick={() => queue.addAnyway(job.id)}
|
||||
>
|
||||
Add anyway
|
||||
</button>
|
||||
{/if}
|
||||
</span>
|
||||
{:else}
|
||||
<span class="block font-mono text-[10px] text-muted-foreground tabular-nums">
|
||||
|
||||
@@ -21,8 +21,6 @@ export interface UploadJob {
|
||||
* and still carries these, since the reader asked for those files too.
|
||||
*/
|
||||
duplicates?: DuplicateFile[];
|
||||
/** Send this one again with `allow_duplicates`, from "Add anyway". */
|
||||
force?: boolean;
|
||||
}
|
||||
|
||||
export interface UploadSummary {
|
||||
@@ -174,27 +172,6 @@ export class UploadQueueState {
|
||||
void this.#run();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a job again, telling the server to store it even though it matched.
|
||||
*
|
||||
* The hash samples a small part of the file, so a match is strong evidence
|
||||
* rather than proof; this is how someone who knows better overrules it.
|
||||
*/
|
||||
addAnyway(id: string) {
|
||||
this.jobs = this.jobs.map((job) =>
|
||||
job.id === id
|
||||
? {
|
||||
...job,
|
||||
status: 'queued' as UploadStatus,
|
||||
force: true,
|
||||
duplicates: undefined,
|
||||
error: undefined
|
||||
}
|
||||
: job
|
||||
);
|
||||
void this.#run();
|
||||
}
|
||||
|
||||
async #run(onFinished?: (summary: UploadSummary) => void) {
|
||||
if (this.#running) return;
|
||||
this.#running = true;
|
||||
@@ -217,14 +194,10 @@ export class UploadQueueState {
|
||||
const body = new FormData();
|
||||
for (const file of job.files) body.append('files', file);
|
||||
|
||||
const query =
|
||||
`library_id=${encodeURIComponent(String(job.libraryId))}` +
|
||||
(job.force ? '&allow_duplicates=true' : '');
|
||||
|
||||
const response = await fetch(`/api/books/fromFiles?${query}`, {
|
||||
method: 'POST',
|
||||
body
|
||||
});
|
||||
const response = await fetch(
|
||||
`/api/books/fromFiles?library_id=${encodeURIComponent(String(job.libraryId))}`,
|
||||
{ method: 'POST', body }
|
||||
);
|
||||
|
||||
if (!response.ok) throw new Error(`The server returned ${response.status}`);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user