File size: 3,813 Bytes
452f691
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
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;