refact: improve input prompt and button layout in dashboard

rabbitprincess committed May 8, 2026 at 22:56 UTC 93fa0d3135c7b79d337759e37d5ee6cb14edafc1
1 file changed +13 -46
cmd/portal-tunnel/agent/dashboard.go
+13 -46
@@ -19,8 +19,9 @@ import (
19 )
20
21 const (
22 - agentDashboardPollInterval = 2 * time.Second
23 - agentDashboardMinRelayRows = 1
22 + agentDashboardPollInterval = 2 * time.Second
23 + agentDashboardMinRelayRows = 1
24 + agentDashboardTunnelInputMaxWidth = 80
25 )
26
27 type agentDashboardAction int
@@ -102,11 +103,12 @@ var (
103 func RunDashboard(configPath, stateDir string) error {
104 input := textinput.New()
105 input.CharLimit = 512
105 - input.Prompt = ""
106 - input.Placeholder = "name port"
106 + input.Prompt = "New tunnel: "
107 + input.Placeholder = "name target (Examples: myname 3000)"
108 + input.PromptStyle = agentDashboardSectionStyle
109 input.TextStyle = agentDashboardInputStyle
110 input.PlaceholderStyle = agentDashboardMutedStyle
109 - input.Width = 32
111 + input.Width = agentDashboardTunnelInputMaxWidth
112 _ = input.Focus()
113
114 _, err := tea.NewProgram(agentDashboardModel{
@@ -126,8 +128,9 @@ func (m agentDashboardModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
128 case tea.WindowSizeMsg:
129 m.width = msg.Width
130 m.height = msg.Height
129 - buttonsWidth := lipgloss.Width("[ Add Tunnel ]") + lipgloss.Width("[ Delete ]") + 2
130 - m.input.Width = max(1, min(32, msg.Width-buttonsWidth))
131 + availableWidth := msg.Width - lipgloss.Width(m.input.Prompt)
132 + clearWidth := lipgloss.Width(m.input.Prompt) + lipgloss.Width(m.input.Placeholder)
133 + m.input.Width = max(clearWidth, min(agentDashboardTunnelInputMaxWidth, availableWidth))
134 return m, nil
135 case agentDashboardTickMsg:
136 return m, tea.Batch(agentDashboardFetchStatus(m.stateDir), agentDashboardTick())
@@ -399,7 +402,7 @@ func (m agentDashboardModel) addTunnelFromInput() (tea.Model, tea.Cmd) {
402 }
403 fields := strings.Fields(value)
404 if len(fields) < 2 {
402 - m.err = fmt.Errorf("use: name port")
405 + m.err = fmt.Errorf("use: name target")
406 return m, nil
407 }
408 name := strings.Join(fields[:len(fields)-1], " ")
@@ -613,10 +616,11 @@ func (m agentDashboardModel) layout() agentDashboardView {
616 func (m agentDashboardModel) renderTunnelsSection(width int) agentDashboardView {
617 var pane agentDashboardView
618 pane.addStyled(width, agentDashboardSectionStyle, "Tunnels")
616 - pane.addInputButton(width, m.input.View(),
619 + pane.addButtons(width,
620 agentDashboardButton{label: "Add Tunnel", action: agentDashboardActionAddTunnel, disabled: strings.TrimSpace(m.input.Value()) == ""},
621 agentDashboardButton{label: "Delete", action: agentDashboardActionDeleteTunnel, disabled: len(m.status.Tunnels) == 0},
622 )
623 + pane.addLine(m.input.View())
624 tunnelRowWidth := agentDashboardTunnelTableWidth(width, m.status.Tunnels)
625 pane.addLine(agentDashboardMutedStyle.Render(agentDashboardTunnelRow(tunnelRowWidth, "STATUS", "TARGET", "TUNNEL")))
626
@@ -762,43 +766,6 @@ func (v *agentDashboardView) addButtons(width int, buttons ...agentDashboardButt
766 v.regions = append(v.regions, regions...)
767 }
768
765 -func (v *agentDashboardView) addInputButton(width int, input string, buttons ...agentDashboardButton) {
766 - if width <= 0 {
767 - width = 1
768 - }
769 - line := agentDashboardFit(input, width)
770 - lineWidth := lipgloss.Width(line)
771 - y := len(v.lines)
772 - for _, button := range buttons {
773 - if lineWidth >= width {
774 - break
775 - }
776 - if lineWidth > 0 {
777 - line += " "
778 - lineWidth++
779 - }
780 - buttonText := agentDashboardFit("[ "+button.label+" ]", width-lineWidth)
781 - buttonWidth := lipgloss.Width(buttonText)
782 - if buttonWidth == 0 {
783 - break
784 - }
785 - buttonStyle := agentDashboardButtonStyle
786 - if button.disabled {
787 - buttonStyle = agentDashboardDisabledStyle
788 - } else {
789 - v.regions = append(v.regions, agentDashboardRegion{
790 - x0: lineWidth,
791 - x1: lineWidth + buttonWidth,
792 - y: y,
793 - action: button.action,
794 - })
795 - }
796 - line += buttonStyle.Render(buttonText)
797 - lineWidth += buttonWidth
798 - }
799 - v.lines = append(v.lines, line)
800 -}
801 -
769 func (v *agentDashboardView) addView(child agentDashboardView) {
770 startY := len(v.lines)
771 v.lines = append(v.lines, child.lines...)