All checks were successful
Build & Publish Docker Image / build-and-push (push) Successful in 1m17s
Domain-Admin-Seite bekommt jetzt ein Favicon-Icon vor jedem Eintrag, einen Pencil-Button zum Inline-Editieren von Domain und Anzeigename, und Save/Cancel-Buttons. Beim Ändern des Domain-Namens wird das Favicon zurückgesetzt und beim Speichern frisch nachgeladen (den Filter-Dropdown- Icons reicht der neue favicon_path automatisch zu). Der Filter-Button auf der Hauptseite sitzt jetzt IM weißen Suchfeld- Container (neuer .search-box-Wrapper mit Border) statt daneben, analog zum Referenz-Screenshot von rezeptwelt.de. Neue inline-Prop an SearchFilter schaltet eigenen Border/Background ab und setzt stattdessen einen vertikalen Divider nach rechts. - Neuer PATCH /api/domains/[id] mit zod-Schema. - Repository: updateDomain(id, patch) + getDomainById(id). domain-Change nullt favicon_path → Caller lädt neu. - Tests für updateDomain-Fälle und getDomainById. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
79 lines
2.4 KiB
TypeScript
79 lines
2.4 KiB
TypeScript
import type Database from 'better-sqlite3';
|
|
import type { AllowedDomain } from '$lib/types';
|
|
|
|
export function normalizeDomain(raw: string): string {
|
|
return raw.trim().toLowerCase().replace(/^www\./, '');
|
|
}
|
|
|
|
export function listDomains(db: Database.Database): AllowedDomain[] {
|
|
return db
|
|
.prepare(
|
|
'SELECT id, domain, display_name, favicon_path FROM allowed_domain ORDER BY domain'
|
|
)
|
|
.all() as AllowedDomain[];
|
|
}
|
|
|
|
export function addDomain(
|
|
db: Database.Database,
|
|
domain: string,
|
|
displayName: string | null = null,
|
|
addedByProfileId: number | null = null
|
|
): AllowedDomain {
|
|
const normalized = normalizeDomain(domain);
|
|
const row = db
|
|
.prepare(
|
|
`INSERT INTO allowed_domain(domain, display_name, added_by_profile_id)
|
|
VALUES (?, ?, ?)
|
|
RETURNING id, domain, display_name, favicon_path`
|
|
)
|
|
.get(normalized, displayName, addedByProfileId) as AllowedDomain;
|
|
return row;
|
|
}
|
|
|
|
export function removeDomain(db: Database.Database, id: number): void {
|
|
db.prepare('DELETE FROM allowed_domain WHERE id = ?').run(id);
|
|
}
|
|
|
|
export function setDomainFavicon(
|
|
db: Database.Database,
|
|
id: number,
|
|
faviconPath: string | null
|
|
): void {
|
|
db.prepare('UPDATE allowed_domain SET favicon_path = ? WHERE id = ?').run(
|
|
faviconPath,
|
|
id
|
|
);
|
|
}
|
|
|
|
export function getDomainById(
|
|
db: Database.Database,
|
|
id: number
|
|
): AllowedDomain | null {
|
|
const row = db
|
|
.prepare(
|
|
'SELECT id, domain, display_name, favicon_path FROM allowed_domain WHERE id = ?'
|
|
)
|
|
.get(id) as AllowedDomain | undefined;
|
|
return row ?? null;
|
|
}
|
|
|
|
export function updateDomain(
|
|
db: Database.Database,
|
|
id: number,
|
|
patch: { domain?: string; display_name?: string | null }
|
|
): AllowedDomain | null {
|
|
const current = getDomainById(db, id);
|
|
if (!current) return null;
|
|
const nextDomain =
|
|
patch.domain !== undefined ? normalizeDomain(patch.domain) : current.domain;
|
|
const nextLabel =
|
|
patch.display_name !== undefined ? patch.display_name : current.display_name;
|
|
// Wenn sich die Domain ändert: favicon_path zurücksetzen, damit der Caller
|
|
// es neu laden kann. Sonst zeigen wir fälschlich das alte Icon.
|
|
const nextFavicon = nextDomain !== current.domain ? null : current.favicon_path;
|
|
db.prepare(
|
|
'UPDATE allowed_domain SET domain = ?, display_name = ?, favicon_path = ? WHERE id = ?'
|
|
).run(nextDomain, nextLabel, nextFavicon, id);
|
|
return getDomainById(db, id);
|
|
}
|