refactor(web): consolidate error-copy table to JSON source of truth

Three admin pages had divergent inline error-code → user-copy switch
tables (with wording drift, including a stale "Settings → Integrations"
that should have been Admin). Consolidate into web/src/lib/styles/error-copy.json,
expose via web/src/lib/api/error-copy.ts (ERROR_COPY + copyForCode),
and refactor the three pages to import the helper.

Fixes the three-way drift; the only user-visible behavior change is
the quarantine page now correctly says "Admin → Integrations".

Sets up the JSON for the M7 Flutter client (#356) to consume the same
table.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-02 15:01:46 -04:00
parent ea22807a3f
commit c3be0f3e6e
6 changed files with 40 additions and 68 deletions
+6 -22
View File
@@ -8,13 +8,14 @@
deleteQuarantineViaLidarr
} from '$lib/api/admin';
import { qk } from '$lib/api/queries';
import { copyForCode } from '$lib/api/error-copy';
import { playRadio } from '$lib/player/store.svelte';
import type { AdminQuarantineRow, LidarrQuarantineReason } from '$lib/api/types';
// Aggregated triage queue. One row per track, with per-row resolution
// actions: Resolve (clears reports), Delete file (Bronze; modal-confirm),
// Delete via Lidarr (Oxblood; typed-confirm "DELETE"). Mirrors
// /admin/requests for shape — toast helper, errorCopy(), invalidateQueries.
// /admin/requests for shape — toast helper, copyForCode(), invalidateQueries.
const client = useQueryClient();
@@ -78,23 +79,6 @@
}, 5000);
}
function errorCopy(code: string): string {
switch (code) {
case 'lidarr_unreachable':
return "Lidarr is unreachable right now. Try again, or check Settings → Integrations.";
case 'lidarr_disabled':
return 'Lidarr integration is not enabled.';
case 'lidarr_auth_failed':
return 'Lidarr authentication failed.';
case 'lidarr_album_lookup_failed':
return "Lidarr doesn't recognize this album. Try Resolve or Delete file instead.";
case 'album_mbid_missing':
return 'This track has no Lidarr album to remove.';
default:
return "Couldn't reach Lidarr.";
}
}
async function invalidate() {
await client.invalidateQueries({ queryKey: qk.adminQuarantine() });
}
@@ -105,7 +89,7 @@
await invalidate();
} catch (e) {
const code = (e as { code?: string }).code ?? 'unknown';
showToast(errorCopy(code));
showToast(copyForCode(code));
}
}
@@ -124,7 +108,7 @@
await invalidate();
} catch (e) {
const code = (e as { code?: string }).code ?? 'unknown';
showToast(errorCopy(code));
showToast(copyForCode(code));
}
}
@@ -153,9 +137,9 @@
const code = (e as { code?: string }).code ?? 'unknown';
// Inline error keeps the modal open so the operator sees the failure
// alongside the album they were about to remove.
deleteLidarrError = errorCopy(code);
deleteLidarrError = copyForCode(code);
// Also surface as toast so it's visible after dismissing the modal.
showToast(errorCopy(code));
showToast(copyForCode(code));
}
}