Skip to content

Commit 56f649a

Browse files
committed
feat(ui): add connectivity testing for import tab
Add server and database connection testing functionality to the import tab. Implement SSH connection testing and database connectivity verification for both MySQL and PostgreSQL, with support for Docker containers. Also add a utility function for consistent error handling and logging.
1 parent a140533 commit 56f649a

File tree

2 files changed

+124
-0
lines changed

2 files changed

+124
-0
lines changed

ui/import.go

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,11 +128,50 @@ func (u *UI) createImportTab(w fyne.Window) fyne.CanvasObject {
128128
}
129129
}
130130

131+
// Test Server Connectivity (Import)
132+
testServerBtn := widget.NewButton("Test Connectivity", func() {
133+
connType := models.ConnectionType(connTypeSelect.Selected)
134+
if restoreLocalCheck.Checked {
135+
dialog.ShowInformation("Info", "Localhost selected. No connection test needed.", w)
136+
return
137+
}
138+
139+
if connType == models.ConnectionTypeWordPress {
140+
dialog.ShowInformation("Info", "To test WP, try starting upload.", w)
141+
return
142+
}
143+
144+
// SSH Test
145+
loading := u.showLoading("Testing Connection", "Connecting to server...")
146+
go func() {
147+
p := models.Profile{
148+
Host: strings.TrimSpace(hostEntry.Text),
149+
Port: strings.TrimSpace(portEntry.Text),
150+
SSHUser: strings.TrimSpace(sshUserEntry.Text),
151+
SSHPassword: strings.TrimSpace(sshPasswordEntry.Text),
152+
AuthType: models.AuthType(authTypeSelect.Selected),
153+
AuthKeyPath: strings.TrimSpace(keyPathEntry.Text),
154+
}
155+
156+
client, err := ssh.NewClient(p)
157+
if err != nil {
158+
loading.Hide()
159+
u.showErrorAndLog("SSH Connection Failed", err, "Test SSH (Import)")
160+
return
161+
}
162+
client.Close()
163+
loading.Hide()
164+
dialog.ShowInformation("Success", "SSH Connection Established Successfully!", w)
165+
}()
166+
})
167+
131168
serverGroup := widget.NewCard("Destination Server", "", container.NewVBox(
132169
restoreLocalCheck,
133170
widget.NewForm(widget.NewFormItem("Type", connTypeSelect)),
134171
sshContainer,
135172
wpContainer,
173+
widget.NewSeparator(),
174+
testServerBtn,
136175
))
137176

138177
// --- Destination Database ---
@@ -162,6 +201,81 @@ func (u *UI) createImportTab(w fyne.Window) fyne.CanvasObject {
162201
targetDBEntry := widget.NewEntry()
163202
targetDBEntry.SetPlaceHolder("target_database")
164203

204+
// Test DB Connectivity (Import)
205+
testDBBtn := widget.NewButton("Test DB Connectivity", func() {
206+
if restoreLocalCheck.Checked {
207+
// Local DB Test?
208+
// We can try to run mysqladmin locally?
209+
// For now, support remote testing via SSH as that's the complex part.
210+
// If local, we could run exec.Command.
211+
dialog.ShowInformation("Info", "Local DB test not implemented yet.", w)
212+
return
213+
}
214+
215+
loading := u.showLoading("Testing DB", "Connecting to Database...")
216+
go func() {
217+
p := models.Profile{
218+
Host: strings.TrimSpace(hostEntry.Text),
219+
Port: strings.TrimSpace(portEntry.Text),
220+
SSHUser: strings.TrimSpace(sshUserEntry.Text),
221+
SSHPassword: strings.TrimSpace(sshPasswordEntry.Text),
222+
AuthType: models.AuthType(authTypeSelect.Selected),
223+
AuthKeyPath: strings.TrimSpace(keyPathEntry.Text),
224+
DBHost: strings.TrimSpace(dbHostEntry.Text),
225+
DBPort: strings.TrimSpace(dbPortEntry.Text),
226+
DBUser: strings.TrimSpace(dbUserEntry.Text),
227+
DBPassword: strings.TrimSpace(dbPasswordEntry.Text),
228+
DBType: models.DBType(dbTypeSelect.Selected),
229+
IsDocker: isDockerCheck.Checked,
230+
ContainerID: strings.TrimSpace(containerIDEntry.Text),
231+
}
232+
233+
client, err := ssh.NewClient(p)
234+
if err != nil {
235+
loading.Hide()
236+
u.showErrorAndLog("SSH Connection Failed", err, "Test DB (Import)")
237+
return
238+
}
239+
defer client.Close()
240+
241+
var cmd string
242+
if p.DBType == models.DBTypePostgreSQL {
243+
authEnv := fmt.Sprintf("PGPASSWORD='%s'", p.DBPassword)
244+
if p.IsDocker {
245+
cmd = fmt.Sprintf("docker exec -e %s %s pg_isready -U %s", authEnv, p.ContainerID, p.DBUser)
246+
} else {
247+
hostArgs := fmt.Sprintf("-h %s -p %s", p.DBHost, p.DBPort)
248+
cmd = fmt.Sprintf("%s pg_isready %s -U %s", authEnv, hostArgs, p.DBUser)
249+
}
250+
} else {
251+
authArgs := fmt.Sprintf("-u %s -p'%s'", p.DBUser, p.DBPassword)
252+
if p.IsDocker {
253+
cmd = fmt.Sprintf("docker exec -i %s mysqladmin %s ping", p.ContainerID, authArgs)
254+
} else {
255+
hostArgs := fmt.Sprintf("-h %s -P %s", p.DBHost, p.DBPort)
256+
cmd = fmt.Sprintf("mysqladmin %s %s ping", hostArgs, authArgs)
257+
}
258+
}
259+
260+
_, session, err := client.RunCommandStream(cmd)
261+
if err != nil {
262+
loading.Hide()
263+
u.showErrorAndLog("DB Check Cmd Failed", err, "Test DB (Import)")
264+
return
265+
}
266+
defer session.Close()
267+
268+
if err := session.Wait(); err != nil {
269+
loading.Hide()
270+
u.showErrorAndLog("DB Check Failed (Ping)", err, "Test DB (Import)")
271+
return
272+
}
273+
274+
loading.Hide()
275+
dialog.ShowInformation("Success", "Database Connection Successful!", w)
276+
}()
277+
})
278+
165279
dbGroup := widget.NewCard("Destination Database", "", container.NewVBox(
166280
isDockerCheck,
167281
widget.NewForm(
@@ -173,6 +287,8 @@ func (u *UI) createImportTab(w fyne.Window) fyne.CanvasObject {
173287
widget.NewFormItem("DB Password", dbPasswordEntry),
174288
widget.NewFormItem("Target DB Name", targetDBEntry),
175289
),
290+
widget.NewSeparator(),
291+
testDBBtn,
176292
))
177293

178294
// --- Action ---

ui/ui.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -293,3 +293,11 @@ func (u *UI) showLoading(title, message string) *dialog.CustomDialog {
293293
d.Show()
294294
return d
295295
}
296+
297+
func (u *UI) showErrorAndLog(title string, err error, action string) {
298+
if err == nil {
299+
return
300+
}
301+
u.log(action, fmt.Sprintf("%s: %v", title, err), "", "Failed", err.Error())
302+
dialog.ShowError(err, u.window)
303+
}

0 commit comments

Comments
 (0)