feat(phase3): phase 7 - integration & polish

Fix all build/type/lint errors, write 46 new tests (222 total across
20 files), regenerate Prisma client, update seed with user preferences.
Fix SvelteSet usage, add {#each} keys, clean unused imports.
This commit is contained in:
2026-03-25 01:12:11 +03:00
parent dd6958b4d6
commit 7d8a8fb0fc
14 changed files with 1223 additions and 34 deletions
+15 -14
View File
@@ -1,5 +1,6 @@
<script lang="ts">
import { t } from 'svelte-i18n';
import { SvelteSet } from 'svelte/reactivity';
interface DiscoveredService {
name: string;
@@ -22,7 +23,7 @@
let approving = $state(false);
let services = $state<DiscoveredService[]>([]);
let scanErrors = $state<string[]>([]);
let selected = $state<Set<number>>(new Set());
let selected = new SvelteSet<number>();
let statusMessage = $state('');
let statusType: 'success' | 'error' | '' = $state('');
@@ -36,7 +37,7 @@
scanning = true;
services = [];
scanErrors = [];
selected = new Set();
selected.clear();
try {
const response = await fetch('/api/admin/discover', {
@@ -70,13 +71,11 @@
}
function toggleSelect(index: number) {
const next = new Set(selected);
if (next.has(index)) {
next.delete(index);
if (selected.has(index)) {
selected.delete(index);
} else {
next.add(index);
selected.add(index);
}
selected = next;
}
function toggleSelectAll() {
@@ -84,10 +83,12 @@
.map((s, i) => (s.alreadyRegistered ? -1 : i))
.filter((i) => i >= 0);
if (selected.size === selectableIndices.length) {
selected = new Set();
} else {
selected = new Set(selectableIndices);
const allSelected = selected.size === selectableIndices.length;
selected.clear();
if (!allSelected) {
for (const idx of selectableIndices) {
selected.add(idx);
}
}
}
@@ -124,7 +125,7 @@
services = services.map((s, i) =>
selected.has(i) ? { ...s, alreadyRegistered: true } : s
);
selected = new Set();
selected.clear();
} catch (err) {
statusMessage = err instanceof Error ? err.message : 'Approval failed';
statusType = 'error';
@@ -155,7 +156,7 @@
<!-- Scan Errors -->
{#if scanErrors.length > 0}
<div class="mb-4 rounded-md bg-yellow-100 p-3 text-sm text-yellow-800 dark:bg-yellow-900/30 dark:text-yellow-400">
{#each scanErrors as scanError}
{#each scanErrors as scanError, idx (idx)}
<p>{scanError}</p>
{/each}
</div>
@@ -183,7 +184,7 @@
</tr>
</thead>
<tbody>
{#each services as service, i}
{#each services as service, i (service.url)}
<tr class="border-b border-border/50 hover:bg-muted/50">
<td class="px-2 py-2">
<input