- Add search.ts - header search with keyboard navigation - Debounced search with 300ms delay - Arrow key navigation through results - Escape to close, Enter to select - Library type icons and highlighting - Add collections.ts - collection and rule management - Rule CRUD operations (create, update, delete) - Rule testing functionality - Bulk collection operations - Add bookshelf.ts - book display and navigation - Library selection state management - Book viewing interactions - Pagination logic - Add linking.ts - book matching and manual linking - Search and match functionality - Manual link modal - Bulk auto-link and suggestions - Add api-explorer.ts - API testing interface - Request/response display - cURL command generation - History tracking - Add admin.ts - admin dashboard actions - Library scan triggers - System statistics display - Profile management - Add analytics.ts - analytics data loading - Chart.js integration - Daily reading minutes chart - Device usage and popular books display - Add queue.ts - sync queue management - Process pending items - Clear failed/all items - Filter by status, type, device - Add conflicts.ts - conflict resolution - Individual and bulk resolve operations - Winner device selection - Manual override inputs - Add docs.ts - documentation search - Lunr.js search integration - Sidebar toggle for mobile
104 lines
3.9 KiB
TypeScript
104 lines
3.9 KiB
TypeScript
async function triggerLibraryScan(): Promise<void> {
|
|
const token = localStorage.getItem('token');
|
|
if (!token) return;
|
|
|
|
try {
|
|
const response = await fetch('/api/libraries/scan', {
|
|
method: 'POST',
|
|
headers: { 'Authorization': `Bearer ${token}` }
|
|
});
|
|
|
|
if (response.ok) {
|
|
if ((window as any).showToast?.success) {
|
|
(window as any).showToast.success('Library scan started');
|
|
}
|
|
} else {
|
|
const error = await response.json();
|
|
if ((window as any).showToast?.error) {
|
|
(window as any).showToast.error(error.error || 'Failed to start scan');
|
|
}
|
|
}
|
|
} catch (error) {
|
|
console.error('Scan error:', error);
|
|
if ((window as any).showToast?.error) {
|
|
(window as any).showToast.error('Failed to start library scan');
|
|
}
|
|
}
|
|
}
|
|
|
|
async function triggerQuickScan(): Promise<void> {
|
|
const token = localStorage.getItem('token');
|
|
if (!token) return;
|
|
|
|
try {
|
|
const response = await fetch('/api/libraries/quick-scan', {
|
|
method: 'POST',
|
|
headers: { 'Authorization': `Bearer ${token}` }
|
|
});
|
|
|
|
if (response.ok) {
|
|
if ((window as any).showToast?.success) {
|
|
(window as any).showToast.success('Quick scan started');
|
|
}
|
|
} else {
|
|
const error = await response.json();
|
|
if ((window as any).showToast?.error) {
|
|
(window as any).showToast.error(error.error || 'Failed to start quick scan');
|
|
}
|
|
}
|
|
} catch (error) {
|
|
console.error('Quick scan error:', error);
|
|
if ((window as any).showToast?.error) {
|
|
(window as any).showToast.error('Failed to start quick scan');
|
|
}
|
|
}
|
|
}
|
|
|
|
async function loadSystemStats(): Promise<void> {
|
|
const token = localStorage.getItem('token');
|
|
if (!token) return;
|
|
|
|
try {
|
|
const response = await fetch('/api/admin/stats', {
|
|
headers: { 'Authorization': `Bearer ${token}` }
|
|
});
|
|
|
|
if (response.ok) {
|
|
const stats = await response.json();
|
|
renderSystemStats(stats);
|
|
}
|
|
} catch (error) {
|
|
console.error('Failed to load stats:', error);
|
|
}
|
|
}
|
|
|
|
function renderSystemStats(stats: Record<string, unknown>): void {
|
|
const container = document.getElementById('system-stats');
|
|
if (!container) return;
|
|
|
|
container.innerHTML = `
|
|
<div class="grid grid-cols-2 md:grid-cols-4 gap-4">
|
|
<div class="p-4 rounded-lg" style="background-color: var(--bg-secondary)">
|
|
<p class="text-2xl font-bold" style="color: var(--text-primary)">${stats.total_books || 0}</p>
|
|
<p class="text-sm" style="color: var(--text-secondary)">Total Books</p>
|
|
</div>
|
|
<div class="p-4 rounded-lg" style="background-color: var(--bg-secondary)">
|
|
<p class="text-2xl font-bold" style="color: var(--text-primary)">${stats.total_users || 0}</p>
|
|
<p class="text-sm" style="color: var(--text-secondary)">Users</p>
|
|
</div>
|
|
<div class="p-4 rounded-lg" style="background-color: var(--bg-secondary)">
|
|
<p class="text-2xl font-bold" style="color: var(--text-primary)">${stats.total_devices || 0}</p>
|
|
<p class="text-sm" style="color: var(--text-secondary)">Devices</p>
|
|
</div>
|
|
<div class="p-4 rounded-lg" style="background-color: var(--bg-secondary)">
|
|
<p class="text-2xl font-bold" style="color: var(--text-primary)">${stats.total_libraries || 0}</p>
|
|
<p class="text-sm" style="color: var(--text-secondary)">Libraries</p>
|
|
</div>
|
|
</div>
|
|
`;
|
|
}
|
|
|
|
(window as any).triggerLibraryScan = triggerLibraryScan;
|
|
(window as any).triggerQuickScan = triggerQuickScan;
|
|
(window as any).loadSystemStats = loadSystemStats;
|