Fixed template function call mismatches: - conflicts.templ: Renamed showConflictModal→showResolveModal, hideConflictModal→hideResolveModal, handleResolveConflict→handleResolveSubmit - collections.templ: Fixed case mismatch addSelectedBooks→addbooksToAdd - queue.templ: Removed dead /static/queue.js reference - progress.templ: Removed vestigial x-data="progress" attribute Added missing queue functions: - showQueueItemModal() - Shows queue item detail modal - hideQueueItemModal() - Hides queue item modal - filterQueue() - Filters queue by status (stubbed) Fixed build errors: - main.ts: Removed imports for deleted themeDropdown.ts and woodPaneling.ts files All fixes are minimal and conservative. No breaking changes to existing functionality. TypeScript builds successfully (168KB main.js). Templates regenerate successfully.
168 lines
7.7 KiB
Templ
168 lines
7.7 KiB
Templ
package templates
|
|
|
|
import "bookhoard/internal/handlers"
|
|
|
|
templ Queue(user User, queueItems []handlers.QueueItemResponse, stats handlers.QueueStatsResponse) {
|
|
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8"/>
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
|
<title>Sync Queue - Bookhoard</title>
|
|
<script src="/static/htmx.min.js"></script>
|
|
<script src="/static/main.js"></script>
|
|
<link href="/static/style.css" rel="stylesheet"/>
|
|
</head>
|
|
<body x-data="queue" class="theme-{ user.Theme }">
|
|
@Header(user, "/queue")
|
|
<div class="w-full px-4 sm:px-6 lg:px-8 py-8">
|
|
<div class="mb-8">
|
|
<div class="flex justify-between items-center">
|
|
<div>
|
|
<h1 class="text-3xl font-bold" style="color: var(--text-primary)">Sync Queue</h1>
|
|
<p style="color: var(--text-secondary)">Monitor and manage offline sync queue</p>
|
|
</div>
|
|
<div class="flex space-x-3">
|
|
<button @click="processPendingItems()" class="btn-primary px-4 py-2 rounded-lg">
|
|
Process Queue
|
|
</button>
|
|
<button @click="clearFailedItems()" class="btn-secondary px-4 py-2 rounded-lg">
|
|
Clear Failed
|
|
</button>
|
|
<button @click="clearAllItems()" class="btn-danger px-4 py-2 rounded-lg">
|
|
Clear All
|
|
</button>
|
|
</div>
|
|
</div>
|
|
<div id="stats-bar" class="mt-4 grid grid-cols-2 md:grid-cols-4 gap-4">
|
|
<div class="card p-4 rounded-lg border text-center" style="background-color: var(--bg-secondary); border-color: var(--border);">
|
|
<div class="text-3xl font-bold" style="color: #f59e0b;">{ stats.PendingCount }</div>
|
|
<div class="text-sm" style="color: var(--text-secondary);">Pending</div>
|
|
</div>
|
|
<div class="card p-4 rounded-lg border text-center" style="background-color: var(--bg-secondary); border-color: var(--border);">
|
|
<div class="text-3xl font-bold" style="color: #3b82f6;">{ stats.ProcessingCount }</div>
|
|
<div class="text-sm" style="color: var(--text-secondary);">Processing</div>
|
|
</div>
|
|
<div class="card p-4 rounded-lg border text-center" style="background-color: var(--bg-secondary); border-color: var(--border);">
|
|
<div class="text-3xl font-bold" style="color: #10b981;">{ stats.CompletedCount }</div>
|
|
<div class="text-sm" style="color: var(--text-secondary);">Completed</div>
|
|
</div>
|
|
<div class="card p-4 rounded-lg border text-center" style="background-color: var(--bg-secondary); border-color: var(--border);">
|
|
<div class="text-3xl font-bold" style="color: #ef4444;">{ stats.FailedCount }</div>
|
|
<div class="text-sm" style="color: var(--text-secondary);">Failed</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="card p-4 rounded-lg border mb-6" style="background-color: var(--bg-secondary); border-color: var(--border);">
|
|
<div class="flex flex-wrap gap-4 items-center">
|
|
<div>
|
|
<label class="block text-sm font-medium mb-2" style="color: var(--text-secondary)">Status Filter</label>
|
|
<select
|
|
id="status-filter"
|
|
onchange="filterQueue()"
|
|
class="px-4 py-2 border rounded-lg"
|
|
style="background-color: var(--bg-primary); color: var(--text-primary); border-color: var(--border);"
|
|
>
|
|
<option value="all">All Items</option>
|
|
<option value="pending" selected>Pending</option>
|
|
<option value="processing">Processing</option>
|
|
<option value="completed">Completed</option>
|
|
<option value="failed">Failed</option>
|
|
</select>
|
|
</div>
|
|
<div>
|
|
<label class="block text-sm font-medium mb-2" style="color: var(--text-secondary)">Sync Type</label>
|
|
<select
|
|
id="type-filter"
|
|
onchange="filterQueue()"
|
|
class="px-4 py-2 border rounded-lg"
|
|
style="background-color: var(--bg-primary); color: var(--text-primary); border-color: var(--border);"
|
|
>
|
|
<option value="all">All Types</option>
|
|
<option value="progress">Progress</option>
|
|
<option value="note">Notes</option>
|
|
<option value="highlight">Highlights</option>
|
|
<option value="bookmark">Bookmarks</option>
|
|
</select>
|
|
</div>
|
|
<div>
|
|
<label class="block text-sm font-medium mb-2" style="color: var(--text-secondary)">Device</label>
|
|
<select
|
|
id="device-filter"
|
|
onchange="filterQueue()"
|
|
class="px-4 py-2 border rounded-lg"
|
|
style="background-color: var(--bg-primary); color: var(--text-primary); border-color: var(--border);"
|
|
>
|
|
<option value="all">All Devices</option>
|
|
</select>
|
|
</div>
|
|
<div class="flex-1"></div>
|
|
<button @click="refreshQueue()" class="btn-secondary px-4 py-2 rounded-lg">
|
|
Refresh
|
|
</button>
|
|
</div>
|
|
</div>
|
|
<div id="loading" class="hidden text-center py-16" style="color: var(--text-secondary)">
|
|
<div class="loading-spinner mx-auto mb-4"></div>
|
|
<p>Loading queue...</p>
|
|
</div>
|
|
<div id="empty-state" class="hidden text-center py-16" style="color: var(--text-secondary)">
|
|
<div class="text-6xl mb-4">📭</div>
|
|
<h3 class="text-xl font-semibold mb-2" style="color: var(--text-primary)">Queue Empty</h3>
|
|
<p>No items in the sync queue</p>
|
|
</div>
|
|
<div id="queue-list" class="space-y-3">
|
|
if len(queueItems) == 0 {
|
|
<div class="text-center py-16" style="color: var(--text-secondary)">
|
|
<div class="text-6xl mb-4">📭</div>
|
|
<h3 class="text-xl font-semibold mb-2" style="color: var(--text-primary)">Queue Empty</h3>
|
|
<p>No items in the sync queue</p>
|
|
</div>
|
|
}
|
|
for _, item := range queueItems {
|
|
<div class="card p-4 rounded-lg border" style="background-color: var(--bg-secondary); border-color: var(--border);">
|
|
<div class="flex justify-between items-start mb-2">
|
|
<div class="flex items-center space-x-3">
|
|
<span class="inline-block px-2 py-0.5 rounded text-[11px] font-semibold uppercase status-{ item.Status }">{ item.Status }</span>
|
|
<span class="text-sm" style="color: var(--text-secondary)">{ item.SyncType }</span>
|
|
</div>
|
|
<span class="inline-block px-2 py-0.5 rounded text-[10px] font-semibold priority-{ item.Priority }">P{ item.Priority }</span>
|
|
</div>
|
|
<div class="text-sm mb-2" style="color: var(--text-secondary)">
|
|
Device ID: { item.DeviceID }
|
|
if item.MediaTitle != nil {
|
|
| Book: { *item.MediaTitle }
|
|
}
|
|
</div>
|
|
<div class="flex justify-between items-center text-sm" style="color: var(--text-secondary)">
|
|
<span>Attempts: { item.Attempts }/{ item.MaxAttempts }</span>
|
|
<span>{ item.CreatedAt }</span>
|
|
</div>
|
|
if item.ErrorMessage != nil {
|
|
<div class="mt-2 text-sm" style="color: #ef4444;">
|
|
Error: { *item.ErrorMessage }
|
|
</div>
|
|
}
|
|
</div>
|
|
}
|
|
</div>
|
|
<div id="queue-item-modal" class="hidden fixed inset-0 z-50 flex items-center justify-center overflow-y-auto" style="background-color: rgba(0, 0, 0, 0.7);">
|
|
<div class="card rounded-lg p-6 w-full max-w-2xl mx-4 my-8" style="background-color: var(--bg-secondary); border-color: var(--border);">
|
|
<div class="flex justify-between items-center mb-6">
|
|
<h2 class="text-2xl font-bold" style="color: var(--text-primary)">Queue Item Details</h2>
|
|
<button @click="hideQueueItemModal()" class="p-2 hover:opacity-80 rounded-lg" style="color: var(--text-primary); background-color: var(--bg-primary);">
|
|
X
|
|
</button>
|
|
</div>
|
|
<div id="queue-item-details"></div>
|
|
<div class="flex justify-end space-x-3 mt-6">
|
|
<button @click="hideQueueItemModal()" class="btn-secondary px-4 py-2 rounded-lg">Close</button>
|
|
<button @click="retryQueueItem()" class="btn-primary px-4 py-2 rounded-lg">Retry</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</body>
|
|
</html>
|
|
}
|