generated from Dicken/dickendock
round13: manuelle vs. echte Aenderungen trennen, Scan-Uebersicht ueber Navigation persistieren, ausgeblendete Dienste als Tab, Suche ueber Geraetenamen
This commit is contained in:
@@ -53,6 +53,8 @@ export function ensureSchema(): void {
|
||||
url TEXT NOT NULL,
|
||||
https INTEGER NOT NULL DEFAULT 0,
|
||||
visible INTEGER NOT NULL DEFAULT 1,
|
||||
display_name_edited_manually INTEGER NOT NULL DEFAULT 0,
|
||||
category_edited_manually INTEGER NOT NULL DEFAULT 0,
|
||||
port INTEGER NOT NULL,
|
||||
favicon TEXT,
|
||||
description TEXT,
|
||||
@@ -123,6 +125,11 @@ export function ensureSchema(): void {
|
||||
// sich am bisherigen Verhalten nichts unerwartet ändert.
|
||||
ensureColumn("services", "visible", "INTEGER NOT NULL DEFAULT 1");
|
||||
ensureColumn("categories", "color", "TEXT");
|
||||
// Für Datenbanken vor Einführung der Unterscheidung "manuell angepasst" vs.
|
||||
// "vom Scan abweichend" bei displayName/category (siehe schema.ts). Default
|
||||
// 0 (nicht manuell bearbeitet) ist für Bestandsdaten die richtige Annahme.
|
||||
ensureColumn("services", "display_name_edited_manually", "INTEGER NOT NULL DEFAULT 0");
|
||||
ensureColumn("services", "category_edited_manually", "INTEGER NOT NULL DEFAULT 0");
|
||||
}
|
||||
|
||||
function ensureColumn(table: string, column: string, definition: string): void {
|
||||
|
||||
@@ -91,6 +91,14 @@ export function createService(input: ServiceCreateInput): Service {
|
||||
* Für automatische Scan-Ergebnisse siehe upsertServiceFromScan() unten – die
|
||||
* NIEMALS displayName, category, favorite, order, alias, icon, hostname, url,
|
||||
* https oder visible eines bereits bekannten Dienstes überschreibt.
|
||||
*
|
||||
* Ein PATCH mit displayName/category markiert das jeweilige Feld standardmäßig
|
||||
* als "manuell bearbeitet" (displayNameEditedManually/categoryEditedManually),
|
||||
* damit ein späterer Scan-Vorschlag, der davon abweicht, in der Änderungs-
|
||||
* übersicht klar als "weicht nur wegen deiner manuellen Anpassung ab" markiert
|
||||
* werden kann statt als echte inhaltliche Änderung. Beim Übernehmen eines
|
||||
* Scan-Vorschlags wird die jeweilige *EditedManually-Flag explizit auf false
|
||||
* gesetzt (siehe ScannerPage/DevicesPage "Übernehmen"-Button).
|
||||
*/
|
||||
export function updateService(id: string, input: ServiceUpdateInput): Service | null {
|
||||
const existing = getService(id);
|
||||
@@ -98,12 +106,18 @@ export function updateService(id: string, input: ServiceUpdateInput): Service |
|
||||
|
||||
db.update(services)
|
||||
.set({
|
||||
...(input.displayName !== undefined && { displayName: input.displayName }),
|
||||
...(input.displayName !== undefined && {
|
||||
displayName: input.displayName,
|
||||
displayNameEditedManually: input.displayNameEditedManually ?? true,
|
||||
}),
|
||||
...(input.hostname !== undefined && { hostname: input.hostname }),
|
||||
...(input.url !== undefined && { url: input.url }),
|
||||
...(input.https !== undefined && { https: input.https }),
|
||||
...(input.port !== undefined && { port: input.port }),
|
||||
...(input.category !== undefined && { category: input.category }),
|
||||
...(input.category !== undefined && {
|
||||
category: input.category,
|
||||
categoryEditedManually: input.categoryEditedManually ?? true,
|
||||
}),
|
||||
...(input.icon !== undefined && { icon: input.icon }),
|
||||
...(input.favicon !== undefined && { favicon: input.favicon }),
|
||||
...(input.description !== undefined && { description: input.description }),
|
||||
@@ -163,6 +177,14 @@ export interface ScanNameChange {
|
||||
field: "displayName" | "category";
|
||||
current: string | null;
|
||||
suggested: string;
|
||||
/**
|
||||
* true, wenn der aktuell gespeicherte Wert vom Scan-Vorschlag nur deshalb
|
||||
* abweicht, weil der Nutzer ihn zuvor manuell angepasst hat (siehe
|
||||
* displayNameEditedManually/categoryEditedManually). Solche Änderungen sind
|
||||
* erwartbar/harmlos und sollten in der UI klar von echten inhaltlichen
|
||||
* Änderungen getrennt dargestellt werden.
|
||||
*/
|
||||
manualOverride: boolean;
|
||||
}
|
||||
|
||||
export interface ScanUpsertResult {
|
||||
@@ -201,6 +223,10 @@ export function upsertServiceFromScan(input: ServiceScanInput): ScanUpsertResult
|
||||
const timestamp = nowIso();
|
||||
|
||||
if (existing) {
|
||||
// Rohzeile inkl. der *EditedManually-Flags laden, die mapRow() bewusst
|
||||
// nicht nach außen gibt (nur intern für den Vergleich hier relevant).
|
||||
const existingRow = db.select().from(services).where(eq(services.id, existing.id)).get()!;
|
||||
|
||||
db.update(services)
|
||||
.set({
|
||||
favicon: input.favicon ?? existing.favicon,
|
||||
@@ -216,6 +242,7 @@ export function upsertServiceFromScan(input: ServiceScanInput): ScanUpsertResult
|
||||
field: "displayName",
|
||||
current: existing.displayName,
|
||||
suggested: input.suggestedDisplayName,
|
||||
manualOverride: existingRow.displayNameEditedManually,
|
||||
});
|
||||
}
|
||||
if (
|
||||
@@ -227,6 +254,7 @@ export function upsertServiceFromScan(input: ServiceScanInput): ScanUpsertResult
|
||||
field: "category",
|
||||
current: existing.category,
|
||||
suggested: input.suggestedCategory,
|
||||
manualOverride: existingRow.categoryEditedManually,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -42,6 +42,17 @@ export const services = sqliteTable("services", {
|
||||
https: integer("https", { mode: "boolean" }).notNull().default(false),
|
||||
// Ausgeblendete Dienste erscheinen nicht in der Suche, bleiben aber im Adminbereich.
|
||||
visible: integer("visible", { mode: "boolean" }).notNull().default(true),
|
||||
// Wird true, sobald displayName/category einmal manuell über die Admin-UI
|
||||
// gesetzt wurden (siehe updateService). Dient dazu, bei einem erneuten Scan
|
||||
// zu erkennen: weicht der Wert vom Scan-Vorschlag ab, WEIL der Nutzer ihn
|
||||
// manuell angepasst hat (harmlos, nur zur Info) oder weil sich der
|
||||
// tatsächlich erkannte Wert geändert hat (echte Änderung)?
|
||||
displayNameEditedManually: integer("display_name_edited_manually", { mode: "boolean" })
|
||||
.notNull()
|
||||
.default(false),
|
||||
categoryEditedManually: integer("category_edited_manually", { mode: "boolean" })
|
||||
.notNull()
|
||||
.default(false),
|
||||
|
||||
// Bei jedem Scan aktualisierbar
|
||||
port: integer("port").notNull(),
|
||||
|
||||
Reference in New Issue
Block a user