Fix MySQL support and TUI auto-confirm mode

- Fix format detection to read database_type from .meta.json metadata file
- Add ensureMySQLDatabaseExists() for MySQL/MariaDB database creation
- Route database creation to correct implementation based on db type
- Add TUI auto-forward in auto-confirm mode (no input required for debugging)
- All TUI components now exit automatically when --auto-confirm is set
- Fix status view to skip loading in auto-confirm mode
This commit is contained in:
2025-12-12 12:38:20 +01:00
parent 5536b797a4
commit d710578c48
14 changed files with 187 additions and 7 deletions

View File

@@ -164,6 +164,10 @@ func (m ArchiveBrowserModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
if len(m.archives) == 0 {
m.message = "No backup archives found"
}
// Auto-forward in auto-confirm mode
if m.config.TUIAutoConfirm {
return m.parent, tea.Quit
}
return m, nil
case tea.KeyMsg:

View File

@@ -199,6 +199,10 @@ func (m BackupExecutionModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
} else {
m.status = fmt.Sprintf("❌ Backup failed: %v", m.err)
}
// Auto-forward in debug/auto-confirm mode
if m.config.TUIAutoConfirm {
return m.parent, tea.Quit
}
return m, nil
case tea.KeyMsg:

View File

@@ -61,6 +61,10 @@ func (m BackupManagerModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
// Get free space (simplified - just show message)
m.message = fmt.Sprintf("Loaded %d archive(s)", len(m.archives))
// Auto-forward in auto-confirm mode
if m.config.TUIAutoConfirm {
return m.parent, tea.Quit
}
return m, nil
case tea.KeyMsg:

View File

@@ -49,12 +49,36 @@ func NewConfirmationModelWithAction(cfg *config.Config, log logger.Logger, paren
}
func (m ConfirmationModel) Init() tea.Cmd {
// Auto-confirm in debug/auto-confirm mode
if m.config.TUIAutoConfirm {
if m.onConfirm != nil {
return func() tea.Msg {
return autoConfirmMsg{}
}
}
}
return nil
}
// autoConfirmMsg triggers automatic confirmation
type autoConfirmMsg struct{}
func (m ConfirmationModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
switch msg := msg.(type) {
case autoConfirmMsg:
// Auto-confirm triggered
m.confirmed = true
if m.onConfirm != nil {
return m.onConfirm()
}
executor := NewBackupExecution(m.config, m.logger, m.parent, m.ctx, "cluster", "", 0)
return executor, executor.Init()
case tea.KeyMsg:
// Auto-forward ESC/quit in auto-confirm mode
if m.config.TUIAutoConfirm {
return m.parent, tea.Quit
}
switch msg.String() {
case "ctrl+c", "q", "esc", "n":
return m.parent, nil

View File

@@ -85,18 +85,25 @@ func (m DatabaseSelectorModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
} else {
m.databases = msg.databases
// Auto-select database if specified
if m.config.TUIAutoDatabase != "" {
// Auto-select database if specified, or first database if auto-confirm is enabled
autoSelectDB := m.config.TUIAutoDatabase
if autoSelectDB == "" && m.config.TUIAutoConfirm && len(m.databases) > 0 {
// Auto-confirm mode: select first database automatically
autoSelectDB = m.databases[0]
m.logger.Info("Auto-confirm mode: selecting first database", "database", autoSelectDB)
}
if autoSelectDB != "" {
for i, db := range m.databases {
if db == m.config.TUIAutoDatabase {
if db == autoSelectDB {
m.cursor = i
m.selected = db
m.logger.Info("Auto-selected database", "database", db)
// If sample backup, ask for ratio (or auto-use default)
if m.backupType == "sample" {
if m.config.TUIDryRun {
// In dry-run, use default ratio
if m.config.TUIDryRun || m.config.TUIAutoConfirm {
// In dry-run or auto-confirm, use default ratio
executor := NewBackupExecution(m.config, m.logger, m.parent, m.ctx, m.backupType, m.selected, 10)
return executor, executor.Init()
}
@@ -119,6 +126,10 @@ func (m DatabaseSelectorModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
return m, nil
case tea.KeyMsg:
// Auto-forward ESC/quit in auto-confirm mode
if m.config.TUIAutoConfirm {
return m.parent, tea.Quit
}
switch msg.String() {
case "ctrl+c", "q", "esc":
return m.parent, nil

View File

@@ -113,6 +113,11 @@ func (m HistoryViewModel) Init() tea.Cmd {
func (m HistoryViewModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
maxVisible := 15 // Show max 15 items at once
// Auto-forward in auto-confirm mode
if m.config.TUIAutoConfirm {
return m.parent, tea.Quit
}
switch msg := msg.(type) {
case tea.KeyMsg:
switch msg.String() {

View File

@@ -39,11 +39,30 @@ func NewInputModel(cfg *config.Config, log logger.Logger, parent tea.Model, titl
}
func (m InputModel) Init() tea.Cmd {
// Auto-confirm: use default value and proceed
if m.config.TUIAutoConfirm && m.value != "" {
return func() tea.Msg {
return inputAutoConfirmMsg{}
}
}
return nil
}
// inputAutoConfirmMsg triggers automatic input confirmation
type inputAutoConfirmMsg struct{}
func (m InputModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
switch msg := msg.(type) {
case inputAutoConfirmMsg:
// Use default value and proceed
if selector, ok := m.parent.(DatabaseSelectorModel); ok {
ratio, _ := strconv.Atoi(m.value)
executor := NewBackupExecution(selector.config, selector.logger, selector.parent, selector.ctx,
selector.backupType, selector.selected, ratio)
return executor, executor.Init()
}
return m.parent, tea.Quit
case tea.KeyMsg:
switch msg.String() {
case "ctrl+c", "esc":

View File

@@ -30,6 +30,11 @@ func (m OperationsViewModel) Init() tea.Cmd {
}
func (m OperationsViewModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
// Auto-forward in auto-confirm mode
if m.config.TUIAutoConfirm {
return m.parent, tea.Quit
}
switch msg := msg.(type) {
case tea.KeyMsg:
switch msg.String() {

View File

@@ -254,6 +254,10 @@ func (m RestoreExecutionModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
m.status = "Failed"
m.phase = "Error"
}
// Auto-forward in auto-confirm mode when done
if m.config.TUIAutoConfirm && m.done {
return m.parent, tea.Quit
}
return m, nil
case tea.KeyMsg:

View File

@@ -212,6 +212,10 @@ func (m RestorePreviewModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
m.canProceed = msg.canProceed
m.existingDBCount = msg.existingDBCount
m.existingDBs = msg.existingDBs
// Auto-forward in auto-confirm mode
if m.config.TUIAutoConfirm {
return m.parent, tea.Quit
}
return m, nil
case tea.KeyMsg:

View File

@@ -390,12 +390,24 @@ func NewSettingsModel(cfg *config.Config, log logger.Logger, parent tea.Model) S
// Init initializes the settings model
func (m SettingsModel) Init() tea.Cmd {
// Auto-forward in auto-confirm mode
if m.config.TUIAutoConfirm {
return func() tea.Msg {
return settingsAutoQuitMsg{}
}
}
return nil
}
// settingsAutoQuitMsg triggers automatic quit in settings
type settingsAutoQuitMsg struct{}
// Update handles messages
func (m SettingsModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
switch msg := msg.(type) {
case settingsAutoQuitMsg:
return m.parent, tea.Quit
case tea.KeyMsg:
// Handle directory browsing mode
if m.browsingDir && m.dirBrowser != nil {

View File

@@ -37,12 +37,21 @@ func NewStatusView(cfg *config.Config, log logger.Logger, parent tea.Model) Stat
}
func (m StatusViewModel) Init() tea.Cmd {
// Auto-forward in auto-confirm mode - skip status check
if m.config.TUIAutoConfirm {
return func() tea.Msg {
return statusAutoQuitMsg{}
}
}
return tea.Batch(
fetchStatus(m.config, m.logger),
tickCmd(),
)
}
// statusAutoQuitMsg triggers automatic quit
type statusAutoQuitMsg struct{}
type tickMsg time.Time
func tickCmd() tea.Cmd {
@@ -109,6 +118,9 @@ func fetchStatus(cfg *config.Config, log logger.Logger) tea.Cmd {
func (m StatusViewModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
switch msg := msg.(type) {
case statusAutoQuitMsg:
return m.parent, tea.Quit
case tickMsg:
if m.loading {
return m, tickCmd()
@@ -126,6 +138,10 @@ func (m StatusViewModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
m.dbVersion = msg.dbVersion
}
m.connected = msg.connected
// Auto-forward in auto-confirm mode after status loads
if m.config.TUIAutoConfirm {
return m.parent, tea.Quit
}
return m, nil
case tea.KeyMsg: