Improve consistency for server-discovered documents

- Separate "Has Errors" section for erroneous server documents (already
  uploaded but have validation errors)
- "Ready to Upload" section now only shows truly local documents
- Erroneous server docs show only "Delete from server" button (no retry)
- Improved metadata display: show document ID for server docs, hide
  unknown file size
- Clean up verbose debug logging

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-01-16 22:49:07 +01:00
parent 327943bc18
commit 24daa4bf82
2 changed files with 42 additions and 32 deletions

View File

@@ -316,13 +316,10 @@ async function loadPDFQueue() {
*/
async function syncWithServer() {
if (!currentCredentials) {
console.log('[Popup] No credentials, skipping server sync');
return;
}
try {
console.log('[Popup] Syncing with Binect server...');
// Get list of documents from server
const result = await chrome.runtime.sendMessage({
action: 'listServerDocuments',
@@ -330,8 +327,6 @@ async function syncWithServer() {
password: currentCredentials.password
});
console.log('[Popup] listServerDocuments result:', result);
if (!result.success || !result.documents) {
console.warn('[Popup] Failed to list server documents:', result.error);
return;
@@ -347,15 +342,11 @@ async function syncWithServer() {
errorDetails?: string;
}>;
console.log('[Popup] Found', serverDocs.length, 'documents on server');
for (const doc of serverDocs) {
console.log('[Popup] Server doc:', doc.id, doc.filename, 'status:', doc.status, doc.statusText);
}
console.log('[Popup] Syncing', serverDocs.length, 'server documents');
// Sync each server document to local proxy
for (const doc of serverDocs) {
console.log('[Popup] Syncing doc', doc.id, 'to local proxy...');
const syncResult = await chrome.runtime.sendMessage({
await chrome.runtime.sendMessage({
action: 'syncFromServer',
binectDocumentId: doc.id,
filename: doc.filename,
@@ -365,10 +356,7 @@ async function syncWithServer() {
recipientAddress: doc.recipientAddress,
errorDetails: doc.errorDetails
});
console.log('[Popup] Sync result for doc', doc.id, ':', syncResult);
}
console.log('[Popup] Server sync complete');
} catch (error) {
console.error('[Popup] Server sync error:', error);
}
@@ -444,13 +432,20 @@ function renderPDFList() {
</div>`;
} else {
// Live view - group by Binect status
const pendingUpload = pdfQueue.filter(p => p.binectStatus === 'pending' || p.binectStatus === 'uploading' || p.binectStatus === 'failed');
// Separate truly local pending uploads from server documents with errors
const pendingUpload = pdfQueue.filter(p =>
(p.binectStatus === 'pending' || p.binectStatus === 'uploading') ||
(p.binectStatus === 'failed' && !p.binectDocumentId) // Local failed uploads
);
const erroneous = pdfQueue.filter(p =>
p.binectStatus === 'failed' && p.binectDocumentId // Server documents with errors
);
const inBasket = pdfQueue.filter(p => p.binectStatus === 'in_basket' || p.binectStatus === 'ordering');
const inProduction = pdfQueue.filter(p => p.binectStatus === 'in_production');
const completed = pdfQueue.filter(p => p.binectStatus === 'sent' || p.binectStatus === 'canceled');
// Count actionable items
const actionableCount = pendingUpload.length + inBasket.length;
const actionableCount = pendingUpload.length + erroneous.length + inBasket.length;
// Update count
if (actionableCount > 0) {
@@ -470,6 +465,13 @@ function renderPDFList() {
</div>`;
}
if (erroneous.length > 0) {
html += `<div class="pdf-section">
<div class="pdf-section-header">Has Errors</div>
${erroneous.map(pdf => renderPDFItem(pdf, 'erroneous')).join('')}
</div>`;
}
if (inBasket.length > 0) {
html += `<div class="pdf-section">
<div class="pdf-section-header">In Basket</div>
@@ -504,7 +506,7 @@ function renderPDFList() {
/**
* Render a single PDF item
*/
function renderPDFItem(pdf: DocumentProxy, section: 'pending' | 'basket' | 'production' | 'completed' | 'archived'): string {
function renderPDFItem(pdf: DocumentProxy, section: 'pending' | 'erroneous' | 'basket' | 'production' | 'completed' | 'archived'): string {
const statusClass = getStatusClass(pdf.binectStatus);
const statusText = getStatusText(pdf);
const priceText = pdf.price ? `${(pdf.price / 100).toFixed(2)}` : '';
@@ -522,10 +524,13 @@ function renderPDFItem(pdf: DocumentProxy, section: 'pending' | 'basket' | 'prod
<button class="btn-send-item" data-id="${escapeHtml(pdf.id)}" ${pdf.binectStatus === 'uploading' ? 'disabled' : ''}>
${pdf.binectStatus === 'uploading' ? 'Uploading...' : (pdf.binectStatus === 'failed' ? 'Retry' : 'Upload')}
</button>
${canDeleteFromServer
? `<button class="btn-delete-server" data-id="${escapeHtml(pdf.id)}">Delete from server</button>`
: `<button class="btn-archive" data-id="${escapeHtml(pdf.id)}">Archive</button>`
}
<button class="btn-archive" data-id="${escapeHtml(pdf.id)}">Archive</button>
`;
break;
case 'erroneous':
// Server documents with errors - can only delete from server
actionsHtml = `
<button class="btn-delete-server" data-id="${escapeHtml(pdf.id)}">Delete from server</button>
`;
break;
case 'basket':
@@ -563,6 +568,20 @@ function renderPDFItem(pdf: DocumentProxy, section: 'pending' | 'basket' | 'prod
// Show detailed error info for erroneous documents
const hasErrorDetails = pdf.binectStatus === 'failed' && pdf.errorMessage && pdf.binectStatusCode === 7;
// Build metadata parts - only include what we have
const metaParts: string[] = [];
if (pdf.size > 0) {
metaParts.push(formatFileSize(pdf.size));
}
if (pdf.sourceDomain && pdf.sourceDomain !== 'binect.de') {
metaParts.push(escapeHtml(pdf.sourceDomain));
} else if (pdf.binectDocumentId && pdf.sourceDomain === 'binect.de') {
metaParts.push(`ID: ${pdf.binectDocumentId}`);
}
if (priceText) {
metaParts.push(`<span class="pdf-price">${priceText}</span>`);
}
return `
<div class="pdf-list-item ${statusClass}" data-id="${escapeHtml(pdf.id)}">
<div class="pdf-item-icon">${getStatusIcon(pdf.binectStatus)}</div>
@@ -571,10 +590,7 @@ function renderPDFItem(pdf: DocumentProxy, section: 'pending' | 'basket' | 'prod
${escapeHtml(displayFilename)}
${isLocalOnly ? '<span class="tag-local">local</span>' : ''}
</div>
<div class="pdf-item-meta">
${formatFileSize(pdf.size)} · ${escapeHtml(pdf.sourceDomain)}
${priceText ? ` · <span class="pdf-price">${priceText}</span>` : ''}
</div>
${metaParts.length > 0 ? `<div class="pdf-item-meta">${metaParts.join(' · ')}</div>` : ''}
${pdf.recipientAddress ? `<div class="pdf-item-recipient">${escapeHtml(pdf.recipientAddress.split('\n')[0])}</div>` : ''}
<div class="pdf-item-status ${statusClass}">${statusText}</div>
${hasErrorDetails ? `<div class="pdf-item-error">${escapeHtml(pdf.errorMessage!)}</div>` : ''}

View File

@@ -500,23 +500,17 @@ export async function listServerDocuments(
});
// Get shippable documents (status 2)
console.log('[Binect API] Fetching shippable documents...');
const shippableResponse = await client.documents.list();
console.log('[Binect API] Shippable response:', JSON.stringify(shippableResponse));
const shippable = shippableResponse.items || [];
console.log('[Binect API] Found', shippable.length, 'shippable documents');
// Get erroneous documents (status 7)
console.log('[Binect API] Fetching erroneous documents...');
const errorsResponse = await client.documents.listErrors();
console.log('[Binect API] Errors response:', JSON.stringify(errorsResponse));
const erroneous = errorsResponse.items || [];
console.log('[Binect API] Found', erroneous.length, 'erroneous documents');
// Combine and map to our format
const allDocs = [...shippable, ...erroneous];
console.log('[Binect API] Total documents on server:', allDocs.length);
console.log('[Binect API] Found', allDocs.length, 'documents on server (', shippable.length, 'shippable,', erroneous.length, 'erroneous)');
return allDocs.map(doc => {
let errorDetails: string | undefined;