fix: guard AddToCollectionModal against out-of-order load results
Retargeting the modal mid-load could resolve responses out of order, overwriting the newer target's membership with the older one's (audit FE-2). Route load() through the tested CancellableLoader so a superseded result is dropped. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2
backend/Cargo.lock
generated
2
backend/Cargo.lock
generated
@@ -1558,7 +1558,7 @@ checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4"
|
||||
|
||||
[[package]]
|
||||
name = "mangalord"
|
||||
version = "0.128.14"
|
||||
version = "0.128.15"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"argon2",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "mangalord"
|
||||
version = "0.128.14"
|
||||
version = "0.128.15"
|
||||
edition = "2021"
|
||||
default-run = "mangalord"
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "mangalord-frontend",
|
||||
"version": "0.128.14",
|
||||
"version": "0.128.15",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<script lang="ts">
|
||||
import AdaptiveDialog from './AdaptiveDialog.svelte';
|
||||
import { CancellableLoader } from '$lib/util/cancellable';
|
||||
import {
|
||||
addMangaToCollection,
|
||||
createCollection,
|
||||
@@ -74,19 +75,30 @@
|
||||
: removePageFromCollection(collectionId, t.id);
|
||||
}
|
||||
|
||||
// Reopening for a different target (or an in-flight retarget) fires load()
|
||||
// again; without this guard the two responses can resolve out of order and
|
||||
// the first target's membership overwrites the second's (audit FE-2). The
|
||||
// CancellableLoader drops a superseded call's result — the newer load then
|
||||
// owns both the state and the spinner.
|
||||
const loader = new CancellableLoader();
|
||||
|
||||
async function load() {
|
||||
loading = true;
|
||||
error = null;
|
||||
try {
|
||||
const result = await loader.run(async () => {
|
||||
const [page, ids] = await Promise.all([
|
||||
listMyCollections({ limit: 200 }),
|
||||
loadContaining(target)
|
||||
]);
|
||||
collections = page.items;
|
||||
containingIds = new Set(ids);
|
||||
return { items: page.items, ids };
|
||||
});
|
||||
if (result === null) return; // superseded — a newer load owns the state
|
||||
collections = result.items;
|
||||
containingIds = new Set(result.ids);
|
||||
loading = false;
|
||||
} catch (e) {
|
||||
error = (e as Error).message;
|
||||
} finally {
|
||||
loading = false;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user