@@ -21,7 +21,6 @@ import (
21
21
"fmt"
22
22
"io"
23
23
"net/http"
24
- "os/exec"
25
24
"strings"
26
25
"time"
27
26
@@ -180,6 +179,7 @@ type modelSavedQueries struct {
180
179
list list.Model
181
180
commandOutput string
182
181
viewport viewport.Model
182
+ queryExecuted bool // New field to track query execution
183
183
}
184
184
185
185
func (m modelSavedQueries ) Init () tea.Cmd {
@@ -189,93 +189,93 @@ func (m modelSavedQueries) Init() tea.Cmd {
189
189
// Define a message type for command results
190
190
type commandResultMsg string
191
191
192
- // RunCommand executes a command based on the selected item
193
- func RunCommand ( item Item ) ( string , error ) {
194
- // Clean the description by removing any backslashes
195
- cleaned := strings . ReplaceAll ( item . desc , " \\ " , "" ) // Remove any backslashes
196
- cleaned = strings . TrimSpace ( cleaned ) // Trim any leading/trailing whitespace
197
- cleanedStr := strings . ReplaceAll ( cleaned , `"` , "" )
192
+ func ( m modelSavedQueries ) Update ( msg tea. Msg ) (tea. Model , tea. Cmd ) {
193
+ switch msg := msg .( type ) {
194
+ case tea. KeyMsg :
195
+ switch msg . String () {
196
+ case "ctrl+c" :
197
+ return m , tea . Quit
198
198
199
- // Prepare the command with the cleaned SQL query
200
- fmt .Printf ("Executing command: pb query run %s\n " , cleanedStr ) // Log the command for debugging
199
+ case "a" , "enter" :
200
+ // Only execute if a query hasn't already been run
201
+ if m .queryExecuted {
202
+ return m , nil // Skip execution if already executed
203
+ }
204
+ selectedQueryApply := m .list .SelectedItem ().(Item )
205
+ m .queryExecuted = true // Mark as executed
201
206
202
- if item .StartTime () != "" && item .EndTime () != "" {
203
- cleanedStr = cleanedStr + " --from=" + item .StartTime () + " --to=" + item .EndTime ()
204
- }
205
- cmd := exec .Command ("pb" , "query" , "run" , cleanedStr ) // Directly pass cleaned
207
+ cmd := func () tea.Msg {
208
+ // Load user profile configuration
209
+ userConfig , err := config .ReadConfigFromFile ()
210
+ if err != nil {
211
+ return commandResultMsg (fmt .Sprintf ("Error: %s" , err ))
212
+ }
206
213
207
- // Set up pipes to capture stdout and stderr
208
- var output bytes. Buffer
209
- cmd . Stdout = & output
210
- cmd . Stderr = & output // Capture both stdout and stderr in the same buffer
214
+ profile , profileExists := userConfig . Profiles [ userConfig . DefaultProfile ]
215
+ if ! profileExists {
216
+ return commandResultMsg ( "Error: Profile not found" )
217
+ }
211
218
212
- // Run the command
213
- err := cmd .Run ()
214
- if err != nil {
215
- return "" , fmt .Errorf ("error executing command: %v, output: %s" , err , output .String ())
216
- }
219
+ // Clean the query string
220
+ cleanedQuery := strings .TrimSpace (strings .ReplaceAll (selectedQueryApply .desc , `\` , "" ))
221
+ cleanedQuery = strings .ReplaceAll (cleanedQuery , `"` , "" )
217
222
218
- // Log the raw output for debugging
219
- fmt .Printf ("Raw output: %s\n " , output . String () )
223
+ // Log the command for debugging
224
+ fmt .Printf ("Executing command: pb query run %s\n " , cleanedQuery )
220
225
221
- // Format the output as pretty-printed JSON
222
- var jsonResponse interface {}
223
- if err := json .Unmarshal (output .Bytes (), & jsonResponse ); err != nil {
224
- return "" , fmt .Errorf ("invalid JSON output: %s, error: %v" , output .String (), err )
225
- }
226
+ // Prepare HTTP client
227
+ client := & http.Client {Timeout : 60 * time .Second }
226
228
227
- prettyOutput , err := json .MarshalIndent (jsonResponse , "" , " " )
228
- if err != nil {
229
- return "" , fmt .Errorf ("error formatting JSON output: %v" , err )
230
- }
229
+ // Determine query time range
230
+ startTime := selectedQueryApply .StartTime ()
231
+ endTime := selectedQueryApply .EndTime ()
231
232
232
- // Return the output as a string
233
- return string (prettyOutput ), nil
234
- }
233
+ // If start and end times are not set, use a default range
234
+ if startTime == "" && endTime == "" {
235
+ startTime = "10m"
236
+ endTime = "now"
237
+ }
235
238
236
- func (m modelSavedQueries ) Update (msg tea.Msg ) (tea.Model , tea.Cmd ) {
237
- switch msg := msg .(type ) {
238
- case tea.KeyMsg :
239
- switch msg .String () {
240
- case "ctrl+c" :
241
- return m , tea .Quit
242
- case "a" , "enter" :
243
- // Apply the selected query
244
- selectedQueryApply = m .list .SelectedItem ().(Item )
245
- cmd := func () tea.Msg {
246
- output , err := RunCommand (selectedQueryApply )
239
+ // Run the query
240
+ data , err := RunQuery (client , & profile , cleanedQuery , startTime , endTime )
247
241
if err != nil {
248
242
return commandResultMsg (fmt .Sprintf ("Error: %s" , err ))
249
243
}
250
- return commandResultMsg (output )
244
+ return commandResultMsg (data )
251
245
}
252
246
return m , cmd
247
+
253
248
case "b" : // 'b' to go back to the saved query list
254
249
m .commandOutput = "" // Clear the command output
255
250
m .viewport .SetContent ("" ) // Clear viewport content
256
251
m .viewport .GotoTop () // Reset viewport to the top
252
+ m .queryExecuted = false // Reset the execution flag to allow a new query
257
253
return m , nil
254
+
258
255
case "down" , "j" :
259
256
m .viewport .LineDown (1 ) // Scroll down in the viewport
257
+
260
258
case "up" , "k" :
261
259
m .viewport .LineUp (1 ) // Scroll up in the viewport
262
260
}
261
+
263
262
case tea.WindowSizeMsg :
264
263
h , v := docStyle .GetFrameSize ()
265
264
m .list .SetSize (msg .Width - h , msg .Height - v )
266
265
m .viewport .Width = msg .Width - h
267
266
m .viewport .Height = msg .Height - v
267
+
268
268
case commandResultMsg :
269
269
m .commandOutput = string (msg )
270
270
m .viewport .SetContent (m .commandOutput ) // Update viewport content with command output
271
271
return m , nil
272
272
}
273
273
274
+ // Update the list and return
274
275
var cmd tea.Cmd
275
276
m .list , cmd = m .list .Update (msg )
276
277
return m , cmd
277
278
}
278
-
279
279
func (m modelSavedQueries ) View () string {
280
280
if m .commandOutput != "" {
281
281
return m .viewport .View ()
@@ -367,3 +367,51 @@ func QueryToApply() Item {
367
367
func QueryToDelete () Item {
368
368
return selectedQueryDelete
369
369
}
370
+
371
+ func RunQuery (client * http.Client , profile * config.Profile , query string , startTime string , endTime string ) (string , error ) {
372
+ queryTemplate := `{
373
+ "query": "%s",
374
+ "startTime": "%s",
375
+ "endTime": "%s"
376
+ }`
377
+
378
+ finalQuery := fmt .Sprintf (queryTemplate , query , startTime , endTime )
379
+
380
+ endpoint := fmt .Sprintf ("%s/%s" , profile .URL , "api/v1/query" )
381
+ req , err := http .NewRequest ("POST" , endpoint , bytes .NewBuffer ([]byte (finalQuery )))
382
+ if err != nil {
383
+ return "" , err
384
+ }
385
+ req .SetBasicAuth (profile .Username , profile .Password )
386
+ req .Header .Add ("Content-Type" , "application/json" )
387
+
388
+ resp , err := client .Do (req )
389
+ if err != nil {
390
+ return "" , err
391
+ }
392
+ defer resp .Body .Close ()
393
+
394
+ if resp .StatusCode == http .StatusOK {
395
+ var jsonResponse []map [string ]interface {}
396
+
397
+ // Read and parse the JSON response
398
+ body , err := io .ReadAll (resp .Body )
399
+ if err != nil {
400
+ return "" , err
401
+ }
402
+
403
+ // Decode JSON into a map
404
+ if err := json .Unmarshal (body , & jsonResponse ); err != nil {
405
+ return "" , err
406
+ }
407
+
408
+ // Pretty-print the JSON response
409
+ jsonData , err := json .MarshalIndent (jsonResponse , "" , " " )
410
+ if err != nil {
411
+ return "" , err
412
+ }
413
+ return string (jsonData ), nil
414
+ }
415
+
416
+ return "" , fmt .Errorf ("unexpected status code: %d" , resp .StatusCode )
417
+ }
0 commit comments