/** * AdminDemoConfigPage * * SysAdmin page for managing demo configurations. * Lists available demo configs with Load / Remove actions. */ import React, { useState, useEffect, useCallback } from 'react'; import { FaPlay, FaTrash, FaSync, FaCubes } from 'react-icons/fa'; import api from '../../api'; import styles from './Admin.module.css'; import demoStyles from './AdminDemoConfigPage.module.css'; import { useLanguage } from '../../providers/language/LanguageContext'; import { useConfirm } from '../../hooks/useConfirm'; interface _DemoConfig { code: string; label: string; description: string; } interface _ActionResult { code: string; action: 'load' | 'remove'; status: 'ok' | 'error'; summary?: Record; error?: string; } export const AdminDemoConfigPage: React.FC = () => { const { t } = useLanguage(); const { confirm, ConfirmDialog } = useConfirm(); const [configs, setConfigs] = useState<_DemoConfig[]>([]); const [loading, setLoading] = useState(false); const [actionInProgress, setActionInProgress] = useState(null); const [lastResult, setLastResult] = useState<_ActionResult | null>(null); const [error, setError] = useState(null); const _fetchConfigs = useCallback(async () => { try { setLoading(true); setError(null); const response = await api.get('/api/admin/demo-config'); setConfigs(response.data.configs || []); } catch (err: any) { setError(err.response?.data?.detail || t('Error loading demo configs')); } finally { setLoading(false); } }, [t]); useEffect(() => { _fetchConfigs(); }, [_fetchConfigs]); const _handleLoad = async (code: string) => { if (actionInProgress) return; setActionInProgress(code); setLastResult(null); try { const response = await api.post(`/api/admin/demo-config/${code}/load`); setLastResult({ code, action: 'load', status: 'ok', summary: response.data.summary }); } catch (err: any) { setLastResult({ code, action: 'load', status: 'error', error: err.response?.data?.detail || String(err) }); } finally { setActionInProgress(null); } }; const _handleRemove = async (code: string) => { if (actionInProgress) return; const ok = await confirm( t('Alle Demo-Daten für diese Konfiguration wirklich entfernen?'), { confirmLabel: t('Entfernen'), cancelLabel: t('Abbrechen'), variant: 'danger' }, ); if (!ok) return; setActionInProgress(code); setLastResult(null); try { const response = await api.post(`/api/admin/demo-config/${code}/remove`); setLastResult({ code, action: 'remove', status: 'ok', summary: response.data.summary }); } catch (err: any) { setLastResult({ code, action: 'remove', status: 'error', error: err.response?.data?.detail || String(err) }); } finally { setActionInProgress(null); } }; return (

{t('Demo-Konfigurationen')}

{t('Demo-Umgebungen für Präsentationen und Tests laden oder entfernen.')}

{error &&
{error}
} {lastResult && (
{lastResult.action === 'load' ? t('Geladen') : t('Entfernt')}:{' '} {lastResult.status === 'ok' ? ( <_SummaryDisplay summary={lastResult.summary} /> ) : ( {lastResult.error} )}
)} {loading && configs.length === 0 ? (
{t('Lade…')}
) : configs.length === 0 ? (
{t('Keine Demo-Konfigurationen gefunden.')}
) : (
{configs.map((cfg) => (

{cfg.label}

{cfg.description}

{cfg.code}
))}
)}
); }; const _SummaryDisplay: React.FC<{ summary?: Record }> = ({ summary }) => { const { t } = useLanguage(); if (!summary) return null; const sections = Object.entries(summary).filter(([, v]) => Array.isArray(v) && (v as unknown[]).length > 0); if (sections.length === 0) return {t('Abgeschlossen (keine Änderungen)')}; return ( {sections.map(([key, items]) => ( {key}: {(items as string[]).length} ))} ); };