/** * ActionsPanel * * Displays available workflow actions for copy/paste into templates. * Groups actions by method and shows parameters + example JSON. */ import React, { useState, useMemo, useEffect } from 'react'; import { useWorkflowActions, type WorkflowAction } from '../../hooks/useAutomations'; import { FaSearch, FaCopy, FaChevronDown, FaChevronRight, FaCheck } from 'react-icons/fa'; import { useToast } from '../../contexts/ToastContext'; import styles from './ActionsPanel.module.css'; interface ActionsPanelProps { /** Callback when action JSON is inserted (optional) */ onInsert?: (actionJson: string) => void; /** Callback when action JSON is copied (optional) */ onCopy?: (actionJson: string) => void; } export const ActionsPanel: React.FC = ({ onInsert, onCopy }) => { const { actions, loading, error, fetchActions } = useWorkflowActions(); const { showSuccess } = useToast(); const [filter, setFilter] = useState(''); const [expandedMethods, setExpandedMethods] = useState>(new Set()); const [expandedAction, setExpandedAction] = useState(null); const [copiedAction, setCopiedAction] = useState(null); useEffect(() => { fetchActions(); }, [fetchActions]); // Filter actions by search term const filteredActions = useMemo(() => { if (!filter) return actions; const lower = filter.toLowerCase(); return actions.filter(a => a.method.toLowerCase().includes(lower) || a.action.toLowerCase().includes(lower) || a.description.toLowerCase().includes(lower) || a.actionId.toLowerCase().includes(lower) ); }, [actions, filter]); // Group actions by method const groupedActions = useMemo(() => { const groups: Record = {}; filteredActions.forEach(action => { if (!groups[action.method]) { groups[action.method] = []; } groups[action.method].push(action); }); return groups; }, [filteredActions]); // Toggle method expansion const toggleMethod = (method: string) => { setExpandedMethods(prev => { const newSet = new Set(prev); if (newSet.has(method)) { newSet.delete(method); } else { newSet.add(method); } return newSet; }); }; // Toggle action details const toggleAction = (actionId: string) => { setExpandedAction(prev => prev === actionId ? null : actionId); }; // Copy action JSON to clipboard const handleCopy = async (action: WorkflowAction) => { const json = JSON.stringify(action.exampleJson, null, 2); try { await navigator.clipboard.writeText(json); setCopiedAction(action.actionId); setTimeout(() => setCopiedAction(null), 2000); showSuccess('JSON kopiert'); onCopy?.(json); } catch (err) { console.error('Failed to copy:', err); } }; // Insert action JSON const handleInsert = (action: WorkflowAction) => { const json = JSON.stringify(action.exampleJson, null, 2); onInsert?.(json); }; if (loading) { return (
Lade Actions...
); } if (error) { return (
Fehler: {error}
); } return (

Verfügbare Actions

setFilter(e.target.value)} className={styles.searchInput} />
{Object.keys(groupedActions).length === 0 ? (
Keine Actions gefunden
) : ( Object.entries(groupedActions).map(([method, methodActions]) => (
{expandedMethods.has(method) && (
{methodActions.map(action => (
toggleAction(action.actionId)} >
{action.action} {action.description}
{expandedAction === action.actionId && (
{action.parameters.length > 0 && (
Parameter:
    {action.parameters.map(param => (
  • {param.name} {param.required && *} {param.type} {param.description && ( {param.description} )}
  • ))}
)}
Beispiel JSON:
{JSON.stringify(action.exampleJson, null, 2)}
{onInsert && ( )}
)}
))}
)}
)) )}
); }; export default ActionsPanel;