fetch_ml/cmd/tui/internal/model/state.go
Jeremie Fraeys fb2bbbaae5
refactor: Phase 7 - TUI cleanup - reorganize model package
Phase 7 of the monorepo maintainability plan:

New files created:
- model/jobs.go - Job type, JobStatus constants, list.Item interface
- model/messages.go - tea.Msg types (JobsLoadedMsg, StatusMsg, TickMsg, etc.)
- model/styles.go - NewJobListDelegate(), JobListTitleStyle(), SpinnerStyle()
- model/keys.go - KeyMap struct, DefaultKeys() function

Modified files:
- model/state.go - reduced from 226 to ~130 lines
  - Removed: Job, JobStatus, KeyMap, Keys, inline styles
  - Kept: State struct, domain re-exports, ViewMode, DatasetInfo, InitialState()
- controller/commands.go - use model. prefix for message types
- controller/controller.go - use model. prefix for message types
- controller/settings.go - use model.SettingsContentMsg

Deleted files:
- controller/keys.go (moved to model/keys.go since State references KeyMap)

Result:
- No file >150 lines in model/ package
- Single concern per file: state, jobs, messages, styles, keys
- All 41 test packages pass
2026-02-17 20:22:04 -05:00

129 lines
3.7 KiB
Go

// Package model provides TUI data structures and state management
package model
import (
"time"
"github.com/charmbracelet/bubbles/list"
"github.com/charmbracelet/bubbles/spinner"
"github.com/charmbracelet/bubbles/textinput"
"github.com/charmbracelet/bubbles/viewport"
"github.com/jfraeys/fetch_ml/internal/domain"
)
// Re-export domain types for TUI use
// Task represents a task in the TUI
type Task = domain.Task
// TrackingConfig specifies experiment tracking tools
type TrackingConfig = domain.TrackingConfig
// MLflowTrackingConfig controls MLflow integration
type MLflowTrackingConfig = domain.MLflowTrackingConfig
// TensorBoardTrackingConfig controls TensorBoard integration
type TensorBoardTrackingConfig = domain.TensorBoardTrackingConfig
// WandbTrackingConfig controls Weights & Biases integration
type WandbTrackingConfig = domain.WandbTrackingConfig
// ViewMode represents the current view mode in the TUI
type ViewMode int
// ViewMode constants represent different TUI views
const (
ViewModeJobs ViewMode = iota // Jobs view mode
ViewModeGPU // GPU status view mode
ViewModeQueue // Queue status view mode
ViewModeContainer // Container status view mode
ViewModeSettings // Settings view mode
ViewModeDatasets // Datasets view mode
ViewModeExperiments // Experiments view mode
)
// DatasetInfo represents dataset information in the TUI
type DatasetInfo struct {
Name string `json:"name"`
SizeBytes int64 `json:"size_bytes"`
Location string `json:"location"`
LastAccess time.Time `json:"last_access"`
}
// State holds the application state
type State struct {
Jobs []Job
QueuedTasks []*Task
Datasets []DatasetInfo
JobList list.Model
GpuView viewport.Model
ContainerView viewport.Model
QueueView viewport.Model
SettingsView viewport.Model
DatasetView viewport.Model
ExperimentsView viewport.Model
Input textinput.Model
APIKeyInput textinput.Model
Status string
ErrorMsg string
InputMode bool
Width int
Height int
ShowHelp bool
Spinner spinner.Model
ActiveView ViewMode
LastRefresh time.Time
IsLoading bool
JobStats map[JobStatus]int
APIKey string
SettingsIndex int
Keys KeyMap
}
// InitialState creates the initial application state
func InitialState(apiKey string) State {
items := []list.Item{}
delegate := NewJobListDelegate()
jobList := list.New(items, delegate, 0, 0)
jobList.Title = "ML Jobs & Queue"
jobList.SetShowStatusBar(true)
jobList.SetFilteringEnabled(true)
jobList.SetShowHelp(false)
jobList.Styles.Title = JobListTitleStyle()
input := textinput.New()
input.Placeholder = "Args: --epochs 100 --lr 0.001 --priority 5"
input.Width = 60
input.CharLimit = 200
apiKeyInput := textinput.New()
apiKeyInput.Placeholder = "Enter API key..."
apiKeyInput.Width = 40
apiKeyInput.CharLimit = 200
s := spinner.New()
s.Spinner = spinner.Dot
s.Style = SpinnerStyle()
return State{
JobList: jobList,
GpuView: viewport.New(0, 0),
ContainerView: viewport.New(0, 0),
QueueView: viewport.New(0, 0),
SettingsView: viewport.New(0, 0),
DatasetView: viewport.New(0, 0),
ExperimentsView: viewport.New(0, 0),
Input: input,
APIKeyInput: apiKeyInput,
Status: "Connected",
InputMode: false,
ShowHelp: false,
Spinner: s,
ActiveView: ViewModeJobs,
LastRefresh: time.Now(),
IsLoading: false,
JobStats: make(map[JobStatus]int),
APIKey: apiKey,
SettingsIndex: 0,
Keys: DefaultKeys(),
}
}