feat(260924-i8v): Titel und Serverauswahl der Proxmox-Kachel an der Kachel und in den Einstellungen
- ProxmoxServerPicker gemeinsam fuer Kachel und Einstellungsformular - Bearbeitungsmodus: entprelltes Titelfeld, Server auswaehlen statt Liste, sofort gespeichert - ProxmoxWidgetConfigForm unter Einstellungen > Dashboard, Titel-Zusatz in der Kopfzeile Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,81 @@
|
||||
'use client';
|
||||
|
||||
import { useTranslations } from 'next-intl';
|
||||
import { type ReactNode, useEffect, useState } from 'react';
|
||||
import { resolveProxmoxWidgetConfig } from '@/components/dashboard/widgets/proxmox-widget-model';
|
||||
import { ProxmoxServerPicker } from '@/components/proxmox/proxmox-server-picker';
|
||||
// T-I8V-02: nur die Leseabfrage des Zwischenlagers, nie die manuelle Abfrage.
|
||||
import { listServers, type ProxmoxServer } from '@/lib/proxmox-api';
|
||||
|
||||
interface ProxmoxWidgetConfigFormProps {
|
||||
config: Record<string, unknown>;
|
||||
onChange: (cfg: Record<string, unknown>) => void;
|
||||
}
|
||||
|
||||
/**
|
||||
* Einstellungen der Proxmox-Kachel unter Einstellungen > Dashboard
|
||||
* (quick-260924-i8v): Titel und Serverauswahl. Laedt die Serverliste einmal;
|
||||
* dieselbe Auswahl gibt es an der Kachel im Bearbeitungsmodus (dort auch
|
||||
* fuer Kacheln auf weiteren Reitern, die diese Seite nicht zeigt).
|
||||
*/
|
||||
export function ProxmoxWidgetConfigForm({ config, onChange }: ProxmoxWidgetConfigFormProps) {
|
||||
const t = useTranslations('widgets');
|
||||
const tp = useTranslations('proxmox');
|
||||
const { title: rawTitle, serverIds } = resolveProxmoxWidgetConfig(config);
|
||||
// Anzeige getrimmt (Leerraum-Titel sind fachlich „kein Titel“), gesendet
|
||||
// wird der rohe Tippwert — Muster FavoritesConfig.
|
||||
const title = rawTitle.trim() === '' ? '' : rawTitle;
|
||||
|
||||
const [servers, setServers] = useState<ProxmoxServer[] | null>(null);
|
||||
const [loadFailed, setLoadFailed] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
let cancelled = false;
|
||||
listServers()
|
||||
.then((list) => {
|
||||
if (!cancelled) setServers(list);
|
||||
})
|
||||
.catch(() => {
|
||||
if (!cancelled) setLoadFailed(true);
|
||||
});
|
||||
return () => {
|
||||
cancelled = true;
|
||||
};
|
||||
}, []);
|
||||
|
||||
let serverPart: ReactNode;
|
||||
if (loadFailed) {
|
||||
serverPart = <p className="text-sm text-muted-foreground">{tp('loadError')}</p>;
|
||||
} else if (servers === null) {
|
||||
serverPart = <p className="text-sm text-muted-foreground">{tp('loading')}</p>;
|
||||
} else if (servers.length === 0) {
|
||||
serverPart = <p className="text-sm text-muted-foreground">{t('proxmox.empty')}</p>;
|
||||
} else {
|
||||
serverPart = (
|
||||
<ProxmoxServerPicker
|
||||
servers={servers}
|
||||
selectedIds={serverIds}
|
||||
onChange={(next) => onChange({ serverIds: next })}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
<div>
|
||||
<label htmlFor="proxmox-widget-title" className="mb-1 block text-sm text-foreground">
|
||||
{t('proxmox.titleLabel')}
|
||||
</label>
|
||||
<input
|
||||
id="proxmox-widget-title"
|
||||
type="text"
|
||||
className="h-9 w-full max-w-xs rounded border border-border bg-background px-3 text-sm text-foreground"
|
||||
value={title}
|
||||
placeholder={t('proxmox.titlePlaceholder')}
|
||||
onChange={(e) => onChange({ title: e.target.value })}
|
||||
/>
|
||||
</div>
|
||||
{serverPart}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -5,6 +5,7 @@ import { useTranslations } from 'next-intl';
|
||||
import Link from 'next/link';
|
||||
import { WIDGET_REGISTRY, type WidgetType } from '@/components/dashboard/widget-registry';
|
||||
import { PictureFrameConfigForm } from '@/components/settings/picture-frame-config-form';
|
||||
import { ProxmoxWidgetConfigForm } from '@/components/settings/proxmox-widget-config-form';
|
||||
import { SearchProviderForm } from '@/components/settings/search-provider-form';
|
||||
import { XframeConfigForm } from '@/components/settings/xframe-config-form';
|
||||
import { updateWidgetConfig } from '@/lib/dashboard-api';
|
||||
@@ -122,7 +123,8 @@ export function WidgetSettingsPanel({
|
||||
{t(def.nameKey)} #{idx + 1}
|
||||
{(widget.widgetType === 'note' ||
|
||||
widget.widgetType === 'favorites' ||
|
||||
widget.widgetType === 'xframe') &&
|
||||
widget.widgetType === 'xframe' ||
|
||||
widget.widgetType === 'proxmox') &&
|
||||
typeof widget.config.title === 'string' &&
|
||||
widget.config.title.trim() !== '' && (
|
||||
<span className="ml-2 text-muted-foreground">
|
||||
@@ -232,6 +234,16 @@ export function WidgetSettingsPanel({
|
||||
}
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* Proxmox: Titel und Serverauswahl (quick-260924-i8v) */}
|
||||
{widget.widgetType === 'proxmox' && (
|
||||
<ProxmoxWidgetConfigForm
|
||||
config={widget.config}
|
||||
onChange={(cfg) =>
|
||||
handleConfigChange(widget.id, cfg)
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user