generated from Dicken/dickendock
139 lines
5.1 KiB
TypeScript
139 lines
5.1 KiB
TypeScript
import { z } from "zod";
|
|
|
|
export const deviceSourceValues = [
|
|
"fritzbox",
|
|
"dns",
|
|
"http",
|
|
"https",
|
|
"portscan",
|
|
"manual",
|
|
"plugin",
|
|
] as const;
|
|
|
|
export const DeviceSourceSchema = z.enum(deviceSourceValues);
|
|
|
|
export const DeviceCreateSchema = z.object({
|
|
hostname: z.string().min(1, "hostname darf nicht leer sein"),
|
|
ip: z.string().min(1, "ip darf nicht leer sein"),
|
|
mac: z.string().optional(),
|
|
manufacturer: z.string().optional(),
|
|
model: z.string().optional(),
|
|
online: z.boolean().optional(),
|
|
source: DeviceSourceSchema.optional(),
|
|
});
|
|
export type DeviceCreateInput = z.infer<typeof DeviceCreateSchema>;
|
|
|
|
export const DeviceUpdateSchema = DeviceCreateSchema.partial();
|
|
export type DeviceUpdateInput = z.infer<typeof DeviceUpdateSchema>;
|
|
|
|
export const ServiceCreateSchema = z.object({
|
|
deviceId: z.string().min(1, "deviceId darf nicht leer sein"),
|
|
displayName: z.string().min(1, "displayName darf nicht leer sein"),
|
|
hostname: z.string().min(1, "hostname darf nicht leer sein"),
|
|
url: z.string().url("url muss eine gültige URL sein"),
|
|
https: z.boolean().optional(),
|
|
port: z.number().int().min(1).max(65535),
|
|
category: z.string().optional(),
|
|
icon: z.string().optional(),
|
|
favicon: z.string().optional(),
|
|
description: z.string().optional(),
|
|
favorite: z.boolean().optional(),
|
|
alias: z.array(z.string()).optional(),
|
|
order: z.number().optional(),
|
|
visible: z.boolean().optional(),
|
|
});
|
|
export type ServiceCreateInput = z.infer<typeof ServiceCreateSchema>;
|
|
|
|
export const ServiceUpdateSchema = ServiceCreateSchema.omit({
|
|
deviceId: true,
|
|
})
|
|
.partial()
|
|
.extend({
|
|
// Frontend schickt beim Leeren eines Felds bewusst null (nicht nur
|
|
// "Feld weglassen") - .partial() allein akzeptiert dafür nur
|
|
// string|undefined, ein PATCH mit category:null schlug daher bisher mit
|
|
// 400 fehl, ohne dass das Formular das sichtbar gemacht hätte.
|
|
category: z.string().nullable().optional(),
|
|
description: z.string().nullable().optional(),
|
|
icon: z.string().nullable().optional(),
|
|
favicon: z.string().nullable().optional(),
|
|
// Standardmäßig markiert ein PATCH mit displayName/category den jeweiligen
|
|
// Wert als "manuell bearbeitet" (siehe updateService-Doku in
|
|
// repositories/services.ts). Wird explizit false mitgeschickt - z. B. beim
|
|
// Übernehmen eines Scan-Vorschlags in der Änderungsübersicht -, bleibt der
|
|
// Wert stattdessen als "vom Scan" markiert.
|
|
displayNameEditedManually: z.boolean().optional(),
|
|
categoryEditedManually: z.boolean().optional(),
|
|
});
|
|
export type ServiceUpdateInput = z.infer<typeof ServiceUpdateSchema>;
|
|
|
|
/** Für Drag & Drop: neue Reihenfolge mehrerer Dienste auf einmal setzen. */
|
|
export const ServiceReorderSchema = z
|
|
.array(
|
|
z.object({
|
|
id: z.string().min(1),
|
|
order: z.number(),
|
|
})
|
|
)
|
|
.min(1, "mindestens ein Eintrag erforderlich");
|
|
export type ServiceReorderInput = z.infer<typeof ServiceReorderSchema>;
|
|
|
|
export const CategoryCreateSchema = z.object({
|
|
name: z.string().min(1, "name darf nicht leer sein"),
|
|
color: z
|
|
.string()
|
|
.regex(/^#[0-9a-fA-F]{6}$/, "Farbe muss ein Hex-Code sein, z. B. #3b82f6")
|
|
.optional(),
|
|
});
|
|
export type CategoryCreateInput = z.infer<typeof CategoryCreateSchema>;
|
|
|
|
export const CategoryUpdateSchema = CategoryCreateSchema.partial();
|
|
export type CategoryUpdateInput = z.infer<typeof CategoryUpdateSchema>;
|
|
|
|
/** Für Drag & Drop: neue Reihenfolge mehrerer Kategorien auf einmal setzen. */
|
|
export const CategoryReorderSchema = z
|
|
.array(
|
|
z.object({
|
|
id: z.string().min(1),
|
|
order: z.number(),
|
|
})
|
|
)
|
|
.min(1, "mindestens ein Eintrag erforderlich");
|
|
export type CategoryReorderInput = z.infer<typeof CategoryReorderSchema>;
|
|
|
|
export const BookmarkCreateSchema = z.object({
|
|
url: z.string().url("url muss eine gültige URL sein"),
|
|
// Optional: wird nicht angegeben, versucht das Backend automatisch den
|
|
// Seitentitel zu lesen (siehe apps/backend/src/routes/bookmarks.ts).
|
|
displayName: z.string().min(1).optional(),
|
|
description: z.string().optional(),
|
|
category: z.string().optional(),
|
|
icon: z.string().optional(),
|
|
favicon: z.string().optional(),
|
|
favorite: z.boolean().optional(),
|
|
alias: z.array(z.string()).optional(),
|
|
order: z.number().optional(),
|
|
});
|
|
export type BookmarkCreateInput = z.infer<typeof BookmarkCreateSchema>;
|
|
|
|
export const BookmarkUpdateSchema = BookmarkCreateSchema.partial().extend({
|
|
// Siehe Kommentar bei ServiceUpdateSchema: null muss erlaubt sein, damit
|
|
// sich Kategorie/Beschreibung/Icons im Bearbeiten-Formular leeren lassen.
|
|
category: z.string().nullable().optional(),
|
|
description: z.string().nullable().optional(),
|
|
icon: z.string().nullable().optional(),
|
|
favicon: z.string().nullable().optional(),
|
|
});
|
|
export type BookmarkUpdateInput = z.infer<typeof BookmarkUpdateSchema>;
|
|
|
|
/** Für Drag & Drop: neue Reihenfolge mehrerer Lesezeichen auf einmal setzen. */
|
|
export const BookmarkReorderSchema = z
|
|
.array(
|
|
z.object({
|
|
id: z.string().min(1),
|
|
order: z.number(),
|
|
})
|
|
)
|
|
.min(1, "mindestens ein Eintrag erforderlich");
|
|
export type BookmarkReorderInput = z.infer<typeof BookmarkReorderSchema>;
|