/** * Integrations Page - MCP Integration Configuration * * Allows users to configure project integrations: * - Figma (design tokens, components) * - Jira (issue tracking) * - Confluence (documentation) */ import claudeService from '../services/claude-service.js'; import logger from '../core/logger.js'; class IntegrationsPage { constructor() { this.container = null; this.projectId = null; this.integrations = []; this.healthStatus = []; } /** * Initialize the page */ async init(container, projectId) { this.container = container; this.projectId = projectId; claudeService.setProject(projectId); await this.loadData(); this.render(); } /** * Load integrations data */ async loadData() { try { // Load global health status this.healthStatus = await claudeService.getIntegrations(); // Load project-specific integrations if (this.projectId) { this.integrations = await claudeService.getProjectIntegrations(this.projectId); } } catch (error) { logger.error('Integrations', 'Failed to load data', error); } } /** * Render the page */ render() { if (!this.container) return; this.container.innerHTML = `
${this.renderIntegrationCard('figma', { title: 'Figma', description: 'Connect to Figma for design tokens, components, and styles', icon: '', fields: [ { name: 'api_token', label: 'API Token', type: 'password', placeholder: 'Enter Figma API token' } ] })} ${this.renderIntegrationCard('jira', { title: 'Jira', description: 'Connect to Jira for issue tracking and project management', icon: '', fields: [ { name: 'url', label: 'Jira URL', type: 'url', placeholder: 'https://your-domain.atlassian.net' }, { name: 'username', label: 'Email', type: 'email', placeholder: 'your-email@example.com' }, { name: 'api_token', label: 'API Token', type: 'password', placeholder: 'Enter Jira API token' } ] })} ${this.renderIntegrationCard('confluence', { title: 'Confluence', description: 'Connect to Confluence for documentation and knowledge base', icon: '', fields: [ { name: 'url', label: 'Confluence URL', type: 'url', placeholder: 'https://your-domain.atlassian.net/wiki' }, { name: 'username', label: 'Email', type: 'email', placeholder: 'your-email@example.com' }, { name: 'api_token', label: 'API Token', type: 'password', placeholder: 'Enter Confluence API token' } ] })}

Available MCP Tools

Loading tools...

`; this.attachEventListeners(); this.loadToolsList(); } /** * Render an integration card */ renderIntegrationCard(type, config) { const health = this.healthStatus.find(h => h.integration_type === type) || {}; const projectConfig = this.integrations.find(i => i.integration_type === type); const isConfigured = !!projectConfig; const isEnabled = projectConfig?.enabled ?? false; const healthClass = health.is_healthy ? 'healthy' : 'unhealthy'; const healthText = health.is_healthy ? 'Healthy' : `Unhealthy (${health.failure_count} failures)`; return `
${config.icon}

${config.title}

${config.description}

${healthText} ${isConfigured ? 'Configured' : ''}
${config.fields.map(field => `
`).join('')}
${isConfigured ? ` ` : ''}
`; } /** * Attach event listeners */ attachEventListeners() { // Form submissions this.container.querySelectorAll('.integration-form').forEach(form => { form.addEventListener('submit', (e) => this.handleFormSubmit(e)); }); // Toggle buttons this.container.querySelectorAll('.toggle-btn').forEach(btn => { btn.addEventListener('click', (e) => this.handleToggle(e)); }); // Delete buttons this.container.querySelectorAll('.delete-btn').forEach(btn => { btn.addEventListener('click', (e) => this.handleDelete(e)); }); } /** * Handle form submission */ async handleFormSubmit(e) { e.preventDefault(); const form = e.target; const type = form.dataset.type; const formData = new FormData(form); const config = {}; formData.forEach((value, key) => { if (value) config[key] = value; }); if (Object.keys(config).length === 0) { alert('Please fill in at least one field'); return; } try { await claudeService.configureIntegration(type, config, this.projectId); alert(`${type} integration configured successfully!`); await this.loadData(); this.render(); } catch (error) { alert(`Failed to configure ${type}: ${error.message}`); } } /** * Handle toggle */ async handleToggle(e) { const card = e.target.closest('.integration-card'); const type = card.dataset.type; const currentlyEnabled = e.target.dataset.enabled === 'true'; try { await claudeService.toggleIntegration(type, !currentlyEnabled, this.projectId); await this.loadData(); this.render(); } catch (error) { alert(`Failed to toggle ${type}: ${error.message}`); } } /** * Handle delete */ async handleDelete(e) { const card = e.target.closest('.integration-card'); const type = card.dataset.type; if (!confirm(`Are you sure you want to disconnect ${type}?`)) { return; } try { await claudeService.deleteIntegration(type, this.projectId); await this.loadData(); this.render(); } catch (error) { alert(`Failed to disconnect ${type}: ${error.message}`); } } /** * Load and display MCP tools list */ async loadToolsList() { const toolsList = this.container.querySelector('#tools-list'); try { const result = await claudeService.getMcpTools(); const html = Object.entries(result.tools).map(([category, tools]) => `

${category.charAt(0).toUpperCase() + category.slice(1)} Tools (${tools.length})

`).join(''); toolsList.innerHTML = html || '

No tools available

'; } catch (error) { toolsList.innerHTML = '

Failed to load tools

'; } } } // Export singleton const integrationsPage = new IntegrationsPage(); export default integrationsPage; export { IntegrationsPage };