()
| 397 | } |
| 398 | |
| 399 | func (m portsForwardModel) renderCompleteStep() string { |
| 400 | if m.err != nil { |
| 401 | return errorStyleTUI.Render(fmt.Sprintf("\n✗ Failed to update ports: %v\n\n", m.err)) |
| 402 | } |
| 403 | |
| 404 | headerStyle := theme.Primary().Bold(true) |
| 405 | labelStyle := theme.Neutral() |
| 406 | valueStyle := lipgloss.NewStyle().Bold(true) |
| 407 | boxStyle := lipgloss.NewStyle(). |
| 408 | Border(lipgloss.RoundedBorder()). |
| 409 | BorderForeground(lipgloss.Color(theme.PrimaryColor)). |
| 410 | Padding(1, 2) |
| 411 | |
| 412 | var lines []string |
| 413 | successTitleStyle := theme.Success() |
| 414 | lines = append(lines, successTitleStyle.Render("✓ Ports updated successfully!")) |
| 415 | lines = append(lines, "") |
| 416 | lines = append(lines, labelStyle.Render("Instance ID:")+" "+valueStyle.Render(m.selectedInstance.ID)) |
| 417 | lines = append(lines, labelStyle.Render("Instance UUID:")+" "+valueStyle.Render(m.selectedInstance.UUID)) |
| 418 | |
| 419 | // Resolve the latest port list. m.resp is nil when only removes happened, |
| 420 | // in which case we derive the result from the local diff instead. |
| 421 | var finalPorts []int |
| 422 | if m.resp != nil { |
| 423 | finalPorts = m.resp.HTTPPorts |
| 424 | } else { |
| 425 | removedSet := make(map[int]bool, len(m.removePorts)) |
| 426 | for _, p := range m.removePorts { |
| 427 | removedSet[p] = true |
| 428 | } |
| 429 | for _, p := range m.currentPorts { |
| 430 | if !removedSet[p] { |
| 431 | finalPorts = append(finalPorts, p) |
| 432 | } |
| 433 | } |
| 434 | } |
| 435 | |
| 436 | if len(finalPorts) > 0 { |
| 437 | lines = append(lines, labelStyle.Render("Forwarded Ports:")+" "+valueStyle.Render(utils.FormatPorts(finalPorts))) |
| 438 | } else { |
| 439 | lines = append(lines, labelStyle.Render("Forwarded Ports:")+" "+valueStyle.Render("(none)")) |
| 440 | } |
| 441 | |
| 442 | lines = append(lines, "") |
| 443 | lines = append(lines, headerStyle.Render("Access your services:")) |
| 444 | if len(finalPorts) > 0 { |
| 445 | lines = append(lines, labelStyle.Render(fmt.Sprintf(" • https://%s-<port>.thundercompute.net", m.selectedInstance.UUID))) |
| 446 | } |
| 447 | lines = append(lines, labelStyle.Render(" • Run 'tnr ports list' to see all forwarded ports")) |
| 448 | |
| 449 | content := lipgloss.JoinVertical(lipgloss.Left, lines...) |
| 450 | return "\n" + boxStyle.Render(content) + "\n\n" |
| 451 | } |
| 452 | |
| 453 | // RunPortsForwardInteractive starts the interactive port forwarding flow |
| 454 | func RunPortsForwardInteractive(client *api.Client, instances []api.Instance) error { |
no test coverage detected