ui

package
v0.0.0-...-99cc010 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 6, 2026 License: MIT Imports: 48 Imported by: 0

Documentation

Index

Constants

View Source
const (
	StatusOk   = "ok"
	StatusWarn = "warn"
	StatusErr  = "err"
	StatusIdle = "idle"
)

Status keys mirror the design's four states. Locorum's data model only distinguishes Running (ok) and Stopped (idle); Warning and Error are reserved for richer health signals later.

View Source
const ActivityFullMax = 200

ActivityFullMax caps the per-site row count cached for the Activity tab. The DB enforces the same retention via storage.ActivityRetentionDefault; duplicating the constant here means the UI never holds more than the designed maximum even if a future schema change widens retention.

View Source
const ActivityRecentMax = 5

ActivityRecentMax caps the per-site row count cached for the overview panel. Mirrors sites.activityRecentLimit; declared here so the UI layer is self-contained.

View Source
const MaxHookOutputLinesPerSite = 200

MaxHookOutputLinesPerSite caps how many output lines we keep in memory for a site's live-output panel. Older lines are dropped (the on-disk run log retains the full output).

Variables

View Source
var IconSize = unit.Dp(16)

IconSize is the default icon dimension, sized to balance with body text.

View Source
var LogoSize = unit.Dp(20)

LogoSize is the default mark dimension used in the rail brand.

View Source
var MonoFont = font.Font{Typeface: "JetBrains Mono"}

MonoFont is the font.Font value to use for code/output text (logs, WP-CLI output, link checker, DB credentials).

Functions

func AnimatedModalOverlay

func AnimatedModalOverlay(gtx layout.Context, th *Theme, anim *modalShowState, content layout.Widget) layout.Dimensions

AnimatedModalOverlay draws the overlay with a 200ms fade-in driven by anim. Callers should keep an *modalShowState (via NewModalAnim) on their modal struct and pass it here.

func BorderedEditor

func BorderedEditor(gtx layout.Context, th *Theme, editor *widget.Editor, hint string) layout.Dimensions

BorderedEditor draws a text editor with a border.

func BorderedMonoEditor

func BorderedMonoEditor(gtx layout.Context, th *Theme, editor *widget.Editor, hint string) layout.Dimensions

BorderedMonoEditor draws a bordered text editor using the monospace font, suitable for code or shell-command input.

func CopyToClipboard

func CopyToClipboard(gtx layout.Context, text string)

CopyToClipboard writes text to the system clipboard.

func DangerButton

func DangerButton(gtx layout.Context, th *Theme, btn *widget.Clickable, text string) layout.Dimensions

func Divider

func Divider(gtx layout.Context, col color.NRGBA, verticalMargin unit.Dp) layout.Dimensions

Divider renders a horizontal 1px line with configurable vertical margin.

func EdgeLine

func EdgeLine(gtx layout.Context, col color.NRGBA, edge string) layout.Dimensions

EdgeLine paints a 1-px line along one edge of the constrained area. edge: "top" | "bottom" | "left" | "right". The widget reports its size as gtx.Constraints.Min so it doesn't inflate the surrounding Stack — inside a Stack's Expanded pass, Min equals the largest Stacked child.

func FillBackground

func FillBackground(gtx layout.Context, col color.NRGBA, w layout.Widget) layout.Dimensions

FillBackground paints a rectangle with the given color behind the widget.

func FormatActivityTime

func FormatActivityTime(t time.Time, now time.Time) string

FormatActivityTime renders t as a short string suitable for the Activity feed's leading time chip. Uses relative form for recent events and absolute for older ones — the goal is "readable at a glance, unambiguous for old entries":

< 60 seconds      "just now"
< 60 minutes      "Nm ago"
same calendar day "15:04"
yesterday         "Yesterday 15:04"
same year         "Jan 2 15:04"
older             "2006-01-02"

now is taken as a parameter so the caller can pin a clock for tests and so the function never depends on time.Now's monotonic clock semantics. All formatting uses now's location so a local-timezone "Yesterday" is computed against the user's wall clock rather than UTC.

func IconChevronLeft

func IconChevronLeft(gtx layout.Context, th *Theme, size unit.Dp, col color.NRGBA) layout.Dimensions

IconChevronLeft — a left-pointing angle bracket "‹".

func IconChevronRight

func IconChevronRight(gtx layout.Context, th *Theme, size unit.Dp, col color.NRGBA) layout.Dimensions

IconChevronRight — a right-pointing angle bracket "›".

func IconClose

func IconClose(gtx layout.Context, th *Theme, size unit.Dp, col color.NRGBA) layout.Dimensions

IconClose — a diagonal cross "×", used as a modal close affordance.

func IconCog

func IconCog(gtx layout.Context, th *Theme, size unit.Dp, col color.NRGBA) layout.Dimensions

IconCog — a six-tooth gear silhouette, used for "panel settings" actions.

func IconDatabase

func IconDatabase(gtx layout.Context, th *Theme, size unit.Dp, col color.NRGBA) layout.Dimensions

IconDatabase — a stacked-cylinder database mark.

func IconEye

func IconEye(gtx layout.Context, th *Theme, size unit.Dp, col color.NRGBA) layout.Dimensions

IconEye — a lens with a pupil dot, used for "Open site / view".

func IconFilter

func IconFilter(gtx layout.Context, th *Theme, size unit.Dp, col color.NRGBA) layout.Dimensions

IconFilter — a funnel: a closed flared shape narrowing to the bottom.

func IconFolder

func IconFolder(gtx layout.Context, th *Theme, size unit.Dp, col color.NRGBA) layout.Dimensions

IconFolder — a folder with a tab corner.

func IconLogs

func IconLogs(gtx layout.Context, th *Theme, size unit.Dp, col color.NRGBA) layout.Dimensions

IconLogs — three horizontal lines suggesting log entries.

func IconMail

func IconMail(gtx layout.Context, th *Theme, size unit.Dp, col color.NRGBA) layout.Dimensions

IconMail — an envelope outline + flap.

func IconPlus

func IconPlus(gtx layout.Context, th *Theme, size unit.Dp, col color.NRGBA) layout.Dimensions

IconPlus — a "+" sign.

func IconSearch

func IconSearch(gtx layout.Context, th *Theme, size unit.Dp, col color.NRGBA) layout.Dimensions

IconSearch — a magnifying glass: circle + diagonal handle.

func IconSettings

func IconSettings(gtx layout.Context, th *Theme, size unit.Dp, col color.NRGBA) layout.Dimensions

IconSettings — three horizontal sliders with knob dots, an unambiguous "preferences" silhouette that scales cleanly even at 14dp.

func IconSites

func IconSites(gtx layout.Context, th *Theme, size unit.Dp, col color.NRGBA) layout.Dimensions

IconSites — a globe: circle + horizontal equator + meridian arc.

func IconTerminal

func IconTerminal(gtx layout.Context, th *Theme, size unit.Dp, col color.NRGBA) layout.Dimensions

IconTerminal — a rounded rect with a "> " prompt, used for Shell action.

func KVRows

func KVRows(gtx layout.Context, th *Theme, items []KV) layout.Dimensions

KVRows renders a list of key-value pairs with consistent label column width.

func LabeledInput

func LabeledInput(gtx layout.Context, th *Theme, label string, editor *widget.Editor, hint string) layout.Dimensions

LabeledInput draws a label above a styled text editor.

func LayoutHealthBadge

func LayoutHealthBadge(gtx layout.Context, kind HealthBadgeKind, th *Theme) layout.Dimensions

LayoutHealthBadge paints a small dot in the given foreground colour. Used by the nav rail to flag the Settings entry. Caller is responsible for positioning.

func LayoutLogo(gtx layout.Context, th *Theme, size unit.Dp) layout.Dimensions

LayoutLogo draws the LocorumMark — a vertical accent bar plus three horizontal bars of decreasing width and decreasing opacity, forming a stylised "L". Geometry is specified in a 32×32 design grid; visible content occupies x: 5..27 (span 22) × y: 6..26 (span 20). The bars are scaled and offset so that visible content fills the requested size, preserving the original 22:20 aspect ratio.

func LiveStatusDot

func LiveStatusDot(gtx layout.Context, th *Theme, key string, live bool) layout.Dimensions

LiveStatusDot draws a small filled circle in the status color. When status==StatusOk and live==true, it animates an expanding pulse ring on a 2-second cycle. The widget reports a square layout sized to fit the largest pulse extent so neighbouring text isn't shoved around as the ring grows.

func LoadFontCollection

func LoadFontCollection() ([]font.FontFace, error)

LoadFontCollection parses the embedded Inter (sans-serif) and JetBrains Mono (monospace) faces, plus the bundled gofont family as a unicode fallback, and returns them as a font.FontFace collection suitable for text.NewShaper. Without the gofont fallback, glyphs missing from Inter or JetBrains Mono cause Gio to escape to system fontconfig, which on Linux triggers GLib-GIO-CRITICAL warnings on every frame.

func Loader

func Loader(gtx layout.Context, th *Theme, size unit.Dp) layout.Dimensions

Loader renders a material loading spinner at the given size.

func ModalOverlay

func ModalOverlay(gtx layout.Context, th *Theme, content layout.Widget) layout.Dimensions

ModalOverlay draws a semi-transparent overlay and centers the content widget. It is the legacy entry point with no fade animation.

func NewModalAnim

func NewModalAnim() *modalShowState

NewModalAnim returns a fresh animation state. Call (*ModalAnim).Show on the frame where the modal becomes visible and (*ModalAnim).Hide on the frame where it disappears. Pass the returned value to AnimatedModalOverlay.

func PrimaryButton

func PrimaryButton(gtx layout.Context, th *Theme, btn *widget.Clickable, text string) layout.Dimensions

Backward-compatible top-level helpers (delegate to *Theme methods).

func RoundedFill

func RoundedFill(gtx layout.Context, col color.NRGBA, radius unit.Dp, w layout.Widget) layout.Dimensions

RoundedFill paints a rounded-rect background behind the widget.

func SecondaryButton

func SecondaryButton(gtx layout.Context, th *Theme, btn *widget.Clickable, text string) layout.Dimensions

func Section

func Section(gtx layout.Context, th *Theme, title string, content layout.Widget) layout.Dimensions

Section renders a titled section with consistent header styling and bottom spacing.

func SectionDirty

func SectionDirty(gtx layout.Context, th *Theme, title string, content layout.Widget) layout.Dimensions

SectionDirty renders a Section with the title coloured by th.Color.Brand, signalling that the contained controls have unsaved changes.

func SelectableLabel

func SelectableLabel(gtx layout.Context, th *Theme, sel *widget.Selectable, text string, size unit.Sp, col color.NRGBA, f font.Font) layout.Dimensions

SelectableLabel renders a widget.Selectable with material-style text appearance. Users can click-drag to select text and Ctrl+C to copy.

func SiteAvatar

func SiteAvatar(gtx layout.Context, th *Theme, name string, size unit.Dp) layout.Dimensions

SiteAvatar renders a rounded square containing the first two alphanumerics from name (uppercase mono semibold) on a Bg2 surface with a 1px Line border. Used in the sites list (size=36) and in the site detail header (size=30). Favicons are not yet wired in.

func SmallButton

func SmallButton(gtx layout.Context, th *Theme, btn *widget.Clickable, text string) layout.Dimensions

func StatusForSite

func StatusForSite(started bool) (key, label string)

StatusForSite maps a site's Started flag onto a (status key, label) pair. A running site uses the live-pulse "ok" treatment; a stopped site is the neutral "idle" gray (rather than red "err"), since stopping is normal.

func StatusPill

func StatusPill(gtx layout.Context, th *Theme, key string, live bool) layout.Dimensions

StatusPill renders a rounded pill containing a colored dot + uppercase mono status label. Used in the site detail header and at the top of the nav rail brand area. live=true enables the pulse ring on "ok".

func SuccessButton

func SuccessButton(gtx layout.Context, th *Theme, btn *widget.Clickable, text string) layout.Dimensions

func TabBar

func TabBar(gtx layout.Context, th *Theme, tabs []string, active int, clicks []*widget.Clickable) layout.Dimensions

TabBar renders a horizontal row of tab buttons. The active tab is highlighted with the primary accent color and an underline indicator.

func TruncateWords

func TruncateWords(s string, maxRunes int) string

TruncateWords returns s shortened to at most maxRunes runes, breaking at the last word boundary that fits and appending an ellipsis. Strings shorter than the budget are returned unchanged. If no whitespace exists within the budget, falls back to a hard rune-boundary cut.

Types

type ActivityTab

type ActivityTab struct {
	// contains filtered or unexported fields
}

ActivityTab renders the per-site lifecycle audit feed. Each row is one orch.Plan outcome; clicking a row toggles an inline expander with the step list and final error captured at write time.

State that needs to survive across frames lives on this struct: the scroll position, the per-row expand toggles, and the per-site set of loads we've already kicked off. Storage reads happen in goroutines — Layout() is purely a function of the cached snapshot.

func NewActivityTab

func NewActivityTab(state *UIState, sm *sites.SiteManager) *ActivityTab

func (*ActivityTab) HandleUserInteractions

func (at *ActivityTab) HandleUserInteractions(layout.Context)

HandleUserInteractions is a no-op today — Layout() consumes clicks as it renders so the matching row's expander opens within the same frame. Kept as a stub so the tab plugs into SiteDetail's HandleUserInteractions dispatch without an awkward conditional.

func (*ActivityTab) Layout

func (at *ActivityTab) Layout(gtx layout.Context, th *Theme, siteID string) layout.Dimensions

Layout renders the activity tab body for siteID. Triggers a one-time background load of the full per-site history on first paint and on site-switch.

type CloneModal

type CloneModal struct {
	// contains filtered or unexported fields
}

CloneModal is a dialog for cloning a site with a new name.

func NewCloneModal

func NewCloneModal(state *UIState, sm *sites.SiteManager, toasts *Notifications) *CloneModal

func (*CloneModal) HandleUserInteractions

func (cm *CloneModal) HandleUserInteractions(gtx layout.Context)

HandleUserInteractions processes Cancel / Clone button clicks. Called by the root UI before Layout when the modal is visible.

func (*CloneModal) Layout

func (cm *CloneModal) Layout(gtx layout.Context, th *Theme) layout.Dimensions

type ConfirmDialog

type ConfirmDialog struct {
	// contains filtered or unexported fields
}

ConfirmDialog holds state for a reusable confirmation modal dialog.

func (*ConfirmDialog) HandleUserInteractions

func (cd *ConfirmDialog) HandleUserInteractions(gtx layout.Context) (confirmed, cancelled bool)

HandleUserInteractions reads the confirm/cancel button click state for the frame. Must be called before Layout each frame and only once (Clicked() consumes events).

func (*ConfirmDialog) Layout

Layout renders the confirmation dialog inside a modal overlay. Use HandleUserInteractions to detect confirm/cancel clicks.

func (*ConfirmDialog) LayoutWithExtras

func (cd *ConfirmDialog) LayoutWithExtras(gtx layout.Context, th *Theme, style ConfirmDialogStyle, extras layout.Widget) layout.Dimensions

LayoutWithExtras renders the confirmation dialog with an optional extras widget (e.g. a checkbox) sandwiched between the message and the action buttons. Pass nil for extras when no additional UI is needed; the result is identical to Layout().

type ConfirmDialogStyle

type ConfirmDialogStyle struct {
	Title        string
	Message      string
	ConfirmLabel string
	ConfirmColor color.NRGBA
}

ConfirmDialogStyle configures the appearance of a ConfirmDialog.

type DBCredentials

type DBCredentials struct {
	// contains filtered or unexported fields
}

DBCredentials renders the Database section with selectable values, copy buttons, and an opt-in host-port publish toggle so the user can connect from desktop DB clients.

func NewDBCredentials

func NewDBCredentials() *DBCredentials

func (*DBCredentials) Bind

func (dc *DBCredentials) Bind(sm *sites.SiteManager, state *UIState, toasts *Notifications)

Bind stores the SiteManager + UI bridges DBCredentials needs for the publish-port flow. Called from NewSiteDetail after construction so the existing zero-arg NewDBCredentials still compiles.

func (*DBCredentials) HandleUserInteractions

func (dc *DBCredentials) HandleUserInteractions(gtx layout.Context, site *types.Site)

HandleUserInteractions processes per-row Copy button clicks + the publish-port toggle.

func (*DBCredentials) Layout

func (dc *DBCredentials) Layout(gtx layout.Context, th *Theme, site *types.Site) layout.Dimensions

type Dims

type Dims struct {
	RailExpanded   unit.Dp
	RailCollapsed  unit.Dp
	SitesListWidth unit.Dp
	ModalWidth     unit.Dp
	LoaderSize     unit.Dp
	LoaderSizeSM   unit.Dp
	OutputAreaMax  unit.Dp
	LabelColWidth  unit.Dp

	// Legacy alias for the old single-sidebar layout.
	SidebarWidth unit.Dp
}

Dims holds fixed layout dimensions independent of theme mode.

RailExpanded   — Column 1 nav rail width, expanded.
RailCollapsed  — Column 1 nav rail width, collapsed (icons only).
SitesListWidth — Column 2 sites-list panel width.

func DefaultDims

func DefaultDims() *Dims
type Dropdown struct {
	Selected int
	Options  []string
	// contains filtered or unexported fields
}

Dropdown widget for selecting from a list of options.

func NewDropdown

func NewDropdown(options []string) *Dropdown
func (d *Dropdown) Layout(gtx layout.Context, th *Theme, label string) layout.Dimensions

type HealthBadgeKind

type HealthBadgeKind int

HealthBadgeKind is the styling key for the nav-rail badge.

const (
	HealthBadgeNone    HealthBadgeKind = iota
	HealthBadgeInfo                    // hidden in the rail; shown only in the panel
	HealthBadgeWarn                    // amber
	HealthBadgeBlocker                 // red
)

func HealthBadgeFor

func HealthBadgeFor(snap health.Snapshot) HealthBadgeKind

HealthBadgeFor maps a snapshot onto the rail-badge styling. Returns HealthBadgeNone when the snapshot has no findings or only Info-level ones.

type HealthBlockerModal

type HealthBlockerModal struct {
	// contains filtered or unexported fields
}

HealthBlockerModal renders the full-screen modal that fires when at least one Blocker finding is present. The user has two options: "Re-check" (calls runner.RunNow) and "Quit". There is deliberately no "Ignore" — DDEV's discipline.

func NewHealthBlockerModal

func NewHealthBlockerModal(state *UIState, runNow func(), onQuit func()) *HealthBlockerModal

NewHealthBlockerModal builds the modal. quit is invoked when the user clicks Quit; main.go wires it to a graceful shutdown.

func (*HealthBlockerModal) HandleUserInteractions

func (m *HealthBlockerModal) HandleUserInteractions(gtx layout.Context)

HandleUserInteractions processes button clicks. Called by the root UI before Layout when the modal is visible.

func (*HealthBlockerModal) HasBlocker

func (m *HealthBlockerModal) HasBlocker() bool

HasBlocker reports whether the current snapshot contains a blocker.

func (*HealthBlockerModal) Layout

Layout renders the blocker modal as a full-screen overlay.

type HealthPanel

type HealthPanel struct {
	// contains filtered or unexported fields
}

HealthPanel renders the System Health card in the Settings panel. It reads the snapshot from UIState (atomic, lock-free) every frame and renders one row per Finding plus a "Re-check now" button.

HealthPanel does NOT own the runner — it only reads. Action invocations route back through the runner via the optional submitAction callback, which the wiring layer (main.go) provides as a closure over runner.SubmitAction.

func NewHealthPanel

func NewHealthPanel(state *UIState, submitAction func(id string, a health.Action) error, runNow func()) *HealthPanel

NewHealthPanel constructs the panel. submitAction is the runner's SubmitAction wrapped in a closure; runNow is runner.RunNow + Snapshot publication. Both may be nil for tests.

func (*HealthPanel) HandleUserInteractions

func (p *HealthPanel) HandleUserInteractions(gtx layout.Context)

HandleUserInteractions reads the re-check button and any per-finding action button. Called by the parent panel each frame.

func (*HealthPanel) Layout

func (p *HealthPanel) Layout(gtx layout.Context, th *Theme) layout.Dimensions

Layout renders the System Health card.

type HookEditor

type HookEditor struct {
	// contains filtered or unexported fields
}

HookEditor is the add/edit dialog for a single hook. It is created once per SiteDetail and mutated to represent either a new hook (Open with Hook.ID == 0) or an existing one (Open with Hook.ID != 0).

func NewHookEditor

func NewHookEditor() *HookEditor

NewHookEditor constructs a HookEditor with the active event list as dropdown options.

func (*HookEditor) Close

func (he *HookEditor) Close()

Close hides the editor without saving.

func (*HookEditor) HandleUserInteractions

func (he *HookEditor) HandleUserInteractions(gtx layout.Context, state *UIState)

HandleUserInteractions runs each frame the editor is visible.

func (*HookEditor) IsVisible

func (he *HookEditor) IsVisible() bool

IsVisible reports whether the editor is open.

func (*HookEditor) Layout

func (he *HookEditor) Layout(gtx layout.Context, th *Theme) layout.Dimensions

Layout draws the modal. Caller is responsible for only invoking when IsVisible() is true.

func (*HookEditor) Open

func (he *HookEditor) Open(siteID string, h hooks.Hook, onSubmit func(hooks.Hook))

Open prepares the editor for adding (h.ID == 0) or editing (h.ID != 0). onSubmit fires when the user clicks Save with a valid form.

type HookOutput

type HookOutput struct {
	// contains filtered or unexported fields
}

HookOutput renders the live output panel for the most recent hook run on the selected site. It tracks no per-output state of its own — everything it draws comes from UIState.HookSnapshot.

func NewHookOutput

func NewHookOutput(state *UIState, sm *sites.SiteManager) *HookOutput

NewHookOutput builds a fresh output panel. `sm` is unused at present but reserved for future cancel-run / re-run integration.

func (*HookOutput) HandleUserInteractions

func (ho *HookOutput) HandleUserInteractions(gtx layout.Context, siteID string)

HandleUserInteractions handles open-log and clear-output clicks.

func (*HookOutput) Layout

func (ho *HookOutput) Layout(gtx layout.Context, th *Theme, siteID string) layout.Dimensions

Layout renders the panel for the given site.

type HookSnapshot

type HookSnapshot struct {
	Running *hooks.Hook
	Last    *hooks.Result
	Summary *hooks.Summary
	Lines   []hookLine
}

HookSnapshot is a frame-stable copy of the per-site hook output / progress. Renderers receive a snapshot so the layout pass never holds the state mutex while iterating.

func (HookSnapshot) HasActivity

func (h HookSnapshot) HasActivity() bool

HasActivity reports whether there is anything worth displaying.

type HooksPanel

type HooksPanel struct {
	// contains filtered or unexported fields
}

HooksPanel is the per-site hooks tab. It loads hooks lazily on display, caches them in memory, and refreshes whenever the user makes a change.

func NewHooksPanel

func NewHooksPanel(state *UIState, sm *sites.SiteManager, provider hookListProvider, toasts *Notifications) *HooksPanel

NewHooksPanel builds a HooksPanel.

func (*HooksPanel) HandleUserInteractions

func (hp *HooksPanel) HandleUserInteractions(gtx layout.Context, siteID string)

HandleUserInteractions processes clicks for the hooks tab. It delegates to the editor / confirm dialog as needed.

func (*HooksPanel) HasActiveModal

func (hp *HooksPanel) HasActiveModal() bool

HasActiveModal reports whether the panel is showing the editor or the delete-confirm modal.

func (*HooksPanel) Layout

func (hp *HooksPanel) Layout(gtx layout.Context, th *Theme, siteID string) layout.Dimensions

Layout renders the hooks tab body for the given site.

func (*HooksPanel) LayoutModalLayer

func (hp *HooksPanel) LayoutModalLayer(gtx layout.Context, th *Theme) layout.Dimensions

LayoutModalLayer is called from the root UI's modal stack so the hook editor and delete-confirm dialogs sit above the rest of the chrome.

type IconFunc

type IconFunc func(gtx layout.Context, th *Theme, size unit.Dp, col color.NRGBA) layout.Dimensions

IconFunc paints a stroke icon at the requested size in the given color. All icons are designed against a 24×24 grid with a 1.6 stroke width and scale uniformly.

type KV

type KV struct {
	Key   string
	Value string
}

KV holds a key-value pair for display in info sections.

type LifecycleSnapshot

type LifecycleSnapshot struct {
	PlanName   string
	Steps      []orch.StepResult
	Pulls      []docker.PullProgress
	FinalError error
	RolledBack bool
	Done       bool
}

LifecycleSnapshot is a frame-stable copy of a site's running lifecycle Plan. Renderers receive a snapshot so the Layout pass never holds the state mutex while iterating.

func (LifecycleSnapshot) HasActivity

func (l LifecycleSnapshot) HasActivity() bool

HasActivity reports whether there is anything worth displaying.

type LinkChecker

type LinkChecker struct {
	// contains filtered or unexported fields
}

LinkChecker provides a UI panel for checking broken links on a running site.

func NewLinkChecker

func NewLinkChecker(state *UIState, sm *sites.SiteManager) *LinkChecker

func (*LinkChecker) HandleUserInteractions

func (lc *LinkChecker) HandleUserInteractions(gtx layout.Context, siteID string)

HandleUserInteractions processes the Check Links button click.

func (*LinkChecker) Layout

func (lc *LinkChecker) Layout(gtx layout.Context, th *Theme, siteID string) layout.Dimensions

type LogViewer

type LogViewer struct {
	// contains filtered or unexported fields
}

LogViewer renders the container log viewer panel with service selector and output area.

func NewLogViewer

func NewLogViewer(state *UIState, sm *sites.SiteManager) *LogViewer

func (*LogViewer) HandleUserInteractions

func (lv *LogViewer) HandleUserInteractions(gtx layout.Context, siteID string)

HandleUserInteractions processes the Refresh button click.

func (*LogViewer) Layout

func (lv *LogViewer) Layout(gtx layout.Context, th *Theme, siteID string) layout.Dimensions

type ModalFocus

type ModalFocus struct {
	Tag event.Tag
	// contains filtered or unexported fields
}

FocusModalKeys declares tag as a key event receiver and requests focus on the first call after the modal becomes visible. Call from the modal's Layout() before Process is called for the next frame.

func NewModalFocus

func NewModalFocus() *ModalFocus

NewModalFocus creates a focus tracker for a modal. Tag should be a stable pointer (e.g. &ModalFocus{} stored on the modal struct).

func (*ModalFocus) Layout

func (mf *ModalFocus) Layout(gtx layout.Context)

Layout registers the focus tag and requests keyboard focus the first frame it is shown. Call OnHide when the modal closes to re-arm focus for next time.

func (*ModalFocus) OnHide

func (mf *ModalFocus) OnHide()

OnHide resets the focus tracker so the next time the modal is shown, focus is requested again.

type ModalKeyResult

type ModalKeyResult struct {
	Escape bool
	Enter  bool
}

ModalKeyResult reports which key terminated a frame's key processing.

func ProcessModalKeys

func ProcessModalKeys(gtx layout.Context, tag event.Tag) ModalKeyResult

ProcessModalKeys consumes Escape/Enter key events delivered to the given tag and returns which one fired (if any). Call once per frame from HandleUserInteractions while the modal is visible.

The caller is responsible for declaring the tag in the layout pass via FocusModalKeys, which also requests focus the first time it is shown.

type NavRail struct {
	// contains filtered or unexported fields
}

NavRail is the leftmost column: the brand mark, two top-level nav items (Sites / Settings), a hardcoded GROUPS section, and a collapse chevron at the bottom. The rail's width is read from UIState.NavCollapsed and its right edge bears a 1-px line.

func NewNavRail

func NewNavRail(state *UIState, sm *sites.SiteManager) *NavRail
func (n *NavRail) HandleUserInteractions(gtx layout.Context)

HandleUserInteractions processes clicks on the nav items and the collapse toggle. Called by the root UI before Layout each frame.

func (n *NavRail) Layout(gtx layout.Context, th *Theme) layout.Dimensions
type NavView string

NavView identifies which root area is shown in columns 2+3. The nav rail in column 1 toggles this; the chrome adapts accordingly.

const (
	NavViewSites    NavView = "sites"
	NavViewSettings NavView = "settings"
)

type NewSiteModal

type NewSiteModal struct {
	// contains filtered or unexported fields
}

func NewNewSiteModal

func NewNewSiteModal(state *UIState, sm *sites.SiteManager, toasts *Notifications) *NewSiteModal

func (*NewSiteModal) HandleUserInteractions

func (m *NewSiteModal) HandleUserInteractions(gtx layout.Context)

HandleUserInteractions processes Cancel / Browse / Create button clicks. Called by the root UI before Layout when the modal is visible.

func (*NewSiteModal) Layout

func (m *NewSiteModal) Layout(gtx layout.Context, th *Theme) layout.Dimensions

type NoticeSnapshot

type NoticeSnapshot struct {
	Message     string
	ActionLabel string
	HasAction   bool
	Busy        bool
}

NoticeSnapshot is a frame-stable copy of the notice banner state. The Layout pass reads this once per frame so it can render the message and (optionally) an action button without holding the state mutex.

type Notification

type Notification struct {
	ID        int64
	Type      NotificationType
	Message   string
	CreatedAt time.Time
	Duration  time.Duration
	// contains filtered or unexported fields
}

Notification is a single message with a type, creation time, and TTL after which the floating banner auto-docks into the history panel.

type NotificationType

type NotificationType int

NotificationType determines the visual style of a notification.

const (
	NotificationError NotificationType = iota
	NotificationSuccess
	NotificationInfo
)

type Notifications

type Notifications struct {
	// contains filtered or unexported fields
}

Notifications is a notification center that floats new entries transiently in the bottom-right corner and docks expired entries into a history panel toggled by a bell icon. Archive entries persist until the user dismisses them individually or clears all.

func NewNotifications

func NewNotifications(state *UIState) *Notifications

func (*Notifications) Add

func (n *Notifications) Add(msg string, t NotificationType)

Add inserts a new notification of the given type and starts its floating timer.

func (*Notifications) Error

func (n *Notifications) Error(msg string)

Error / Success / Info are sugar over Add.

func (*Notifications) HandleUserInteractions

func (n *Notifications) HandleUserInteractions(gtx layout.Context)

HandleUserInteractions processes the bell-toggle and archive-dismiss clicks. Call from the root UI before Layout each frame.

func (*Notifications) Info

func (n *Notifications) Info(msg string)

func (*Notifications) Layout

func (n *Notifications) Layout(gtx layout.Context, th *Theme) layout.Dimensions

Layout draws floating notifications in the bottom-right and, when the bell is open, the history panel above them.

func (*Notifications) LayoutBell

func (n *Notifications) LayoutBell(gtx layout.Context, th *Theme) layout.Dimensions

LayoutBell draws the bell icon with an unread-count badge. Call from the sidebar so the bell sits beside the search field or app title.

func (*Notifications) ShowError

func (n *Notifications) ShowError(msg string)

ShowError / ShowSuccess preserve the previous toast API.

func (*Notifications) ShowInfo

func (n *Notifications) ShowInfo(msg string)

func (*Notifications) ShowSuccess

func (n *Notifications) ShowSuccess(msg string)

func (*Notifications) Success

func (n *Notifications) Success(msg string)

type OutputView

type OutputView struct {
	// contains filtered or unexported fields
}

OutputView is the persistent state for an output panel (logs, WP-CLI output, link-checker results). It wraps a read-only widget.Editor so the user can click-drag to select text and Ctrl+C to copy. lastText caches the most recently applied content; SetText resets the caret and selection, so we only re-apply when the output actually changes.

func NewOutputView

func NewOutputView() *OutputView

NewOutputView constructs an OutputView with a read-only editor.

func (*OutputView) Layout

func (ov *OutputView) Layout(gtx layout.Context, th *Theme, output, placeholder string, maxHeight unit.Dp) layout.Dimensions

Layout renders the output panel: a Surface-colored card containing a scrollable, selectable monospace text area. When output is empty, placeholder is shown via the editor's hint.

type Palette

type Palette struct {
	// ── Design tokens ─────────────────────────────────────────────────
	// Surface hierarchy: Bg flush / Bg1 panels / Bg2 hover-active /
	// Bg3 input fills.
	Bg  color.NRGBA
	Bg1 color.NRGBA
	Bg2 color.NRGBA
	Bg3 color.NRGBA

	// Lines: Line for muted dividers; LineStrong for input/button borders.
	Line       color.NRGBA
	LineStrong color.NRGBA

	// Foreground hierarchy.
	Fg  color.NRGBA // body text
	Fg2 color.NRGBA // secondary
	Fg3 color.NRGBA // muted

	// Accent (single retro cyan, used sparingly).
	Accent     color.NRGBA
	AccentSoft color.NRGBA // tint background
	AccentLine color.NRGBA // tint border
	AccentFg   color.NRGBA // text on accent surface

	// Status: each pair is solid (foreground / dot / border-base) and
	// soft (background tint).
	Ok       color.NRGBA
	OkSoft   color.NRGBA
	Warn     color.NRGBA
	WarnSoft color.NRGBA
	Err      color.NRGBA
	ErrSoft  color.NRGBA

	// Active/hover row tint (semi-transparent — paint over Bg1).
	RowActive color.NRGBA

	// Modal backdrop overlay.
	Overlay color.NRGBA

	// ── Legacy aliases (back-compat with existing widget code) ───────
	// Surface aliases.
	SidebarBg       color.NRGBA // Bg
	ContentBg       color.NRGBA // Bg
	SurfaceDeep     color.NRGBA // Bg1
	Surface         color.NRGBA // Bg1
	SurfaceAlt      color.NRGBA // Bg2
	SurfaceElevated color.NRGBA // Bg1

	// Text aliases.
	TextPrimary   color.NRGBA // Fg
	TextStrong    color.NRGBA // Fg
	TextSecondary color.NRGBA // Fg2
	TextMuted     color.NRGBA // Fg3
	OnPrimary     color.NRGBA // AccentFg

	// Brand alias — formerly gold; now the cyan accent.
	Brand color.NRGBA // Accent

	// Action aliases.
	Primary    color.NRGBA // Accent
	Danger     color.NRGBA // Err
	DangerDeep color.NRGBA // Err
	Success    color.NRGBA // Ok

	// Banner aliases.
	InfoBg    color.NRGBA // pre-blended cyan-tinted surface
	InfoFg    color.NRGBA // Accent
	SuccessBg color.NRGBA // pre-blended green-tinted surface
	SuccessFg color.NRGBA // Ok
	DangerBg  color.NRGBA // pre-blended red-tinted surface
	DangerFg  color.NRGBA // Err

	// Structural aliases.
	Border        color.NRGBA // Line
	BorderFocused color.NRGBA // Accent
	Separator     color.NRGBA // Line

	// Utility.
	White color.NRGBA
}

Palette holds the semantic color set for a single theme mode (dark or light). The "design token" fields (Bg, Bg1, Fg, Accent, etc.) are the canonical names used by new layout code; the legacy fields below them (SidebarBg, Surface, TextPrimary, etc.) are aliases retained so existing widgets keep compiling — they map onto the same underlying colors.

func DarkPalette

func DarkPalette() *Palette

DarkPalette returns the dark-mode palette: deep neutral grays with the same retro-cyan accent.

func LightPalette

func LightPalette() *Palette

LightPalette returns the light-mode palette: warm whites + neutral grays with the same retro-cyan accent.

type ProfilingPanel

type ProfilingPanel struct {
	// contains filtered or unexported fields
}

ProfilingPanel is the per-site SPX profiler tab. It owns the toggle, the URL/key card, and the recent-reports list. SPX itself runs inside the existing PHP-FPM container — this panel never spawns or touches Docker; it strictly drives SiteManager and reads the profile-data directory via the SiteManager helpers.

func NewProfilingPanel

func NewProfilingPanel(state *UIState, sm *sites.SiteManager, toasts *Notifications) *ProfilingPanel

NewProfilingPanel constructs a ProfilingPanel. State + SiteManager are required; toasts may be nil (errors then route only through the global error banner via state.ShowError).

func (*ProfilingPanel) HandleUserInteractions

func (pp *ProfilingPanel) HandleUserInteractions(gtx layout.Context, site *types.Site)

HandleUserInteractions processes button clicks. Must be called once per frame, before Layout.

func (*ProfilingPanel) Layout

func (pp *ProfilingPanel) Layout(gtx layout.Context, th *Theme, site *types.Site) layout.Dimensions

Layout renders the panel.

type Radii

type Radii struct {
	R1 unit.Dp
	R2 unit.Dp
	R3 unit.Dp
	R4 unit.Dp

	SM unit.Dp
	MD unit.Dp
	LG unit.Dp
}

Radii is the corner-radius scale: R1 (4dp) for tight chips, R2 (6dp) for buttons/inputs, R3 (10dp) for panels, R4 (14dp) for the outer window. SM/MD/LG aliases retained for back-compat.

func DefaultRadii

func DefaultRadii() *Radii

type ServicesHealth

type ServicesHealth struct {
	Status ServicesHealthStatus
	Detail string
}

ServicesHealth captures the rolled-up health of Locorum's global services. Status is the worst observed state across the three; Detail is a human-readable suffix shown in the top status bar.

type ServicesHealthStatus

type ServicesHealthStatus int

ServicesHealthStatus is a tri-state for the global-services bar.

const (
	ServicesHealthUnknown ServicesHealthStatus = iota
	ServicesHealthHealthy
	ServicesHealthDegraded
	ServicesHealthDown
)

type SettingsPanel

type SettingsPanel struct {
	// contains filtered or unexported fields
}

SettingsPanel takes over columns 2+3 when the nav rail's Settings item is active. Sections (top to bottom):

  • System Health: runner findings + re-check.
  • Appearance: theme picker (System / Light / Dark).
  • New site defaults: pre-fill values for the new-site modal.
  • Network & TLS: router HTTP/HTTPS host ports + mkcert path.

Each section reads from sm.Config() at construction time and pushes validated changes back through the typed setters. Validation errors surface as a transient toast — never an uncaught panic.

func NewSettingsPanel

func NewSettingsPanel(state *UIState, sm *sites.SiteManager, onThemeChange func(ThemeMode)) *SettingsPanel

NewSettingsPanel constructs a SettingsPanel. onThemeChange is invoked whenever the user changes the theme mode (e.g. to apply + persist).

func (*SettingsPanel) HandleUserInteractions

func (s *SettingsPanel) HandleUserInteractions(gtx layout.Context)

HandleUserInteractions watches the theme picker for selection changes, syncs the engine→version dropdown, and persists any changed defaults.

func (*SettingsPanel) Layout

func (s *SettingsPanel) Layout(gtx layout.Context, th *Theme) layout.Dimensions

func (*SettingsPanel) SetHealthPanel

func (s *SettingsPanel) SetHealthPanel(hp *HealthPanel)

SetHealthPanel attaches the system-health panel renderer. Optional — callers that don't wire a runner (early startup, tests) can leave it nil and the section is omitted from the layout.

type SiteDetail

type SiteDetail struct {
	// contains filtered or unexported fields
}

SiteDetail is column 3: a header bar (avatar/name/domain/status pill + action buttons), a tab strip, and the active tab's body content. Hosts the per-tab sub-components (DB credentials, logs, WP-CLI, hooks, etc).

func NewSiteDetail

func NewSiteDetail(state *UIState, sm *sites.SiteManager, toasts *Notifications) *SiteDetail

func (*SiteDetail) HandleUserInteractions

func (sd *SiteDetail) HandleUserInteractions(gtx layout.Context)

HandleUserInteractions processes header-bar clicks, tab selection, and per-tab sub-component interactions. Called by the root UI before Layout each frame.

func (*SiteDetail) HooksPanel

func (sd *SiteDetail) HooksPanel() *HooksPanel

HooksPanel exposes the hooks tab so the root UI can render its modal overlays above the main chrome.

func (*SiteDetail) Layout

func (sd *SiteDetail) Layout(gtx layout.Context, th *Theme) layout.Dimensions

type SitesPanel

type SitesPanel struct {
	// contains filtered or unexported fields
}

SitesPanel is column 2: a fixed-width sites list with a sticky-feeling header (title, count, +New button, search input) above scrollable rows.

func NewSitesPanel

func NewSitesPanel(state *UIState, sm *sites.SiteManager, toasts *Notifications) *SitesPanel

func (*SitesPanel) HandleUserInteractions

func (p *SitesPanel) HandleUserInteractions(gtx layout.Context)

HandleUserInteractions reads search text, the +New click, and per-row selection clicks into UIState.

func (*SitesPanel) Layout

func (p *SitesPanel) Layout(gtx layout.Context, th *Theme) layout.Dimensions

type SnapshotsPanel

type SnapshotsPanel struct {
	// contains filtered or unexported fields
}

SnapshotsPanel lists snapshots for a site, lets the user create a new one, and offers per-row Restore + Delete actions. Lives in the site detail panel as a tab next to Logs / WP-CLI / Hooks.

func NewSnapshotsPanel

func NewSnapshotsPanel(state *UIState, sm *sites.SiteManager, toasts *Notifications) *SnapshotsPanel

func (*SnapshotsPanel) HandleUserInteractions

func (p *SnapshotsPanel) HandleUserInteractions(gtx layout.Context, site *types.Site)

HandleUserInteractions processes button clicks. Called by the parent before Layout when this panel is visible.

func (*SnapshotsPanel) Layout

func (p *SnapshotsPanel) Layout(gtx layout.Context, th *Theme, site *types.Site) layout.Dimensions

type Spacing

type Spacing struct {
	XXS unit.Dp
	XS  unit.Dp
	SM  unit.Dp
	MD  unit.Dp
	LG  unit.Dp
	XL  unit.Dp
	XXL unit.Dp
}

Spacing is the padding/margin scale, calibrated to the design's em rhythm at an 18px base (so 1em ≈ 18dp). XS≈0.35em, SM≈0.55em, MD≈0.85em, LG≈1.1em, XL≈1.55em.

func DefaultSpacing

func DefaultSpacing() *Spacing

type TextInput

type TextInput struct {
	Editor widget.Editor
	// contains filtered or unexported fields
}

TextInput wraps widget.Editor with a self-resetting Changed() helper that returns true the first time it's called after the user has modified the text, then resets until the next change.

func NewMultiline

func NewMultiline(initial string) *TextInput

NewMultiline returns a multi-line TextInput.

func NewTextInput

func NewTextInput(initial string) *TextInput

NewTextInput returns a single-line TextInput preloaded with the given value.

func (*TextInput) Changed

func (t *TextInput) Changed() bool

Changed returns true if the text changed since the last call to Changed, then resets. Pair with Update() each frame.

func (*TextInput) SetText

func (t *TextInput) SetText(s string)

SetText replaces the editor text and resyncs the Changed baseline so a programmatic update doesn't read as user input.

func (*TextInput) Text

func (t *TextInput) Text() string

Text returns the current editor text.

func (*TextInput) Update

func (t *TextInput) Update(gtx layout.Context)

Update should be called once per frame (typically from HandleUserInteractions). It reads the editor's current text and flips the internal changed flag if it differs from the previous frame's value.

type TextSizes

type TextSizes struct {
	Micro   unit.Sp
	Mono    unit.Sp
	MonoSM  unit.Sp
	Body    unit.Sp
	Tab     unit.Sp
	Header  unit.Sp
	Section unit.Sp
	H1      unit.Sp

	// Legacy aliases.
	XS   unit.Sp
	SM   unit.Sp
	Base unit.Sp
	LG   unit.Sp
}

TextSizes is the typography scale, em-based at an 18sp base.

Micro   12sp — uppercase mono labels (~0.65em)
Mono    13sp — mono captions, status, domain (~0.72em)
MonoSM  14sp — mono values (~0.78em)
Body    15sp — body text, nav items (~0.85em)
Tab     15sp — tab labels (~0.82em, rounded up)
Header  17sp — detail header name, section heading (~0.92em)
H1      22sp — modal titles

XS/SM/Base/LG are aliases retained for back-compat with existing widgets.

func DefaultTextSizes

func DefaultTextSizes() *TextSizes

type Theme

type Theme struct {
	*material.Theme
	Color   *Palette
	Spacing *Spacing
	Sizes   *TextSizes
	Radii   *Radii
	Dims    *Dims
	Mode    ThemeMode // user preference (Dark, Light, or System)
}

Theme bundles the material theme plus the custom palette, spacing, text sizes, corner radii, and layout dimensions. It is threaded through every Layout() function in the UI. Access the underlying *material.Theme via th.Theme (e.g. material.Body2(th.Theme, "...")).

func NewTheme

func NewTheme() *Theme

NewTheme constructs a Theme with the system-resolved palette as default. Use (*Theme).SetMode to switch palettes at runtime.

func (*Theme) ContrastText

func (t *Theme) ContrastText(bg color.NRGBA) color.NRGBA

ContrastText returns black or white depending on whether the input background color is light or dark, optimised for body text legibility.

func (*Theme) Danger

func (th *Theme) Danger(gtx layout.Context, btn *widget.Clickable, text string) layout.Dimensions

Danger draws a destructive action button.

func (*Theme) Disabled

func (t *Theme) Disabled(c color.NRGBA) color.NRGBA

Disabled returns a desaturated, alpha-reduced version of the input color, suitable for disabled controls.

func (*Theme) Hovered

func (t *Theme) Hovered(c color.NRGBA) color.NRGBA

Hovered returns a slightly lighter (dark theme) or darker (light theme) variant of the input color, suitable for hover states.

func (*Theme) Primary

func (th *Theme) Primary(gtx layout.Context, btn *widget.Clickable, text string) layout.Dimensions

Primary draws a neon cyan primary action button.

func (*Theme) PrimaryGated

func (th *Theme) PrimaryGated(gtx layout.Context, btn *widget.Clickable, text string, enabled bool) layout.Dimensions

PrimaryGated draws a primary button that is visually muted and ignores clicks when enabled is false. Pair with .Changed() / dirty-tracking so the button only activates when the user has edited something.

func (*Theme) ResolvedMode

func (t *Theme) ResolvedMode() ThemeMode

ResolvedMode returns the effective theme mode, resolving ThemeSystem to either ThemeDark or ThemeLight via DetectSystemTheme.

func (*Theme) Secondary

func (th *Theme) Secondary(gtx layout.Context, btn *widget.Clickable, text string) layout.Dimensions

Secondary draws a muted surface secondary action button.

func (*Theme) SetMode

func (t *Theme) SetMode(mode ThemeMode)

SetMode swaps the active palette to the requested mode. ThemeSystem resolves to Dark or Light via DetectSystemTheme().

func (*Theme) Small

func (th *Theme) Small(gtx layout.Context, btn *widget.Clickable, text string) layout.Dimensions

Small draws a compact secondary button for inline use (e.g., Copy buttons).

func (*Theme) SmallGated

func (th *Theme) SmallGated(gtx layout.Context, btn *widget.Clickable, text string, enabled bool) layout.Dimensions

SmallGated mirrors Small but is muted and ignores clicks when enabled is false.

func (*Theme) Success

func (th *Theme) Success(gtx layout.Context, btn *widget.Clickable, text string) layout.Dimensions

Success draws a confirmation action button.

type ThemeMode

type ThemeMode int

ThemeMode selects the active color palette. ThemeSystem follows the host OS setting (resolved to Dark or Light at theme construction / switch time).

const (
	ThemeDark ThemeMode = iota
	ThemeLight
	ThemeSystem
)

func DetectSystemTheme

func DetectSystemTheme() ThemeMode

DetectSystemTheme inspects the host OS for a light/dark preference. Falls back to ThemeDark if the preference can't be determined.

func ParseThemeMode

func ParseThemeMode(s string) ThemeMode

ParseThemeMode converts a stored string into a ThemeMode. Unknown / empty values fall back to ThemeSystem (so a freshly-installed app follows the OS).

func (ThemeMode) String

func (m ThemeMode) String() string

String returns the canonical persistence string for a ThemeMode.

type UI

type UI struct {
	Theme *Theme
	State *UIState
	SM    *sites.SiteManager

	// Sub-components
	NavRail    *NavRail
	SitesPanel *SitesPanel
	Settings   *SettingsPanel
	SiteDetail *SiteDetail
	NewSite    *NewSiteModal
	Toasts     *Notifications

	// Modals
	CloneModal    *CloneModal
	HealthBlocker *HealthBlockerModal
	// contains filtered or unexported fields
}

func New

func New(sm *sites.SiteManager) *UI

func (*UI) HandleUserInteractions

func (ui *UI) HandleUserInteractions(gtx layout.Context)

HandleUserInteractions processes all user input for the current frame. Modal interactions are only processed when their modal is visible, preventing phantom clicks against hidden widgets.

func (*UI) Layout

func (ui *UI) Layout(gtx layout.Context) layout.Dimensions

type UIState

type UIState struct {
	// contains filtered or unexported fields
}

UIState holds all mutable UI state, protected by a mutex for thread-safe access from background goroutines (Docker operations, site loading, etc.).

func NewUIState

func NewUIState() *UIState

func (*UIState) ActiveError

func (s *UIState) ActiveError() string

ActiveError returns the current error message if it hasn't expired, or "".

func (*UIState) ActivityFull

func (s *UIState) ActivityFull(siteID string) ([]storage.ActivityEvent, bool)

ActivityFull returns a snapshot copy of the cached full rows for siteID and a flag indicating whether the full cache has been populated. The caller uses the flag to decide whether to kick off a load.

func (*UIState) ActivityRecent

func (s *UIState) ActivityRecent(siteID string) []storage.ActivityEvent

ActivityRecent returns a snapshot copy of the cached recent rows for siteID. Returns an empty slice (not nil) if no cache entry exists.

func (*UIState) AppendActivity

func (s *UIState) AppendActivity(siteID string, ev storage.ActivityEvent)

AppendActivity prepends ev to both the recent and (if loaded) full cache for siteID, trimming each to its respective cap. Used from the OnActivityAppended callback.

The full cache is only mutated if it was previously loaded — otherwise the row is on disk and will appear next time the Activity tab is opened. This avoids growing an unbounded cache for sites the user never visits.

func (*UIState) AppendLinkCheckOutput

func (s *UIState) AppendLinkCheckOutput(line string)

func (*UIState) ClearActivity

func (s *UIState) ClearActivity(siteID string)

ClearActivity drops the cache entry for siteID. Called when a site is removed so we don't leak per-site state for the lifetime of the process.

func (*UIState) ClearDeleteConfirm

func (s *UIState) ClearDeleteConfirm() (id string, purgeVolume bool)

ClearDeleteConfirm closes the delete confirmation modal and returns the target site ID and the user's purge choice.

func (*UIState) ClearHookOutput

func (s *UIState) ClearHookOutput(siteID string)

ClearHookOutput discards the cached output for a site (e.g. when the user switches sites or the panel resets).

func (*UIState) ClearInitError

func (s *UIState) ClearInitError()

ClearInitError clears the init error.

func (*UIState) DiskFreeBytes

func (s *UIState) DiskFreeBytes() int64

DiskFreeBytes returns the cached host-filesystem free-byte reading. Zero means "unknown" (typical until the first health cycle completes).

func (*UIState) DismissCloneModal

func (s *UIState) DismissCloneModal()

func (*UIState) DismissDeleteConfirm

func (s *UIState) DismissDeleteConfirm()

DismissDeleteConfirm closes the delete confirmation modal without deleting.

func (*UIState) GetCloneModalState

func (s *UIState) GetCloneModalState() (show bool, id, name string)

func (*UIState) GetDeleteConfirmState

func (s *UIState) GetDeleteConfirmState() (show bool, name string, purgeVolume bool)

GetDeleteConfirmState returns the current delete confirmation state.

func (*UIState) GetInitError

func (s *UIState) GetInitError() string

GetInitError returns the current initialization error, or "".

func (*UIState) GetLinkCheckState

func (s *UIState) GetLinkCheckState() (output string, loading bool)

func (*UIState) GetLogState

func (s *UIState) GetLogState() (output, service string, loading bool)

GetLogState returns the current log viewer state.

func (*UIState) GetRetryInit

func (s *UIState) GetRetryInit() func()

GetRetryInit returns the retry callback.

func (*UIState) GetSearchTerm

func (s *UIState) GetSearchTerm() string

GetSearchTerm returns the current search filter.

func (*UIState) GetSelectedID

func (s *UIState) GetSelectedID() string

GetSelectedID returns the selected site ID.

func (*UIState) GetSites

func (s *UIState) GetSites() []types.Site

GetSites returns a copy of the current site list.

func (*UIState) GetWPCLIState

func (s *UIState) GetWPCLIState() (output string, loading bool)

GetWPCLIState returns the current WP-CLI state.

func (*UIState) HealthClearFirstFire

func (s *UIState) HealthClearFirstFire()

HealthClearFirstFire ends the first-fire suppression window. Called once after the first snapshot finishes. Subsequent toasts behave normally.

func (*UIState) HealthHydrateSeen

func (s *UIState) HealthHydrateSeen(keys []string)

HealthHydrateSeen seeds the seen-keys set from the persisted JSON. Idempotent.

func (*UIState) HealthSeenKeys

func (s *UIState) HealthSeenKeys() []string

HealthSeenKeys returns a snapshot of the seen-keys set, suitable for JSON serialisation into the persistent settings table.

func (*UIState) HealthShouldToast

func (s *UIState) HealthShouldToast(key string) bool

HealthShouldToast reports whether the given finding key has been seen before in this process. The first call for any key returns true (the caller should fire a toast); subsequent calls return false.

Returns false during the first-fire window — the runner publishes the initial snapshot but the UI suppresses toasts so a fresh install isn't flooded.

func (*UIState) HealthSnapshot

func (s *UIState) HealthSnapshot() health.Snapshot

HealthSnapshot returns the most recently stored snapshot. Never nil because NewUIState publishes an empty snapshot at construction time.

func (*UIState) HookAllDone

func (s *UIState) HookAllDone(siteID string, summary hooks.Summary)

HookAllDone records the run summary.

func (*UIState) HookSnapshot

func (s *UIState) HookSnapshot(siteID string) HookSnapshot

HookSnapshot returns a copy of the per-site hook output for safe reading from a Layout pass.

func (*UIState) HookTaskDone

func (s *UIState) HookTaskDone(siteID string, r hooks.Result)

HookTaskDone records the result and clears the running marker.

func (*UIState) HookTaskOutput

func (s *UIState) HookTaskOutput(siteID string, line string, stderr bool)

HookTaskOutput appends a line to the site's output ring.

func (*UIState) HookTaskStarted

func (s *UIState) HookTaskStarted(siteID string, h hooks.Hook)

HookTaskStarted clears any prior summary and records that h is running.

func (*UIState) Invalidate

func (s *UIState) Invalidate()

Invalidate triggers a redraw from any goroutine safely.

func (*UIState) IsCloneLoading

func (s *UIState) IsCloneLoading() bool

func (*UIState) IsExportLoading

func (s *UIState) IsExportLoading() bool

IsExportLoading returns whether an export is in progress.

func (*UIState) IsShowNewSiteModal

func (s *UIState) IsShowNewSiteModal() bool

IsShowNewSiteModal returns whether the new site modal is visible.

func (*UIState) IsSiteToggling

func (s *UIState) IsSiteToggling(id string) bool

IsSiteToggling returns whether a site is currently starting or stopping.

func (*UIState) LifecyclePlanDone

func (s *UIState) LifecyclePlanDone(siteID string, res orch.Result)

LifecyclePlanDone records the final Result.

func (*UIState) LifecyclePullProgress

func (s *UIState) LifecyclePullProgress(siteID string, p docker.PullProgress)

LifecyclePullProgress records the latest pull progress for an image. Per-image: aggregated across layers by the engine before it reaches us.

func (*UIState) LifecycleSnapshot

func (s *UIState) LifecycleSnapshot(siteID string) LifecycleSnapshot

LifecycleSnapshot returns a frame-stable copy of the lifecycle state.

func (*UIState) LifecycleStepDone

func (s *UIState) LifecycleStepDone(siteID string, step orch.StepResult)

LifecycleStepDone updates the recorded step (matched by name) with the final outcome.

func (*UIState) LifecycleStepStarted

func (s *UIState) LifecycleStepStarted(siteID string, step orch.StepResult)

LifecycleStepStarted records an in-flight step. Earlier completed steps are preserved so the GUI shows the full trail.

func (*UIState) NavCollapsed

func (s *UIState) NavCollapsed() bool

NavCollapsed reports whether the nav rail is in icon-only collapsed mode.

func (*UIState) NavView

func (s *UIState) NavView() NavView

NavView returns the active root view ("sites" or "settings").

func (*UIState) NoticeSnapshot

func (s *UIState) NoticeSnapshot() NoticeSnapshot

NoticeSnapshot returns the current banner state as a frame-stable copy.

func (*UIState) ResetLifecycleProgress

func (s *UIState) ResetLifecycleProgress(siteID string)

ResetLifecycleProgress clears the cached Plan progress for a site, in preparation for a fresh lifecycle method run.

func (*UIState) SelectedSite

func (s *UIState) SelectedSite() *types.Site

SelectedSite returns the currently selected site, or nil.

func (*UIState) ServicesHealthSnapshot

func (s *UIState) ServicesHealthSnapshot() ServicesHealth

ServicesHealthSnapshot returns the current global-services health.

func (*UIState) SetActivityFull

func (s *UIState) SetActivityFull(siteID string, evs []storage.ActivityEvent)

SetActivityFull replaces the full-rows cache for siteID and marks the full cache as loaded. Mirrors SetActivityRecent's copy semantics.

If evs is longer than ActivityFullMax, only the newest N are kept.

func (*UIState) SetActivityRecent

func (s *UIState) SetActivityRecent(siteID string, evs []storage.ActivityEvent)

SetActivityRecent replaces the recent-rows cache for siteID. Caller is responsible for fetching newest-first; this method does not re-sort.

The slice is copied (not retained) so the caller can recycle the input. If evs is longer than ActivityRecentMax, only the first N entries are kept — the recent panel never renders more than that.

func (*UIState) SetCloneLoading

func (s *UIState) SetCloneLoading(loading bool)

func (*UIState) SetDeletePurgeVolume

func (s *UIState) SetDeletePurgeVolume(purge bool)

SetDeletePurgeVolume toggles the "also delete database volume" choice in the delete-confirm modal.

func (*UIState) SetDiskFreeBytes

func (s *UIState) SetDiskFreeBytes(n int64)

SetDiskFreeBytes stores the most recent host-filesystem free-byte reading for the top status bar. The runner publishes this via the disk-low check; main.go pulls it out and pushes here on the same cadence the services- health bar polls so the UI updates feel synchronous to the user.

func (*UIState) SetExportLoading

func (s *UIState) SetExportLoading(loading bool)

SetExportLoading sets the export loading state.

func (*UIState) SetHealthSnapshot

func (s *UIState) SetHealthSnapshot(snap health.Snapshot)

SetHealthSnapshot publishes a new snapshot from the runner. Lock-free (atomic.Pointer). Triggers a window invalidation so the Layout pass picks up the new content on the next frame.

Toast bookkeeping is delegated to the caller, which knows when first-fire suppression should apply (see UIState.HealthShouldToast).

func (*UIState) SetInitDone

func (s *UIState) SetInitDone()

SetInitDone marks initialization as complete.

func (*UIState) SetInitError

func (s *UIState) SetInitError(msg string)

SetInitError records an initialization failure.

func (*UIState) SetLinkCheckLoading

func (s *UIState) SetLinkCheckLoading(loading bool)

func (*UIState) SetLinkCheckOutput

func (s *UIState) SetLinkCheckOutput(output string)

func (*UIState) SetLogLoading

func (s *UIState) SetLogLoading(loading bool)

SetLogLoading sets the log viewer loading state.

func (*UIState) SetLogOutput

func (s *UIState) SetLogOutput(service, output string)

SetLogOutput updates the log viewer content.

func (*UIState) SetNavCollapsed

func (s *UIState) SetNavCollapsed(c bool)

SetNavCollapsed toggles the rail's collapsed state.

func (*UIState) SetNavView

func (s *UIState) SetNavView(v NavView)

SetNavView switches the active root view. Triggers a redraw so the chrome can swap columns 2 and 3 immediately.

func (*UIState) SetNotice

func (s *UIState) SetNotice(msg string)

SetNotice sets a persistent informational banner with no action button (or clears it with ""). Used for non-fatal status like "HTTPS will be untrusted". Always clears any prior action callback.

func (*UIState) SetNoticeBusy

func (s *UIState) SetNoticeBusy(busy bool)

SetNoticeBusy gates the banner action button while a triggered task is in flight, swapping the label for an in-progress hint.

func (*UIState) SetNoticeWithAction

func (s *UIState) SetNoticeWithAction(msg, label string, action func())

SetNoticeWithAction sets a persistent banner with an action button. The callback fires when the user clicks the button; it should kick off any long-running work in its own goroutine and call SetNoticeBusy to gate double-clicks.

func (*UIState) SetRetryInit

func (s *UIState) SetRetryInit(fn func())

SetRetryInit sets the retry callback.

func (*UIState) SetSearchTerm

func (s *UIState) SetSearchTerm(term string)

SetSearchTerm updates the sidebar search filter.

func (*UIState) SetSelectedID

func (s *UIState) SetSelectedID(id string)

SetSelectedID sets the selected site ID.

func (*UIState) SetServicesHealth

func (s *UIState) SetServicesHealth(h ServicesHealth)

SetServicesHealth replaces the rolled-up global-services health snapshot shown in the top status bar.

func (*UIState) SetShowNewSiteModal

func (s *UIState) SetShowNewSiteModal(show bool)

SetShowNewSiteModal controls visibility of the new site modal.

func (*UIState) SetSiteToggling

func (s *UIState) SetSiteToggling(id string, toggling bool)

SetSiteToggling sets the loading state for a site's start/stop operation.

func (*UIState) SetSites

func (s *UIState) SetSites(sites []types.Site)

SetSites replaces the site list.

func (*UIState) SetWPCLILoading

func (s *UIState) SetWPCLILoading(loading bool)

SetWPCLILoading sets the WP-CLI loading state.

func (*UIState) SetWPCLIOutput

func (s *UIState) SetWPCLIOutput(output string)

SetWPCLIOutput updates the WP-CLI output content.

func (*UIState) SetWindow

func (s *UIState) SetWindow(w *app.Window)

SetWindow stores the app window reference for invalidation.

func (*UIState) ShowCloneModal

func (s *UIState) ShowCloneModal(id, name string)

func (*UIState) ShowDeleteConfirm

func (s *UIState) ShowDeleteConfirm(id, name string)

ShowDeleteConfirm opens the delete confirmation modal for a site.

func (*UIState) ShowError

func (s *UIState) ShowError(msg string)

ShowError sets the error banner message with an 8-second auto-dismiss.

func (*UIState) TriggerNoticeAction

func (s *UIState) TriggerNoticeAction() bool

TriggerNoticeAction atomically claims the busy slot and invokes the banner's action callback. Returns true if an action was started, false when no callback is registered or one is already in flight. The action is responsible for clearing the busy state when it completes.

func (*UIState) UpdateSite

func (s *UIState) UpdateSite(site types.Site)

UpdateSite replaces a single site in the list by ID.

type VersionEditor

type VersionEditor struct {
	// contains filtered or unexported fields
}

VersionEditor shows read-only version info when a site is running, and editable dropdowns when it is stopped. The DB row understands both the engine kind and the version so users can switch between MySQL and MariaDB; engine swaps and unsafe version transitions route through the migrate-via-snapshot flow rather than landing in-place.

func NewVersionEditor

func NewVersionEditor(state *UIState, sm *sites.SiteManager, toasts *Notifications) *VersionEditor

func (*VersionEditor) HandleUserInteractions

func (ve *VersionEditor) HandleUserInteractions(gtx layout.Context, site *types.Site)

HandleUserInteractions processes the Save button click on the version editor. Only meaningful when the site is stopped; no-op otherwise.

func (*VersionEditor) Layout

func (ve *VersionEditor) Layout(gtx layout.Context, th *Theme, site *types.Site) layout.Dimensions

type WPCLIPanel

type WPCLIPanel struct {
	// contains filtered or unexported fields
}

WPCLIPanel renders the WP-CLI command input and output panel.

func NewWPCLIPanel

func NewWPCLIPanel(state *UIState, sm *sites.SiteManager) *WPCLIPanel

func (*WPCLIPanel) HandleUserInteractions

func (wp *WPCLIPanel) HandleUserInteractions(gtx layout.Context, siteID string)

HandleUserInteractions processes the Run button click.

func (*WPCLIPanel) Layout

func (wp *WPCLIPanel) Layout(gtx layout.Context, th *Theme, siteID string) layout.Dimensions

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL