[#1223] lens/tui: Add app help

Signed-off-by: Aleksey Savchuk <a.savchuk@yadro.com>
This commit is contained in:
Aleksey Savchuk 2024-08-16 17:27:35 +03:00
parent b99d75f08e
commit ff724f8dfb
No known key found for this signature in database
4 changed files with 179 additions and 1 deletions

View file

@ -0,0 +1,38 @@
[green::b]HOTKEYS[-::-]
[green::b]Navigation[-::-]
[yellow::b]Down Arrow[-::-] / [yellow::b]j[-::-]
Scroll down.
[yellow::b]Up Arrow[-::-] / [yellow::b]k[-::-]
Scroll up.
[yellow::b]Page Down[-::-] / [yellow::b]Ctrl-f[-::-]
Scroll down by a full page.
[yellow::b]Page Up[-::-] / [yellow::b]Ctrl-b[-::-]
Scroll up by a full page.
[green::b]Actions[-::-]
[yellow::b]Enter[-::-]
Perform actions based on the current context:
- In Buckets View:
- Expand/collapse the selected bucket to show/hide its nested buckets.
- If no nested buckets exist, navigate to the selected bucket's records.
- In Records View: Open the detailed view of the selected record.
[yellow::b]Escape[-::-]
Return to the previous page, opposite of [yellow::b]Enter[-::-].
Refer to the [green::b]SEARCHING[-::-] section for more specific actions.
[green::b]Alternative Action Hotkeys[-::-]
[yellow::b]Ctrl-r[-::-]
Directly navigate to the selected bucket's records.
[yellow::b]Ctrl-d[-::-]
Access the detailed view of the selected bucket.

View file

@ -0,0 +1,26 @@
[green::b]SEARCHING[-::-]
[green::b]Hotkeys[-::-]
[yellow::b]/[-::-]
Initiate the search prompt.
- The prompt follows this syntax: [yellow::b]tag:value [+ tag:value]...[-::-]
- Multiple filter can be combined with [yellow::b]+[-::-], the result is an intersection of those filters' result sets.
- Any leading and trailing whitespace will be ignored.
- An empty prompt will return all results with no filters applied.
- Refer to the [green::b]Available Search Filters[-::-] section below for a list of valid filter tags.
[yellow::b]Enter[-::-]
Execute the search based on the entered prompt.
- If the prompt is invalid, an error message will be displayed.
[yellow::b]Escape[-::-]
Exit the search prompt without performing a search.
[yellow::b]Down Arrow[-::-], [yellow::b]Up Arrow[-::-]
Scroll through the search history.
[green::b]Available Search Filters[-::-]
%s

View file

@ -0,0 +1,101 @@
package tui
import (
_ "embed"
"fmt"
"strings"
"github.com/gdamore/tcell/v2"
"github.com/rivo/tview"
)
var (
//go:embed help-pages/hotkeys.txt
hotkeysHelpText string
//go:embed help-pages/searching.txt
searchingHelpText string
)
type HelpPage struct {
*tview.Box
pages []*tview.TextView
currentPage int
filters []string
filterHints map[string]string
}
func NewHelpPage(filters []string, hints map[string]string) *HelpPage {
hp := &HelpPage{
Box: tview.NewBox(),
filters: filters,
filterHints: hints,
}
page := tview.NewTextView().
SetDynamicColors(true).
SetText(hotkeysHelpText)
hp.addPage(page)
page = tview.NewTextView().
SetDynamicColors(true).
SetText(fmt.Sprintf(searchingHelpText, hp.getFiltersText()))
hp.addPage(page)
return hp
}
func (hp *HelpPage) addPage(page *tview.TextView) {
hp.pages = append(hp.pages, page)
}
func (hp *HelpPage) getFiltersText() string {
if len(hp.filters) == 0 {
return "\t\tNo filters defined.\n"
}
filtersText := strings.Builder{}
gapSize := 4
tagMaxWidth := 3
for _, filter := range hp.filters {
tagMaxWidth = max(tagMaxWidth, len(filter))
}
filtersText.WriteString("\t\t[yellow::b]Tag")
filtersText.WriteString(strings.Repeat(" ", gapSize))
filtersText.WriteString("\tValue[-::-]\n\n")
for _, filter := range hp.filters {
filtersText.WriteString("\t\t")
filtersText.WriteString(filter)
filtersText.WriteString(strings.Repeat(" ", tagMaxWidth-len(filter)+gapSize))
filtersText.WriteString(hp.filterHints[filter])
filtersText.WriteRune('\n')
}
return filtersText.String()
}
func (hp *HelpPage) Draw(screen tcell.Screen) {
x, y, width, height := hp.GetInnerRect()
hp.pages[hp.currentPage].SetRect(x+1, y+1, width-2, height-2)
hp.pages[hp.currentPage].Draw(screen)
}
func (hp *HelpPage) InputHandler() func(event *tcell.EventKey, setFocus func(p tview.Primitive)) {
return hp.WrapInputHandler(func(event *tcell.EventKey, _ func(tview.Primitive)) {
if event.Key() == tcell.KeyEnter {
hp.currentPage++
hp.currentPage %= len(hp.pages)
return
}
hp.pages[hp.currentPage].InputHandler()(event, func(tview.Primitive) {})
})
}
func (hp *HelpPage) MouseHandler() func(action tview.MouseAction, event *tcell.EventMouse, setFocus func(p tview.Primitive)) (consumed bool, capture tview.Primitive) {
return hp.WrapMouseHandler(func(action tview.MouseAction, event *tcell.EventMouse, _ func(tview.Primitive)) (consumed bool, capture tview.Primitive) {
return hp.pages[hp.currentPage].MouseHandler()(action, event, func(tview.Primitive) {})
})
}

View file

@ -60,6 +60,8 @@ type UI struct {
loadingBar *LoadingBar
helpBar *tview.TextView
helpPage *HelpPage
searchErrorBar *tview.TextView
isSearching bool
@ -275,7 +277,17 @@ func (ui *UI) draw(screen tcell.Screen) {
switch {
case ui.isShowingHelp:
pageToDraw = ui.pageStub
if ui.helpPage == nil {
var filters []string
for f := range ui.filters {
filters = append(filters, f)
}
for f := range ui.compositeFilters {
filters = append(filters, f)
}
ui.helpPage = NewHelpPage(filters, ui.filterHints)
}
pageToDraw = ui.helpPage
case ui.mountedPage != nil:
pageToDraw = ui.mountedPage
default:
@ -429,6 +441,7 @@ func (ui *UI) handleInputOnShowingHelp(event *tcell.EventKey) {
case k == tcell.KeyRune && r == 'q':
ui.stop()
default:
ui.helpPage.InputHandler()(event, func(tview.Primitive) {})
}
}