Files
bookhoard/templates/types.go
T
john-okeefe 598d70f735 feat(admin): editable tunable settings UI with grouped sub-sections
Replace the read-only "System Information" card (which listed hardcoded
values) with editable HTMX forms, organized so the live vs restart
distinction and related settings are visually clear.

admin_settings.templ:
- AdminSettings signature now takes liveGroups and restartGroups
  ([]SettingGroup) instead of a flat entry list.
- Remove the static System Information list. Render two cards: "Live"
  (green, applies immediately) and "Restart Required" (warning header,
  saved but only takes effect after restart).
- Within each card, TunableSettingsSection clusters entries into
  labeled sub-sections by Group (e.g. "Password Quality", "Device Rate
  Limits", "Login Lockout", "Worker Pool") with uppercase tracked
  sub-headers.
- TunableSettingRow renders an inline HTMX form per setting: a Yes/No
  select for bools, a number input with min/max for ints, text
  otherwise, posting to /admin/settings/tunable. Rows show "modified
  from default" when the value differs from the compiled default.

types.go:
- Add SettingEntry (template-local mirror of database.SettingEntry,
  keeps templates from importing database) and SettingGroup.

utils.go:
- Add GroupTunableSettings: splits a flat, group-sorted entry list into
  live and restart []SettingGroup buckets preserving source order.
  utils_test.go covers the multi-group + empty cases.

frontend.go:
- The /admin/settings page handler now loads entries from the registry,
  drops the three keys that have dedicated UI cards (default_timezone
  dropdown, scan_poll_interval_seconds, auto_scan_enabled) so they are
  not listed twice, groups the rest, and passes liveGroups/restartGroups
  into the template.
2026-08-10 08:03:02 -04:00

276 lines
5.4 KiB
Go

package templates
import (
"time"
"github.com/a-h/templ"
)
type User struct {
ID string
Username string
Email string
Role string
Theme string
FirstName string
LastName string
CreatedAt time.Time
Token string
Timezone string
}
type PageData struct {
User User
CurrentPage string
}
type CollectionData struct {
ID string
Name string
Description string
Color string
Icon string
IsSystem bool
}
type LibraryData struct {
ID string
Name string
Description string
TypeName string
TypeValue string
MediaCount int64
FolderCount int
}
type FolderData struct {
FolderPath string
}
type DirEntry struct {
Name string
Path string
}
type UserVisibilityData struct {
UserID string
Username string
Email string
IsVisible bool
}
type AdminStats struct {
LibraryCount int
MediaCount int
UserCount int
DeviceCount int
}
type ScanSettingsData struct {
AutoScanEnabled bool
ScanPollIntervalSeconds int
}
// SettingEntry mirrors database.SettingEntry for the admin UI. Kept as a
// template-local type so the templates package does not import database.
type SettingEntry struct {
Key string
Value string
Type string
Min string
Max string
RequiresRestart bool
Category string
Group string
Description string
IsDefault bool
}
// SettingGroup is a labeled cluster of related settings rendered as a
// sub-section within a tunable-settings card.
type SettingGroup struct {
Name string
Entries []SettingEntry
}
type SeriesCardData struct {
Name string
BookCount int64
TotalInSeries int
CoverPaths []string
}
type PendingRegistrationData struct {
RegistrationID string
DeviceName string
DeviceType string
ExpiresAt string
}
type ConflictData struct {
ID string
MediaItemID string
MediaItemTitle string
ConflictType string
ResolutionStatus string
CreatedAt string
ResolutionData map[string]interface{}
ResolvedBy string
ResolvedAt string
}
type QueueItemData struct {
ID string
DeviceID string
DeviceName string
DeviceType string
SyncType string
Status string
Priority int32
Attempts int32
CreatedAt string
}
type DeviceShelfMappingData struct {
ID string
CollectionID string
CollectionName string
DeviceShelfName string
SyncDirection string
CreatedAt string
}
type UnlinkedBookData struct {
ProgressID string
DeviceID string
DeviceType string
DeviceName string
FilePath string
SHA256 string
TitleFromDevice string
LastSyncTime string
ConfidenceScore float64
PotentialMatches []PotentialMatchData
}
type PotentialMatchData struct {
MediaItemID string
Title string
Author string
CoverImagePath string
MatchMethod string
Confidence float64
}
// Documentation types
type Navigation struct {
Sections []NavSection
}
type NavSection struct {
Title string
Items []NavItem
Collapsed bool
}
type NavItem struct {
Title string
URL string
Icon string
}
type Document struct {
Title string
Content string
TOC []TOCItem
Breadcrumb []BreadcrumbItem
Category string
SourceFile string
}
type TOCItem struct {
Level int
Title string
Anchor string
}
type BreadcrumbItem struct {
Title string
URL string
}
// UnsafeHTML is used for rendering raw HTML (like rendered markdown)
type UnsafeHTML string
// ToComponent converts UnsafeHTML to a templ Component
func (u UnsafeHTML) ToComponent() templ.Component {
return templ.Raw(string(u))
}
// Reader types
type ReaderMetadata struct {
MediaItemID string `json:"media_item_id"`
Title string `json:"title"`
Author string `json:"author"`
CoverImagePath string `json:"cover_image_path"`
LibraryType string `json:"library_type"`
MimeType string `json:"mime_type"`
FilePath string `json:"file_path"`
TotalPages int `json:"total_pages"`
ChapterCount int `json:"chapter_count"`
FormatGroup string `json:"format_group"`
MangaType string `json:"manga_type"`
ReadingDirection string `json:"reading_direction"`
FileURL string `json:"file_url"`
LibraryID string `json:"library_id"`
TotalCharacters int64 `json:"total_characters"`
EstimatedPages int `json:"estimated_pages"`
}
type ReadingProgress struct {
ID string
MediaItemID string
UserID string
CurrentPage int
TotalPages int
Percentage float64
EpubCfi string
LastReadAt time.Time
Chapter int
ChapterProgress float64
FormatGroup string
}
type Bookmark struct {
ID string
MediaItemID string
UserID string
PageNumber *int
ChapterNumber *int
CfiPosition string
Title string
Position string
Notes string
CreatedAt time.Time
}
// ProcessingIssueData - Processing issue types
type ProcessingIssueData struct {
ID string
MediaItemID string
Title string
FilePath string
FormatGroup string
LibraryTypeName string
IssueType string
IssueDescription string
Severity string
CreatedAt time.Time
}
type IssueStats struct {
ErrorCount int64
WarningCount int64
InfoCount int64
}