diff --git a/templates/admin_library.templ b/templates/admin_library.templ index 3bd5b56..a864b4f 100644 --- a/templates/admin_library.templ +++ b/templates/admin_library.templ @@ -1,170 +1,178 @@ package templates templ AdminLibrary(user User, libraries []LibraryData, users []User) { - - - - - Library Management - Bookhoard - - - - @Header(user, "/admin/library") + + + + + Library Management - Bookhoard + + + + @Header(user, "/admin/library") +
+ +
+
+
+
+ + ← Back to Dashboard + + +
+

Library Management

+

Manage libraries and configure media scanning

+
+
+ +
+

Libraries

+

Manage media libraries and their folders

+
+ if len(libraries) == 0 { +

+ No libraries yet. Create your first library to get started. +

+ } else { + for _, library := range libraries { +
+
+
+

{ library.Name }

+ if library.Description != "" { +

{ library.Description }

+ } + + { library.TypeName } + +
+
+ + + +
+
+ +
+ } + } +
+
+ +
+

Library Visibility

+

Control which libraries are visible to users

+
+ +
+
+
+ +
+

User Library Access

+

Manage individual user access to specific libraries

+
+ +
+
+ +
+
+
+
+
+ + + + -
- + + - -
- - - - - - - - - - - - - - -} \ No newline at end of file + + + + + + + +} diff --git a/templates/admin_library_templ.go b/templates/admin_library_templ.go index ff0e5d8..3bc7cb9 100644 --- a/templates/admin_library_templ.go +++ b/templates/admin_library_templ.go @@ -55,7 +55,7 @@ func AdminLibrary(user User, libraries []LibraryData, users []User) templ.Compon var templ_7745c5c3_Var2 string templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(library.Name) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/admin_library.templ`, Line: 63, Col: 127} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `admin_library.templ`, Line: 59, Col: 89} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var2)) if templ_7745c5c3_Err != nil { @@ -73,7 +73,7 @@ func AdminLibrary(user User, libraries []LibraryData, users []User) templ.Compon var templ_7745c5c3_Var3 string templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(library.Description) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/admin_library.templ`, Line: 65, Col: 133} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `admin_library.templ`, Line: 61, Col: 92} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3)) if templ_7745c5c3_Err != nil { @@ -91,55 +91,107 @@ func AdminLibrary(user User, libraries []LibraryData, users []User) templ.Compon var templ_7745c5c3_Var4 string templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(library.TypeName) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/admin_library.templ`, Line: 68, Col: 74} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `admin_library.templ`, Line: 64, Col: 33} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 9, "
") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 9, "
") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } } } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, "

Library Visibility

Control which libraries are visible to users

User Library Access

Manage individual user access to specific libraries

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } for _, user := range users { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 11, "") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 17, ")") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 14, "

Create Library

") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 18, "

Create Library

Browse Folders

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } diff --git a/web/src/library.ts b/web/src/library.ts index 6ceba84..cf8d9dc 100644 --- a/web/src/library.ts +++ b/web/src/library.ts @@ -195,33 +195,7 @@ async function deleteLibrary(libraryId: string): Promise { const library = libraries.find(l => l.id === libraryId); if (!library) return; - const message = `Are you sure you want to delete "${library.name}"? - -This will remove: -• Library metadata from the database -• All folder references -• All book records from the database - -⚠️ Book files on disk will NOT be deleted. - -This action cannot be undone.`; - - if (!confirm(message)) { - return; - } - - try { - const response = await (window as any).api.delete(`/libraries/${libraryId}`); - await (window as any).api.handleVoidResponse(response); - - if ((window as any).showToast?.success) { - (window as any).showToast.success('Library deleted successfully'); - } - - await reloadLibraries(); - } catch (error) { - (window as any).api.handleError(error, 'Failed to delete library'); - } + showDeleteModal(library); } // Show library folders @@ -361,6 +335,60 @@ function hideCreateLibraryModal(): void { } } +// Delete modal state +let libraryToDelete: Library | null = null; + +function showDeleteModal(library: Library): void { + libraryToDelete = library; + + const modal = document.getElementById('delete-library-modal') as HTMLElement; + const content = document.getElementById('delete-modal-content') as HTMLElement; + + if (modal && content) { + const message = `Are you sure you want to delete "${escapeHtmlLocal(library.name)}"? + +This will remove: +• Library metadata from the database +• All folder references +• All book records from the database + +⚠️ Book files on disk will NOT be deleted. + +This action cannot be undone.`; + + content.innerHTML = message.replace(/\n/g, '
'); + modal.classList.remove('hidden'); + } +} + +function hideDeleteModal(): void { + const modal = document.getElementById('delete-library-modal') as HTMLElement; + if (modal) { + modal.classList.add('hidden'); + } + libraryToDelete = null; +} + +async function confirmDeleteLibrary(): Promise { + if (!libraryToDelete) return; + + const libraryId = libraryToDelete.id; + hideDeleteModal(); + + try { + const response = await (window as any).api.delete(`/libraries/${libraryId}`); + await (window as any).api.handleVoidResponse(response); + + if ((window as any).showToast?.success) { + (window as any).showToast.success('Library deleted successfully'); + } + + await reloadLibraries(); + } catch (error) { + (window as any).api.handleError(error, 'Failed to delete library'); + } +} + // Local escape HTML helper function escapeHtmlLocal(text: string): string { const div = document.createElement('div'); @@ -443,6 +471,12 @@ function handleGlobalClick(event: Event): void { case 'hide-create-modal': hideCreateLibraryModal(); break; + case 'hide-delete-modal': + hideDeleteModal(); + break; + case 'confirm-delete': + void confirmDeleteLibrary(); + break; } } @@ -564,12 +598,8 @@ function initializeLibraryAdmin(): void { createLibraryForm.addEventListener('submit', handleCreateLibrarySubmit); } - // Initial data is already SSR'd, no need to fetch - // Just store it for updates - const ssrLibraries = document.querySelectorAll('#libraries-list [data-library-id]'); - if (ssrLibraries.length === 0) { - // No libraries SSR'd, which is fine - } + // Load libraries from API on page load + void reloadLibraries(); } // Export functions for global access @@ -585,6 +615,9 @@ function initializeLibraryAdmin(): void { (window as any).navigateFolderBrowser = navigateFolderBrowser; (window as any).selectBrowseFolder = selectBrowseFolder; (window as any).hideFolderBrowser = hideFolderBrowser; +(window as any).showDeleteModal = showDeleteModal; +(window as any).hideDeleteModal = hideDeleteModal; +(window as any).confirmDeleteLibrary = confirmDeleteLibrary; // Initialize on DOM ready if (document.readyState === 'loading') {