🪻 distributed transcription service thistle.dunkirk.sh
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

feat: use the query param to indicate tab in admin ui

+42 -12
+10 -1
CRUSH.md
··· 565 565 566 566 **Admin UI features:** 567 567 - Statistics cards (total users, total/failed transcriptions) 568 - - Tabbed interface (Transcriptions / Users) 568 + - Tabbed interface (Pending Recordings / Transcriptions / Users / Classes) 569 569 - Status badges for transcription states 570 570 - Delete buttons for transcriptions with confirmation 571 571 - Role dropdown for changing user roles ··· 573 573 - User avatars and info display 574 574 - Timestamp formatting 575 575 - Admin badge on user listings 576 + - Query parameter support for direct tab navigation (`?tab=<tabname>`) 577 + 578 + **Admin tab navigation:** 579 + - `/admin` - Opens to default "pending" tab 580 + - `/admin?tab=pending` - Pending recordings tab 581 + - `/admin?tab=transcriptions` - All transcriptions tab 582 + - `/admin?tab=users` - Users management tab 583 + - `/admin?tab=classes` - Classes management tab 584 + - URL updates when switching tabs (browser history support) 576 585 577 586 **Implementation notes:** 578 587 - `role` column in users table ('user' or 'admin', default 'user')
+32 -11
src/pages/admin.html
··· 301 301 } 302 302 303 303 // Tab switching 304 + function switchTab(tabName) { 305 + document.querySelectorAll('.tab').forEach(t => { 306 + t.classList.remove('active'); 307 + }); 308 + document.querySelectorAll('.tab-content').forEach(c => { 309 + c.classList.remove('active'); 310 + }); 311 + 312 + const tabButton = document.querySelector(`[data-tab="${tabName}"]`); 313 + const tabContent = document.getElementById(`${tabName}-tab`); 314 + 315 + if (tabButton && tabContent) { 316 + tabButton.classList.add('active'); 317 + tabContent.classList.add('active'); 318 + 319 + // Update URL without reloading 320 + const url = new URL(window.location.href); 321 + url.searchParams.set('tab', tabName); 322 + window.history.pushState({}, '', url); 323 + } 324 + } 325 + 304 326 document.querySelectorAll('.tab').forEach(tab => { 305 327 tab.addEventListener('click', () => { 306 - const tabName = tab.dataset.tab; 307 - 308 - document.querySelectorAll('.tab').forEach(t => { 309 - t.classList.remove('active'); 310 - }); 311 - document.querySelectorAll('.tab-content').forEach(c => { 312 - c.classList.remove('active'); 313 - }); 314 - 315 - tab.classList.add('active'); 316 - document.getElementById(`${tabName}-tab`).classList.add('active'); 328 + switchTab(tab.dataset.tab); 317 329 }); 318 330 }); 331 + 332 + // Check for tab query parameter on load 333 + const params = new URLSearchParams(window.location.search); 334 + const initialTab = params.get('tab'); 335 + const validTabs = ['pending', 'transcriptions', 'users', 'classes']; 336 + 337 + if (initialTab && validTabs.includes(initialTab)) { 338 + switchTab(initialTab); 339 + } 319 340 320 341 // Initialize 321 342 loadStats();