feat: the admin settings cards read as menus: each a titled group of rows with one short line, status first, failures in words (M503 #5607)
release / govulncheck (push) Successful in 16s
release / web (push) Failing after 1m27s
release / go (push) Successful in 1m44s
release / android (push) Successful in 5m13s
release / integration (push) Successful in 5m18s
release / Build signed APK (releases and dev) (push) Successful in 5m26s
release / Attach APK to the Release (tag releases only) (push) Skipped
release / Build + push container image (push) Skipped
release / Verify release artifacts (tag releases only) (push) Skipped
release / govulncheck (push) Successful in 16s
release / web (push) Failing after 1m27s
release / go (push) Successful in 1m44s
release / android (push) Successful in 5m13s
release / integration (push) Successful in 5m18s
release / Build signed APK (releases and dev) (push) Successful in 5m26s
release / Attach APK to the Release (tag releases only) (push) Skipped
release / Build + push container image (push) Skipped
release / Verify release artifacts (tag releases only) (push) Skipped
Indexers and clients, searching, missing files, Lidarr's neighbours, AcoustID, fingerprinting, loudness, outgoing email's schedule, public address and proxies move from paragraph cards to SettingsGroup and SettingRow. Switches are role="switch". Also fixes the two type errors run 9023 found: the Lidarr test result is narrowed before its lists are read, and the tag-source save mock carries version_bumped. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -7,10 +7,16 @@
|
||||
} from '#lib/api/admin.js';
|
||||
import { errMessage } from '#lib/api/errors.js';
|
||||
import { pushToast } from '#lib/stores/toast.svelte.js';
|
||||
import SettingsGroup from '#lib/components/settings/SettingsGroup.svelte';
|
||||
import SettingRow from '#lib/components/settings/SettingRow.svelte';
|
||||
|
||||
// When notification emails go out (M489 #5346). Nothing is emailed per
|
||||
// event: new music is a daily summary, everything else a batch.
|
||||
|
||||
const button =
|
||||
'rounded-md border border-border px-3 py-1.5 text-sm text-text-secondary hover:bg-surface-hover hover:text-text-primary disabled:opacity-50';
|
||||
const field = 'w-24 rounded-md border border-border bg-background px-2 py-1.5 text-sm';
|
||||
|
||||
let saved = $state<NotificationEmailSettings | null>(null);
|
||||
let form = $state<NotificationEmailSettings | null>(null);
|
||||
let saving = $state(false);
|
||||
@@ -58,69 +64,30 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
<section class="space-y-4 rounded-xl border border-border bg-surface p-5">
|
||||
<div>
|
||||
<h3 class="font-display text-lg font-medium text-text-primary">Notification emails</h3>
|
||||
<p class="mt-1 text-sm text-text-secondary">
|
||||
Nothing is emailed per event. Each person chooses which notifications reach their email in
|
||||
their own settings.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<SettingsGroup title="Notification emails" id="notification-emails" hint="Never one per event. Each person picks theirs in their own settings.">
|
||||
{#if loadError}
|
||||
<p class="text-sm text-action-destructive">
|
||||
<p class="px-4 py-3 text-sm text-error-fg">
|
||||
Couldn't load the email schedule.
|
||||
<button type="button" class="underline hover:no-underline" onclick={load}>Try again</button>
|
||||
</p>
|
||||
{:else if form === null}
|
||||
<p class="text-sm text-text-secondary">Loading the email schedule…</p>
|
||||
<p class="px-4 py-3 text-sm text-text-secondary">Loading the email schedule…</p>
|
||||
{:else}
|
||||
<div class="grid gap-4 sm:grid-cols-2">
|
||||
<label class="block">
|
||||
<span class="text-sm text-text-primary">New music summary</span>
|
||||
<span class="block text-xs text-text-secondary">
|
||||
Once a day at this hour, in each person's own timezone.
|
||||
</span>
|
||||
<select
|
||||
bind:value={form.summary_hour}
|
||||
class="mt-1 w-28 rounded border border-border bg-background px-2 py-1 text-sm
|
||||
text-text-primary focus-visible:outline-solid focus-visible:outline-2
|
||||
focus-visible:outline-accent"
|
||||
>
|
||||
{#each hours as h (h)}
|
||||
<option value={h}>{hourLabel(h)}</option>
|
||||
{/each}
|
||||
</select>
|
||||
</label>
|
||||
|
||||
<label class="block">
|
||||
<span class="text-sm text-text-primary">Batch everything else (minutes)</span>
|
||||
<span class="block text-xs text-text-secondary">
|
||||
One email this long after the first item, holding all that came in.
|
||||
</span>
|
||||
<input
|
||||
type="number"
|
||||
min="15"
|
||||
max="1440"
|
||||
bind:value={form.batch_window_minutes}
|
||||
class="mt-1 w-28 rounded border border-border bg-background px-2 py-1 text-sm
|
||||
text-text-primary focus-visible:outline-solid focus-visible:outline-2
|
||||
focus-visible:outline-accent"
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="flex justify-end">
|
||||
<button
|
||||
type="button"
|
||||
class="rounded-md bg-action-secondary px-4 py-2 text-sm text-action-fg hover:opacity-90
|
||||
focus-visible:outline-solid focus-visible:outline-2 focus-visible:outline-accent
|
||||
disabled:cursor-not-allowed disabled:opacity-50"
|
||||
disabled={!dirty || saving}
|
||||
onclick={save}
|
||||
>
|
||||
<SettingRow label="New music summary" for="summary-hour" hint="Daily, at this hour in each person's timezone.">
|
||||
<select id="summary-hour" bind:value={form.summary_hour} class={field}>
|
||||
{#each hours as h (h)}
|
||||
<option value={h}>{hourLabel(h)}</option>
|
||||
{/each}
|
||||
</select>
|
||||
</SettingRow>
|
||||
<SettingRow label="Batch everything else" for="batch-window" hint="One email this long after the first item.">
|
||||
<input id="batch-window" type="number" min="15" max="1440" bind:value={form.batch_window_minutes} class={field} />
|
||||
<span class="text-sm text-text-secondary">minutes</span>
|
||||
</SettingRow>
|
||||
<div class="flex justify-end px-4 py-3">
|
||||
<button type="button" class={button} disabled={!dirty || saving} onclick={save}>
|
||||
{saving ? 'Saving…' : 'Save'}
|
||||
</button>
|
||||
</div>
|
||||
{/if}
|
||||
</section>
|
||||
</SettingsGroup>
|
||||
|
||||
Reference in New Issue
Block a user