/**
* Integrations Panel Component
*
* Third-party integration management:
* - View all integrations
* - Configure API keys
* - Enable/disable integrations
* - Run health checks
*/
import React, { useState, useEffect, useCallback } from 'react';
import {
Link2, RefreshCw, Settings, Check, XCircle, AlertTriangle,
Eye, EyeOff, Save, Power, Activity, Zap, Cloud, Mail, CreditCard,
Bot, Brain, Server
} from 'lucide-react';
import { getToken } from '../../services/api';
const API_BASE = import.meta.env.VITE_API_URL || '';
// Integration icons mapping
const getIntegrationIcon = (name) => {
const icons = {
openai: Zap,
aws_s3: Cloud,
sendgrid: Mail,
stripe: CreditCard
};
return icons[name] || Server;
};
// Status indicator
const StatusIndicator = ({ connected, enabled }) => {
if (!enabled) {
return (
Disabled
);
}
return connected ? (
Connected
) : (
Not Connected
);
};
// Integration card component
const IntegrationCard = ({ integration, onUpdate, onHealthCheck }) => {
const [editing, setEditing] = useState(false);
const [apiKey, setApiKey] = useState('');
const [apiSecret, setApiSecret] = useState('');
const [showKey, setShowKey] = useState(false);
const [showSecret, setShowSecret] = useState(false);
const [saving, setSaving] = useState(false);
const [checking, setChecking] = useState(false);
const [healthResult, setHealthResult] = useState(null);
const Icon = getIntegrationIcon(integration.name);
const handleSave = async () => {
setSaving(true);
try {
const updates = {
is_enabled: integration.is_enabled
};
if (apiKey) updates.api_key = apiKey;
if (apiSecret) updates.api_secret = apiSecret;
await onUpdate(integration.id, updates);
setEditing(false);
setApiKey('');
setApiSecret('');
} catch (err) {
console.error('Error saving:', err);
} finally {
setSaving(false);
}
};
const handleToggle = async () => {
setSaving(true);
try {
await onUpdate(integration.id, { is_enabled: !integration.is_enabled });
} catch (err) {
console.error('Error toggling:', err);
} finally {
setSaving(false);
}
};
const handleHealthCheck = async () => {
setChecking(true);
setHealthResult(null);
try {
const result = await onHealthCheck(integration.name);
setHealthResult(result);
} catch (err) {
setHealthResult({ status: 'error', message: err.message });
} finally {
setChecking(false);
}
};
return (
{integration.display_name}
{integration.description}
API Key:
{integration.api_key_preview || 'Not configured'}
{integration.config && Object.keys(integration.config).length > 0 && (
Config:
{JSON.stringify(integration.config)}
)}
{editing && (
{integration.name !== 'openai' && (
)}
)}
{healthResult && (
{healthResult.status === 'healthy' ? (
) : (
)}
{healthResult.message || healthResult.status}
)}
{editing ? (
<>
>
) : (
)}
);
};
function IntegrationsPanel() {
const [integrations, setIntegrations] = useState([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
// Fetch integrations
const fetchIntegrations = useCallback(async () => {
setLoading(true);
setError(null);
try {
const token = getToken();
const response = await fetch(`${API_BASE}/api/admin/integrations`, {
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
}
});
if (!response.ok) throw new Error('Failed to fetch integrations');
const data = await response.json();
if (data.success) {
setIntegrations(data.integrations);
}
} catch (err) {
setError(err.message);
} finally {
setLoading(false);
}
}, []);
// Update integration
const updateIntegration = async (integrationId, updates) => {
const token = getToken();
const response = await fetch(`${API_BASE}/api/admin/integrations/${integrationId}`, {
method: 'PUT',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
},
body: JSON.stringify(updates)
});
if (!response.ok) throw new Error('Failed to update integration');
fetchIntegrations();
};
// Health check
const healthCheck = async (integrationName) => {
const token = getToken();
const response = await fetch(`${API_BASE}/api/admin/integrations/${integrationName}/health-check`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
}
});
if (!response.ok) throw new Error('Health check failed');
const data = await response.json();
return data.health;
};
// Initial fetch
useEffect(() => {
fetchIntegrations();
}, [fetchIntegrations]);
if (loading) {
return (
);
}
return (
{/* Header */}
Third-Party Integrations
{/* Stats */}
{integrations.filter(i => i.is_enabled).length}
Enabled
{integrations.filter(i => i.is_configured).length}
Configured
{integrations.length}
Total
{/* Integrations Grid */}
{integrations.map((integration) => (
))}
{integrations.length === 0 && (
No integrations configured
)}
);
}
export default IntegrationsPanel;