/** * Zammad Plugin Settings Component * Configuration interface for Zammad plugin */ import React, { useState, useEffect } from 'react'; import { Box, Card, CardContent, Typography, TextField, Button, Switch, FormControlLabel, FormGroup, Select, MenuItem, FormControl, InputLabel, Alert, Divider, Accordion, AccordionSummary, AccordionDetails, Chip, LinearProgress } from '@mui/material'; import { ExpandMore as ExpandMoreIcon, Save as SaveIcon, TestTube as TestIcon, Security as SecurityIcon, Sync as SyncIcon, Smart as AIIcon } from '@mui/icons-material'; interface ZammadConfig { name: string; zammad_url: string; api_token: string; chatbot_id: string; ai_summarization: { enabled: boolean; model: string; max_tokens: number; auto_summarize: boolean; }; sync_settings: { enabled: boolean; interval_hours: number; sync_articles: boolean; max_tickets_per_sync: number; }; webhook_settings: { secret: string; enabled_events: string[]; }; notification_settings: { email_notifications: boolean; slack_webhook_url: string; notification_events: string[]; }; } const defaultConfig: ZammadConfig = { name: '', zammad_url: '', api_token: '', chatbot_id: '', ai_summarization: { enabled: true, model: 'gpt-3.5-turbo', max_tokens: 150, auto_summarize: true }, sync_settings: { enabled: true, interval_hours: 2, sync_articles: true, max_tickets_per_sync: 100 }, webhook_settings: { secret: '', enabled_events: ['ticket.create', 'ticket.update'] }, notification_settings: { email_notifications: false, slack_webhook_url: '', notification_events: ['sync_error', 'api_error'] } }; export const ZammadSettings: React.FC = () => { const [config, setConfig] = useState(defaultConfig); const [loading, setLoading] = useState(false); const [saving, setSaving] = useState(false); const [testing, setTesting] = useState(false); const [error, setError] = useState(null); const [success, setSuccess] = useState(null); const [testResult, setTestResult] = useState(null); useEffect(() => { loadConfiguration(); }, []); const loadConfiguration = async () => { setLoading(true); try { const response = await fetch('/api/v1/plugins/zammad/configurations'); if (response.ok) { const data = await response.json(); if (data.configurations.length > 0) { // Load the first (active) configuration const loadedConfig = data.configurations[0]; setConfig({ ...defaultConfig, ...loadedConfig }); } } } catch (err) { setError('Failed to load configuration'); } finally { setLoading(false); } }; const handleConfigChange = (path: string, value: any) => { setConfig(prev => { const newConfig = { ...prev }; const keys = path.split('.'); let current: any = newConfig; for (let i = 0; i < keys.length - 1; i++) { current = current[keys[i]]; } current[keys[keys.length - 1]] = value; return newConfig; }); }; const handleTestConnection = async () => { setTesting(true); setTestResult(null); setError(null); try { const response = await fetch('/api/v1/plugins/zammad/configurations/test', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ zammad_url: config.zammad_url, api_token: config.api_token }) }); const result = await response.json(); setTestResult(result); if (!result.success) { setError(`Connection test failed: ${result.error}`); } } catch (err) { setError('Connection test failed'); } finally { setTesting(false); } }; const handleSaveConfiguration = async () => { setSaving(true); setError(null); setSuccess(null); try { const response = await fetch('/api/v1/plugins/zammad/configurations', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(config) }); if (response.ok) { setSuccess('Configuration saved successfully'); } else { const errorData = await response.json(); setError(errorData.detail || 'Failed to save configuration'); } } catch (err) { setError('Failed to save configuration'); } finally { setSaving(false); } }; const handleArrayToggle = (path: string, value: string) => { const currentArray = path.split('.').reduce((obj, key) => obj[key], config) as string[]; const newArray = currentArray.includes(value) ? currentArray.filter(item => item !== value) : [...currentArray, value]; handleConfigChange(path, newArray); }; if (loading) { return ( Zammad Settings ); } return ( Zammad Settings {error && ( {error} )} {success && ( {success} )} {testResult && ( {testResult.success ? `Connection successful! User: ${testResult.user}, Version: ${testResult.zammad_version}` : `Connection failed: ${testResult.error}` } )} {/* Basic Configuration */} Basic Configuration handleConfigChange('name', e.target.value)} fullWidth required /> handleConfigChange('zammad_url', e.target.value)} fullWidth required placeholder="https://company.zammad.com" /> handleConfigChange('api_token', e.target.value)} fullWidth required helperText="Zammad API token with ticket read/write permissions" /> handleConfigChange('chatbot_id', e.target.value)} fullWidth required helperText="Platform chatbot ID for AI summarization" /> {/* AI Summarization Settings */} }> AI Summarization handleConfigChange('ai_summarization.enabled', e.target.checked)} /> } label="Enable AI Summarization" /> AI Model handleConfigChange('ai_summarization.max_tokens', parseInt(e.target.value))} inputProps={{ min: 50, max: 500 }} /> handleConfigChange('ai_summarization.auto_summarize', e.target.checked)} /> } label="Auto-summarize New Tickets" /> {/* Sync Settings */} }> Sync Settings handleConfigChange('sync_settings.enabled', e.target.checked)} /> } label="Enable Automatic Sync" /> handleConfigChange('sync_settings.interval_hours', parseInt(e.target.value))} inputProps={{ min: 1, max: 24 }} /> handleConfigChange('sync_settings.sync_articles', e.target.checked)} /> } label="Sync Ticket Articles" /> handleConfigChange('sync_settings.max_tickets_per_sync', parseInt(e.target.value))} inputProps={{ min: 10, max: 1000 }} /> {/* Webhook Settings */} }> Webhook Settings handleConfigChange('webhook_settings.secret', e.target.value)} fullWidth helperText="Secret for webhook signature validation" /> Enabled Webhook Events {['ticket.create', 'ticket.update', 'ticket.close', 'article.create'].map((event) => ( handleArrayToggle('webhook_settings.enabled_events', event)} /> } label={event} /> ))} {/* Notification Settings */} }> Notification Settings handleConfigChange('notification_settings.email_notifications', e.target.checked)} /> } label="Email Notifications" /> handleConfigChange('notification_settings.slack_webhook_url', e.target.value)} fullWidth placeholder="https://hooks.slack.com/services/..." /> Notification Events {['sync_error', 'api_error', 'new_tickets', 'summarization_complete'].map((event) => ( handleArrayToggle('notification_settings.notification_events', event)} /> } label={event.replace('_', ' ').replace(/\b\w/g, l => l.toUpperCase())} /> ))} ); };