fetch_ml/cmd/tui/internal/model/state.go
Jeremie Fraeys 6028779239
feat: update CLI, TUI, and security documentation
- Add safety checks to Zig build
- Add TUI with job management and narrative views
- Add WebSocket support and export services
- Add smart configuration defaults
- Update API routes with security headers
- Update SECURITY.md with comprehensive policy
- Add Makefile security scanning targets
2026-02-19 15:35:05 -05:00

173 lines
5.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
ViewModeNarrative // Narrative/Outcome view mode
ViewModeTeam // Team collaboration view mode
ViewModeExperimentHistory // Experiment history view mode
ViewModeConfig // Config view mode
ViewModeLogs // Logs streaming 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
NarrativeView viewport.Model
TeamView viewport.Model
ExperimentHistoryView viewport.Model
ConfigView viewport.Model
LogsView viewport.Model
SelectedJob Job
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
LastFrameTime time.Time
RefreshRate float64 // measured in ms
FrameCount int
LastGPUUpdate 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),
NarrativeView: viewport.New(0, 0),
TeamView: viewport.New(0, 0),
ExperimentHistoryView: viewport.New(0, 0),
ConfigView: viewport.New(0, 0),
LogsView: 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(),
}
}
// LogMsg represents a log line from a job
type LogMsg struct {
JobName string `json:"job_name"`
Line string `json:"line"`
Time string `json:"time"`
}
// JobUpdateMsg represents a real-time job status update via WebSocket
type JobUpdateMsg struct {
JobName string `json:"job_name"`
Status string `json:"status"`
TaskID string `json:"task_id"`
Progress int `json:"progress"`
}
// GPUUpdateMsg represents a real-time GPU status update via WebSocket
type GPUUpdateMsg struct {
DeviceID int `json:"device_id"`
Utilization int `json:"utilization"`
MemoryUsed int64 `json:"memory_used"`
MemoryTotal int64 `json:"memory_total"`
Temperature int `json:"temperature"`
}