e6b50fb4f1
Fix all build/type/lint errors (zod 3.25 compat wrapper, Svelte 5 fixes), write 115 unit tests across 10 test files, expand seed script with demo data, update Docker config with migration on startup.
159 lines
6.0 KiB
Svelte
159 lines
6.0 KiB
Svelte
<script lang="ts">
|
|
import { superForm, type SuperValidated } from 'sveltekit-superforms/client';
|
|
import type { updateSystemSettingsSchema } from '$lib/utils/validators.js';
|
|
import type { z } from 'zod';
|
|
|
|
let { form: formData }: { form: SuperValidated<z.infer<typeof updateSystemSettingsSchema>> } = $props();
|
|
|
|
const { form, errors, enhance, delayed } = superForm(formData);
|
|
</script>
|
|
|
|
<form method="POST" action="?/update" use:enhance class="space-y-8">
|
|
<!-- Authentication -->
|
|
<section class="rounded-lg border border-border bg-card p-6">
|
|
<h2 class="mb-4 text-lg font-semibold text-card-foreground">Authentication</h2>
|
|
<div class="grid grid-cols-1 gap-4 sm:grid-cols-2">
|
|
<div>
|
|
<label for="authMode" class="mb-1 block text-sm font-medium text-foreground">Auth Mode</label>
|
|
<select
|
|
id="authMode"
|
|
name="authMode"
|
|
bind:value={$form.authMode}
|
|
class="w-full rounded-md border border-input bg-background px-3 py-2 text-sm text-foreground"
|
|
>
|
|
<option value="local">Local</option>
|
|
<option value="oauth">OAuth</option>
|
|
<option value="both">Both</option>
|
|
</select>
|
|
{#if $errors.authMode}<span class="text-xs text-destructive">{$errors.authMode}</span>{/if}
|
|
</div>
|
|
<div class="flex items-center gap-2 pt-6">
|
|
<input
|
|
id="registrationEnabled"
|
|
name="registrationEnabled"
|
|
type="checkbox"
|
|
bind:checked={$form.registrationEnabled}
|
|
class="h-4 w-4 rounded border-input"
|
|
/>
|
|
<label for="registrationEnabled" class="text-sm font-medium text-foreground">
|
|
Allow user registration
|
|
</label>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- OAuth (stored but non-functional in MVP) -->
|
|
<section class="rounded-lg border border-border bg-card p-6">
|
|
<h2 class="mb-4 text-lg font-semibold text-card-foreground">OAuth Configuration</h2>
|
|
<p class="mb-4 text-xs text-muted-foreground">OAuth settings are stored but not active in this MVP version.</p>
|
|
<div class="grid grid-cols-1 gap-4 sm:grid-cols-2">
|
|
<div>
|
|
<label for="oauthClientId" class="mb-1 block text-sm font-medium text-foreground">Client ID</label>
|
|
<input
|
|
id="oauthClientId"
|
|
name="oauthClientId"
|
|
type="text"
|
|
bind:value={$form.oauthClientId}
|
|
class="w-full rounded-md border border-input bg-background px-3 py-2 text-sm text-foreground"
|
|
placeholder="OAuth client ID"
|
|
/>
|
|
</div>
|
|
<div>
|
|
<label for="oauthClientSecret" class="mb-1 block text-sm font-medium text-foreground">Client Secret</label>
|
|
<input
|
|
id="oauthClientSecret"
|
|
name="oauthClientSecret"
|
|
type="password"
|
|
bind:value={$form.oauthClientSecret}
|
|
class="w-full rounded-md border border-input bg-background px-3 py-2 text-sm text-foreground"
|
|
placeholder="OAuth client secret"
|
|
/>
|
|
</div>
|
|
<div class="sm:col-span-2">
|
|
<label for="oauthDiscoveryUrl" class="mb-1 block text-sm font-medium text-foreground">Discovery URL</label>
|
|
<input
|
|
id="oauthDiscoveryUrl"
|
|
name="oauthDiscoveryUrl"
|
|
type="url"
|
|
bind:value={$form.oauthDiscoveryUrl}
|
|
class="w-full rounded-md border border-input bg-background px-3 py-2 text-sm text-foreground"
|
|
placeholder="https://example.com/.well-known/openid-configuration"
|
|
/>
|
|
{#if $errors.oauthDiscoveryUrl}<span class="text-xs text-destructive">{$errors.oauthDiscoveryUrl}</span>{/if}
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- Theme Defaults -->
|
|
<section class="rounded-lg border border-border bg-card p-6">
|
|
<h2 class="mb-4 text-lg font-semibold text-card-foreground">Theme Defaults</h2>
|
|
<div class="grid grid-cols-1 gap-4 sm:grid-cols-2">
|
|
<div>
|
|
<label for="defaultTheme" class="mb-1 block text-sm font-medium text-foreground">Default Theme</label>
|
|
<select
|
|
id="defaultTheme"
|
|
name="defaultTheme"
|
|
bind:value={$form.defaultTheme}
|
|
class="w-full rounded-md border border-input bg-background px-3 py-2 text-sm text-foreground"
|
|
>
|
|
<option value="dark">Dark</option>
|
|
<option value="light">Light</option>
|
|
</select>
|
|
</div>
|
|
<div>
|
|
<label for="defaultPrimaryColor" class="mb-1 block text-sm font-medium text-foreground">Default Primary Color</label>
|
|
<div class="flex items-center gap-2">
|
|
<input
|
|
id="defaultPrimaryColor"
|
|
name="defaultPrimaryColor"
|
|
type="text"
|
|
bind:value={$form.defaultPrimaryColor}
|
|
class="w-full rounded-md border border-input bg-background px-3 py-2 text-sm text-foreground"
|
|
placeholder="#6366f1"
|
|
pattern="^#[0-9a-fA-F]{6}$"
|
|
/>
|
|
{#if $form.defaultPrimaryColor}
|
|
<div
|
|
class="h-8 w-8 shrink-0 rounded border border-border"
|
|
style:background-color={$form.defaultPrimaryColor}
|
|
></div>
|
|
{/if}
|
|
</div>
|
|
{#if $errors.defaultPrimaryColor}<span class="text-xs text-destructive">{$errors.defaultPrimaryColor}</span>{/if}
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- Healthcheck Defaults -->
|
|
<section class="rounded-lg border border-border bg-card p-6">
|
|
<h2 class="mb-4 text-lg font-semibold text-card-foreground">Healthcheck Defaults</h2>
|
|
<p class="mb-4 text-xs text-muted-foreground">JSON configuration for default healthcheck behavior (interval, timeout, method).</p>
|
|
<div>
|
|
<label for="healthcheckDefaults" class="mb-1 block text-sm font-medium text-foreground">Defaults (JSON)</label>
|
|
<textarea
|
|
id="healthcheckDefaults"
|
|
name="healthcheckDefaults"
|
|
bind:value={$form.healthcheckDefaults}
|
|
rows="4"
|
|
class="w-full rounded-md border border-input bg-background px-3 py-2 font-mono text-sm text-foreground"
|
|
placeholder={'{"interval": 300, "timeout": 5000, "method": "GET"}'}
|
|
></textarea>
|
|
{#if $errors.healthcheckDefaults}<span class="text-xs text-destructive">{$errors.healthcheckDefaults}</span>{/if}
|
|
</div>
|
|
</section>
|
|
|
|
{#if $errors._errors}
|
|
<p class="text-sm text-destructive">{$errors._errors}</p>
|
|
{/if}
|
|
|
|
<div class="flex items-center gap-3">
|
|
<button
|
|
type="submit"
|
|
class="rounded-md bg-primary px-6 py-2 text-sm font-medium text-primary-foreground hover:bg-primary/90 focus:outline-none focus:ring-2 focus:ring-ring"
|
|
disabled={$delayed}
|
|
>
|
|
{$delayed ? 'Saving...' : 'Save Settings'}
|
|
</button>
|
|
</div>
|
|
</form>
|