// Providers Page Module class ProvidersPage { constructor() { this.providers = []; this.init(); } async init() { // Load data await this.loadProviderStats(); await this.loadProvidersList(); await this.loadModelsList(); await this.loadConnectionTests(); // Setup event listeners this.setupEventListeners(); } async loadProviderStats() { const container = document.getElementById('provider-stats'); if (!container) return; container.innerHTML = `
4
Total Providers
3 active
3
Connected
All systems operational
1
Issues
DeepSeek: 85% health
1
Offline
Grok: Connection failed
`; } async loadProvidersList() { const container = document.getElementById('providers-list'); if (!container) return; this.providers = [ { name: 'OpenAI', enabled: true, status: 'online', apiKey: 'sk-*****123', models: ['gpt-4', 'gpt-3.5-turbo'], lastUsed: '2024-01-15 14:32:15' }, { name: 'Gemini', enabled: true, status: 'online', apiKey: 'AIza*****456', models: ['gemini-pro', 'gemini-pro-vision'], lastUsed: '2024-01-15 14:30:45' }, { name: 'DeepSeek', enabled: true, status: 'warning', apiKey: 'sk-*****789', models: ['deepseek-chat', 'deepseek-coder'], lastUsed: '2024-01-15 14:28:12' }, { name: 'Grok', enabled: false, status: 'offline', apiKey: 'gk-*****012', models: ['grok-beta'], lastUsed: '2024-01-12 10:15:22' } ]; container.innerHTML = this.providers.map(provider => { const statusClass = provider.status === 'online' ? 'success' : provider.status === 'warning' ? 'warning' : 'danger'; const statusIcon = provider.status === 'online' ? 'check-circle' : provider.status === 'warning' ? 'exclamation-triangle' : 'times-circle'; return `

${provider.name}

${provider.status}
API Key: ${provider.apiKey}
Models: ${provider.models.join(', ')}
Last Used: ${provider.lastUsed}
`; }).join(''); // Add CSS for provider cards this.addProviderStyles(); } addProviderStyles() { const style = document.createElement('style'); style.textContent = ` .provider-card { background-color: var(--bg-card); border: 1px solid var(--border-color); border-radius: var(--border-radius); padding: 1rem; margin-bottom: 1rem; } .provider-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 1rem; } .provider-info { display: flex; align-items: center; gap: 0.5rem; } .provider-name { font-size: 1rem; font-weight: 600; color: var(--text-primary); margin: 0; } .provider-actions { display: flex; align-items: center; gap: 0.5rem; } .toggle-switch { position: relative; display: inline-block; width: 50px; height: 24px; } .toggle-switch input { opacity: 0; width: 0; height: 0; } .toggle-slider { position: absolute; cursor: pointer; top: 0; left: 0; right: 0; bottom: 0; background-color: var(--text-light); transition: .4s; border-radius: 24px; } .toggle-slider:before { position: absolute; content: ""; height: 16px; width: 16px; left: 4px; bottom: 4px; background-color: white; transition: .4s; border-radius: 50%; } input:checked + .toggle-slider { background-color: var(--success); } input:checked + .toggle-slider:before { transform: translateX(26px); } .provider-details { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 0.75rem; font-size: 0.875rem; } .detail-item { display: flex; align-items: center; gap: 0.5rem; } .detail-label { color: var(--text-secondary); font-weight: 500; min-width: 70px; } .detail-value { color: var(--text-primary); flex: 1; } .btn-copy { background: none; border: none; color: var(--text-secondary); cursor: pointer; font-size: 0.75rem; padding: 0.25rem; transition: color 0.2s ease; } .btn-copy:hover { color: var(--primary); } `; document.head.appendChild(style); } async loadModelsList() { const container = document.getElementById('models-list'); if (!container) return; const models = [ { provider: 'OpenAI', name: 'gpt-4', enabled: true, context: 8192, maxTokens: 4096 }, { provider: 'OpenAI', name: 'gpt-3.5-turbo', enabled: true, context: 16384, maxTokens: 4096 }, { provider: 'Gemini', name: 'gemini-pro', enabled: true, context: 32768, maxTokens: 8192 }, { provider: 'Gemini', name: 'gemini-pro-vision', enabled: true, context: 32768, maxTokens: 4096 }, { provider: 'DeepSeek', name: 'deepseek-chat', enabled: true, context: 16384, maxTokens: 4096 }, { provider: 'DeepSeek', name: 'deepseek-coder', enabled: true, context: 16384, maxTokens: 4096 }, { provider: 'Grok', name: 'grok-beta', enabled: false, context: 8192, maxTokens: 2048 } ]; container.innerHTML = models.map(model => `
${model.name} ${model.provider}
Context: ${model.context.toLocaleString()} tokens Max: ${model.maxTokens.toLocaleString()} tokens ${model.enabled ? 'Enabled' : 'Disabled'}
`).join(''); // Add CSS for model items this.addModelStyles(); } addModelStyles() { const style = document.createElement('style'); style.textContent = ` .model-item { background-color: var(--bg-secondary); border-radius: var(--border-radius-sm); padding: 0.75rem; margin-bottom: 0.5rem; } .model-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 0.5rem; } .model-name { font-weight: 600; color: var(--text-primary); } .model-provider { font-size: 0.75rem; color: var(--text-secondary); background-color: var(--bg-primary); padding: 0.25rem 0.5rem; border-radius: 12px; } .model-details { display: flex; flex-wrap: wrap; gap: 1rem; font-size: 0.75rem; } .model-detail { display: flex; align-items: center; gap: 0.25rem; color: var(--text-secondary); } .model-detail i { font-size: 0.625rem; } .model-status { font-size: 0.75rem; padding: 0.125rem 0.5rem; border-radius: 12px; } .model-status.enabled { background-color: rgba(16, 185, 129, 0.1); color: var(--success); } .model-status.disabled { background-color: rgba(239, 68, 68, 0.1); color: var(--danger); } `; document.head.appendChild(style); } async loadConnectionTests() { const container = document.getElementById('connection-tests'); if (!container) return; const tests = [ { provider: 'OpenAI', status: 'success', latency: 245, timestamp: '2024-01-15 14:35:00' }, { provider: 'Gemini', status: 'success', latency: 189, timestamp: '2024-01-15 14:34:30' }, { provider: 'DeepSeek', status: 'warning', latency: 520, timestamp: '2024-01-15 14:34:00' }, { provider: 'Grok', status: 'error', latency: null, timestamp: '2024-01-15 14:33:30' } ]; container.innerHTML = tests.map(test => { const statusClass = test.status === 'success' ? 'success' : test.status === 'warning' ? 'warning' : 'danger'; const statusIcon = test.status === 'success' ? 'check-circle' : test.status === 'warning' ? 'exclamation-triangle' : 'times-circle'; return `
${test.provider}
${test.status}
${test.latency ? `${test.latency}ms` : 'N/A'}
${test.timestamp}
`; }).join(''); // Add CSS for test results this.addTestStyles(); } addTestStyles() { const style = document.createElement('style'); style.textContent = ` .test-result { display: grid; grid-template-columns: 1fr 1fr 1fr 2fr; gap: 1rem; align-items: center; padding: 0.75rem; border-bottom: 1px solid var(--border-color); } .test-result:last-child { border-bottom: none; } .test-provider { font-weight: 500; color: var(--text-primary); } .test-latency { color: var(--text-secondary); font-family: monospace; } .test-time { color: var(--text-light); font-size: 0.75rem; } `; document.head.appendChild(style); } setupEventListeners() { // Test all providers button const testAllBtn = document.getElementById('test-all-providers'); if (testAllBtn) { testAllBtn.addEventListener('click', () => { this.testAllProviders(); }); } // Toggle switches document.addEventListener('change', (e) => { if (e.target.matches('.toggle-switch input')) { const provider = e.target.dataset.provider; const enabled = e.target.checked; this.toggleProvider(provider, enabled); } }); // Action buttons document.addEventListener('click', (e) => { if (e.target.closest('.btn-action')) { const button = e.target.closest('.btn-action'); const action = button.dataset.action; const provider = button.dataset.provider; switch (action) { case 'configure': this.configureProvider(provider); break; case 'test': this.testProvider(provider); break; } } // Copy buttons if (e.target.closest('.btn-copy')) { const button = e.target.closest('.btn-copy'); const text = button.dataset.text; this.copyToClipboard(text); if (window.authManager) { window.authManager.showToast('Copied to clipboard', 'success'); } } }); } toggleProvider(providerName, enabled) { const provider = this.providers.find(p => p.name === providerName); if (!provider) return; // In a real app, this would update the provider via API provider.enabled = enabled; provider.status = enabled ? 'online' : 'offline'; if (window.authManager) { window.authManager.showToast( `${providerName} ${enabled ? 'enabled' : 'disabled'}`, enabled ? 'success' : 'warning' ); } // Refresh providers list this.loadProvidersList(); } configureProvider(providerName) { const provider = this.providers.find(p => p.name === providerName); if (!provider) return; // Show configuration modal const modal = document.createElement('div'); modal.className = 'modal active'; modal.innerHTML = ` `; document.body.appendChild(modal); // Setup event listeners const closeBtn = modal.querySelector('.modal-close'); const closeModalBtn = modal.querySelector('.close-modal'); const saveBtn = modal.querySelector('.save-config'); const closeModal = () => { modal.classList.remove('active'); setTimeout(() => modal.remove(), 300); }; closeBtn.addEventListener('click', closeModal); closeModalBtn.addEventListener('click', closeModal); saveBtn.addEventListener('click', () => { // In a real app, this would save provider configuration if (window.authManager) { window.authManager.showToast(`${providerName} configuration saved`, 'success'); } closeModal(); }); // Close on background click modal.addEventListener('click', (e) => { if (e.target === modal) { closeModal(); } }); } testProvider(providerName) { const provider = this.providers.find(p => p.name === providerName); if (!provider) return; // Show testing in progress if (window.authManager) { window.authManager.showToast(`Testing ${providerName} connection...`, 'info'); } // Simulate API test setTimeout(() => { // In a real app, this would test the provider connection via API const success = Math.random() > 0.3; // 70% success rate for demo if (window.authManager) { window.authManager.showToast( `${providerName} connection ${success ? 'successful' : 'failed'}`, success ? 'success' : 'error' ); } // Refresh connection tests this.loadConnectionTests(); }, 1500); } testAllProviders() { if (window.authManager) { window.authManager.showToast('Testing all providers...', 'info'); } // Test each provider sequentially this.providers.forEach((provider, index) => { setTimeout(() => { this.testProvider(provider.name); }, index * 2000); // Stagger tests }); } copyToClipboard(text) { navigator.clipboard.writeText(text).catch(err => { console.error('Failed to copy:', err); }); } refresh() { this.loadProviderStats(); this.loadProvidersList(); this.loadModelsList(); this.loadConnectionTests(); } } // Initialize providers page when needed window.initProviders = async () => { window.providersPage = new ProvidersPage(); }; // Export for use in other modules if (typeof module !== 'undefined' && module.exports) { module.exports = ProvidersPage; }