@@ -16,6 +16,8 @@ type ErrorMsg struct {
16
16
Error error
17
17
}
18
18
19
+ type QuitMsg struct {}
20
+
19
21
type AddTunnelMsg struct {
20
22
Config * config.Tunnel
21
23
ClientConfig * config.ClientConfig
@@ -91,33 +93,42 @@ type model struct {
91
93
}
92
94
93
95
func New (debug bool ) * tea.Program {
94
- // Regular table setup
96
+ // Initial default widths
97
+ const (
98
+ timeWidth = 12
99
+ tunnelWidth = 15
100
+ methodWidth = 8
101
+ statusWidth = 8
102
+ urlWidth = 50
103
+ )
104
+
105
+ // Regular table setup with minimum widths
95
106
columns := []table.Column {
96
- {Title : "Time" , Width : 12 },
97
- {Title : "Tunnel" , Width : 15 },
98
- {Title : "Method" , Width : 8 },
99
- {Title : "Status" , Width : 8 },
100
- {Title : "URL" , Width : 50 },
107
+ {Title : "Time" , Width : timeWidth },
108
+ {Title : "Tunnel" , Width : tunnelWidth },
109
+ {Title : "Method" , Width : methodWidth },
110
+ {Title : "Status" , Width : statusWidth },
111
+ {Title : "URL" , Width : urlWidth },
101
112
}
102
113
103
114
t := table .New (
104
115
table .WithColumns (columns ),
105
116
table .WithFocused (true ),
106
- table .WithHeight (15 ),
117
+ table .WithHeight (10 ), // Reduced default height
107
118
)
108
119
109
- // Debug table setup
120
+ // Debug table setup with minimum widths
110
121
debugColumns := []table.Column {
111
- {Title : "Time" , Width : 12 },
112
- {Title : "Level" , Width : 8 },
113
- {Title : "Message" , Width : 50 },
114
- {Title : "Error" , Width : 30 },
122
+ {Title : "Time" , Width : timeWidth },
123
+ {Title : "Level" , Width : methodWidth },
124
+ {Title : "Message" , Width : 30 },
125
+ {Title : "Error" , Width : 20 },
115
126
}
116
127
117
128
dt := table .New (
118
129
table .WithColumns (debugColumns ),
119
130
table .WithFocused (false ),
120
- table .WithHeight (10 ),
131
+ table .WithHeight (6 ), // Reduced default height
121
132
)
122
133
123
134
// Set styles for both tables
@@ -127,10 +138,6 @@ func New(debug bool) *tea.Program {
127
138
BorderForeground (lipgloss .Color ("240" )).
128
139
BorderBottom (true ).
129
140
Bold (false )
130
- s .Selected = s .Selected .
131
- Foreground (lipgloss .Color ("229" )).
132
- Background (lipgloss .Color ("57" )).
133
- Bold (false )
134
141
135
142
t .SetStyles (s )
136
143
dt .SetStyles (s )
@@ -164,29 +171,24 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
164
171
165
172
switch msg := msg .(type ) {
166
173
case tea.KeyMsg :
174
+ if m .err != nil {
175
+ // Any key press when there's an error will quit
176
+ m .quitting = true
177
+ return m , tea .Quit
178
+ }
179
+
167
180
switch msg .String () {
168
181
case "q" , "ctrl+c" :
169
182
m .quitting = true
170
183
return m , tea .Quit
171
-
172
- case "tab" :
173
- // Cycle through tunnels
174
- var ports []string
175
- for port := range m .tunnels {
176
- ports = append (ports , port )
177
- }
178
- if len (ports ) > 0 {
179
- for i , port := range ports {
180
- if port == m .selected {
181
- m .selected = ports [(i + 1 )% len (ports )]
182
- break
183
- }
184
- }
185
- }
186
184
}
187
185
188
186
case ErrorMsg :
189
187
m .err = msg .Error
188
+ // Don't quit immediately, let the user see the error
189
+ return m , nil
190
+
191
+ case QuitMsg :
190
192
m .quitting = true
191
193
return m , tea .Quit
192
194
@@ -207,8 +209,54 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
207
209
}
208
210
209
211
case tea.WindowSizeMsg :
210
- m .table .SetWidth (msg .Width - 4 )
211
- m .debugTable .SetWidth (msg .Width - 4 )
212
+ // Calculate dynamic widths based on terminal size
213
+ totalWidth := msg .Width - 4 // Account for margins
214
+
215
+ // Adjust table heights based on terminal height
216
+ tableHeight := (msg .Height - 15 ) / 2 // Account for headers and other UI elements
217
+ tableHeight = max (tableHeight , 5 )
218
+
219
+ m .table .SetHeight (tableHeight )
220
+
221
+ if m .debug {
222
+ m .debugTable .SetHeight (tableHeight / 2 )
223
+ }
224
+
225
+ // Adjust URL column width to fill remaining space
226
+ timeWidth := 12
227
+ tunnelWidth := 15
228
+ methodWidth := 8
229
+ statusWidth := 8
230
+ urlWidth := totalWidth - (timeWidth + tunnelWidth + methodWidth + statusWidth + 5 )
231
+
232
+ urlWidth = max (urlWidth , 20 )
233
+
234
+ // Update main table columns
235
+ cols := []table.Column {
236
+ {Title : "Time" , Width : timeWidth },
237
+ {Title : "Tunnel" , Width : tunnelWidth },
238
+ {Title : "Method" , Width : methodWidth },
239
+ {Title : "Status" , Width : statusWidth },
240
+ {Title : "URL" , Width : urlWidth },
241
+ }
242
+ m .table .SetColumns (cols )
243
+
244
+ // Update debug table columns if debug is enabled
245
+ if m .debug {
246
+ debugWidth := totalWidth / 2
247
+ debugWidth = max (debugWidth , 40 )
248
+
249
+ debugCols := []table.Column {
250
+ {Title : "Time" , Width : timeWidth },
251
+ {Title : "Level" , Width : methodWidth },
252
+ {Title : "Message" , Width : debugWidth / 2 },
253
+ {Title : "Error" , Width : debugWidth / 2 },
254
+ }
255
+ m .debugTable .SetColumns (debugCols )
256
+ }
257
+
258
+ m .table .SetWidth (totalWidth )
259
+ m .debugTable .SetWidth (totalWidth )
212
260
return m , nil
213
261
214
262
case tickMsg :
@@ -231,11 +279,16 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
231
279
func (m model ) View () string {
232
280
if m .quitting {
233
281
if m .err != nil {
234
- return errorStyle .Render (fmt .Sprintf ("Error: %v\n " , m .err ))
282
+ return " \n " + errorStyle .Render (fmt .Sprintf ("Error: %v" , m .err )) + " \n "
235
283
}
236
284
return "Goodbye!\n "
237
285
}
238
286
287
+ if m .err != nil {
288
+ return "\n " + errorStyle .Render (fmt .Sprintf ("Error: %v" , m .err )) + "\n \n " +
289
+ subtitleStyle .Render ("Press any key to exit..." ) + "\n "
290
+ }
291
+
239
292
var s string
240
293
241
294
s += titleStyle .Render ("🌍 Portr Tunnel Dashboard" ) + "\n "
@@ -300,12 +353,20 @@ func (m model) View() string {
300
353
}
301
354
s += "\n "
302
355
303
- // Just render the table - no need to query DB
356
+ // Add waiting message if no logs
357
+ if len (m .table .Rows ()) == 0 {
358
+ // Create empty table with just headers
359
+ m .table .SetRows ([]table.Row {{"" , "" , "" , "" , "Waiting for logs..." }})
360
+ }
304
361
s += tableStyle .Render (m .table .View ()) + "\n "
305
362
306
363
// Show debug table if debug mode is enabled
307
364
if m .debug {
308
365
s += "\n " + titleStyle .Render ("🔍 Debug Logs" ) + "\n "
366
+ if len (m .debugTable .Rows ()) == 0 {
367
+ // Create empty debug table with just headers
368
+ m .debugTable .SetRows ([]table.Row {{"" , "" , "Waiting for logs..." , "" }})
369
+ }
309
370
s += tableStyle .Render (m .debugTable .View ()) + "\n "
310
371
}
311
372
@@ -317,6 +378,11 @@ func (m model) View() string {
317
378
}
318
379
319
380
func (m * model ) AddLog (msg AddLogMsg ) {
381
+ // Clear waiting message if it exists
382
+ if len (m .table .Rows ()) == 1 && m .table .Rows ()[0 ][4 ] == "Waiting for logs..." {
383
+ m .table .SetRows ([]table.Row {})
384
+ }
385
+
320
386
rows := []table.Row {{
321
387
msg .Time ,
322
388
msg .Name ,
@@ -342,6 +408,11 @@ func (m *model) AddDebugLog(msg AddDebugLogMsg) {
342
408
return
343
409
}
344
410
411
+ // Clear waiting message if it exists
412
+ if len (m .debugTable .Rows ()) == 1 && m .debugTable .Rows ()[0 ][2 ] == "Waiting for logs..." {
413
+ m .debugTable .SetRows ([]table.Row {})
414
+ }
415
+
345
416
rows := []table.Row {{
346
417
msg .Time ,
347
418
msg .Level ,
0 commit comments