From 6287088bc17bd2161f520d4cce1b2ba9e73123ef Mon Sep 17 00:00:00 2001 From: John O'Keefe Date: Mon, 13 Apr 2026 09:24:25 -0400 Subject: [PATCH] feat(router): Add admin processing issues UI route Add frontend route /admin/libraries/:id/issues to display processing issues management page for a specific library. internal/router/frontend.go: - Register GET /admin/libraries/:id/issues with admin middleware - Fetch processing issue stats from database - List processing issues for the library - Convert database models to template types - Render AdminProcessingIssues template with issues and stats This provides the admin UI for viewing and managing processing errors that occur during media scanning and import workflows. --- internal/router/frontend.go | 56 +++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/internal/router/frontend.go b/internal/router/frontend.go index 840c5b9..b63dc8e 100644 --- a/internal/router/frontend.go +++ b/internal/router/frontend.go @@ -818,6 +818,62 @@ func registerFrontendRoutes(cfg *Config) { return c.HTML(http.StatusOK, buf.String()) })) + frontendProtected.GET("/admin/libraries/:id/issues", handlers.AdminMiddleware(func(c *echo.Context) error { + user, err := getTemplateUserWithTheme(c, cfg) + if err != nil { + return renderErrorPage(c, "Error loading user", "user_load_error") + } + libraryID := c.Param("id") + libUUID, err := uuid.Parse(libraryID) + if err != nil { + return renderErrorPage(c, "Invalid library ID", "invalid_id") + } + // Fetch stats + stats, err := cfg.Queries.GetProcessingIssueStats( + c.Request().Context(), + uuidToPGType(libUUID), + ) + if err != nil { + return renderErrorPage(c, "Error loading stats", "stats_load_error") + } + // Fetch issues + dbIssues, err := cfg.Queries.ListProcessingIssuesByLibrary( + c.Request().Context(), + uuidToPGType(libUUID), + ) + if err != nil { + return renderErrorPage(c, "Error loading issues", "issues_load_error") + } + // Convert to template data + issues := make([]templates.ProcessingIssueData, len(dbIssues)) + for i, issue := range dbIssues { + issueUUID, _ := uuid.FromBytes(issue.ID.Bytes[0:16]) + issues[i] = templates.ProcessingIssueData{ + ID: issueUUID.String(), + MediaItemID: uuid.UUID(issue.MediaItemID.Bytes).String(), + Title: issue.Title, + FilePath: issue.FilePath, + FormatGroup: issue.FormatGroup, + LibraryTypeName: issue.LibraryTypeName, + IssueType: issue.IssueType, + IssueDescription: issue.IssueDescription, + Severity: issue.Severity, + CreatedAt: issue.CreatedAt.Time, + } + } + statsData := templates.IssueStats{ + ErrorCount: stats.ErrorCount, + WarningCount: stats.WarningCount, + InfoCount: stats.InfoCount, + } + var buf bytes.Buffer + err = templates.AdminProcessingIssues(user, libraryID, issues, statsData).Render(c.Request().Context(), &buf) + if err != nil { + return err + } + return c.HTML(http.StatusOK, buf.String()) + })) + // Admin users page frontendProtected.GET("/admin/users", handlers.AdminMiddleware(func(c *echo.Context) error { user, err := getTemplateUserWithTheme(c, cfg)