generated from coulomb/repo-seed
Add PDF list view with upload status tracking
- Show all pending PDFs in a scrollable list instead of single PDF - Track upload status (pending/uploading/uploaded/failed) per PDF - Store queue in chrome.storage.local for persistence - Prevent duplicate uploads by checking URL against uploaded PDFs - Add Dismiss button to remove PDFs from queue - Show badge with count of pending PDFs - Auto-cleanup old entries (uploaded >7 days, failed >24h) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,13 +1,19 @@
|
||||
/**
|
||||
* Service Worker (Background Script)
|
||||
* Handles PDF detection and credential expiry checks
|
||||
* Handles PDF detection, queue management, and credential expiry checks
|
||||
*/
|
||||
|
||||
import { startPDFDetection, DetectedPDF } from '../utils/pdf-detector';
|
||||
import { loadCredentials } from '../utils/storage';
|
||||
|
||||
// Store last detected PDF in memory (ephemeral)
|
||||
let lastDetectedPDF: DetectedPDF | null = null;
|
||||
import {
|
||||
addPDF,
|
||||
getPendingCount,
|
||||
getPendingPDFs,
|
||||
updatePDFStatus,
|
||||
removePDF,
|
||||
cleanupOldEntries,
|
||||
PDFStatus
|
||||
} from '../utils/pdf-queue';
|
||||
|
||||
/**
|
||||
* Initialize extension on install
|
||||
@@ -16,9 +22,10 @@ chrome.runtime.onInstalled.addListener((details) => {
|
||||
console.log('[Service Worker] onInstalled event:', details.reason);
|
||||
if (details.reason === 'install') {
|
||||
console.log('[Service Worker] BinectChrome installed');
|
||||
setupCredentialExpiryAlarm();
|
||||
setupAlarms();
|
||||
} else if (details.reason === 'update') {
|
||||
console.log('[Service Worker] BinectChrome updated');
|
||||
setupAlarms();
|
||||
}
|
||||
});
|
||||
|
||||
@@ -27,16 +34,24 @@ chrome.runtime.onInstalled.addListener((details) => {
|
||||
*/
|
||||
chrome.runtime.onStartup.addListener(() => {
|
||||
console.log('[Service Worker] onStartup event - BinectChrome started');
|
||||
setupCredentialExpiryAlarm();
|
||||
setupAlarms();
|
||||
updateBadge();
|
||||
});
|
||||
|
||||
/**
|
||||
* Set up alarm to check credential expiry daily
|
||||
* Set up alarms for periodic tasks
|
||||
*/
|
||||
function setupCredentialExpiryAlarm() {
|
||||
function setupAlarms() {
|
||||
// Credential expiry check
|
||||
chrome.alarms.create('checkCredentialExpiry', {
|
||||
delayInMinutes: 1, // First check in 1 minute
|
||||
periodInMinutes: 24 * 60 // Then every 24 hours
|
||||
delayInMinutes: 1,
|
||||
periodInMinutes: 24 * 60 // Every 24 hours
|
||||
});
|
||||
|
||||
// PDF queue cleanup
|
||||
chrome.alarms.create('cleanupPDFQueue', {
|
||||
delayInMinutes: 60, // First cleanup in 1 hour
|
||||
periodInMinutes: 6 * 60 // Every 6 hours
|
||||
});
|
||||
}
|
||||
|
||||
@@ -47,6 +62,9 @@ chrome.alarms.onAlarm.addListener((alarm) => {
|
||||
if (alarm.name === 'checkCredentialExpiry') {
|
||||
checkAndDeleteExpiredCredentials();
|
||||
}
|
||||
if (alarm.name === 'cleanupPDFQueue') {
|
||||
cleanupOldEntries();
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
@@ -54,39 +72,43 @@ chrome.alarms.onAlarm.addListener((alarm) => {
|
||||
*/
|
||||
async function checkAndDeleteExpiredCredentials() {
|
||||
const credentials = await loadCredentials();
|
||||
// loadCredentials already handles expiry check and deletion
|
||||
// If credentials are expired, it returns null and deletes them
|
||||
if (credentials === null) {
|
||||
console.log('Credentials expired and deleted');
|
||||
console.log('[Service Worker] Credentials expired and deleted');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize badge with default icon
|
||||
* Update badge with pending PDF count
|
||||
*/
|
||||
function initializeBadge() {
|
||||
// Set a default badge to make extension visible
|
||||
chrome.action.setBadgeText({ text: '•' });
|
||||
async function updateBadge() {
|
||||
const count = await getPendingCount();
|
||||
const text = count > 0 ? count.toString() : '•';
|
||||
chrome.action.setBadgeText({ text });
|
||||
chrome.action.setBadgeBackgroundColor({ color: '#4A90E2' }); // Binect Blue
|
||||
console.log('[Service Worker] Default badge set');
|
||||
console.log('[Service Worker] Badge updated:', text);
|
||||
}
|
||||
|
||||
// Initialize badge on load
|
||||
initializeBadge();
|
||||
updateBadge();
|
||||
|
||||
/**
|
||||
* Start PDF detection
|
||||
*/
|
||||
console.log('[Service Worker] Initializing PDF detection...');
|
||||
startPDFDetection((pdf: DetectedPDF) => {
|
||||
console.log('[Service Worker] PDF DETECTED CALLBACK:', pdf.filename);
|
||||
lastDetectedPDF = pdf;
|
||||
startPDFDetection(async (pdf: DetectedPDF) => {
|
||||
console.log('[Service Worker] PDF DETECTED:', pdf.filename);
|
||||
|
||||
// Update badge to indicate PDF detected
|
||||
chrome.action.setBadgeText({ text: '1' });
|
||||
chrome.action.setBadgeBackgroundColor({ color: '#4A90E2' }); // Binect Blue
|
||||
// Add to persistent queue
|
||||
const entry = await addPDF(pdf);
|
||||
|
||||
console.log('[Service Worker] Badge updated, PDF stored in memory');
|
||||
if (entry) {
|
||||
console.log('[Service Worker] PDF added to queue:', entry.filename);
|
||||
} else {
|
||||
console.log('[Service Worker] PDF skipped (already uploaded):', pdf.filename);
|
||||
}
|
||||
|
||||
// Update badge
|
||||
await updateBadge();
|
||||
});
|
||||
|
||||
/**
|
||||
@@ -95,25 +117,47 @@ startPDFDetection((pdf: DetectedPDF) => {
|
||||
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
|
||||
console.log('[Service Worker] Message received:', request.action);
|
||||
|
||||
if (request.action === 'getPDFQueue') {
|
||||
getPendingPDFs().then(entries => {
|
||||
console.log('[Service Worker] Returning PDF queue:', entries.length, 'entries');
|
||||
sendResponse({ entries });
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
if (request.action === 'updatePDFStatus') {
|
||||
const { id, status, meta } = request as { id: string; status: PDFStatus; meta?: object };
|
||||
updatePDFStatus(id, status, meta).then(() => {
|
||||
return updateBadge();
|
||||
}).then(() => {
|
||||
sendResponse({ success: true });
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
if (request.action === 'removePDF') {
|
||||
removePDF(request.id).then(() => {
|
||||
return updateBadge();
|
||||
}).then(() => {
|
||||
sendResponse({ success: true });
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
// Legacy handlers for backward compatibility
|
||||
if (request.action === 'getLastPDF') {
|
||||
console.log('[Service Worker] Returning last PDF:', lastDetectedPDF ? lastDetectedPDF.filename : 'none');
|
||||
sendResponse({ pdf: lastDetectedPDF });
|
||||
// Return the first pending PDF for backward compatibility
|
||||
getPendingPDFs().then(entries => {
|
||||
const pdf = entries.length > 0 ? entries[0] : null;
|
||||
sendResponse({ pdf });
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
if (request.action === 'clearLastPDF') {
|
||||
console.log('[Service Worker] Clearing last PDF');
|
||||
lastDetectedPDF = null;
|
||||
chrome.action.setBadgeText({ text: '•' }); // Reset to default badge
|
||||
sendResponse({ success: true });
|
||||
return true;
|
||||
}
|
||||
|
||||
if (request.action === 'pdfSent') {
|
||||
console.log('[Service Worker] PDF sent, resetting badge');
|
||||
// Reset badge after successful send
|
||||
chrome.action.setBadgeText({ text: '•' }); // Reset to default badge
|
||||
sendResponse({ success: true });
|
||||
if (request.action === 'clearLastPDF' || request.action === 'pdfSent') {
|
||||
updateBadge().then(() => {
|
||||
sendResponse({ success: true });
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user