refactor(web): runMutation helper for generic-toast admin handlers (#375)
Wraps the dominant pattern (try { await fn } catch { pushToast(errMessage,
'error') }) for the 5 admin/+page.svelte handlers that surface errMessage
directly: onApprove, onReject, onResolve, onDeleteFile, onDeleteLidarr.
Tighter scope than originally planned — the 3 handlers in
admin/users/+page.svelte (onToggleAutoApprove, onGenerateInvite,
onRevokeInvite) use errCode + verb prefix ("Generate failed: ${code}")
which is structurally different and would change UX wire output if
forced through the helper. Skipping them keeps behavior identical.
The helper SWALLOWS errors so callers no longer need try/finally for
busy-state — `saving = true; await runMutation(...); saving = false;`
is correct because runMutation can't throw.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,28 @@
|
|||||||
|
// Wraps the dominant admin-handler mutation pattern:
|
||||||
|
// try { await fn(); pushToast(success?); }
|
||||||
|
// catch (e) { pushToast(errMessage(e), 'error'); }
|
||||||
|
//
|
||||||
|
// Errors are SWALLOWED — caller does not need a try/catch. Any
|
||||||
|
// `saving = true / saving = false` state flag can sit around the
|
||||||
|
// `await runMutation(...)` call without try/finally because the
|
||||||
|
// helper never rethrows.
|
||||||
|
//
|
||||||
|
// Use ONLY for handlers that surface errMessage(e) directly.
|
||||||
|
// Handlers that branch on specific error codes (last_admin,
|
||||||
|
// password_too_short) or build custom copy with errCode keep
|
||||||
|
// their inline catch — wrapping those would obscure intent.
|
||||||
|
|
||||||
|
import { errMessage } from '$lib/api/errors';
|
||||||
|
import { pushToast } from '$lib/stores/toast.svelte';
|
||||||
|
|
||||||
|
export async function runMutation(
|
||||||
|
fn: () => Promise<unknown>,
|
||||||
|
opts: { successMessage?: string } = {}
|
||||||
|
): Promise<void> {
|
||||||
|
try {
|
||||||
|
await fn();
|
||||||
|
if (opts.successMessage) pushToast(opts.successMessage);
|
||||||
|
} catch (e) {
|
||||||
|
pushToast(errMessage(e), 'error');
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -24,8 +24,9 @@
|
|||||||
type ScanScheduleMode
|
type ScanScheduleMode
|
||||||
} from '$lib/api/admin';
|
} from '$lib/api/admin';
|
||||||
import { qk } from '$lib/api/queries';
|
import { qk } from '$lib/api/queries';
|
||||||
import { errCode, errMessage } from '$lib/api/errors';
|
import { errCode } from '$lib/api/errors';
|
||||||
import { pushToast } from '$lib/stores/toast.svelte';
|
import { pushToast } from '$lib/stores/toast.svelte';
|
||||||
|
import { runMutation } from '$lib/util/runMutation';
|
||||||
import type {
|
import type {
|
||||||
AdminQuarantineRow,
|
AdminQuarantineRow,
|
||||||
LidarrRequest,
|
LidarrRequest,
|
||||||
@@ -119,20 +120,16 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function onApprove(r: LidarrRequest) {
|
async function onApprove(r: LidarrRequest) {
|
||||||
try {
|
await runMutation(async () => {
|
||||||
await approveRequest(r.id);
|
await approveRequest(r.id);
|
||||||
await invalidateRequests();
|
await invalidateRequests();
|
||||||
} catch (e) {
|
});
|
||||||
pushToast(errMessage(e), 'error');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
async function onReject(r: LidarrRequest) {
|
async function onReject(r: LidarrRequest) {
|
||||||
try {
|
await runMutation(async () => {
|
||||||
await rejectRequest(r.id);
|
await rejectRequest(r.id);
|
||||||
await invalidateRequests();
|
await invalidateRequests();
|
||||||
} catch (e) {
|
});
|
||||||
pushToast(errMessage(e), 'error');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function invalidateQuarantine() {
|
async function invalidateQuarantine() {
|
||||||
@@ -143,12 +140,10 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function onResolve(row: AdminQuarantineRow) {
|
async function onResolve(row: AdminQuarantineRow) {
|
||||||
try {
|
await runMutation(async () => {
|
||||||
await resolveQuarantine(row.track_id);
|
await resolveQuarantine(row.track_id);
|
||||||
await invalidateQuarantine();
|
await invalidateQuarantine();
|
||||||
} catch (e) {
|
});
|
||||||
pushToast(errMessage(e), 'error');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
async function onDeleteFile(row: AdminQuarantineRow) {
|
async function onDeleteFile(row: AdminQuarantineRow) {
|
||||||
const key = confirmKey(row.track_id, 'delete-file');
|
const key = confirmKey(row.track_id, 'delete-file');
|
||||||
@@ -157,12 +152,10 @@
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
clearConfirm();
|
clearConfirm();
|
||||||
try {
|
await runMutation(async () => {
|
||||||
await deleteQuarantineFile(row.track_id);
|
await deleteQuarantineFile(row.track_id);
|
||||||
await invalidateQuarantine();
|
await invalidateQuarantine();
|
||||||
} catch (e) {
|
});
|
||||||
pushToast(errMessage(e), 'error');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
async function onDeleteLidarr(row: AdminQuarantineRow) {
|
async function onDeleteLidarr(row: AdminQuarantineRow) {
|
||||||
const key = confirmKey(row.track_id, 'delete-lidarr');
|
const key = confirmKey(row.track_id, 'delete-lidarr');
|
||||||
@@ -171,12 +164,10 @@
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
clearConfirm();
|
clearConfirm();
|
||||||
try {
|
await runMutation(async () => {
|
||||||
await deleteQuarantineViaLidarr(row.track_id);
|
await deleteQuarantineViaLidarr(row.track_id);
|
||||||
await invalidateQuarantine();
|
await invalidateQuarantine();
|
||||||
} catch (e) {
|
});
|
||||||
pushToast(errMessage(e), 'error');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---- Library scan ----
|
// ---- Library scan ----
|
||||||
|
|||||||
Reference in New Issue
Block a user