217 lines
8 KiB
TypeScript
217 lines
8 KiB
TypeScript
/**
|
||
* AutomationTemplatesPage
|
||
*
|
||
* Page for managing automation templates (CRUD).
|
||
* Uses FormGeneratorTable for listing and AutomationEditor for editing.
|
||
*/
|
||
|
||
import React, { useState, useMemo, useEffect } from 'react';
|
||
import { useAutomationTemplates, type AutomationTemplate } from '../../hooks/useAutomations';
|
||
import { FormGeneratorTable } from '../../components/FormGenerator/FormGeneratorTable';
|
||
import { AutomationEditor } from '../../components/AutomationEditor';
|
||
import { FaSync, FaPlus, FaFileAlt } from 'react-icons/fa';
|
||
import { useToast } from '../../contexts/ToastContext';
|
||
import styles from '../admin/Admin.module.css';
|
||
|
||
export const AutomationTemplatesPage: React.FC = () => {
|
||
const {
|
||
templates,
|
||
attributes,
|
||
loading,
|
||
error,
|
||
permissions,
|
||
refetch,
|
||
createTemplate,
|
||
updateTemplate,
|
||
deleteTemplate,
|
||
getTemplate,
|
||
} = useAutomationTemplates();
|
||
|
||
const { showSuccess, showError } = useToast();
|
||
|
||
// Editor states
|
||
const [showEditor, setShowEditor] = useState(false);
|
||
const [editingTemplate, setEditingTemplate] = useState<AutomationTemplate | null>(null);
|
||
const [saving, setSaving] = useState(false);
|
||
|
||
// Initial fetch
|
||
useEffect(() => {
|
||
refetch();
|
||
}, []);
|
||
|
||
// Check permissions
|
||
const canCreate = permissions?.create !== 'n';
|
||
const canUpdate = permissions?.update !== 'n';
|
||
const canDelete = permissions?.delete !== 'n';
|
||
|
||
// Table columns - FormGeneratorTable auto-renders TextMultilingual in user language
|
||
const columns = useMemo(() => [
|
||
{ key: 'label', label: 'Label', type: 'string' as const, sortable: true, searchable: true, width: 200 },
|
||
{ key: 'overview', label: 'Beschreibung', type: 'string' as const, width: 300 },
|
||
{ key: '_createdByUserName', label: 'Erstellt von', type: 'string' as const, width: 150 },
|
||
], []);
|
||
|
||
// Handle edit click - open editor with template data
|
||
const handleEditClick = async (template: AutomationTemplate) => {
|
||
// Fetch full template data
|
||
const fullTemplate = await getTemplate(template.id);
|
||
setEditingTemplate(fullTemplate || template);
|
||
setShowEditor(true);
|
||
};
|
||
|
||
// Handle create click - open editor for new template
|
||
const handleCreateClick = () => {
|
||
setEditingTemplate(null);
|
||
setShowEditor(true);
|
||
};
|
||
|
||
// Handle editor save
|
||
const handleEditorSave = async (data: Partial<AutomationTemplate>) => {
|
||
setSaving(true);
|
||
try {
|
||
if (editingTemplate) {
|
||
await updateTemplate(editingTemplate.id, data);
|
||
showSuccess('Vorlage aktualisiert');
|
||
} else {
|
||
await createTemplate(data as any);
|
||
showSuccess('Vorlage erstellt');
|
||
}
|
||
setShowEditor(false);
|
||
setEditingTemplate(null);
|
||
await refetch();
|
||
} catch (err: any) {
|
||
showError(`Fehler: ${err.message}`);
|
||
} finally {
|
||
setSaving(false);
|
||
}
|
||
};
|
||
|
||
// Handle editor cancel
|
||
const handleEditorCancel = () => {
|
||
setShowEditor(false);
|
||
setEditingTemplate(null);
|
||
};
|
||
|
||
// Handle delete by ID (used by DeleteActionButton via hookData)
|
||
const handleDelete = async (templateId: string): Promise<boolean> => {
|
||
try {
|
||
await deleteTemplate(templateId);
|
||
showSuccess('Vorlage gelöscht');
|
||
return true;
|
||
} catch (err: any) {
|
||
showError(`Fehler: ${err.message}`);
|
||
return false;
|
||
}
|
||
};
|
||
|
||
if (error) {
|
||
return (
|
||
<div className={styles.adminPage}>
|
||
<div className={styles.errorContainer}>
|
||
<span className={styles.errorIcon}>⚠️</span>
|
||
<p className={styles.errorMessage}>Fehler beim Laden der Vorlagen: {error}</p>
|
||
<button className={styles.secondaryButton} onClick={() => refetch()}>
|
||
<FaSync /> Erneut versuchen
|
||
</button>
|
||
</div>
|
||
</div>
|
||
);
|
||
}
|
||
|
||
return (
|
||
<div className={styles.adminPage}>
|
||
<div className={styles.pageHeader}>
|
||
<div>
|
||
<h1 className={styles.pageTitle}>Automation-Vorlagen</h1>
|
||
<p className={styles.pageSubtitle}>Verwalten Sie Ihre Workflow-Vorlagen</p>
|
||
</div>
|
||
<div className={styles.headerActions}>
|
||
<button
|
||
className={styles.secondaryButton}
|
||
onClick={() => refetch()}
|
||
disabled={loading}
|
||
>
|
||
<FaSync className={loading ? 'spinning' : ''} /> Aktualisieren
|
||
</button>
|
||
{canCreate && (
|
||
<button
|
||
className={styles.primaryButton}
|
||
onClick={handleCreateClick}
|
||
>
|
||
<FaPlus /> Neue Vorlage
|
||
</button>
|
||
)}
|
||
</div>
|
||
</div>
|
||
|
||
<div className={styles.tableContainer}>
|
||
{loading && (!templates || templates.length === 0) ? (
|
||
<div className={styles.loadingContainer}>
|
||
<div className={styles.spinner} />
|
||
<span>Lade Vorlagen...</span>
|
||
</div>
|
||
) : !templates || templates.length === 0 ? (
|
||
<div className={styles.emptyState}>
|
||
<FaFileAlt className={styles.emptyIcon} />
|
||
<h3 className={styles.emptyTitle}>Keine Vorlagen vorhanden</h3>
|
||
<p className={styles.emptyDescription}>
|
||
Erstellen Sie eine neue Vorlage für Ihre Workflows.
|
||
</p>
|
||
{canCreate && (
|
||
<button
|
||
className={styles.primaryButton}
|
||
onClick={handleCreateClick}
|
||
>
|
||
<FaPlus /> Vorlage erstellen
|
||
</button>
|
||
)}
|
||
</div>
|
||
) : (
|
||
<FormGeneratorTable
|
||
data={templates as any[]}
|
||
columns={columns}
|
||
apiEndpoint="/api/automation-templates"
|
||
loading={loading}
|
||
pagination={true}
|
||
pageSize={25}
|
||
searchable={true}
|
||
filterable={true}
|
||
sortable={true}
|
||
selectable={false}
|
||
actionButtons={[
|
||
...(canUpdate ? [{
|
||
type: 'edit' as const,
|
||
onAction: handleEditClick,
|
||
title: 'Bearbeiten',
|
||
}] : []),
|
||
...(canDelete ? [{
|
||
type: 'delete' as const,
|
||
title: 'Löschen',
|
||
}] : []),
|
||
]}
|
||
onDelete={(template) => handleDelete(template.id)}
|
||
hookData={{
|
||
refetch,
|
||
handleDelete,
|
||
attributes,
|
||
}}
|
||
emptyMessage="Keine Vorlagen gefunden"
|
||
/>
|
||
)}
|
||
</div>
|
||
|
||
{/* Automation Editor */}
|
||
{showEditor && (
|
||
<AutomationEditor
|
||
mode="template"
|
||
initialData={editingTemplate}
|
||
onSave={handleEditorSave}
|
||
onCancel={handleEditorCancel}
|
||
saving={saving}
|
||
/>
|
||
)}
|
||
</div>
|
||
);
|
||
};
|
||
|
||
export default AutomationTemplatesPage;
|