Files
bookhoard/templates/admin_users_templ.go
T
john-okeefe af7533529c refactor(templates): remove duplicate main.js script tags, consolidate to header component
Remove redundant <script src="/static/main.js" defer></script> tags from 17+
templates that include the @Header component, eliminating duplicate script
loading that was causing Alpine.js to initialize twice per page load.

The header.templ component now serves as the single source of truth for
main.js inclusion, following the DRY principle and ensuring consistent
script loading across all pages that use the header navigation.

Additionally, add type="button" attribute to all buttons in header navigation
to prevent default form submission behavior when buttons are clicked.

Changes:
- Remove main.js script tag from templates using @Header component
- Keep main.js in header.templ (line 279) as universal inclusion point
- Preserve main.js in special pages: index.templ, login.templ, register.templ
  (these don't use @Header and are standalone entry points)
- Add type="button" to theme toggle, theme selection, wood paneling, and user menu buttons
  to prevent unwanted form submissions or page navigation

Benefits:
- Eliminates Alpine.js double-initialization bug
- Reduces HTTP requests (one script load instead of two)
- Improves maintainability (add header, get scripts automatically)
- Fixes broken @click handlers on collections, devices, and other pages
- Prevents buttons from triggering default form submission behavior

Technical notes:
- Templates affected: admin, analytics, bookshelf, collection_rules,
  collections, conflicts, custom_section, dashboard, devices, docs,
  library, profile, progress, queue, unlinked_books
- No changes to entry pages (index, login, register) which don't use @Header
- HTMX script remains in individual templates (stateless, no double-load issue)
- All interactive buttons in header now explicitly marked type="button" to
  prevent default browser form submission behavior

Related to: previous commit fixing Vite code-splitting
2026-03-13 22:25:12 -04:00

257 lines
14 KiB
Go

// Code generated by templ - DO NOT EDIT.
// templ: version: v0.3.1001
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 AdminUsers(currentUser User, users []User, adminCount int) 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, "<!doctype html><html lang=\"en\"><head><meta charset=\"UTF-8\"><title>Users - Bookhoard Admin</title><script src=\"/static/htmx.min.js\"></script><link href=\"/static/style.css\" rel=\"stylesheet\"></head><body class=\"theme-{ currentUser.Theme }\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = Header(currentUser, "/admin/users").Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "<!-- Modal Container (populated by HTMX) --><div id=\"modal-container\"></div><div class=\"flex min-h-screen\" style=\"background-color: var(--bg-primary)\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = AdminSidebar(currentUser, "/admin/users").Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "<main class=\"flex-1 p-8\"><div class=\"w-full\"><h1 class=\"text-3xl font-bold mb-2\" style=\"color: var(--text-primary)\">User Management</h1><p style=\"color: var(--text-secondary)\">Manage user accounts and permissions</p></div><!-- Users Table --><div class=\"card rounded-lg border overflow-hidden\" style=\"background-color: var(--bg-secondary); border-color: var(--border)\"><table class=\"w-full\"><thead style=\"background-color: var(--bg-primary)\"><tr><th class=\"px-6 py-3 text-left text-xs font-medium uppercase tracking-wider\" style=\"color: var(--text-secondary)\">Username</th><th class=\"px-6 py-3 text-left text-xs font-medium uppercase tracking-wider\" style=\"color: var(--text-secondary)\">Email</th><th class=\"px-6 py-3 text-left text-xs font-medium uppercase tracking-wider\" style=\"color: var(--text-secondary)\">Role</th><th class=\"px-6 py-3 text-left text-xs font-medium uppercase tracking-wider\" style=\"color: var(--text-secondary)\">Created</th><th class=\"px-6 py-3 text-right text-xs font-medium uppercase tracking-wider\" style=\"color: var(--text-secondary)\">Actions</th></tr></thead> <tbody class=\"divide-y\" style=\"divide-color: var(--border)\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
for _, user := range users {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "<tr id=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var2 string
templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs("user-" + user.ID)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/admin_users.templ`, Line: 37, Col: 35}
}
_, 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, 5, "\" class=\"hover:bg-opacity-50\" style=\"transition: background-color 0.2s;\"><!-- Username --><td class=\"px-6 py-4 whitespace-nowrap\"><div class=\"flex items-center\"><div><div class=\"text-sm font-medium\" style=\"color: var(--text-primary)\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var3 string
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(user.Username)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/admin_users.templ`, Line: 42, Col: 96}
}
_, 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, 6, "</div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
if user.ID == currentUser.ID {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, "<span class=\"text-xs px-2 py-1 rounded\" style=\"background-color: var(--accent); color: white;\">You</span>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 8, "</div></div></td><!-- Email --><td class=\"px-6 py-4 whitespace-nowrap\"><div class=\"text-sm\" style=\"color: var(--text-primary)\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var4 string
templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(user.Email)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/admin_users.templ`, Line: 51, Col: 79}
}
_, 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, "</div></td><!-- Role Toggle (with last-admin protection) --><td class=\"px-6 py-4 whitespace-nowrap\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
if user.Role == "admin" && adminCount == 1 {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, "<!-- Last admin - disabled --> <div class=\"relative\"><select disabled class=\"text-sm rounded px-2 py-1 cursor-not-allowed opacity-50\" style=\"background-color: var(--bg-primary); color: var(--text-secondary); border: 1px solid var(--border);\" title=\"Cannot demote the last admin\"><option value=\"user\">User</option> <option value=\"admin\" selected>Admin</option></select></div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
} else {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 11, "<select hx-put=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var5 string
templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs("/api/auth/profile/" + user.ID)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/admin_users.templ`, Line: 70, Col: 52}
}
_, 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, 12, "\" hx-headers='{\"Authorization\": \"Bearer \" + localStorage.getItem(\"token\")}' hx-target=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var6 string
templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs("#role-result-" + user.ID)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/admin_users.templ`, Line: 72, Col: 50}
}
_, 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, 13, "\" hx-swap=\"innerHTML\" name=\"role\" class=\"text-sm rounded px-2 py-1\" style=\"background-color: var(--bg-primary); color: var(--text-primary); border: 1px solid var(--border);\" onchange=\"this.dispatchEvent(new Event('htmx:trigger'))\" hx-trigger=\"change\" hx-vals='{\"role\": this.value}'><option value=\"user\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
if user.Role == "user" {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 14, " selected")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 15, ">User</option> <option value=\"admin\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
if user.Role == "admin" {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 16, " selected")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 17, ">Admin</option></select><div id=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var7 string
templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs("role-result-" + user.ID)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/admin_users.templ`, Line: 84, Col: 46}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 18, "\" class=\"text-xs mt-1\"></div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 19, "</td><!-- Created --><td class=\"px-6 py-4 whitespace-nowrap\"><div class=\"text-sm\" style=\"color: var(--text-secondary)\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var8 string
templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinStringErrs(user.CreatedAt.Format("2006-01-02"))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/admin_users.templ`, Line: 89, Col: 106}
}
_, 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, 20, "</div></td><!-- Actions --><td class=\"px-6 py-4 whitespace-nowrap text-right\"><button hx-get=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var9 string
templ_7745c5c3_Var9, templ_7745c5c3_Err = templ.JoinStringErrs("/admin/users/" + user.ID + "/profile-modal")
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/admin_users.templ`, Line: 94, Col: 65}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var9))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 21, "\" hx-target=\"#modal-container\" hx-swap=\"innerHTML\" class=\"text-sm px-3 py-1 rounded mr-2\" style=\"background-color: var(--accent); color: white;\">Edit</button> ")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
if user.Role == "admin" && adminCount == 1 {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 22, "<button disabled class=\"text-sm px-3 py-1 rounded cursor-not-allowed opacity-50\" style=\"background-color: #dc2626; color: white;\" title=\"Cannot delete the last admin\">Delete</button>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
} else {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 23, "<button hx-delete=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var10 string
templ_7745c5c3_Var10, templ_7745c5c3_Err = templ.JoinStringErrs("/api/auth/profile/" + user.ID)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/admin_users.templ`, Line: 113, Col: 55}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var10))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 24, "\" hx-headers='{\"Authorization\": \"Bearer \" + localStorage.getItem(\"token\")}' hx-target=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var11 string
templ_7745c5c3_Var11, templ_7745c5c3_Err = templ.JoinStringErrs("#user-" + user.ID)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/admin_users.templ`, Line: 115, Col: 43}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var11))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 25, "\" hx-swap=\"outerHTML swap:0.5s\" hx-confirm=\"Are you sure you want to delete this user? This action cannot be undone.\" class=\"text-sm px-3 py-1 rounded\" style=\"background-color: #dc2626; color: white;\">Delete</button>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 26, "</td></tr>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 27, "</tbody></table></div></main></div></body></html>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return nil
})
}
var _ = templruntime.GeneratedTemplate