@@ -21,7 +21,6 @@ import (
2121 "fmt"
2222 "io"
2323 "net/http"
24- "os/exec"
2524 "strings"
2625 "time"
2726
@@ -180,6 +179,7 @@ type modelSavedQueries struct {
180179 list list.Model
181180 commandOutput string
182181 viewport viewport.Model
182+ queryExecuted bool // New field to track query execution
183183}
184184
185185func (m modelSavedQueries ) Init () tea.Cmd {
@@ -189,93 +189,93 @@ func (m modelSavedQueries) Init() tea.Cmd {
189189// Define a message type for command results
190190type commandResultMsg string
191191
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
198198
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
201206
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+ }
206213
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+ }
211218
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 , `"` , "" )
217222
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 )
220225
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 }
226228
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 ()
231232
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+ }
235238
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 )
247241 if err != nil {
248242 return commandResultMsg (fmt .Sprintf ("Error: %s" , err ))
249243 }
250- return commandResultMsg (output )
244+ return commandResultMsg (data )
251245 }
252246 return m , cmd
247+
253248 case "b" : // 'b' to go back to the saved query list
254249 m .commandOutput = "" // Clear the command output
255250 m .viewport .SetContent ("" ) // Clear viewport content
256251 m .viewport .GotoTop () // Reset viewport to the top
252+ m .queryExecuted = false // Reset the execution flag to allow a new query
257253 return m , nil
254+
258255 case "down" , "j" :
259256 m .viewport .LineDown (1 ) // Scroll down in the viewport
257+
260258 case "up" , "k" :
261259 m .viewport .LineUp (1 ) // Scroll up in the viewport
262260 }
261+
263262 case tea.WindowSizeMsg :
264263 h , v := docStyle .GetFrameSize ()
265264 m .list .SetSize (msg .Width - h , msg .Height - v )
266265 m .viewport .Width = msg .Width - h
267266 m .viewport .Height = msg .Height - v
267+
268268 case commandResultMsg :
269269 m .commandOutput = string (msg )
270270 m .viewport .SetContent (m .commandOutput ) // Update viewport content with command output
271271 return m , nil
272272 }
273273
274+ // Update the list and return
274275 var cmd tea.Cmd
275276 m .list , cmd = m .list .Update (msg )
276277 return m , cmd
277278}
278-
279279func (m modelSavedQueries ) View () string {
280280 if m .commandOutput != "" {
281281 return m .viewport .View ()
@@ -367,3 +367,51 @@ func QueryToApply() Item {
367367func QueryToDelete () Item {
368368 return selectedQueryDelete
369369}
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