Depassage's picture
### 1. ABSTRACT
c6db453 verified
Raw
History Blame Contribute Delete
8.08 kB
class CustomList extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: 'open' });
this.shadowRoot.innerHTML = `
<style>
@import url('https://cdnjs.cloudflare.com/ajax/libs/tailwindcss/2.2.19/tailwind.min.css');
table {
width: 100%;
border-collapse: collapse;
}
th {
cursor: pointer;
user-select: none;
}
th:hover {
background-color: #f3f4f6;
}
.sort-icon {
margin-left: 4px;
opacity: 0.5;
}
.sort-icon.active {
opacity: 1;
}
</style>
<div class="overflow-x-auto">
<table class="min-w-full divide-y divide-gray-200">
<thead class="bg-gray-50">
<tr>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider" data-sort="id">
ID <i data-feather="chevron-down" class="sort-icon"></i>
</th>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider" data-sort="type">
Type <i data-feather="chevron-down" class="sort-icon"></i>
</th>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider" data-sort="status">
Status <i data-feather="chevron-down" class="sort-icon"></i>
</th>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
Actions
</th>
</tr>
</thead>
<tbody id="batchTableBody" class="bg-white divide-y divide-gray-200">
<!-- Batches will be loaded here -->
</tbody>
</table>
</div>
<div id="loading" class="flex justify-center items-center py-8">
<div class="animate-spin rounded-full h-8 w-8 border-b-2 border-indigo-600"></div>
</div>
<div id="emptyState" class="hidden text-center py-12">
<i data-feather="inbox" class="mx-auto h-12 w-12 text-gray-400"></i>
<h3 class="mt-2 text-sm font-medium text-gray-900">No batches yet</h3>
<p class="mt-1 text-sm text-gray-500">Upload a file to get started</p>
</div>
`;
this.sortConfig = {
key: 'id',
direction: 'desc'
};
}
connectedCallback() {
this.loadBatches();
feather.replace({ width: 16, height: 16 });
// Add event listeners for sorting
this.shadowRoot.querySelectorAll('th[data-sort]').forEach(th => {
th.addEventListener('click', () => this.handleSort(th.dataset.sort));
});
// Listen for new batch events
document.addEventListener('batch-created', () => this.loadBatches());
}
async loadBatches() {
const tableBody = this.shadowRoot.getElementById('batchTableBody');
const loading = this.shadowRoot.getElementById('loading');
const emptyState = this.shadowRoot.getElementById('emptyState');
tableBody.innerHTML = '';
loading.classList.remove('hidden');
emptyState.classList.add('hidden');
try {
const batches = await window.batchService.getAllBatches();
if (batches.length === 0) {
loading.classList.add('hidden');
emptyState.classList.remove('hidden');
return;
}
// Apply sorting
const sortedBatches = [...batches].sort((a, b) => {
if (a[this.sortConfig.key] < b[this.sortConfig.key]) {
return this.sortConfig.direction === 'asc' ? -1 : 1;
}
if (a[this.sortConfig.key] > b[this.sortConfig.key]) {
return this.sortConfig.direction === 'asc' ? 1 : -1;
}
return 0;
});
sortedBatches.forEach(batch => {
const row = document.createElement('tr');
let statusBadgeClass = '';
switch (batch.status) {
case 'PENDING':
statusBadgeClass = 'processing-badge-pending';
break;
case 'RUNNING':
statusBadgeClass = 'processing-badge-running';
break;
case 'COMPLETED':
statusBadgeClass = 'processing-badge-completed';
break;
}
row.innerHTML = `
<td class="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900">${batch.id}</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">${batch.type}</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
<span class="processing-badge ${statusBadgeClass}">${batch.status}</span>
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
<button class="download-btn" ${batch.status !== 'COMPLETED' ? 'disabled' : ''} data-id="${batch.id}">
<i data-feather="download" class="w-4 h-4 mr-1"></i> Download
</button>
</td>
`;
tableBody.appendChild(row);
});
// Add event listeners to download buttons
this.shadowRoot.querySelectorAll('.download-btn').forEach(btn => {
btn.addEventListener('click', () => this.handleDownload(btn.dataset.id));
});
// Update sort indicators
this.updateSortIndicators();
} catch (error) {
console.error('Error loading batches:', error);
} finally {
loading.classList.add('hidden');
feather.replace({ width: 16, height: 16 });
}
}
handleSort(key) {
if (this.sortConfig.key === key) {
this.sortConfig.direction = this.sortConfig.direction === 'asc' ? 'desc' : 'asc';
} else {
this.sortConfig.key = key;
this.sortConfig.direction = 'desc';
}
this.loadBatches();
}
updateSortIndicators() {
this.shadowRoot.querySelectorAll('.sort-icon').forEach(icon => {
icon.classList.remove('active');
icon.setAttribute('data-feather', 'chevron-down');
});
const activeTh = this.shadowRoot.querySelector(`th[data-sort="${this.sortConfig.key}"]`);
if (activeTh) {
const icon = activeTh.querySelector('.sort-icon');
icon.classList.add('active');
icon.setAttribute('data-feather', this.sortConfig.direction === 'asc' ? 'chevron-up' : 'chevron-down');
feather.replace({ width: 16, height: 16 });
}
}
async handleDownload(batchId) {
try {
await window.batchService.downloadResult(parseInt(batchId));
} catch (error) {
console.error('Error downloading batch result:', error);
}
}
}
customElements.define('custom-list', CustomList);