generated from coulomb/repo-seed
Move refresh to global header button
- Add refresh button in header (before help button) - Refresh updates all uploaded documents at once (in_basket, in_production) - Remove individual refresh buttons from production items - Add spinning animation while refresh is in progress - Show count of refreshed documents in status message Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -93,6 +93,30 @@ body {
|
||||
outline-offset: 2px;
|
||||
}
|
||||
|
||||
.icon-btn svg {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.icon-btn.refreshing svg {
|
||||
animation: spin 1s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
from {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
/* Header actions */
|
||||
.header-actions {
|
||||
display: flex;
|
||||
gap: var(--spacing-sm);
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
/* Views */
|
||||
.view {
|
||||
flex: 1;
|
||||
|
||||
@@ -10,7 +10,16 @@
|
||||
<!-- Header -->
|
||||
<div class="header">
|
||||
<h1>BinectChrome</h1>
|
||||
<button id="helpBtn" class="icon-btn" aria-label="Help and tracking info" title="Help & Info">?</button>
|
||||
<div class="header-actions">
|
||||
<button id="refreshBtn" class="icon-btn" aria-label="Refresh status from server" title="Refresh status">
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<polyline points="23 4 23 10 17 10"></polyline>
|
||||
<polyline points="1 20 1 14 7 14"></polyline>
|
||||
<path d="M3.51 9a9 9 0 0 1 14.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0 0 20.49 15"></path>
|
||||
</svg>
|
||||
</button>
|
||||
<button id="helpBtn" class="icon-btn" aria-label="Help and tracking info" title="Help & Info">?</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Authentication View -->
|
||||
|
||||
@@ -25,6 +25,7 @@ const loginBtn = document.getElementById('loginBtn') as HTMLButtonElement;
|
||||
const authError = document.getElementById('authError')!;
|
||||
|
||||
const logoutBtn = document.getElementById('logoutBtn')!;
|
||||
const refreshBtn = document.getElementById('refreshBtn')!;
|
||||
const helpBtn = document.getElementById('helpBtn')!;
|
||||
const togglePasswordBtn = document.getElementById('togglePassword') as HTMLButtonElement;
|
||||
const eyeIcon = document.getElementById('eyeIcon')!;
|
||||
@@ -75,6 +76,7 @@ async function init() {
|
||||
function setupEventListeners() {
|
||||
loginForm.addEventListener('submit', handleLogin);
|
||||
logoutBtn.addEventListener('click', handleLogout);
|
||||
refreshBtn.addEventListener('click', handleRefreshAll);
|
||||
helpBtn.addEventListener('click', handleHelp);
|
||||
togglePasswordBtn.addEventListener('click', handleTogglePassword);
|
||||
}
|
||||
@@ -336,9 +338,8 @@ function renderPDFItem(pdf: PDFQueueEntry, section: 'pending' | 'basket' | 'prod
|
||||
`;
|
||||
break;
|
||||
case 'production':
|
||||
actionsHtml = `
|
||||
<button class="btn-refresh-item" data-id="${escapeHtml(pdf.id)}">Refresh</button>
|
||||
`;
|
||||
// No individual actions - use global refresh button in header
|
||||
actionsHtml = '';
|
||||
break;
|
||||
case 'completed':
|
||||
actionsHtml = `
|
||||
@@ -386,14 +387,6 @@ function setupPDFListEventListeners() {
|
||||
});
|
||||
});
|
||||
|
||||
// Refresh buttons
|
||||
pdfList.querySelectorAll('.btn-refresh-item').forEach(btn => {
|
||||
btn.addEventListener('click', (e) => {
|
||||
const id = (e.target as HTMLElement).dataset.id;
|
||||
if (id) handleRefreshStatus(id);
|
||||
});
|
||||
});
|
||||
|
||||
// Dismiss/Cancel/Remove buttons
|
||||
pdfList.querySelectorAll('.btn-dismiss').forEach(btn => {
|
||||
btn.addEventListener('click', (e) => {
|
||||
@@ -685,6 +678,53 @@ async function handleOrderPDF(id: string) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle refresh all documents that have been uploaded to server
|
||||
*/
|
||||
async function handleRefreshAll() {
|
||||
if (!currentCredentials) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Find all documents that have been uploaded and are still visible
|
||||
const uploadedDocs = pdfQueue.filter(p =>
|
||||
p.binectDocumentId &&
|
||||
(p.status === 'in_basket' || p.status === 'in_production')
|
||||
);
|
||||
|
||||
if (uploadedDocs.length === 0) {
|
||||
showStatus('No documents to refresh', 'success');
|
||||
setTimeout(() => hideStatus(), 2000);
|
||||
return;
|
||||
}
|
||||
|
||||
// Disable refresh button during refresh
|
||||
refreshBtn.classList.add('refreshing');
|
||||
showStatus(`Refreshing ${uploadedDocs.length} document${uploadedDocs.length > 1 ? 's' : ''}...`, 'uploading');
|
||||
|
||||
let successCount = 0;
|
||||
let errorCount = 0;
|
||||
|
||||
for (const pdf of uploadedDocs) {
|
||||
try {
|
||||
await handleRefreshStatus(pdf.id);
|
||||
successCount++;
|
||||
} catch {
|
||||
errorCount++;
|
||||
}
|
||||
}
|
||||
|
||||
refreshBtn.classList.remove('refreshing');
|
||||
|
||||
if (errorCount === 0) {
|
||||
showStatus(`Refreshed ${successCount} document${successCount > 1 ? 's' : ''}`, 'success');
|
||||
} else {
|
||||
showStatus(`Refreshed ${successCount}, ${errorCount} failed`, 'error');
|
||||
}
|
||||
|
||||
setTimeout(() => hideStatus(), 3000);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle refresh document status
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user