From a87c8afc2282429b47c78f9993a50f42f80d4b1a Mon Sep 17 00:00:00 2001 From: John O'Keefe Date: Fri, 7 Aug 2026 09:35:30 -0400 Subject: [PATCH] refactor(admin): remove separate sidebar, integrate admin nav into main sidebar - Delete AdminSidebar component entirely - Add Administration section (Dashboard, Libraries, Users, Settings) to header sidebar, visible only for admin users - Remove Admin Panel link from user dropdown - Strip admin chrome (sidebar wrapper, back buttons) from all 5 admin page templates - Fix activeClass to handle trailing-slash routes correctly - Add isUserVisible helper for library visibility toggles - Fix processing issues page: remove dead Alpine JS, wire HTMX dismiss with proper mediaItemId, add issue ID swap targets - Add processing issue resolve/delete routes to library router - Add GetProcessingIssueStatsData context-based method - Fix users page: remove broken hx-headers auth, simplify role select - Fix settings page: remove dead adminSettings Alpine ref --- internal/handlers/processing_issues.go | 6 + internal/router/library.go | 2 + templates/admin_processing_issues.templ | 59 +++--- templates/admin_processing_issues_templ.go | 171 ++++++++++-------- templates/admin_settings.templ | 41 ++--- templates/admin_settings_templ.go | 168 ++++++++--------- templates/admin_sidebar.templ | 32 ---- templates/admin_sidebar_templ.go | 168 ----------------- templates/admin_users.templ | 25 +-- templates/admin_users_templ.go | 88 +++++---- templates/header.templ | 29 ++- templates/header_templ.go | 200 ++++++++++++++++----- templates/utils.go | 11 +- 13 files changed, 467 insertions(+), 533 deletions(-) delete mode 100644 templates/admin_sidebar.templ delete mode 100644 templates/admin_sidebar_templ.go diff --git a/internal/handlers/processing_issues.go b/internal/handlers/processing_issues.go index cb5b03e..7d34c8f 100644 --- a/internal/handlers/processing_issues.go +++ b/internal/handlers/processing_issues.go @@ -2,6 +2,7 @@ package handlers import ( "bookhoard/internal/database" + "context" "net/http" "time" @@ -139,3 +140,8 @@ func (h *ProcessingIssuesHandler) DeleteProcessingIssue(c *echo.Context) error { "message": "Issue deleted", }) } + +// GetProcessingIssueStatsData returns stats for SSR (not JSON response) +func (h *ProcessingIssuesHandler) GetProcessingIssueStatsData(ctx context.Context, libraryID pgtype.UUID) (database.GetProcessingIssueStatsRow, error) { + return h.db.GetProcessingIssueStats(ctx, libraryID) +} diff --git a/internal/router/library.go b/internal/router/library.go index f2582c6..b86cb4a 100644 --- a/internal/router/library.go +++ b/internal/router/library.go @@ -38,6 +38,8 @@ func registerLibraryRoutes(cfg *Config) { adminLibrary.GET("/:id/stats", cfg.LibraryHandler.GetLibraryStats) adminLibrary.GET("/:id/issues/list", cfg.ProcessingIssuesHandler.ListProcessingIssues) adminLibrary.GET("/:id/issues/stats", cfg.ProcessingIssuesHandler.GetProcessingIssueStats) + adminLibrary.POST("/:id/issues/:issueId/:mediaItemId/resolve", cfg.ProcessingIssuesHandler.ResolveProcessingIssue) + adminLibrary.DELETE("/:id/issues/:issueId", cfg.ProcessingIssuesHandler.DeleteProcessingIssue) adminLibrary.POST("/:id/scan", func(c *echo.Context) error { libraryID := c.Param("id") scanReq := map[string]interface{}{ diff --git a/templates/admin_processing_issues.templ b/templates/admin_processing_issues.templ index 9c58178..82d5bf7 100644 --- a/templates/admin_processing_issues.templ +++ b/templates/admin_processing_issues.templ @@ -8,27 +8,21 @@ templ AdminProcessingIssues(user User, libraryID string, issues []ProcessingIssu Processing Issues - Bookhoard - - @Header(user, "/admin/libraries/"+libraryID) -
-
-
-
-
-
- - @Icon("alert", "h-5 w-5") - -

Processing Issues

-
-

Items that couldn't be processed in this library

-
- - @Icon("arrow-left", "h-4 w-4") - Back to Library - + + @Header(user, "/admin/library") +
+
+
+
+
+ + @Icon("alert", "h-5 w-5") + +

Processing Issues

+

Items that couldn't be processed in this library

+
if stats.ErrorCount > 0 || stats.WarningCount > 0 || stats.InfoCount > 0 {
@@ -72,7 +66,7 @@ templ AdminProcessingIssues(user User, libraryID string, issues []ProcessingIssu
for _, issue := range issues { -
+

{ issue.Title }

@@ -94,17 +88,20 @@ templ AdminProcessingIssues(user User, libraryID string, issues []ProcessingIssu }
-
- if issue.Severity == "warning" || issue.Severity == "info" { - - } -
+
+ if issue.Severity == "warning" || issue.Severity == "info" { + + } +
}
diff --git a/templates/admin_processing_issues_templ.go b/templates/admin_processing_issues_templ.go index 0b56c9a..0242e7e 100644 --- a/templates/admin_processing_issues_templ.go +++ b/templates/admin_processing_issues_templ.go @@ -29,15 +29,15 @@ func AdminProcessingIssues(user User, libraryID string, issues []ProcessingIssue templ_7745c5c3_Var1 = templ.NopComponent } ctx = templ.ClearChildren(ctx) - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "Processing Issues - Bookhoard") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "Processing Issues - Bookhoard") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = Header(user, "/admin/libraries/"+libraryID).Render(ctx, templ_7745c5c3_Buffer) + templ_7745c5c3_Err = Header(user, "/admin/library").Render(ctx, templ_7745c5c3_Buffer) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "
") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "
") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -45,25 +45,17 @@ func AdminProcessingIssues(user User, libraryID string, issues []ProcessingIssue if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "

Processing Issues

Items that couldn't be processed in this library

") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = Icon("arrow-left", "h-4 w-4").Render(ctx, templ_7745c5c3_Buffer) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "Back to Library
") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "

Processing Issues

Items that couldn't be processed in this library

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } if stats.ErrorCount > 0 || stats.WarningCount > 0 || stats.InfoCount > 0 { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "
") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "
") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } if stats.ErrorCount > 0 { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "
") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "
") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -71,26 +63,26 @@ func AdminProcessingIssues(user User, libraryID string, issues []ProcessingIssue if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, "

Errors

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

Errors

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } var templ_7745c5c3_Var2 string templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(stats.ErrorCount) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/admin_processing_issues.templ`, Line: 41, Col: 92} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/admin_processing_issues.templ`, Line: 35, Col: 92} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var2)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 8, "

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

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } } if stats.WarningCount > 0 { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 9, "
") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 8, "
") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -98,26 +90,26 @@ func AdminProcessingIssues(user User, libraryID string, issues []ProcessingIssue if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, "

Warnings

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

Warnings

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } var templ_7745c5c3_Var3 string templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(stats.WarningCount) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/admin_processing_issues.templ`, Line: 50, Col: 94} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/admin_processing_issues.templ`, Line: 44, Col: 94} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 11, "

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

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } } if stats.InfoCount > 0 { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 12, "
") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 11, "
") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -125,31 +117,31 @@ func AdminProcessingIssues(user User, libraryID string, issues []ProcessingIssue if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, "

Info

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

Info

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } var templ_7745c5c3_Var4 string templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(stats.InfoCount) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/admin_processing_issues.templ`, Line: 59, Col: 91} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/admin_processing_issues.templ`, Line: 53, Col: 91} } _, 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, 14, "

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

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 15, "
") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 14, "
") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } } if len(issues) == 0 { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 16, "
") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 15, "
") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -157,26 +149,39 @@ func AdminProcessingIssues(user User, libraryID string, issues []ProcessingIssue if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 17, "

No processing issues found for this library.

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

No processing issues found for this library.

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } } else { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 18, "
") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 17, "
") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } for _, issue := range issues { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 19, "

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

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var6 string + templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(issue.Title) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/admin_processing_issues.templ`, Line: 72, Col: 98} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -184,12 +189,12 @@ func AdminProcessingIssues(user User, libraryID string, issues []ProcessingIssue if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - var templ_7745c5c3_Var6 string - templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(issue.IssueDescription) + var templ_7745c5c3_Var7 string + templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(issue.IssueDescription) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/admin_processing_issues.templ`, Line: 79, Col: 96} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/admin_processing_issues.templ`, Line: 73, Col: 96} } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6)) + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -197,12 +202,12 @@ func AdminProcessingIssues(user User, libraryID string, issues []ProcessingIssue if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - var templ_7745c5c3_Var7 string - templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(issue.IssueType) + var templ_7745c5c3_Var8 string + templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinStringErrs(issue.IssueType) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/admin_processing_issues.templ`, Line: 81, Col: 140} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/admin_processing_issues.templ`, Line: 75, Col: 140} } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7)) + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var8)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -210,12 +215,12 @@ func AdminProcessingIssues(user User, libraryID string, issues []ProcessingIssue if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - var templ_7745c5c3_Var8 string - templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinStringErrs(issue.FormatGroup) + var templ_7745c5c3_Var9 string + templ_7745c5c3_Var9, templ_7745c5c3_Err = templ.JoinStringErrs(issue.FormatGroup) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/admin_processing_issues.templ`, Line: 82, Col: 144} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/admin_processing_issues.templ`, Line: 76, Col: 144} } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var8)) + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var9)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -223,12 +228,12 @@ func AdminProcessingIssues(user User, libraryID string, issues []ProcessingIssue if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - var templ_7745c5c3_Var9 string - templ_7745c5c3_Var9, templ_7745c5c3_Err = templ.JoinStringErrs(issue.FilePath) + var templ_7745c5c3_Var10 string + templ_7745c5c3_Var10, templ_7745c5c3_Err = templ.JoinStringErrs(issue.FilePath) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/admin_processing_issues.templ`, Line: 83, Col: 139} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/admin_processing_issues.templ`, Line: 77, Col: 139} } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var9)) + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var10)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -236,12 +241,12 @@ func AdminProcessingIssues(user User, libraryID string, issues []ProcessingIssue if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - var templ_7745c5c3_Var10 string - templ_7745c5c3_Var10, templ_7745c5c3_Err = templ.JoinStringErrs(issue.LibraryTypeName) + var templ_7745c5c3_Var11 string + templ_7745c5c3_Var11, templ_7745c5c3_Err = templ.JoinStringErrs(issue.LibraryTypeName) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/admin_processing_issues.templ`, Line: 84, Col: 149} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/admin_processing_issues.templ`, Line: 78, Col: 149} } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var10)) + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var11)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -254,12 +259,12 @@ func AdminProcessingIssues(user User, libraryID string, issues []ProcessingIssue if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - var templ_7745c5c3_Var11 string - templ_7745c5c3_Var11, templ_7745c5c3_Err = templ.JoinStringErrs(issue.Severity) + var templ_7745c5c3_Var12 string + templ_7745c5c3_Var12, templ_7745c5c3_Err = templ.JoinStringErrs(issue.Severity) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/admin_processing_issues.templ`, Line: 89, Col: 62} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/admin_processing_issues.templ`, Line: 83, Col: 62} } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var11)) + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var12)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -272,12 +277,12 @@ func AdminProcessingIssues(user User, libraryID string, issues []ProcessingIssue if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - var templ_7745c5c3_Var12 string - templ_7745c5c3_Var12, templ_7745c5c3_Err = templ.JoinStringErrs(issue.Severity) + var templ_7745c5c3_Var13 string + templ_7745c5c3_Var13, templ_7745c5c3_Err = templ.JoinStringErrs(issue.Severity) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/admin_processing_issues.templ`, Line: 91, Col: 63} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/admin_processing_issues.templ`, Line: 85, Col: 63} } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var12)) + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var13)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -290,12 +295,12 @@ func AdminProcessingIssues(user User, libraryID string, issues []ProcessingIssue if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - var templ_7745c5c3_Var13 string - templ_7745c5c3_Var13, templ_7745c5c3_Err = templ.JoinStringErrs(issue.Severity) + var templ_7745c5c3_Var14 string + templ_7745c5c3_Var14, templ_7745c5c3_Err = templ.JoinStringErrs(issue.Severity) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/admin_processing_issues.templ`, Line: 93, Col: 66} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/admin_processing_issues.templ`, Line: 87, Col: 66} } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var13)) + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var14)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -309,7 +314,33 @@ func AdminProcessingIssues(user User, libraryID string, issues []ProcessingIssue return templ_7745c5c3_Err } if issue.Severity == "warning" || issue.Severity == "info" { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 33, "") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 36, "Dismiss") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 35, "

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

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 36, "
") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 38, "
") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 37, "
") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 39, "
") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } diff --git a/templates/admin_settings.templ b/templates/admin_settings.templ index d0e2a1e..4490eea 100644 --- a/templates/admin_settings.templ +++ b/templates/admin_settings.templ @@ -9,27 +9,19 @@ templ AdminSettings(user User, systemConfig map[string]string, errorMessage stri - - @Header(user, "/admin/settings") -
- @AdminSidebar(user, "/admin/settings") -
-
-
- -
- - @Icon("settings", "h-5 w-5") - -

System Settings

-
-

Configure your Bookhoard instance

-
+ + @Header(user, "/admin/settings") +
+
+
+
+ + @Icon("gear", "h-5 w-5") + +

System Settings

+
+

Configure your Bookhoard instance

+
if errorMessage != "" {
@Icon("alert", "h-5 w-5 shrink-0 mt-0.5") @@ -113,9 +105,8 @@ templ AdminSettings(user User, systemConfig map[string]string, errorMessage stri

Device Sync: { systemConfig["base_url"] }/api/sync

-
-
-
- +
+
+ } diff --git a/templates/admin_settings_templ.go b/templates/admin_settings_templ.go index ec93dcc..20e51e8 100644 --- a/templates/admin_settings_templ.go +++ b/templates/admin_settings_templ.go @@ -29,7 +29,7 @@ func AdminSettings(user User, systemConfig map[string]string, errorMessage strin templ_7745c5c3_Var1 = templ.NopComponent } ctx = templ.ClearChildren(ctx) - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "System Settings - Bookhoard") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "System Settings - Bookhoard") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -37,36 +37,20 @@ func AdminSettings(user User, systemConfig map[string]string, errorMessage strin if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "
") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "
") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = AdminSidebar(user, "/admin/settings").Render(ctx, templ_7745c5c3_Buffer) + templ_7745c5c3_Err = Icon("gear", "h-5 w-5").Render(ctx, templ_7745c5c3_Buffer) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "
") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = Icon("settings", "h-5 w-5").Render(ctx, templ_7745c5c3_Buffer) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "

System Settings

Configure your Bookhoard instance

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

System Settings

Configure your Bookhoard instance

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } if errorMessage != "" { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "
") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "
") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -74,25 +58,25 @@ func AdminSettings(user User, systemConfig map[string]string, errorMessage strin if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, "") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } var templ_7745c5c3_Var2 string templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(errorMessage) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/admin_settings.templ`, Line: 36, Col: 28} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/admin_settings.templ`, Line: 28, Col: 28} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var2)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 8, "
") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "
") 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, 7, "
") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -100,20 +84,20 @@ func AdminSettings(user User, systemConfig map[string]string, errorMessage strin if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, "

Base URL

Base URL

The public URL of your Bookhoard instance (e.g., https://books.example.com). Used for device sync, OPDS, and API endpoints.

") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, "Save Settings
") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -129,247 +113,247 @@ func AdminSettings(user User, systemConfig map[string]string, errorMessage strin if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, "

System Defaults

Default timezone for users who haven't set their own.

") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 59, ">New Zealand (UTC+12/+13)

Default timezone for users who haven't set their own.

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -377,46 +361,46 @@ func AdminSettings(user User, systemConfig map[string]string, errorMessage strin if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 62, "

URL Paths

OPDS: ") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 60, "

URL Paths

OPDS: ") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } var templ_7745c5c3_Var4 string templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(systemConfig["base_url"]) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/admin_settings.templ`, Line: 111, Col: 145} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/admin_settings.templ`, Line: 103, Col: 145} } _, 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, 63, "/opds

API: ") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 61, "/opds

API: ") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } var templ_7745c5c3_Var5 string templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(systemConfig["base_url"]) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/admin_settings.templ`, Line: 112, Col: 144} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/admin_settings.templ`, Line: 104, Col: 144} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 64, "/api

Device Sync: ") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 62, "/api

Device Sync: ") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } var templ_7745c5c3_Var6 string templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(systemConfig["base_url"]) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/admin_settings.templ`, Line: 113, Col: 152} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/admin_settings.templ`, Line: 105, Col: 152} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 65, "/api/sync

") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 63, "/api/sync

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } diff --git a/templates/admin_sidebar.templ b/templates/admin_sidebar.templ deleted file mode 100644 index f213594..0000000 --- a/templates/admin_sidebar.templ +++ /dev/null @@ -1,32 +0,0 @@ -package templates - -templ AdminSidebar(user User, currentPath string) { - -} diff --git a/templates/admin_sidebar_templ.go b/templates/admin_sidebar_templ.go deleted file mode 100644 index dfa9407..0000000 --- a/templates/admin_sidebar_templ.go +++ /dev/null @@ -1,168 +0,0 @@ -// Code generated by templ - DO NOT EDIT. - -// templ: version: v0.3.1020 -package templates - -//lint:file-ignore SA4006 This context is only used if a nested component is present. - -import "github.com/a-h/templ" -import templruntime "github.com/a-h/templ/runtime" - -func AdminSidebar(user User, currentPath string) templ.Component { - return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { - templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context - if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { - return templ_7745c5c3_CtxErr - } - templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) - if !templ_7745c5c3_IsBuffer { - defer func() { - templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) - if templ_7745c5c3_Err == nil { - templ_7745c5c3_Err = templ_7745c5c3_BufErr - } - }() - } - ctx = templ.InitializeContext(ctx) - templ_7745c5c3_Var1 := templ.GetChildren(ctx) - if templ_7745c5c3_Var1 == nil { - templ_7745c5c3_Var1 = templ.NopComponent - } - ctx = templ.ClearChildren(ctx) - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - return nil - }) -} - -var _ = templruntime.GeneratedTemplate diff --git a/templates/admin_users.templ b/templates/admin_users.templ index 878cb1f..0525d94 100644 --- a/templates/admin_users.templ +++ b/templates/admin_users.templ @@ -10,14 +10,12 @@ templ AdminUsers(currentUser User, users []User, adminCount int) { - @Header(currentUser, "/admin/users") - - -
- @AdminSidebar(currentUser, "/admin/users") -
-
-
+ @Header(currentUser, "/admin/users") + + +
+
+
@Icon("users", "h-5 w-5") @@ -76,14 +74,11 @@ templ AdminUsers(currentUser User, users []User, adminCount int) { } else {
") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 11, "
") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } } else { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, "
Admin
") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 19, "\" class=\"text-xs mt-1\">
") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 21, "
") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 20, "
") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } var templ_7745c5c3_Var8 string templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinStringErrs(FormatInTimezone(user.CreatedAt, currentUser.Timezone)) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/admin_users.templ`, Line: 96, Col: 126} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/admin_users.templ`, Line: 91, Col: 126} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var8)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 22, "
") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 23, "Edit ") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } if user.Role == "admin" && adminCount == 1 { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 25, "") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 25, "Delete") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } } else { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 27, "") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 29, "Delete") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 31, "
") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 30, "
") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 32, "
") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 31, "
") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } diff --git a/templates/header.templ b/templates/header.templ index 92802b4..711d065 100644 --- a/templates/header.templ +++ b/templates/header.templ @@ -122,6 +122,29 @@ templ Header(user User, currentPath string) { } + + if user.Role == "admin" { +
+

Administration

+
+ + @Icon("grid", "h-5 w-5 shrink-0") + Dashboard + + + @Icon("library", "h-5 w-5 shrink-0") + Libraries + + + @Icon("users", "h-5 w-5 shrink-0") + Users + + + @Icon("gear", "h-5 w-5 shrink-0") + Settings + +
+ } @@ -173,12 +196,6 @@ templ SidebarUserMenu(user User) { @Icon("user", "h-4 w-4") Profile - if user.Role == "admin" { - - @Icon("settings", "h-4 w-4") - Admin Panel - - }
") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 48, "
") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -364,7 +494,7 @@ func Header(user User, currentPath string) templ.Component { if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 35, "
") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 49, " ") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -389,12 +519,12 @@ func SidebarUserMenu(user User) templ.Component { }() } ctx = templ.InitializeContext(ctx) - templ_7745c5c3_Var20 := templ.GetChildren(ctx) - if templ_7745c5c3_Var20 == nil { - templ_7745c5c3_Var20 = templ.NopComponent + templ_7745c5c3_Var28 := templ.GetChildren(ctx) + if templ_7745c5c3_Var28 == nil { + templ_7745c5c3_Var28 = templ.NopComponent } ctx = templ.ClearChildren(ctx) - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 36, "
") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 53, "
") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -431,25 +561,7 @@ func SidebarUserMenu(user User) templ.Component { if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 40, "Profile ") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - if user.Role == "admin" { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 41, "") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = Icon("settings", "h-4 w-4").Render(ctx, templ_7745c5c3_Buffer) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 42, "Admin Panel ") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 43, "
") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 55, "Logout
") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -483,12 +595,12 @@ func SidebarSignIn(currentPath string) templ.Component { }() } ctx = templ.InitializeContext(ctx) - templ_7745c5c3_Var22 := templ.GetChildren(ctx) - if templ_7745c5c3_Var22 == nil { - templ_7745c5c3_Var22 = templ.NopComponent + templ_7745c5c3_Var30 := templ.GetChildren(ctx) + if templ_7745c5c3_Var30 == nil { + templ_7745c5c3_Var30 = templ.NopComponent } ctx = templ.ClearChildren(ctx) - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 45, "
Sign in
") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 58, "\">
Create an account
") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } diff --git a/templates/utils.go b/templates/utils.go index 917f973..a836c22 100644 --- a/templates/utils.go +++ b/templates/utils.go @@ -16,7 +16,7 @@ import ( func activeClass(current, target string) string { base := "flex items-center gap-3 px-3 py-2 rounded-lg text-sm font-medium transition-colors " - if current == target { + if strings.TrimRight(current, "/") == strings.TrimRight(target, "/") { return base + "bg-brand/15 text-brand" } return base + "text-content-muted hover:bg-surface-hover hover:text-content" @@ -40,6 +40,15 @@ func ContainsString(slice []string, item string) bool { return false } +func isUserVisible(userID string, visibility []UserVisibilityData) bool { + for _, v := range visibility { + if v.UserID == userID { + return v.IsVisible + } + } + return false +} + // TotalMediaCount sums the MediaCount across the given libraries, // used to display the total next to the "All Libraries" option. func TotalMediaCount(libs []LibraryData) int64 {