Spaces:
Running
Running
| class DataTable extends HTMLElement { | |
| constructor() { | |
| super(); | |
| this.attachShadow({ mode: 'open' }); | |
| this.data = []; | |
| this.sortColumn = null; | |
| this.sortDirection = 'asc'; | |
| } | |
| connectedCallback() { | |
| this.generateData(); | |
| this.render(); | |
| this.attachEvents(); | |
| } | |
| generateData() { | |
| const operations = [ | |
| 'Inference Request', 'Model Update', 'Data Preprocessing', 'API Call', | |
| 'Cache Miss', 'Authentication', 'Validation Check', 'Batch Processing' | |
| ]; | |
| const statuses = ['success', 'pending', 'error']; | |
| for (let i = 0; i < 20; i++) { | |
| this.data.push({ | |
| id: `OP-${10000 + i}`, | |
| operation: operations[Math.floor(Math.random() * operations.length)], | |
| timestamp: new Date(Date.now() - Math.random() * 3600000).toISOString(), | |
| duration: Math.floor(Math.random() * 500 + 10), | |
| status: statuses[Math.floor(Math.random() * statuses.length)] | |
| }); | |
| } | |
| } | |
| sort(column) { | |
| if (this.sortColumn === column) { | |
| this.sortDirection = this.sortDirection === 'asc' ? 'desc' : 'asc'; | |
| } else { | |
| this.sortColumn = column; | |
| this.sortDirection = 'asc'; | |
| } | |
| this.data.sort((a, b) => { | |
| let valA = a[column]; | |
| let valB = b[column]; | |
| if (typeof valA === 'string') valA = valA.toLowerCase(); | |
| if (typeof valB === 'string') valB = valB.toLowerCase(); | |
| if (valA < valB) return this.sortDirection === 'asc' ? -1 : 1; | |
| if (valA > valB) return this.sortDirection === 'asc' ? 1 : -1; | |
| return 0; | |
| }); | |
| this.render(); | |
| } | |
| getStatusBadge(status) { | |
| const styles = { | |
| success: 'bg-green-900/50 text-green-400', | |
| pending: 'bg-yellow-900/50 text-yellow-400', | |
| error: 'bg-red-900/50 text-red-400' | |
| }; | |
| return `<span class="px-2 py-1 rounded text-xs ${styles[status]}">${status.charAt(0).toUpperCase() + status.slice(1)}</span>`; | |
| } | |
| render() { | |
| this.shadowRoot.innerHTML = ` | |
| <style> | |
| :host { | |
| display: block; | |
| } | |
| table { | |
| width: 100%; | |
| border-collapse: collapse; | |
| } | |
| th { | |
| text-align: left; | |
| padding: 12px; | |
| border-bottom: 1px solid #334155; | |
| color: #94a3b8; | |
| font-size: 12px; | |
| text-transform: uppercase; | |
| cursor: pointer; | |
| user-select: none; | |
| } | |
| th:hover { | |
| color: #e2e8f0; | |
| background: rgba(255,255,255,0.02); | |
| } | |
| td { | |
| padding: 12px; | |
| border-bottom: 1px solid #1e293b; | |
| font-size: 14px; | |
| } | |
| tr:hover td { | |
| background: rgba(255,255,255,0.02); | |
| } | |
| .sort-icon { | |
| margin-left: 4px; | |
| opacity: 0.5; | |
| } | |
| </style> | |
| <div style="overflow-x: auto;"> | |
| <table> | |
| <thead> | |
| <tr> | |
| <th onclick="this.getRootNode().host.sort('id')"> | |
| ID ${this.sortColumn === 'id' ? (this.sortDirection === 'asc' ? 'β' : 'β') : ''} | |
| </th> | |
| <th onclick="this.getRootNode().host.sort('operation')"> | |
| Operation ${this.sortColumn === 'operation' ? (this.sortDirection === 'asc' ? 'β' : 'β') : ''} | |
| </th> | |
| <th onclick="this.getRootNode().host.sort('timestamp')"> | |
| Timestamp ${this.sortColumn === 'timestamp' ? (this.sortDirection === 'asc' ? 'β' : 'β') : ''} | |
| </th> | |
| <th onclick="this.getRootNode().host.sort('duration')"> | |
| Duration ${this.sortColumn === 'duration' ? (this.sortDirection === 'asc' ? 'β' : 'β') : ''} | |
| </th> | |
| <th onclick="this.getRootNode().host.sort('status')"> | |
| Status ${this.sortColumn === 'status' ? (this.sortDirection === 'asc' ? 'β' : 'β') : ''} | |
| </th> | |
| </tr> | |
| </thead> | |
| <tbody> | |
| ${this.data.map(row => ` | |
| <tr> | |
| <td class="font-mono text-slate-400">${row.id}</td> | |
| <td class="text-white">${row.operation}</td> | |
| <td class="text-slate-400">${new Date(row.timestamp).toLocaleString()}</td> | |
| <td class="text-slate-300">${row.duration}ms</td> | |
| <td>${this.getStatusBadge(row.status)}</td> | |
| </tr> | |
| `).join('')} | |
| </tbody> | |
| </table> | |
| </div> | |
| `; | |
| } | |
| attachEvents() { | |
| // Add new data periodically | |
| setInterval(() => { | |
| const operations = ['Inference Request', 'Model Update', 'Data Preprocessing', 'API Call']; | |
| const statuses = ['success', 'pending', 'error']; | |
| this.data.unshift({ | |
| id: `OP-${10000 + this.data.length}`, | |
| operation: operations[Math.floor(Math.random() * operations.length)], | |
| timestamp: new Date().toISOString(), | |
| duration: Math.floor(Math.random() * 500 + 10), | |
| status: statuses[Math.floor(Math.random() * statuses.length)] | |
| }); | |
| if (this.data.length > 50) { | |
| this.data.pop(); | |
| } | |
| this.render(); | |
| }, 3000); | |
| } | |
| } | |
| customElements.define('data-table', DataTable); |