[#1223] lens/tui: Enchance help page
- Make help multipage: one page for each chapter. - Improve help information. - Add markup. Signed-off-by: Aleksey Savchuk <a.savchuk@yadro.com>
This commit is contained in:
parent
ff28b7e592
commit
4ed3b273f9
5 changed files with 119 additions and 49 deletions
|
@ -0,0 +1 @@
|
|||
[green::b]Development[white::-] (Work in Progress)
|
27
cmd/frostfs-lens/internal/tuiutil/help-pages/navigation.txt
Normal file
27
cmd/frostfs-lens/internal/tuiutil/help-pages/navigation.txt
Normal file
|
@ -0,0 +1,27 @@
|
|||
[green::b]General Navigation[white::-]
|
||||
|
||||
[yellow::b]Down Arrow[white::-] / [yellow::b]j[white::-]
|
||||
Scroll down.
|
||||
|
||||
[yellow::b]Up Arrow[white::-] / [yellow::b]k[white::-]
|
||||
Scroll up.
|
||||
|
||||
[yellow::b]Page Down[white::-] / [yellow::b]Ctrl-f[white::-]
|
||||
Scroll down by a full page.
|
||||
|
||||
[yellow::b]Page Up[white::-] / [yellow::b]Ctrl-b[white::-]
|
||||
Scroll up by a full page.
|
||||
|
||||
[yellow::b]Enter[white::-]
|
||||
Navigate to a nested view:
|
||||
- In Buckets View: Navigate to the selected bucket's records.
|
||||
- In Records View: Navigate to the selected record's detailed view.
|
||||
|
||||
[yellow::b]Escape[white::-]
|
||||
Return to the previous page, opposite of [yellow::b]Enter[white::-].
|
||||
|
||||
|
||||
[green::b]Buckets View Interactions[white::-]
|
||||
|
||||
[yellow::b]Space[white::-]
|
||||
Expand or collapse the selected bucket to show or hide its nested buckets.
|
16
cmd/frostfs-lens/internal/tuiutil/help-pages/searching.txt
Normal file
16
cmd/frostfs-lens/internal/tuiutil/help-pages/searching.txt
Normal file
|
@ -0,0 +1,16 @@
|
|||
[green::b]Searching[white::-]
|
||||
|
||||
[yellow::b]/[white::-]
|
||||
Initiate a search prompt. Prompt syntax: [yellow::b]<tag>:<args>[white::-]. Leading and trailing white spaces are ignored. See [green::b]Available Search Filters[white::-] section for available filter tags.
|
||||
|
||||
[yellow::b]Enter[white::-]
|
||||
Execute the search based on the entered prompt. An error message will display if the prompt is invalid.
|
||||
|
||||
[yellow::b]Escape[white::-]
|
||||
Exit the search prompt.
|
||||
|
||||
|
||||
[green::b]Available Search Filters[white::-]
|
||||
|
||||
%s
|
||||
If you want to define a new filter, see [green::b]Development[white::-] section.
|
|
@ -1,6 +1,7 @@
|
|||
package tuiutil
|
||||
|
||||
import (
|
||||
_ "embed"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
|
@ -8,76 +9,101 @@ import (
|
|||
"github.com/rivo/tview"
|
||||
)
|
||||
|
||||
const text = `[green]Navigation[white]
|
||||
var (
|
||||
//go:embed help-pages/navigation.txt
|
||||
navigationHelpText string
|
||||
|
||||
- [yellow]Up arrow[white] Move up.
|
||||
//go:embed help-pages/searching.txt
|
||||
searchingHelpText string
|
||||
|
||||
- [yellow]Down arrow[white] Move down.
|
||||
|
||||
- [yellow]Space[white] Show a bucket's subbuckets if on the buckets view.
|
||||
|
||||
- [yellow]Enter[white] Show a bucket's records if on the buckets view,
|
||||
or show a record's detailed view if on the
|
||||
records view. It always navigates to a new page.
|
||||
|
||||
- [yellow]Escape[white] Go to the previous page.
|
||||
|
||||
|
||||
[green]Searching[white]
|
||||
|
||||
- [yellow]/[white] Start search prompt.
|
||||
Prompt syntax is <filter tag>:<filter args...>.
|
||||
It tolerates leading and trailing white space.
|
||||
|
||||
- [yellow]Enter[white] Start searching based on prompt. It shows an
|
||||
error message if the prompt is invalid.
|
||||
|
||||
- [yellow]Escape[white] Stop search prompt.
|
||||
|
||||
|
||||
[green]Available search filters[white]
|
||||
|
||||
%s
|
||||
`
|
||||
//go:embed help-pages/development.txt
|
||||
developmentHelpText string
|
||||
)
|
||||
|
||||
type HelpPage struct {
|
||||
*tview.Box
|
||||
view *tview.TextView
|
||||
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(),
|
||||
view: tview.NewTextView(),
|
||||
Box: tview.NewBox(),
|
||||
filters: filters,
|
||||
filterHints: hints,
|
||||
}
|
||||
|
||||
filtersText := strings.Builder{}
|
||||
page := tview.NewTextView()
|
||||
page.SetDynamicColors(true)
|
||||
page.SetText(navigationHelpText)
|
||||
hp.addPage(page)
|
||||
|
||||
lastIndex := len(filters) - 1
|
||||
for index, filter := range filters {
|
||||
filtersText.WriteString("- ")
|
||||
filtersText.WriteString(filter)
|
||||
filtersText.WriteRune(' ')
|
||||
filtersText.WriteString(hints[filter])
|
||||
if index != lastIndex {
|
||||
filtersText.WriteRune('\n')
|
||||
}
|
||||
}
|
||||
page = tview.NewTextView()
|
||||
page.SetDynamicColors(true)
|
||||
page.SetText(fmt.Sprintf(searchingHelpText, hp.getFiltersText()))
|
||||
hp.addPage(page)
|
||||
|
||||
hp.view.SetDynamicColors(true)
|
||||
hp.view.SetText(fmt.Sprintf(text, filtersText.String()))
|
||||
page = tview.NewTextView()
|
||||
page.SetDynamicColors(true)
|
||||
page.SetText(developmentHelpText)
|
||||
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 "\tNo filters defined.\n"
|
||||
}
|
||||
|
||||
filtersText := strings.Builder{}
|
||||
gapSize := 4
|
||||
|
||||
tagMaxWidth := 3
|
||||
for _, filter := range hp.filters {
|
||||
tagMaxWidth = max(tagMaxWidth, len(filter))
|
||||
}
|
||||
filtersText.WriteString("\t[yellow::b]Tag")
|
||||
filtersText.WriteString(strings.Repeat(" ", gapSize))
|
||||
filtersText.WriteString("\tArgs[white::-]\n\n")
|
||||
|
||||
for _, filter := range hp.filters {
|
||||
filtersText.WriteRune('\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.view.SetRect(x, y, width, height)
|
||||
hp.view.Draw(screen)
|
||||
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)) {
|
||||
hp.view.InputHandler()(event, 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) {})
|
||||
})
|
||||
}
|
||||
|
|
|
@ -102,7 +102,7 @@ func NewUI(ctx context.Context, app *tview.Application, db *bbolt.DB) *UI {
|
|||
|
||||
ui.helpBar.SetBackgroundColor(barBackgroundColor)
|
||||
ui.helpBar.SetTextColor(barTextColor)
|
||||
ui.helpBar.SetText(" Press Escape to quit")
|
||||
ui.helpBar.SetText(" Press Enter for next page or Escape to exit help ")
|
||||
|
||||
ui.searchErrorBar.SetBackgroundColor(barTextColor)
|
||||
ui.searchErrorBar.SetTextColor(barAlertTextColor)
|
||||
|
|
Loading…
Reference in a new issue