From 4819e790c1fa4c9b97b1ec0d0444fbb0984c4422 Mon Sep 17 00:00:00 2001 From: Satyam Singh Date: Fri, 4 Aug 2023 10:15:16 +0530 Subject: [PATCH 01/10] Remove inputs from query view --- cmd/query.go | 9 +- pkg/model/query.go | 213 ++++------------------------------------- pkg/model/timerange.go | 6 +- 3 files changed, 33 insertions(+), 195 deletions(-) diff --git a/cmd/query.go b/cmd/query.go index 7f1408d..692481b 100644 --- a/cmd/query.go +++ b/cmd/query.go @@ -21,6 +21,7 @@ import ( "fmt" "os" "pb/pkg/model" + "strconv" tea "github.com/charmbracelet/bubbletea" "github.com/spf13/cobra" @@ -29,11 +30,15 @@ import ( var QueryProfileCmd = &cobra.Command{ Use: "query name", Short: "Open Query TUI", - Args: cobra.ExactArgs(1), + Args: cobra.ExactArgs(2), PreRunE: PreRunDefaultProfile, RunE: func(cmd *cobra.Command, args []string) error { stream := args[0] - p := tea.NewProgram(model.NewQueryModel(DefaultProfile, stream), tea.WithAltScreen()) + duration, err := strconv.Atoi(args[1]) + if err != nil { + return err + } + p := tea.NewProgram(model.NewQueryModel(DefaultProfile, stream, uint(duration)), tea.WithAltScreen()) if _, err := p.Run(); err != nil { fmt.Printf("Alas, there's been an error: %v", err) os.Exit(1) diff --git a/pkg/model/query.go b/pkg/model/query.go index a82bde7..157f22e 100644 --- a/pkg/model/query.go +++ b/pkg/model/query.go @@ -29,7 +29,7 @@ import ( "pb/pkg/config" - "github.com/charmbracelet/bubbles/textarea" + "github.com/charmbracelet/bubbles/help" tea "github.com/charmbracelet/bubbletea" "github.com/charmbracelet/lipgloss" table "github.com/evertras/bubble-table/table" @@ -42,7 +42,6 @@ var ( baseStyle = lipgloss.NewStyle().BorderForeground(lipgloss.AdaptiveColor{Light: "236", Dark: "248"}) headerStyle = lipgloss.NewStyle().Inherit(baseStyle).Foreground(lipgloss.AdaptiveColor{Light: "#023047", Dark: "#90E0EF"}).Bold(true) tableStyle = lipgloss.NewStyle().Inherit(baseStyle).Align(lipgloss.Left) - focusColor = lipgloss.AdaptiveColor{Light: "#5a189a", Dark: "#e0aaff"} customBorder = table.Border{ Top: "─", @@ -63,17 +62,8 @@ var ( InnerDivider: "║", } - textarea_style = textarea.Style{ - Base: baseStyle, - Text: baseStyle, - } ) -var navigation_map [][]string = [][]string{ - {"query", "time", "execute"}, - {"table"}, -} - type Mode int type FetchResult int @@ -83,12 +73,6 @@ type FetchData struct { data []map[string]interface{} } -const ( - navigation Mode = iota - active - inactive -) - const ( FetchOk FetchResult = iota FetchErr @@ -97,31 +81,17 @@ const ( type QueryModel struct { width int height int - query textarea.Model + query string time_range timeRangeModel table table.Model - mode Mode profile config.Profile stream string + help help.Model status StatusBar - focus struct { - x uint - y uint - } } -func NewQueryModel(profile config.Profile, stream string) QueryModel { - query := textarea.New() - query.ShowLineNumbers = false - query.SetHeight(2) - query.SetWidth(50) - query.FocusedStyle = textarea_style - query.BlurredStyle = textarea_style - default_text := fmt.Sprintf("select * from %s", stream) - query.Placeholder = default_text - query.InsertString(default_text) - query.Focus() - +func NewQueryModel(profile config.Profile, stream string, duration uint) QueryModel { + query := fmt.Sprintf("select * from %s", stream) var w, h, _ = term.GetSize(int(os.Stdout.Fd())) columns := []table.Column{ @@ -152,106 +122,18 @@ func NewQueryModel(profile config.Profile, stream string) QueryModel { width: w, height: h, query: query, - time_range: NewTimeRangeModel(), + time_range: NewTimeRangeModel(duration), table: table, - mode: navigation, profile: profile, stream: stream, + help: help.New(), status: NewStatusBar(profile.Url, stream, w), - focus: struct { - x uint - y uint - }{0, 0}, - } -} - -func (m *QueryModel) currentFocus() string { - return navigation_map[m.focus.y][m.focus.x] -} - -func (m *QueryModel) Blur() { - switch m.currentFocus() { - case "query": - m.query.Blur() - case "table": - m.table.Focused(false) - default: - return - } -} - -func (m *QueryModel) Focus(id string) { - switch id { - case "query": - m.query.Focus() - case "table": - m.table.Focused(true) - } -} - -func (m *QueryModel) Navigate(key tea.KeyMsg) { - switch key.String() { - case "enter": - m.mode = active - m.Focus(m.currentFocus()) - - case "up", "w": - if m.focus.y > 0 { - m.focus.y -= 1 - m.focus.x = 0 - } - case "down", "s": - if m.focus.y < uint(len(navigation_map))-1 { - m.focus.y += 1 - m.focus.x = 0 - } - case "left", "a": - if m.focus.x > 0 { - m.focus.x -= 1 - } - case "right", "d": - if m.focus.x < uint(len(navigation_map[m.focus.y]))-1 { - m.focus.x += 1 - } - default: - return - } -} - -func (m QueryModel) HandleKeyPress(key tea.KeyMsg) (QueryModel, tea.Cmd) { - var cmd tea.Cmd - - if key.Type == tea.KeyEsc { - m.mode = navigation - m.Blur() - return m, nil } - - if m.mode == navigation { - if key.Type == tea.KeyEnter && m.currentFocus() == "execute" { - m.mode = inactive - cmd = NewFetchTask(m.profile, m.stream, m.query.Value(), m.time_range.StartValueUtc(), m.time_range.EndValueUtc()) - } else { - m.Navigate(key) - } - } else { - focused := navigation_map[m.focus.y][m.focus.x] - switch focused { - case "query": - m.query, cmd = m.query.Update(key) - case "time": - m.time_range, cmd = m.time_range.Update(key) - case "table": - m.table, cmd = m.table.Update(key) - } - } - - return m, cmd } func (m QueryModel) Init() tea.Cmd { // Just return `nil`, which means "no I/O right now, please." - return nil + return NewFetchTask(m.profile, m.stream, m.query, m.time_range.StartValueUtc(), m.time_range.EndValueUtc()) } func (m QueryModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { @@ -262,6 +144,7 @@ func (m QueryModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { case tea.WindowSizeMsg: m.width, m.height, _ = term.GetSize(int(os.Stdout.Fd())) + m.help.Width = m.width return m, nil case FetchData: @@ -271,10 +154,9 @@ func (m QueryModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { m.status.Error = "failed to query" } - m.mode = navigation return m, nil - // Is it a key press? + // Is it a key press? case tea.KeyMsg: switch msg.Type { // These keys should exit the program. @@ -282,10 +164,8 @@ func (m QueryModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { return m, tea.Quit default: - if m.mode != inactive { - m, cmd = m.HandleKeyPress(msg) - cmds = append(cmds, cmd) - } + m.table, cmd = m.table.Update(msg) + cmds = append(cmds, cmd) } } @@ -296,72 +176,21 @@ func (m QueryModel) View() string { var outer = lipgloss.NewStyle().Inherit(baseStyle). UnsetMaxHeight().Width(m.width).Height(m.height) - var input_style = lipgloss.NewStyle(). - Inherit(baseStyle). - Border(lipgloss.RoundedBorder(), true). - Margin(0) - - var query_style = input_style.Copy() - var time_style = input_style.Copy() - var execute_style = input_style.Copy().Height(2).Align(lipgloss.Center) - var table_style = input_style.Copy().Border(lipgloss.RoundedBorder(), false) - - var patchStyleFocus = func(style *lipgloss.Style) { - border := lipgloss.RoundedBorder() - border.TopLeft = "╓" - border.Left = "║" - border.BottomLeft = "╙ " - - style.BorderStyle(border).BorderForeground(focusColor) - } - - focused := navigation_map[m.focus.y][m.focus.x] - - switch focused { - case "query": - patchStyleFocus(&query_style) - case "time": - patchStyleFocus(&time_style) - case "execute": - patchStyleFocus(&execute_style) - case "table": - table_style.Border(lipgloss.NormalBorder(), false, false, false, true).BorderForeground(focusColor) - } - m.table.WithMaxTotalWidth(m.width - 10) - button := "execute" - - if m.mode == inactive { - button = "loading" - } - - var inputs = lipgloss.JoinHorizontal( - lipgloss.Bottom, - query_style.Render(m.query.View()), - time_style.Render(fmt.Sprintf("%s\n%s", m.time_range.StartValue(), m.time_range.EndValue())), - execute_style.Render(button), - ) - - inputHeight := lipgloss.Height(inputs) statusHeight := 1 - tableHeight := m.height - inputHeight - statusHeight - - if focused == "table" { - m.table = m.table.WithMaxTotalWidth(m.width - 2) - } else { - m.table = m.table.WithMaxTotalWidth(m.width) - } - + tableHeight := m.height - statusHeight - 4 m.status.width = m.width + m.help.ShowAll = true + m.help.Styles.FullDesc = lipgloss.NewStyle().Foreground(lipgloss.Color("1")) + help := m.help.View(m.table.KeyMap()) - render := fmt.Sprintf("%s\n%s\n%s", inputs, lipgloss.PlaceVertical(tableHeight, lipgloss.Top, table_style.Render(m.table.View())), m.status.View()) + f, _ := tea.LogToFile("debug.log", help) + defer f.Close() - if m.mode == active && focused == "time" { - return outer.Render(lipgloss.Place(m.width-4, m.height-4, lipgloss.Center, lipgloss.Center, m.time_range.View())) - } else { - return outer.Render(render) - } + render := fmt.Sprintf("%s\n%s\n%s", lipgloss.PlaceVertical(tableHeight, lipgloss.Top, m.table.View()), help, m.status.View()) + + return outer.Render(render) } diff --git a/pkg/model/timerange.go b/pkg/model/timerange.go index f7c53a5..0320113 100644 --- a/pkg/model/timerange.go +++ b/pkg/model/timerange.go @@ -166,10 +166,14 @@ func (m *timeRangeModel) currentFocus() string { return rangeNavigationMap[m.focus] } -func NewTimeRangeModel() timeRangeModel { +func NewTimeRangeModel(duration uint) timeRangeModel { end_time := time.Now() start_time := end_time.Add(TenMinute) + if duration != 0 { + start_time = end_time.Add(-(time.Duration(duration) * time.Minute)) + } + list := list.New(timeDurations, timeDurationItemDelegate{}, 20, 10) list.SetShowPagination(false) list.SetShowHelp(false) From 949b40f76f61b99cb47e7780f21bc3d488272d48 Mon Sep 17 00:00:00 2001 From: Satyam Singh Date: Sat, 5 Aug 2023 11:16:36 +0530 Subject: [PATCH 02/10] Format profile list output --- cmd/profile.go | 63 ++++++++++++++++++++++++-------------------------- 1 file changed, 30 insertions(+), 33 deletions(-) diff --git a/cmd/profile.go b/cmd/profile.go index 3c43f21..8de756d 100644 --- a/cmd/profile.go +++ b/cmd/profile.go @@ -25,12 +25,35 @@ import ( "pb/pkg/config" "pb/pkg/model" - "github.com/charmbracelet/bubbles/table" tea "github.com/charmbracelet/bubbletea" "github.com/charmbracelet/lipgloss" "github.com/spf13/cobra" ) +type ProfileListItem struct { + title, url, user string +} + +func (item *ProfileListItem) Render(highlight bool) string { + if highlight { + render := fmt.Sprintf( + "%s\n%s\n%s", + selectedStyle.Render(item.title), + selectedStyleAlt.Render(fmt.Sprintf("url: %s", item.url)), + selectedStyleAlt.Render(fmt.Sprintf("user: %s", item.user)), + ) + return selectedItemOuter.Render(render) + } else { + render := fmt.Sprintf( + "%s\n%s\n%s", + lipgloss.NewStyle().Render(item.title), + inactiveStyle.Render(fmt.Sprintf("url: %s", item.url)), + inactiveStyle.Render(fmt.Sprintf("user: %s", item.user)), + ) + return itemOuter.Render(render) + } +} + var AddProfileCmd = &cobra.Command{ Use: "add name url ", Example: "add local_logs http://0.0.0.0:8000 admin admin", @@ -162,41 +185,15 @@ var ListProfileCmd = &cobra.Command{ if err != nil { return nil } - - cols := []table.Column{ - {Title: "PROFILE", Width: 7}, - {Title: "URL", Width: 5}, - {Title: "USER", Width: 8}, - } - - rows := make([]table.Row, len(file_config.Profiles)) - row_idx := 0 - selected_row := 0 + row := 0 for key, value := range file_config.Profiles { - if file_config.Default_profile == key { - selected_row = row_idx + item := ProfileListItem{key, value.Url, value.Username} + fmt.Println(item.Render(file_config.Default_profile == key)) + row += 1 + if row != len(file_config.Profiles) { + fmt.Println() } - - rows[row_idx] = table.Row{key, value.Url, value.Username} - row_idx += 1 - - // update max width for table - cols[0].Width = Max(cols[0].Width, len(key)) - cols[1].Width = Max(cols[1].Width, len(value.Url)) - cols[2].Width = Max(cols[2].Width, len(value.Password)) } - - tbl := table.New( - table.WithColumns(cols), - table.WithRows(rows), - table.WithHeight(len(rows)), - table.WithStyles(listingTableStyle()), - ) - - tbl.SetCursor(selected_row) - - fmt.Println(tbl.View()) - return nil }, } From cdcafc7e9db01f5735f6a5aa6063193503241dc9 Mon Sep 17 00:00:00 2001 From: Satyam Singh Date: Sat, 5 Aug 2023 11:16:43 +0530 Subject: [PATCH 03/10] Fix error --- cmd/pre.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/pre.go b/cmd/pre.go index f4c7e9b..19ce3d8 100644 --- a/cmd/pre.go +++ b/cmd/pre.go @@ -33,7 +33,7 @@ func PreRunDefaultProfile(cmd *cobra.Command, args []string) error { conf, err := config.ReadConfigFromFile() if err != nil { if os.IsNotExist(err) { - return errors.New("No config found to run this command. Add a profile using pb profile command") + return errors.New("no config found to run this command. add a profile using pb profile command") } else { return err } From 7cf91270e42991033dd18f8e6b219b50249b37d2 Mon Sep 17 00:00:00 2001 From: Satyam Singh Date: Sat, 5 Aug 2023 11:16:52 +0530 Subject: [PATCH 04/10] Add style --- cmd/style.go | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/cmd/style.go b/cmd/style.go index 434577f..bb5279b 100644 --- a/cmd/style.go +++ b/cmd/style.go @@ -18,20 +18,19 @@ package cmd import ( - "github.com/charmbracelet/bubbles/table" "github.com/charmbracelet/lipgloss" ) // styling for cli outputs var ( - selectedStyle = lipgloss.NewStyle(). - Foreground(lipgloss.AdaptiveColor{Light: "4", Dark: "11"}).Bold(true) + adaptiveYellow = lipgloss.AdaptiveColor{Light: "4", Dark: "11"} + + inactiveStyle = lipgloss.NewStyle().Faint(true) + selectedStyle = lipgloss.NewStyle().Foreground(adaptiveYellow).Bold(true) + selectedStyleAlt = lipgloss.NewStyle().Foreground(adaptiveYellow) + + selectedItemOuter = lipgloss.NewStyle().BorderStyle(lipgloss.NormalBorder()).BorderLeft(true).PaddingLeft(1).BorderForeground(adaptiveYellow) + itemOuter = lipgloss.NewStyle().PaddingLeft(1) + styleBold = lipgloss.NewStyle().Bold(true) ) - -func listingTableStyle() table.Styles { - s := table.DefaultStyles() - s.Header = s.Header.Border(lipgloss.NormalBorder(), false, false, true, false) - s.Selected = selectedStyle - return s -} From 8b6f9d73115414c0f313c93740ddcf655c63e499 Mon Sep 17 00:00:00 2001 From: Satyam Singh Date: Sat, 5 Aug 2023 11:17:11 +0530 Subject: [PATCH 05/10] Fetch user role --- cmd/user.go | 68 +++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 64 insertions(+), 4 deletions(-) diff --git a/cmd/user.go b/cmd/user.go index 283fa22..efbd414 100644 --- a/cmd/user.go +++ b/cmd/user.go @@ -21,10 +21,26 @@ import ( "encoding/json" "fmt" "io" + "net/http" + "pb/pkg/config" + "sync" "github.com/spf13/cobra" ) +type UserRoleData struct { + Privilege string `json:"privilege"` + Resource struct { + Stream string `json:"stream"` + Tag string `json:"tag"` + } `json:"resource"` +} + +type FetchUserRoleRes struct { + data []UserRoleData + err error +} + var AddUserCmd = &cobra.Command{ Use: "add name", Example: "add bob", @@ -117,14 +133,37 @@ var ListUserCmd = &cobra.Command{ defer resp.Body.Close() if resp.StatusCode == 200 { - items := []string{} - err = json.Unmarshal(bytes, &items) + users := []string{} + err = json.Unmarshal(bytes, &users) if err != nil { return err } - for _, item := range items { - fmt.Println(item) + + client = DefaultClient() + role_responses := make([]FetchUserRoleRes, len(users)) + + wsg := sync.WaitGroup{} + wsg.Add(len(users)) + for idx, user := range users { + idx := idx + user := user + go func() { + role_responses[idx] = fetchUserRoles(&client.client, &DefaultProfile, user) + wsg.Done() + }() } + wsg.Wait() + for idx, user := range users { + roles := role_responses[idx] + fmt.Println(user) + if roles.err == nil { + for _, role := range roles.data { + fmt.Printf(" %s @ %s %s\n", role.Privilege, role.Resource.Stream, role.Resource.Tag) + } + } + println() + } + } else { body := string(bytes) fmt.Printf("Request Failed\nStatus Code: %s\nResponse: %s\n", resp.Status, body) @@ -133,3 +172,24 @@ var ListUserCmd = &cobra.Command{ return nil }, } + +func fetchUserRoles(client *http.Client, profile *config.Profile, user string) (res FetchUserRoleRes) { + endpoint := fmt.Sprintf("%s/%s", profile.Url, fmt.Sprintf("api/v1/user/%s/role", user)) + req, err := http.NewRequest("GET", endpoint, nil) + if err != nil { + return + } + req.SetBasicAuth(profile.Username, profile.Password) + resp, err := client.Do(req) + if err != nil { + return + } + body, err := io.ReadAll(resp.Body) + if err != nil { + return + } + defer resp.Body.Close() + + res.err = json.Unmarshal(body, &res.data) + return +} From 77ef3bceb7d5d11c7965fd362ce75494d1fbedfd Mon Sep 17 00:00:00 2001 From: Satyam Singh Date: Sat, 5 Aug 2023 11:17:33 +0530 Subject: [PATCH 06/10] Show help in query view --- pkg/model/help.go | 67 ++++++++++++++++++++++++++++++++++++++++++++++ pkg/model/query.go | 33 ++++++++++++++--------- 2 files changed, 88 insertions(+), 12 deletions(-) create mode 100644 pkg/model/help.go diff --git a/pkg/model/help.go b/pkg/model/help.go new file mode 100644 index 0000000..d2db1db --- /dev/null +++ b/pkg/model/help.go @@ -0,0 +1,67 @@ +package model + +import ( + "github.com/charmbracelet/bubbles/key" +) + +type TableKeyMap struct { + Up key.Binding + Down key.Binding + PageUp key.Binding + PageDown key.Binding + ScrollRight key.Binding + ScrollLeft key.Binding + Filter key.Binding + ClearFilter key.Binding +} + +// ShortHelp returns keybindings to be shown in the mini help view. It's part +// of the key.Map interface. +func (k TableKeyMap) ShortHelp() []key.Binding { + return []key.Binding{k.ScrollRight, k.ScrollRight, k.Filter, k.ClearFilter} +} + +// FullHelp returns keybindings for the expanded help view. It's part of the +// key.Map interface. +func (k TableKeyMap) FullHelp() [][]key.Binding { + return [][]key.Binding{ + {k.Up, k.Down, k.PageUp, k.PageDown}, // first column + {k.ScrollLeft, k.ScrollRight}, + {k.ClearFilter, k.Filter}, // second column + } +} + +var tableKeys = TableKeyMap{ + Up: key.NewBinding( + key.WithKeys("up", "k"), + key.WithHelp("↑/k", "move up"), + ), + Down: key.NewBinding( + key.WithKeys("down", "j"), + key.WithHelp("↓/j", "move down"), + ), + PageUp: key.NewBinding( + key.WithKeys("right", "l", "pgdown"), + key.WithHelp("→/l", "prev page"), + ), + PageDown: key.NewBinding( + key.WithKeys("left", "h", "pgup"), + key.WithHelp("←/h", "next page"), + ), + ScrollLeft: key.NewBinding( + key.WithKeys("shift+left", "shift+h"), + key.WithHelp("shift ←/h", "scroll left"), + ), + ScrollRight: key.NewBinding( + key.WithKeys("shift+right", "shift+l"), + key.WithHelp("shift →/l", "scroll right"), + ), + Filter: key.NewBinding( + key.WithKeys("/"), + key.WithHelp("/ .. ", "Filter"), + ), + ClearFilter: key.NewBinding( + key.WithKeys("esc"), + key.WithHelp("esc", "remove filter"), + ), +} diff --git a/pkg/model/query.go b/pkg/model/query.go index 157f22e..3847dc6 100644 --- a/pkg/model/query.go +++ b/pkg/model/query.go @@ -101,11 +101,10 @@ func NewQueryModel(profile config.Profile, stream string, duration uint) QueryMo rows := make([]table.Row, 0) keys := table.DefaultKeyMap() - keys.RowDown.SetKeys("j", "down", "s") - keys.RowUp.SetKeys("k", "up", "w") table := table.New(columns). WithRows(rows). + Filtered(true). HeaderStyle(headerStyle). SelectableRows(false). Border(customBorder). @@ -145,6 +144,8 @@ func (m QueryModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { case tea.WindowSizeMsg: m.width, m.height, _ = term.GetSize(int(os.Stdout.Fd())) m.help.Width = m.width + m.status.width = m.width + m.table = m.table.WithMaxTotalWidth(m.width) return m, nil case FetchData: @@ -179,16 +180,24 @@ func (m QueryModel) View() string { m.table.WithMaxTotalWidth(m.width - 10) statusHeight := 1 - tableHeight := m.height - statusHeight - 4 - m.status.width = m.width - m.help.ShowAll = true - m.help.Styles.FullDesc = lipgloss.NewStyle().Foreground(lipgloss.Color("1")) - help := m.help.View(m.table.KeyMap()) + HelpHeight := 5 + + tableView := m.table.View() + tableHeight := lipgloss.Height(tableView) - f, _ := tea.LogToFile("debug.log", help) - defer f.Close() + if (tableHeight + HelpHeight + statusHeight) > m.height { + m.help.ShowAll = false + HelpHeight = 2 + } else { + m.help.ShowAll = true + } + + tableBoxHeight := m.height - statusHeight - HelpHeight + + m.help.Styles.FullDesc = lipgloss.NewStyle().Foreground(lipgloss.Color("1")) + help := m.help.View(tableKeys) - render := fmt.Sprintf("%s\n%s\n%s", lipgloss.PlaceVertical(tableHeight, lipgloss.Top, m.table.View()), help, m.status.View()) + render := fmt.Sprintf("%s\n%s\n\n%s", lipgloss.PlaceVertical(tableBoxHeight, lipgloss.Top, tableView), help, m.status.View()) return outer.Render(render) @@ -302,7 +311,7 @@ func fetchData(client *http.Client, profile *config.Profile, query string, start } func (m *QueryModel) UpdateTable(data FetchData) { - columns := make([]table.Column, len(data.schema)) + columns := make([]table.Column, len(data.schema)-2) columns[0] = table.NewColumn("p_timestamp", "p_timestamp", 24) columnIndex := 1 @@ -312,7 +321,7 @@ func (m *QueryModel) UpdateTable(data FetchData) { continue default: width := inferWidthForColumns(title, &data.data, 100, 80) + 3 - columns[columnIndex] = table.NewColumn(title, title, width) + columns[columnIndex] = table.NewColumn(title, title, width).WithFiltered(true) columnIndex += 1 } } From f9b75b21f50326aa010e0158940bd196d72f5179 Mon Sep 17 00:00:00 2001 From: Satyam Singh Date: Sat, 5 Aug 2023 11:21:30 +0530 Subject: [PATCH 07/10] One margin to list output --- cmd/profile.go | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/cmd/profile.go b/cmd/profile.go index 8de756d..4975723 100644 --- a/cmd/profile.go +++ b/cmd/profile.go @@ -185,14 +185,17 @@ var ListProfileCmd = &cobra.Command{ if err != nil { return nil } + + if len(file_config.Profiles) != 0 { + println() + } + row := 0 for key, value := range file_config.Profiles { item := ProfileListItem{key, value.Url, value.Username} fmt.Println(item.Render(file_config.Default_profile == key)) row += 1 - if row != len(file_config.Profiles) { - fmt.Println() - } + fmt.Println() } return nil }, From 89effa010adce165ab79f9d7c6cfd03d955e3311 Mon Sep 17 00:00:00 2001 From: Satyam Singh Date: Sat, 5 Aug 2023 11:39:51 +0530 Subject: [PATCH 08/10] Fix styling --- cmd/profile.go | 6 +++--- cmd/style.go | 16 +++++++++++----- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/cmd/profile.go b/cmd/profile.go index 4975723..bb9a37e 100644 --- a/cmd/profile.go +++ b/cmd/profile.go @@ -46,9 +46,9 @@ func (item *ProfileListItem) Render(highlight bool) string { } else { render := fmt.Sprintf( "%s\n%s\n%s", - lipgloss.NewStyle().Render(item.title), - inactiveStyle.Render(fmt.Sprintf("url: %s", item.url)), - inactiveStyle.Render(fmt.Sprintf("user: %s", item.user)), + inactiveStyle.Render(item.title), + inactiveStyleAlt.Render(fmt.Sprintf("url: %s", item.url)), + inactiveStyleAlt.Render(fmt.Sprintf("user: %s", item.user)), ) return itemOuter.Render(render) } diff --git a/cmd/style.go b/cmd/style.go index bb5279b..b0f0fe7 100644 --- a/cmd/style.go +++ b/cmd/style.go @@ -23,13 +23,19 @@ import ( // styling for cli outputs var ( - adaptiveYellow = lipgloss.AdaptiveColor{Light: "4", Dark: "11"} + FocusPrimary = lipgloss.AdaptiveColor{Light: "16", Dark: "226"} + FocusSecondry = lipgloss.AdaptiveColor{Light: "18", Dark: "220"} - inactiveStyle = lipgloss.NewStyle().Faint(true) - selectedStyle = lipgloss.NewStyle().Foreground(adaptiveYellow).Bold(true) - selectedStyleAlt = lipgloss.NewStyle().Foreground(adaptiveYellow) + standardPrimary = lipgloss.AdaptiveColor{Light: "235", Dark: "255"} + standardSecondry = lipgloss.AdaptiveColor{Light: "238", Dark: "254"} - selectedItemOuter = lipgloss.NewStyle().BorderStyle(lipgloss.NormalBorder()).BorderLeft(true).PaddingLeft(1).BorderForeground(adaptiveYellow) + inactiveStyle = lipgloss.NewStyle().Foreground(standardPrimary) + inactiveStyleAlt = lipgloss.NewStyle().Foreground(standardSecondry) + + selectedStyle = lipgloss.NewStyle().Foreground(FocusPrimary).Bold(true) + selectedStyleAlt = lipgloss.NewStyle().Foreground(FocusSecondry) + + selectedItemOuter = lipgloss.NewStyle().BorderStyle(lipgloss.NormalBorder()).BorderLeft(true).PaddingLeft(1).BorderForeground(FocusPrimary) itemOuter = lipgloss.NewStyle().PaddingLeft(1) styleBold = lipgloss.NewStyle().Bold(true) From a87e7eded58ad627ce28e1632b2546875a1a449a Mon Sep 17 00:00:00 2001 From: Satyam Singh Date: Sat, 5 Aug 2023 11:44:06 +0530 Subject: [PATCH 09/10] Add example --- cmd/query.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cmd/query.go b/cmd/query.go index 692481b..4595c34 100644 --- a/cmd/query.go +++ b/cmd/query.go @@ -28,7 +28,8 @@ import ( ) var QueryProfileCmd = &cobra.Command{ - Use: "query name", + Use: "query name minutes", + Example: "query local_logs 20", Short: "Open Query TUI", Args: cobra.ExactArgs(2), PreRunE: PreRunDefaultProfile, From a3173e5c319c7153c83a9627b29692ec5894c19d Mon Sep 17 00:00:00 2001 From: Satyam Singh Date: Sat, 5 Aug 2023 12:07:13 +0530 Subject: [PATCH 10/10] Format user list output --- cmd/profile.go | 6 +++--- cmd/style.go | 5 +++-- cmd/user.go | 23 +++++++++++++++++++++-- 3 files changed, 27 insertions(+), 7 deletions(-) diff --git a/cmd/profile.go b/cmd/profile.go index bb9a37e..db97f6e 100644 --- a/cmd/profile.go +++ b/cmd/profile.go @@ -46,9 +46,9 @@ func (item *ProfileListItem) Render(highlight bool) string { } else { render := fmt.Sprintf( "%s\n%s\n%s", - inactiveStyle.Render(item.title), - inactiveStyleAlt.Render(fmt.Sprintf("url: %s", item.url)), - inactiveStyleAlt.Render(fmt.Sprintf("user: %s", item.user)), + standardStyle.Render(item.title), + standardStyleAlt.Render(fmt.Sprintf("url: %s", item.url)), + standardStyleAlt.Render(fmt.Sprintf("user: %s", item.user)), ) return itemOuter.Render(render) } diff --git a/cmd/style.go b/cmd/style.go index b0f0fe7..f02430a 100644 --- a/cmd/style.go +++ b/cmd/style.go @@ -29,8 +29,9 @@ var ( standardPrimary = lipgloss.AdaptiveColor{Light: "235", Dark: "255"} standardSecondry = lipgloss.AdaptiveColor{Light: "238", Dark: "254"} - inactiveStyle = lipgloss.NewStyle().Foreground(standardPrimary) - inactiveStyleAlt = lipgloss.NewStyle().Foreground(standardSecondry) + standardStyle = lipgloss.NewStyle().Foreground(standardPrimary) + standardStyleBold = lipgloss.NewStyle().Foreground(standardPrimary).Bold(true) + standardStyleAlt = lipgloss.NewStyle().Foreground(standardSecondry) selectedStyle = lipgloss.NewStyle().Foreground(FocusPrimary).Bold(true) selectedStyleAlt = lipgloss.NewStyle().Foreground(FocusSecondry) diff --git a/cmd/user.go b/cmd/user.go index efbd414..95cb4e6 100644 --- a/cmd/user.go +++ b/cmd/user.go @@ -23,6 +23,7 @@ import ( "io" "net/http" "pb/pkg/config" + "strings" "sync" "github.com/spf13/cobra" @@ -36,6 +37,23 @@ type UserRoleData struct { } `json:"resource"` } +func (user *UserRoleData) Render() string { + var s strings.Builder + s.WriteString(standardStyle.Render(user.Privilege)) + + if user.Resource.Stream != "" { + s.WriteString(" - ") + s.WriteString(standardStyleAlt.Render(user.Resource.Stream)) + } + if user.Resource.Tag != "" { + s.WriteString(" ( ") + s.WriteString(standardStyleAlt.Render(user.Resource.Tag)) + s.WriteString(" )") + } + + return s.String() +} + type FetchUserRoleRes struct { data []UserRoleData err error @@ -153,12 +171,13 @@ var ListUserCmd = &cobra.Command{ }() } wsg.Wait() + fmt.Println() for idx, user := range users { roles := role_responses[idx] - fmt.Println(user) + fmt.Println(standardStyleBold.Bold(true).Render(user)) if roles.err == nil { for _, role := range roles.data { - fmt.Printf(" %s @ %s %s\n", role.Privilege, role.Resource.Stream, role.Resource.Tag) + fmt.Printf(" %s\n", role.Render()) } } println()