feat(260924-i8v): Proxmox-Kachel als Durchstich mit Balken und Zusammenfassung

- Typ proxmox am Ende von WIDGET_TYPES, WIDGET_MODULE_SLUGS = { proxmox: 'proxmox' }
- gemeinsame Statusteile (proxmox-status, HealthBar, status-styles) nach components/proxmox/
- HealthBar variant compact: 6 px, ohne Legende, aria-hidden
- Registry 3/4/8/8, Katalog-/Registry-/API-Tests auf die erste Modul-Kachel umgestellt
- ProxmoxWidget liest nur listServers, zeigt Lade-, Leer-, Fehlerzustand

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-09-24 13:24:51 +02:00
parent 8bfa4fc467
commit a906c6705d
19 changed files with 556 additions and 69 deletions
@@ -29,6 +29,8 @@ const ALL_WIDGET_TYPES: WidgetType[] = [
'picture-frame',
// XFrame (quick-260921-qd3)
'xframe',
// Proxmox — erste Modul-Kachel (quick-260924-i8v)
'proxmox',
];
describe('WIDGET_CONSTRAINTS (DASH-11)', () => {
@@ -64,7 +66,7 @@ describe('WIDGET_CONSTRAINTS (DASH-11)', () => {
expect(Object.keys(WIDGET_CONSTRAINTS)).toContain('stopwatch');
});
it('Test A (quick-260916-dyv): Minima = kleinste bedienbare Kachel je Typ, Vorgaben unveraendert (quick-260916-iex: Link-Widget entfernt; quick-260921-pi9: Bilderrahmen dazu; quick-260921-qd3: XFrame dazu, neun Typen)', () => {
it('Test A (quick-260916-dyv): Minima = kleinste bedienbare Kachel je Typ, Vorgaben unveraendert (quick-260916-iex: Link-Widget entfernt; quick-260921-pi9: Bilderrahmen dazu; quick-260921-qd3: XFrame dazu; quick-260924-i8v: Proxmox dazu, zehn Typen)', () => {
// Raster 24 Spalten / 20 px (quick-260916-bwo). Die Minima sind seit
// quick-260916-dyv inhaltsgetrieben (Rechnung im Plan), die Vorgaben
// (defaultW/defaultH) bleiben das Doppelte der alten 12-Spalten-Werte.
@@ -79,6 +81,7 @@ describe('WIDGET_CONSTRAINTS (DASH-11)', () => {
stopwatch: { minW: 4, minH: 3, defaultW: 6, defaultH: 6 },
'picture-frame': { minW: 4, minH: 4, defaultW: 8, defaultH: 12 },
xframe: { minW: 4, minH: 4, defaultW: 12, defaultH: 12 },
proxmox: { minW: 3, minH: 4, defaultW: 8, defaultH: 8 },
});
let counted = 0;
@@ -88,7 +91,7 @@ describe('WIDGET_CONSTRAINTS (DASH-11)', () => {
counted++;
}
}
expect(counted).toBe(36);
expect(counted).toBe(40);
});
});
@@ -104,7 +107,7 @@ describe('Typliste ist an einer Stelle definiert (quick-260922-m1h)', () => {
expect(Object.keys(WIDGET_CONSTRAINTS)).toEqual([...WIDGET_TYPES]);
});
it('die neun erwarteten Kacheln stehen unveraendert und in unveraenderter Reihenfolge in WIDGET_TYPES', () => {
it('die zehn erwarteten Kacheln stehen unveraendert und in unveraenderter Reihenfolge in WIDGET_TYPES', () => {
expect([...WIDGET_TYPES]).toEqual(ALL_WIDGET_TYPES);
});
@@ -114,9 +117,13 @@ describe('Typliste ist an einer Stelle definiert (quick-260922-m1h)', () => {
}
});
it('heute traegt keine der neun Kacheln einen moduleSlug (alle sind Plattform-Kacheln)', () => {
it("nur proxmox traegt moduleSlug 'proxmox', alle anderen Kacheln keinen (quick-260924-i8v)", () => {
for (const type of WIDGET_TYPES) {
expect(WIDGET_REGISTRY[type].moduleSlug).toBeUndefined();
if (type === 'proxmox') {
expect(WIDGET_REGISTRY[type].moduleSlug).toBe('proxmox');
} else {
expect(WIDGET_REGISTRY[type].moduleSlug).toBeUndefined();
}
}
});
});
@@ -154,15 +161,15 @@ describe('registerWidget (quick-260922-m1h)', () => {
expect(() =>
// Absichtlich ein Typ ausserhalb der Union — genau der Fall, den der
// Wurf melden soll (eine Kachel, die in WIDGET_TYPES vergessen wurde).
registerWidget('proxmox' as WidgetType, makeComponent()),
).toThrow(/proxmox/);
registerWidget('gibt-es-nicht' as WidgetType, makeComponent()),
).toThrow(/gibt-es-nicht/);
});
it('ein unbekannter Typ wird in der Produktion still ignoriert', () => {
const previous = process.env.NODE_ENV;
vi.stubEnv('NODE_ENV', 'production');
expect(() => registerWidget('proxmox' as WidgetType, makeComponent())).not.toThrow();
expect(() => registerWidget('gibt-es-nicht' as WidgetType, makeComponent())).not.toThrow();
vi.stubEnv('NODE_ENV', previous ?? 'test');
vi.unstubAllEnvs();
@@ -182,8 +189,14 @@ describe('visibleWidgetTypes (quick-260922-m1h)', () => {
note: {},
};
it('behaelt die Reihenfolge der Registry bei', () => {
expect(visibleWidgetTypes(WIDGET_REGISTRY, [])).toEqual([...WIDGET_TYPES]);
it('behaelt die Reihenfolge der Registry bei; ohne Modulzugriff fehlt nur Proxmox', () => {
expect(visibleWidgetTypes(WIDGET_REGISTRY, [])).toEqual(
WIDGET_TYPES.filter((type) => type !== 'proxmox'),
);
});
it("mit Zugriff auf 'proxmox' erscheinen alle zehn Kacheln in WIDGET_TYPES-Reihenfolge (quick-260924-i8v)", () => {
expect(visibleWidgetTypes(WIDGET_REGISTRY, ['proxmox'])).toEqual([...WIDGET_TYPES]);
});
it('Kacheln ohne moduleSlug sind immer sichtbar', () => {