Reset-Button, Service-Reorder, Port/HTTPS-Spalten, Healthcheck in Sidebar, Kategorien-Sync

This commit is contained in:
2026-07-19 15:14:44 +02:00
parent 20ea4d382d
commit fc1ea4fa70
16 changed files with 447 additions and 20 deletions

View File

@@ -49,6 +49,17 @@ export const ServiceUpdateSchema = ServiceCreateSchema.omit({
}).partial();
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"),
});

View File

@@ -0,0 +1,47 @@
import type { Service } from "@launchpad/shared";
export interface FavoritesBarProps {
services: Service[];
onOpen: (service: Service) => void;
}
/**
* Zeigt Favoriten als anklickbare Chips immer sichtbar, unabhängig vom
* Suchfeld. Reihenfolge folgt service.order (im Adminbereich per Drag & Drop
* änderbar).
*/
export function FavoritesBar({ services, onOpen }: FavoritesBarProps) {
if (services.length === 0) return null;
return (
<div
role="toolbar"
aria-label="Favoriten"
className="flex flex-wrap items-center justify-center gap-2"
>
{services.map((service) => (
<button
key={service.id}
type="button"
onClick={() => onOpen(service)}
title={`${service.displayName} (${service.hostname}:${service.port})`}
className="flex items-center gap-2 rounded-full border border-black/10 bg-white/70
px-3 py-1.5 text-sm text-black transition-colors hover:bg-black/5
dark:border-white/10 dark:bg-white/5 dark:text-white dark:hover:bg-white/10"
>
{service.favicon ? (
<img src={service.favicon} alt="" className="h-4 w-4 shrink-0 rounded" />
) : (
<span
className="flex h-4 w-4 shrink-0 items-center justify-center rounded-full
bg-black/10 text-[9px] font-medium text-black/50 dark:bg-white/10 dark:text-white/50"
>
{service.displayName.charAt(0).toUpperCase()}
</span>
)}
<span className="max-w-[10rem] truncate">{service.displayName}</span>
</button>
))}
</div>
);
}

View File

@@ -9,3 +9,6 @@ export type { ResultsListProps } from "./ResultsList.js";
export { Button } from "./Button.js";
export type { ButtonProps } from "./Button.js";
export { FavoritesBar } from "./FavoritesBar.js";
export type { FavoritesBarProps } from "./FavoritesBar.js";