configui

package
v0.6.3 Latest Latest
Warning

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

Go to latest
Published: Feb 19, 2026 License: MIT Imports: 6 Imported by: 0

Documentation

Overview

Package configui provides schema-driven configuration UI types and metadata.

Package configui provides schema-driven configuration UI types and metadata.

Package configui provides schema-driven configuration UI types and metadata.

Package configui provides schema-driven configuration UI types and metadata.

Index

Constants

This section is empty.

Variables

View Source
var FieldsByPath = map[string]*FieldMeta{
	"groves":                 &SchemaFields[0],
	"notebooks":              &SchemaFields[1],
	"explicit_projects":      &SchemaFields[2],
	"name":                   &SchemaFields[3],
	"workspaces":             &SchemaFields[4],
	"build_cmd":              &SchemaFields[5],
	"build_after":            &SchemaFields[6],
	"tui":                    &SchemaFields[7],
	"logging":                &SchemaFields[8],
	"gemini.api_key_command": &SchemaFields[9],
	"context":                &SchemaFields[10],
	"version":                &SchemaFields[11],
	"gemini.api_key":         &SchemaFields[12],
	"search_paths":           &SchemaFields[13],
}

FieldsByPath provides O(1) lookup by full path.

View Source
var ImportantFields = []*FieldMeta{
	&SchemaFields[0],
	&SchemaFields[1],
	&SchemaFields[9],
	&SchemaFields[12],
}

ImportantFields contains only fields marked as important/key configuration options.

View Source
var SchemaFields = []FieldMeta{
	{
		Path:        []string{"groves"},
		Type:        FieldMap,
		Description: "Root directories to search for projects and ecosystems",
		Layer:       config.SourceGlobal,
		Priority:    1,
		Important:   true,
	},
	{
		Path:        []string{"notebooks"},
		Type:        FieldObject,
		Description: "Notebook configuration",
		Layer:       config.SourceGlobal,
		Priority:    2,
		Important:   true,
		RefType:     "NotebooksConfig",
		Children: []FieldMeta{
			{
				Path:        []string{"notebooks", "definitions"},
				Type:        FieldMap,
				Description: "Map of notebook name to notebook configuration",
			},
			{
				Path:        []string{"notebooks", "rules"},
				Type:        FieldObject,
				Description: "Rules for notebook usage (default notebook",
				RefType:     "NotebookRules",
				Children: []FieldMeta{
					{
						Path:        []string{"notebooks", "rules", "default"},
						Type:        FieldString,
						Description: "Name of the default notebook to use",
						Important:   true,
					},
					{
						Path:        []string{"notebooks", "rules", "global"},
						Type:        FieldObject,
						Description: "Configuration for the system-wide global notebook",
						Important:   true,
						RefType:     "GlobalNotebookConfig",
						Children: []FieldMeta{
							{
								Path:        []string{"notebooks", "rules", "global", "root_dir"},
								Type:        FieldString,
								Description: "Absolute path to the global notebook root directory",
								Important:   true,
								Required:    true,
							},
						},
					},
				},
			},
		},
	},
	{
		Path:        []string{"explicit_projects"},
		Type:        FieldArray,
		Description: "Specific projects to include without discovery",
		Layer:       config.SourceGlobal,
		Priority:    5,
	},
	{
		Path:        []string{"name"},
		Type:        FieldString,
		Description: "Name of the project or ecosystem",
		Layer:       config.SourceEcosystem,
		Priority:    10,
	},
	{
		Path:        []string{"workspaces"},
		Type:        FieldArray,
		Description: "Glob patterns for workspace directories in this ecosystem",
		Layer:       config.SourceEcosystem,
		Priority:    11,
	},
	{
		Path:        []string{"build_cmd"},
		Type:        FieldString,
		Description: "Custom build command (default: make build)",
		Layer:       config.SourceProject,
		Priority:    20,
	},
	{
		Path:        []string{"build_after"},
		Type:        FieldArray,
		Description: "Projects that must be built before this one",
		Layer:       config.SourceProject,
		Priority:    21,
	},
	{
		Path:        []string{"tui"},
		Type:        FieldObject,
		Description: "TUI appearance and behavior settings",
		Layer:       config.SourceGlobal,
		Priority:    50,
		RefType:     "TUIConfig",
		Children: []FieldMeta{
			{
				Path:        []string{"tui", "theme"},
				Type:        FieldSelect,
				Description: "Color theme for terminal interfaces",
				Options:     []string{"kanagawa", "gruvbox", "terminal"},
				Layer:       config.SourceGlobal,
				Priority:    51,
				Important:   true,
			},
			{
				Path:        []string{"tui", "icons"},
				Type:        FieldSelect,
				Description: "Icon set to use: nerd or ascii",
				Options:     []string{"nerd", "ascii"},
				Layer:       config.SourceGlobal,
				Priority:    52,
				Important:   true,
			},
			{
				Path:          []string{"tui", "nvim_embed"},
				Type:          FieldObject,
				Description:   "Embedded Neovim configuration",
				Layer:         config.SourceGlobal,
				Priority:      53,
				RefType:       "NvimEmbedConfig",
				Status:        StatusAlpha,
				StatusMessage: "Experimental Neovim embedding",
				StatusSince:   "v0.6.0",
				StatusTarget:  "v1.0",
				Children: []FieldMeta{
					{
						Path:        []string{"tui", "nvim_embed", "user_config"},
						Type:        FieldBool,
						Description: "If true",
						Required:    true,
					},
				},
			},
		},
	},
	{
		Path:        []string{"logging"},
		Type:        FieldObject,
		Description: "Logging configuration",
		Layer:       config.SourceGlobal,
		Priority:    60,
		RefType:     "LoggingSchemaConfig",
		Children: []FieldMeta{
			{
				Path:        []string{"logging", "groups"},
				Type:        FieldMap,
				Description: "Named collections of component loggers for filtering",
			},
			{
				Path:        []string{"logging", "level"},
				Type:        FieldString,
				Description: "Minimum log level (debug",
				Required:    true,
			},
			{
				Path:        []string{"logging", "log_startup"},
				Type:        FieldBool,
				Description: "Log 'Grove binary started' on first init",
				Required:    true,
			},
			{
				Path:        []string{"logging", "report_caller"},
				Type:        FieldBool,
				Description: "Include file/line/function in output",
				Required:    true,
			},
			{
				Path:        []string{"logging", "show_current_project"},
				Type:        FieldBool,
				Description: "Always show logs from current project regardless of filters",
			},
		},
	},
	{
		Path:        []string{"api_key_command"},
		Type:        FieldString,
		Description: "Shell command to retrieve API key (e.g. gcloud secrets or 1password)",
		Layer:       config.SourceGlobal,
		Priority:    60,
		Important:   true,
		Namespace:   "gemini",
	},
	{
		Path:        []string{"context"},
		Type:        FieldObject,
		Description: "Configuration for the cx (context) tool",
		Layer:       config.SourceGlobal,
		Priority:    80,
		RefType:     "ContextConfig",
		Children: []FieldMeta{
			{
				Path:        []string{"context", "repos_dir"},
				Type:        FieldString,
				Description: "Directory where cx repo stores bare repositories (default: ~/.grove/cx)",
				Layer:       config.SourceGlobal,
				Priority:    80,
			},
			{
				Path:        []string{"context", "default_rules_path"},
				Type:        FieldString,
				Description: "Default rules file path for context filtering",
				Layer:       config.SourceProject,
				Priority:    81,
			},
		},
	},
	{
		Path:        []string{"version"},
		Type:        FieldString,
		Description: "Configuration version (e.g. 1.0)",
		Layer:       config.SourceGlobal,
		Priority:    100,
	},
	{
		Path:        []string{"api_key"},
		Type:        FieldString,
		Description: "Direct API key for Google Gemini",
		Layer:       config.SourceGlobal,
		Priority:    200,
		Sensitive:   true,
		Important:   true,
		Hint:        "Consider using api_key_command to fetch from a secrets manager",
		Namespace:   "gemini",
	},
	{
		Path:             []string{"search_paths"},
		Type:             FieldMap,
		Description:      "DEPRECATED: Use groves instead",
		Layer:            config.SourceGlobal,
		Priority:         1000,
		Status:           StatusDeprecated,
		StatusMessage:    "Use 'groves' for project discovery",
		StatusSince:      "v0.5.0",
		StatusTarget:     "v1.0.0",
		StatusReplacedBy: "groves",
	},
}

SchemaFields contains all config fields sorted by priority.

Functions

func CollapseAll

func CollapseAll(nodes []*ConfigNode)

CollapseAll collapses all expandable nodes in the tree including root level.

func ExpandAll

func ExpandAll(nodes []*ConfigNode)

ExpandAll expands all nodes in the tree.

func FindParentIndex

func FindParentIndex(flatNodes []*ConfigNode, node *ConfigNode) int

FindParentIndex returns the index of the parent node in a flattened list.

func FormatValue

func FormatValue(v interface{}) string

FormatValue returns a human-readable string representation of a config value. It handles primitives, maps (showing key count), slices (showing item count), and structs.

func FormatValuePreview

func FormatValuePreview(v interface{}, maxWidth int) string

FormatValuePreview returns a value string with a preview of content, limited to maxWidth. For maps and structs, it shows key-value pairs up to the width limit.

func FormatValueWithType

func FormatValueWithType(v interface{}, fieldType FieldType) string

FormatValueWithType returns a formatted value string, taking field type into account. This allows for type-specific formatting (e.g., showing array item count for FieldArray).

func ShouldShowField

func ShouldShowField(field FieldMeta, value interface{}, viewMode ViewMode, maturityFilter MaturityFilter) bool

ShouldShowField determines if a field should be visible based on current filters.

func SortNodes

func SortNodes(nodes []*ConfigNode, mode SortMode)

SortNodes sorts a slice of config nodes in place based on the sort mode. Note: This only sorts the given slice, not recursively. Use SortTree for recursive sorting.

func SortTree

func SortTree(nodes []*ConfigNode, mode SortMode)

SortTree recursively sorts the tree at each level, preserving parent-child relationships. This should be called on tree roots BEFORE flattening.

func ToggleNode

func ToggleNode(node *ConfigNode)

ToggleNode toggles the collapsed state of a node.

Types

type ConfigNode

type ConfigNode struct {
	Field        FieldMeta
	Value        interface{}         // Final merged value
	LayerValues  LayeredValue        // Values at each layer
	ActiveSource config.ConfigSource // Which layer provided the value
	Depth        int
	Collapsed    bool
	Children     []*ConfigNode
	Parent       *ConfigNode

	// Key is used for map entries (the map key) or array indices.
	// For regular schema fields, this is empty.
	Key string

	// IsDynamic indicates if this node was dynamically created from map keys
	// rather than defined in the schema.
	IsDynamic bool
}

ConfigNode represents a node in the configuration tree. It holds both schema information (via FieldMeta) and runtime value information.

func BuildTree

func BuildTree(schema []FieldMeta, layered *config.LayeredConfig) []*ConfigNode

BuildTree constructs a tree of ConfigNodes from the schema and layered config.

func FilterNodes

func FilterNodes(nodes []*ConfigNode, viewMode ViewMode, maturityFilter MaturityFilter) []*ConfigNode

FilterNodes returns a filtered list of nodes based on view mode and maturity filter.

func Flatten

func Flatten(nodes []*ConfigNode) []*ConfigNode

Flatten returns a list of visible nodes based on collapsed state. Only visible (expanded) nodes are included in the result.

func (*ConfigNode) DisplayKey

func (n *ConfigNode) DisplayKey() string

DisplayKey returns the appropriate key/label for display. For dynamic map entries, returns the Key; otherwise returns the field label.

func (*ConfigNode) HasValue

func (n *ConfigNode) HasValue() bool

HasValue returns true if the node has a non-nil value.

func (*ConfigNode) IsContainer

func (n *ConfigNode) IsContainer() bool

IsContainer returns true if the node can have children (Map, Object, or Array).

func (*ConfigNode) IsExpandable

func (n *ConfigNode) IsExpandable() bool

IsExpandable returns true if the node has children and can be expanded/collapsed.

type ConfigPage

type ConfigPage interface {
	// Name returns the display name for the tab (e.g., "Global", "Ecosystem", "Project").
	Name() string
	// Layer returns the config layer this page represents.
	Layer() config.ConfigSource
	// Init initializes the page model.
	Init() tea.Cmd
	// Update handles messages for the page.
	Update(tea.Msg) (ConfigPage, tea.Cmd)
	// View renders the page's UI.
	View() string
	// Focus is called when the page becomes active.
	Focus() tea.Cmd
	// Blur is called when the page loses focus.
	Blur()
	// SetSize sets the dimensions for the page.
	SetSize(width, height int)
	// Refresh reloads the page with updated config data.
	Refresh(layered *config.LayeredConfig)
}

ConfigPage defines the interface for a tabbed page in the config editor. This follows the same pattern as cx/cmd/view/Page for consistency.

type FieldMeta

type FieldMeta struct {
	// Path is the dot-separated path to the field (e.g., ["tui", "theme"]).
	Path []string

	// Type is the UI field type.
	Type FieldType

	// Description is the human-readable description from the schema.
	Description string

	// Options contains enum values for FieldSelect type fields.
	Options []string

	// Default is the default value if specified in the schema.
	Default interface{}

	// Layer is the recommended config layer for saving (from x-layer).
	Layer config.ConfigSource

	// Priority determines the sort order (lower = higher in list).
	// 1-10 for wizard fields, 50+ for common, 100+ for advanced.
	Priority int

	// Sensitive indicates if the field contains sensitive data (from x-sensitive).
	// If true, the UI should mask the value and suggest alternatives.
	Sensitive bool

	// Important indicates if the field is a key/important configuration option (from x-important).
	Important bool

	// Hint provides additional guidance shown in the edit dialog (from x-hint).
	Hint string

	// Children contains nested fields for FieldObject type.
	Children []FieldMeta

	// Namespace is the schema namespace (e.g., "gemini", "tmux", empty for core).
	Namespace string

	// Required indicates if this field is required by the schema.
	Required bool

	// RefType is the $ref type name if this field references a definition.
	RefType string

	// Unified Status Fields (alpha, beta, stable, deprecated)
	Status           FieldStatus `json:"status,omitempty"`
	StatusMessage    string      `json:"status_message,omitempty"`
	StatusSince      string      `json:"status_since,omitempty"`
	StatusTarget     string      `json:"status_target,omitempty"`
	StatusReplaces   string      `json:"status_replaces,omitempty"`
	StatusReplacedBy string      `json:"status_replaced_by,omitempty"`
}

FieldMeta contains metadata for a configuration field derived from JSON Schema.

func FilterSchema

func FilterSchema(schema []FieldMeta, layer config.ConfigSource) []FieldMeta

FilterSchema returns a subset of fields belonging to the specified layer. This is used by tabbed config pages to show only fields relevant to each layer.

func (FieldMeta) FullPath

func (f FieldMeta) FullPath() string

FullPath returns the dot-separated full path including namespace.

func (FieldMeta) HasChildren

func (f FieldMeta) HasChildren() bool

HasChildren returns true if this is a nested object with children.

func (FieldMeta) IsDeprecated

func (f FieldMeta) IsDeprecated() bool

IsDeprecated returns true if this field is deprecated.

func (FieldMeta) IsImportant

func (f FieldMeta) IsImportant() bool

IsImportant returns true if this field is a key/important configuration option.

func (FieldMeta) IsNonStable

func (f FieldMeta) IsNonStable() bool

IsNonStable returns true for alpha, beta, or deprecated fields.

func (FieldMeta) IsSensitive

func (f FieldMeta) IsSensitive() bool

IsSensitive returns true if this field contains sensitive data.

func (FieldMeta) IsStable

func (f FieldMeta) IsStable() bool

IsStable returns true if the field is production-ready.

func (FieldMeta) Label

func (f FieldMeta) Label() string

Label returns a human-readable label for the field. Uses the last path component, converted to title case.

func (FieldMeta) StatusBadge

func (f FieldMeta) StatusBadge() string

StatusBadge returns the display badge for the status.

func (FieldMeta) StatusNotice

func (f FieldMeta) StatusNotice() string

StatusNotice returns a formatted status message for the UI.

type FieldStatus

type FieldStatus string

FieldStatus represents the lifecycle stage of a config field.

const (
	StatusAlpha      FieldStatus = "alpha"
	StatusBeta       FieldStatus = "beta"
	StatusStable     FieldStatus = "stable" // default
	StatusDeprecated FieldStatus = "deprecated"
)

type FieldType

type FieldType int

FieldType represents the type of a configuration field for UI rendering.

const (
	FieldString FieldType = iota // Plain text input
	FieldBool                    // Boolean toggle
	FieldInt                     // Integer input
	FieldSelect                  // String with enum (dropdown/select)
	FieldArray                   // Array of strings
	FieldObject                  // Nested object (collapsible in UI)
	FieldMap                     // Object with additionalProperties (key-value editor)
)

func (FieldType) String

func (ft FieldType) String() string

String returns a string representation of the FieldType.

type LayeredValue

type LayeredValue struct {
	Default        interface{}
	Global         interface{}
	GlobalOverride interface{}
	EnvOverlay     interface{}
	Ecosystem      interface{}
	Project        interface{}
	Override       interface{} // From grove.override.toml
}

LayeredValue holds the values for a node across all config layers.

type MaturityFilter

type MaturityFilter string

MaturityFilter controls which maturity levels are displayed.

const (
	MaturityStable       MaturityFilter = "stable"        // stable only
	MaturityExperimental MaturityFilter = "+experimental" // stable + alpha/beta
	MaturityDeprecated   MaturityFilter = "+deprecated"   // stable + deprecated
	MaturityAll          MaturityFilter = "all"           // everything
)

func CycleMaturityFilter

func CycleMaturityFilter(current MaturityFilter) MaturityFilter

CycleMaturityFilter returns the next filter in the rotation.

func CycleMaturityFilterReverse

func CycleMaturityFilterReverse(current MaturityFilter) MaturityFilter

CycleMaturityFilterReverse returns the previous filter in the rotation.

type SortMode

type SortMode string

SortMode controls the order of fields in the TUI.

const (
	SortConfiguredFirst SortMode = "configured-first"
	SortPriority        SortMode = "priority"
	SortAlpha           SortMode = "alpha"
)

func CycleSortMode

func CycleSortMode(current SortMode) SortMode

CycleSortMode returns the next sort mode in the rotation.

func CycleSortModeReverse

func CycleSortModeReverse(current SortMode) SortMode

CycleSortModeReverse returns the previous sort mode in the rotation.

type ViewMode

type ViewMode string

ViewMode controls whether we show all fields or only configured ones.

const (
	ViewAll        ViewMode = "all"
	ViewConfigured ViewMode = "configured"
)

func CycleViewMode

func CycleViewMode(current ViewMode) ViewMode

CycleViewMode toggles between ViewAll and ViewConfigured.

Jump to

Keyboard shortcuts

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