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.
276 lines
5.4 KiB
Go
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
|
|
}
|