@@ -346,6 +370,132 @@ templ UnlinkedBooks(user User, unlinkedBooks []UnlinkedBookData) {
localStorage.removeItem('token');
window.location.href = '/login';
}
+
+ // Bulk Operations Functions
+
+ function toggleAllUnlinked() {
+ const selectAll = document.getElementById('select-all-unlinked');
+ document.querySelectorAll('.unlinked-checkbox').forEach(cb => {
+ cb.checked = selectAll.checked;
+ });
+ updateSelectedCount();
+ }
+
+ function getSelectedUnlinked() {
+ return Array.from(document.querySelectorAll('.unlinked-checkbox:checked'))
+ .map(cb => ({
+ progressId: cb.getAttribute('data-progress-id'),
+ title: cb.getAttribute('data-title')
+ }));
+ }
+
+ function updateSelectedCount() {
+ const count = document.querySelectorAll('.unlinked-checkbox:checked').length;
+ document.getElementById('selected-count').textContent = `${count} selected`;
+ }
+
+ async function bulkAutoLink() {
+ const selected = getSelectedUnlinked();
+ if (selected.length === 0) {
+ showToast('Please select at least one book', 'error');
+ return;
+ }
+
+ if (!confirm(`Auto-link ${selected.length} books with high confidence matches (≥80%)?`)) {
+ return;
+ }
+
+ try {
+ const response = await fetch('/sync/auto-link-books', {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ 'Authorization': 'Bearer ' + localStorage.getItem('token')
+ },
+ body: JSON.stringify({
+ confidence_threshold: 0.8,
+ limit: selected.length
+ })
+ });
+
+ const result = await response.json();
+ showToast(`Auto-linked ${result.auto_linked} books successfully`, 'success');
+ setTimeout(() => location.reload(), 1500);
+ } catch (error) {
+ showToast('Auto-link failed: ' + error.message, 'error');
+ }
+ }
+
+ async function bulkGetSuggestions() {
+ const selected = getSelectedUnlinked();
+ if (selected.length === 0) {
+ showToast('Please select at least one book', 'error');
+ return;
+ }
+
+ for (const book of selected) {
+ try {
+ const response = await fetch(`/sync/unlinked-books/${book.progressId}/suggestions`, {
+ headers: {
+ 'Authorization': 'Bearer ' + localStorage.getItem('token')
+ }
+ });
+
+ const result = await response.json();
+ displaySuggestions(book.progressId, result.suggestions, result.action);
+ } catch (error) {
+ console.error('Failed to get suggestions:', error);
+ }
+ }
+ }
+
+ function displaySuggestions(progressId, suggestions, action) {
+ const container = document.getElementById(`matches-${progressId}`);
+ if (!container) return;
+
+ container.classList.remove('hidden');
+ const listContainer = container.querySelector('.matches-list');
+ listContainer.innerHTML = '';
+
+ if (suggestions.length === 0) {
+ listContainer.innerHTML = '
No matches found
';
+ return;
+ }
+
+ suggestions.forEach(match => {
+ const div = document.createElement('div');
+ div.className = 'p-3 border rounded cursor-pointer hover:bg-opacity-80 transition-colors';
+ div.style.cssText = `background-color: var(--bg-primary); border-color: var(--border);`;
+ div.innerHTML = `
+
+
+
${match.title}
+
Author: ${match.author || 'Unknown'}
+
+
+
+ ${(match.confidence * 100).toFixed(0)}% confidence
+
+
${match.match_method}
+
+
+ `;
+ div.onclick = () => selectMatchForLink(progressId, match);
+ listContainer.appendChild(div);
+ });
+ }
+
+ function showBulkManualLink() {
+ const selected = getSelectedUnlinked();
+ if (selected.length === 0) {
+ showToast('Please select at least one book', 'error');
+ return;
+ }
+
+ showToast(`Bulk manual link for ${selected.length} books - select target book in library`, 'info');
+ // For now, redirect to manual linking. In the future, this could open a modal
+ window.location.href = '/library?mode=link&unlinked=' + selected.map(s => s.progressId).join(',');
+ }