From 879e7575ff27880d124946db63b99508f743267c Mon Sep 17 00:00:00 2001 From: Renz Date: Wed, 12 Nov 2025 14:01:46 +0000 Subject: [PATCH] fix:goroutines --- internal/tui/backup_manager.go | 18 +++++++++++++-- internal/tui/confirmation.go | 33 ++++++++++++++++++++------- internal/tui/menu.go | 8 +++++-- internal/tui/settings.go | 41 ++++++++++++++++++++++++++++++++++ 4 files changed, 88 insertions(+), 12 deletions(-) diff --git a/internal/tui/backup_manager.go b/internal/tui/backup_manager.go index 9159b3b..ef5c5f8 100644 --- a/internal/tui/backup_manager.go +++ b/internal/tui/backup_manager.go @@ -87,9 +87,23 @@ func (m BackupManagerModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { // Delete archive (with confirmation) if len(m.archives) > 0 && m.cursor < len(m.archives) { selected := m.archives[m.cursor] - confirm := NewConfirmationModel(m.config, m.logger, m, + archivePath := selected.Path + confirm := NewConfirmationModelWithAction(m.config, m.logger, m, "🗑️ Delete Archive", - fmt.Sprintf("Delete archive '%s'? This cannot be undone.", selected.Name)) + fmt.Sprintf("Delete archive '%s'? This cannot be undone.", selected.Name), + func() (tea.Model, tea.Cmd) { + // Delete the archive + err := deleteArchive(archivePath) + if err != nil { + m.err = fmt.Errorf("failed to delete archive: %v", err) + m.message = fmt.Sprintf("❌ Failed to delete: %v", err) + } else { + m.message = fmt.Sprintf("✅ Deleted: %s", selected.Name) + } + // Refresh the archive list + m.loading = true + return m, loadArchives(m.config, m.logger) + }) return confirm, nil } diff --git a/internal/tui/confirmation.go b/internal/tui/confirmation.go index 1a9bbf2..631a41f 100644 --- a/internal/tui/confirmation.go +++ b/internal/tui/confirmation.go @@ -12,14 +12,15 @@ import ( // ConfirmationModel for yes/no confirmations type ConfirmationModel struct { - config *config.Config - logger logger.Logger - parent tea.Model - title string - message string - cursor int - choices []string + config *config.Config + logger logger.Logger + parent tea.Model + title string + message string + cursor int + choices []string confirmed bool + onConfirm func() (tea.Model, tea.Cmd) // Callback when confirmed } func NewConfirmationModel(cfg *config.Config, log logger.Logger, parent tea.Model, title, message string) ConfirmationModel { @@ -33,6 +34,18 @@ func NewConfirmationModel(cfg *config.Config, log logger.Logger, parent tea.Mode } } +func NewConfirmationModelWithAction(cfg *config.Config, log logger.Logger, parent tea.Model, title, message string, onConfirm func() (tea.Model, tea.Cmd)) ConfirmationModel { + return ConfirmationModel{ + config: cfg, + logger: log, + parent: parent, + title: title, + message: message, + choices: []string{"Yes", "No"}, + onConfirm: onConfirm, + } +} + func (m ConfirmationModel) Init() tea.Cmd { return nil } @@ -57,7 +70,11 @@ func (m ConfirmationModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { case "enter", "y": if msg.String() == "y" || m.cursor == 0 { m.confirmed = true - // Execute cluster backup + // Execute the onConfirm callback if provided + if m.onConfirm != nil { + return m.onConfirm() + } + // Default: execute cluster backup for backward compatibility executor := NewBackupExecution(m.config, m.logger, m.parent, "cluster", "", 0) return executor, executor.Init() } diff --git a/internal/tui/menu.go b/internal/tui/menu.go index 5e42728..68e3cc8 100644 --- a/internal/tui/menu.go +++ b/internal/tui/menu.go @@ -324,9 +324,13 @@ func (m MenuModel) handleClusterBackup() (tea.Model, tea.Cmd) { m.message = errorStyle.Render("❌ Cluster backup is available only for PostgreSQL targets") return m, nil } - confirm := NewConfirmationModel(m.config, m.logger, m, + confirm := NewConfirmationModelWithAction(m.config, m.logger, m, "🗄️ Cluster Backup", - "This will backup ALL databases in the cluster. Continue?") + "This will backup ALL databases in the cluster. Continue?", + func() (tea.Model, tea.Cmd) { + executor := NewBackupExecution(m.config, m.logger, m, "cluster", "", 0) + return executor, executor.Init() + }) return confirm, nil } diff --git a/internal/tui/settings.go b/internal/tui/settings.go index f4f8f51..4d69da4 100644 --- a/internal/tui/settings.go +++ b/internal/tui/settings.go @@ -60,6 +60,47 @@ func NewSettingsModel(cfg *config.Config, log logger.Logger, parent tea.Model) S Type: "selector", Description: "Target database engine (press Enter to cycle: PostgreSQL → MySQL → MariaDB)", }, + { + Key: "cpu_workload", + DisplayName: "CPU Workload Type", + Value: func(c *config.Config) string { return c.CPUWorkloadType }, + Update: func(c *config.Config, v string) error { + workloads := []string{"balanced", "cpu-intensive", "io-intensive"} + currentIdx := 0 + for i, w := range workloads { + if c.CPUWorkloadType == w { + currentIdx = i + break + } + } + nextIdx := (currentIdx + 1) % len(workloads) + c.CPUWorkloadType = workloads[nextIdx] + + // Recalculate Jobs and DumpJobs based on workload type + if c.CPUInfo != nil && c.AutoDetectCores { + switch c.CPUWorkloadType { + case "cpu-intensive": + c.Jobs = c.CPUInfo.PhysicalCores * 2 + c.DumpJobs = c.CPUInfo.PhysicalCores + case "io-intensive": + c.Jobs = c.CPUInfo.PhysicalCores / 2 + if c.Jobs < 1 { + c.Jobs = 1 + } + c.DumpJobs = 2 + default: // balanced + c.Jobs = c.CPUInfo.PhysicalCores + c.DumpJobs = c.CPUInfo.PhysicalCores / 2 + if c.DumpJobs < 2 { + c.DumpJobs = 2 + } + } + } + return nil + }, + Type: "selector", + Description: "CPU workload profile (press Enter to cycle: Balanced → CPU-Intensive → I/O-Intensive)", + }, { Key: "backup_dir", DisplayName: "Backup Directory",