| import apiClient from './apiClient.js'; |
|
|
| class ProvidersView { |
| constructor(section) { |
| this.section = section; |
| this.tableBody = section?.querySelector('[data-providers-table]'); |
| this.searchInput = section?.querySelector('[data-provider-search]'); |
| this.categorySelect = section?.querySelector('[data-provider-category]'); |
| this.summaryNode = section?.querySelector('[data-provider-summary]'); |
| this.refreshButton = section?.querySelector('[data-provider-refresh]'); |
| this.providers = []; |
| this.filtered = []; |
| } |
|
|
| init() { |
| if (!this.section) return; |
| this.bindEvents(); |
| this.loadProviders(); |
| } |
|
|
| bindEvents() { |
| this.searchInput?.addEventListener('input', () => this.applyFilters()); |
| this.categorySelect?.addEventListener('change', () => this.applyFilters()); |
| this.refreshButton?.addEventListener('click', () => this.loadProviders()); |
| } |
|
|
| async loadProviders() { |
| if (this.tableBody) { |
| this.tableBody.innerHTML = '<tr><td colspan="5">Loading providers...</td></tr>'; |
| } |
| const result = await apiClient.getProviders(); |
| if (!result.ok) { |
| this.tableBody.innerHTML = `<tr><td colspan="5"><div class="inline-message inline-error">${result.error}</div></td></tr>`; |
| return; |
| } |
| |
| const data = result.data || {}; |
| this.providers = data.providers || data || []; |
| this.applyFilters(); |
| } |
|
|
| applyFilters() { |
| const term = (this.searchInput?.value || '').toLowerCase(); |
| const category = this.categorySelect?.value || 'all'; |
| this.filtered = this.providers.filter((provider) => { |
| const matchesTerm = `${provider.name} ${provider.provider_id}`.toLowerCase().includes(term); |
| const matchesCategory = category === 'all' || (provider.category || 'uncategorized') === category; |
| return matchesTerm && matchesCategory; |
| }); |
| this.renderTable(); |
| this.renderSummary(); |
| } |
|
|
| renderTable() { |
| if (!this.tableBody) return; |
| if (!this.filtered.length) { |
| this.tableBody.innerHTML = '<tr><td colspan="5">No providers match the filters.</td></tr>'; |
| return; |
| } |
| this.tableBody.innerHTML = this.filtered |
| .map( |
| (provider) => ` |
| <tr> |
| <td>${provider.name || provider.provider_id}</td> |
| <td>${provider.category || 'general'}</td> |
| <td><span class="badge ${provider.status === 'healthy' ? 'badge-success' : 'badge-danger'}">${ |
| provider.status || 'unknown' |
| }</span></td> |
| <td>${provider.latency_ms ? `${provider.latency_ms}ms` : '—'}</td> |
| <td>${provider.error || provider.status_code || 'OK'}</td> |
| </tr> |
| `, |
| ) |
| .join(''); |
| } |
|
|
| renderSummary() { |
| if (!this.summaryNode) return; |
| const total = this.providers.length; |
| const healthy = this.providers.filter((provider) => provider.status === 'healthy').length; |
| const degraded = total - healthy; |
| this.summaryNode.innerHTML = ` |
| <div class="stat-card glass-card"> |
| <h3>Total Providers</h3> |
| <p class="stat-value">${total}</p> |
| </div> |
| <div class="stat-card glass-card"> |
| <h3>Healthy</h3> |
| <p class="stat-value text-success">${healthy}</p> |
| </div> |
| <div class="stat-card glass-card"> |
| <h3>Issues</h3> |
| <p class="stat-value text-danger">${degraded}</p> |
| </div> |
| `; |
| } |
| } |
|
|
| export default ProvidersView; |
|
|