refactor(web): Modal component; admin + discover modals migrated (W2)

This commit is contained in:
2026-05-08 05:37:58 -04:00
parent 92813ba1bb
commit 970752a153
7 changed files with 543 additions and 512 deletions
+86 -117
View File
@@ -11,6 +11,7 @@
} from '$lib/api/admin';
import { errMessage } from '$lib/api/errors';
import StatusPill from '$lib/components/StatusPill.svelte';
import Modal from '$lib/components/Modal.svelte';
import type { LidarrRequest, LidarrRequestKind, LidarrRequestStatus } from '$lib/api/types';
// Approval queue. Tabs filter by status; rows expose Override/Approve/Reject
@@ -294,127 +295,95 @@
{/if}
</div>
{#if overrideRow}
<!-- svelte-ignore a11y_click_events_have_key_events -->
<!-- svelte-ignore a11y_no_static_element_interactions -->
<div
class="fixed inset-0 z-50 flex items-center justify-center"
style="background: rgba(0,0,0,0.5);"
onclick={cancelOverride}
>
<div
role="dialog"
aria-modal="true"
aria-labelledby="override-title"
class="w-full max-w-md rounded-xl border border-border bg-surface p-5 shadow-lg"
onclick={(e) => e.stopPropagation()}
tabindex="-1"
<Modal
title="Approve with override"
open={overrideRow !== null}
onClose={cancelOverride}
>
<p class="-mt-2 text-sm text-text-secondary">
Leave fields blank to use the saved defaults.
</p>
<label class="mt-4 block">
<span class="block text-sm text-text-secondary">Quality profile</span>
<select
bind:value={qualityOverride}
class="mt-1 w-full rounded-md border border-border bg-background px-3 py-2 text-sm text-text-primary focus:outline-none focus:ring-2 focus:ring-accent"
>
<h3 id="override-title" class="font-display text-lg font-medium text-text-primary">
Approve with override
</h3>
<p class="mt-2 text-sm text-text-secondary">
Leave fields blank to use the saved defaults.
</p>
<option value="">Use default</option>
{#each profiles.data ?? [] as p (p.id)}
<option value={p.id}>{p.name}</option>
{/each}
</select>
</label>
<label class="mt-4 block">
<span class="block text-sm text-text-secondary">Quality profile</span>
<select
bind:value={qualityOverride}
class="mt-1 w-full rounded-md border border-border bg-background px-3 py-2 text-sm text-text-primary focus:outline-none focus:ring-2 focus:ring-accent"
>
<option value="">Use default</option>
{#each profiles.data ?? [] as p (p.id)}
<option value={p.id}>{p.name}</option>
{/each}
</select>
</label>
<label class="mt-3 block">
<span class="block text-sm text-text-secondary">Root folder</span>
<select
bind:value={rootOverride}
class="mt-1 w-full rounded-md border border-border bg-background px-3 py-2 font-mono text-sm text-text-primary focus:outline-none focus:ring-2 focus:ring-accent"
>
<option value="">Use default</option>
{#each folders.data ?? [] as f (f.path)}
<option value={f.path}>{f.path}{f.accessible ? '' : ' (not accessible)'}</option>
{/each}
</select>
</label>
<div class="mt-5 flex justify-end gap-2">
<button
type="button"
class="rounded-md border border-border px-3 py-1.5 text-sm text-text-secondary hover:text-text-primary"
onclick={cancelOverride}
>
Cancel
</button>
<button
type="button"
class="inline-flex items-center gap-1 rounded-md bg-action-primary px-3 py-1.5 text-sm text-action-fg"
onclick={() => confirmOverride(overrideRow!)}
>
<Check size={14} strokeWidth={2} />
Approve with override
</button>
</div>
</div>
</div>
{/if}
{#if rejectRow}
<!-- svelte-ignore a11y_click_events_have_key_events -->
<!-- svelte-ignore a11y_no_static_element_interactions -->
<div
class="fixed inset-0 z-50 flex items-center justify-center"
style="background: rgba(0,0,0,0.5);"
onclick={cancelReject}
>
<div
role="dialog"
aria-modal="true"
aria-labelledby="reject-title"
class="w-full max-w-md rounded-xl border border-border bg-surface p-5 shadow-lg"
onclick={(e) => e.stopPropagation()}
tabindex="-1"
<label class="mt-3 block">
<span class="block text-sm text-text-secondary">Root folder</span>
<select
bind:value={rootOverride}
class="mt-1 w-full rounded-md border border-border bg-background px-3 py-2 font-mono text-sm text-text-primary focus:outline-none focus:ring-2 focus:ring-accent"
>
<h3 id="reject-title" class="font-display text-lg font-medium text-text-primary">
Reject request?
</h3>
<p class="mt-2 text-sm text-text-secondary">
Notes are shown to the requester.
</p>
<label class="mt-3 block">
<span class="block text-sm text-text-secondary">Notes</span>
<textarea
bind:value={rejectNotes}
rows="3"
placeholder="Optional — why this is being set aside"
class="mt-1 w-full rounded-md border border-border bg-background px-3 py-2 text-sm text-text-primary placeholder:text-text-muted focus:outline-none focus:ring-2 focus:ring-accent"
></textarea>
</label>
<div class="mt-5 flex justify-end gap-2">
<button
type="button"
class="rounded-md border border-border px-3 py-1.5 text-sm text-text-secondary hover:text-text-primary"
onclick={cancelReject}
>
Cancel
</button>
<button
type="button"
class="inline-flex items-center gap-1 rounded-md bg-action-secondary px-3 py-1.5 text-sm text-action-fg"
onclick={() => confirmReject(rejectRow!)}
>
<X size={14} strokeWidth={2} />
Confirm reject
</button>
</div>
</div>
<option value="">Use default</option>
{#each folders.data ?? [] as f (f.path)}
<option value={f.path}>{f.path}{f.accessible ? '' : ' (not accessible)'}</option>
{/each}
</select>
</label>
<div class="mt-5 flex justify-end gap-2">
<button
type="button"
class="rounded-md border border-border px-3 py-1.5 text-sm text-text-secondary hover:text-text-primary"
onclick={cancelOverride}
>
Cancel
</button>
<button
type="button"
class="inline-flex items-center gap-1 rounded-md bg-action-primary px-3 py-1.5 text-sm text-action-fg"
onclick={() => overrideRow && confirmOverride(overrideRow)}
>
<Check size={14} strokeWidth={2} />
Approve with override
</button>
</div>
{/if}
</Modal>
<Modal
title="Reject request?"
open={rejectRow !== null}
onClose={cancelReject}
>
<p class="-mt-2 text-sm text-text-secondary">
Notes are shown to the requester.
</p>
<label class="mt-3 block">
<span class="block text-sm text-text-secondary">Notes</span>
<textarea
bind:value={rejectNotes}
rows="3"
placeholder="Optional — why this is being set aside"
class="mt-1 w-full rounded-md border border-border bg-background px-3 py-2 text-sm text-text-primary placeholder:text-text-muted focus:outline-none focus:ring-2 focus:ring-accent"
></textarea>
</label>
<div class="mt-5 flex justify-end gap-2">
<button
type="button"
class="rounded-md border border-border px-3 py-1.5 text-sm text-text-secondary hover:text-text-primary"
onclick={cancelReject}
>
Cancel
</button>
<button
type="button"
class="inline-flex items-center gap-1 rounded-md bg-action-secondary px-3 py-1.5 text-sm text-action-fg"
onclick={() => rejectRow && confirmReject(rejectRow)}
>
<X size={14} strokeWidth={2} />
Confirm reject
</button>
</div>
</Modal>
{#if toast}
<div