Files
trufflehog/pkg/tui/pages/wizard_intro/item.go
Honandmcastorina 47c2b6bed9
Lint / lint (push) Waiting to run
Release / Release (push) Waiting to run
Scan for secrets / test (push) Waiting to run
Snifftest / Run Snifftest (push) Waiting to run
Test / test (push) Waiting to run
Test / test-detectors (push) Waiting to run
Test / test-community (push) Waiting to run
Add terminal UI (#1593)
* Init attempt at tui with bubble tea.

Co-authored-by: mcastorina <[email protected]>

* Add starting and source selection options

Co-authored-by: mcastorina <[email protected]>

* Rewrite models into a state machine

* Update source descriptions

* Make subpages implement tea.Model

* Rename page0 and page1 to be more descriptive

* Adjust styling and adding color consts

Co-authored-by: mcastorina <[email protected]>

* Add helper generic function to call Update and type cast

* Setup plumbing for source configuration page

* Use CLI introspection for source configuration (WIP)

* Experiment with table view

* Replace table with form fields

Co-authored-by: mcastorina <[email protected]>

* Change 🔒 to 💸

* Copy components from soft-serve

Co-authored-by: hxnyk <[email protected]>

* Copy styles from soft-serve

Co-authored-by: hxnyk <[email protected]>

* Copy common from soft-serve

Co-authored-by: hxnyk <[email protected]>

* Refactor into pages

This is still a WIP, but the main structure is there.

Co-authored-by: hxnyk <[email protected]>

* Trying out selector for wizard intro

Co-authored-by: mcastorina <[email protected]>

* Use selector with custom View

Co-authored-by: hxnyk <[email protected]>

* Change Item to be an enum

Co-authored-by: hxnyk <[email protected]>

* Add link pages

Co-authored-by: mcastorina <[email protected]>

* Update source select to use selector

Co-authored-by: mcastorina <[email protected]>

* Delete source configure page and add blank tabs

Co-authored-by: hxnyk <[email protected]>

* Add tab placeholder pages for configurationi

Co-authored-by: mcastorina <[email protected]>

* Added headers and style to each tab

Co-authored-by: hxnyk <[email protected]>

* Update with new sources

* Remove kingpin attribute from SourceItem

* Add basic form field and source structuring

* Hookup git form fields with an underlying textinput component

Co-authored-by: hxnyk <[email protected]>

* Update forms for git and github

Co-authored-by: mcastorina <[email protected]>

* Add labels per text input

* Add sources and adjust styling

* add basic trufflehog configuration page

* Add skip button to textinputs component

* Emit and handle textinputs skip/submit button commands

* Don't quit when q is pressed on the sourceConfigurePage

* Build trufflehog command based on source config vals

Co-authored-by: mcastorina <[email protected]>

* Build flags based on truffle config inputs

* Update summary section

* Add generated truffle fields

Co-authored-by: mcastorina <[email protected]>

* update summary to correctly print info

* Go back a page when escape key is pressed

* WIP run page list

Co-authored-by: hxnyk <[email protected]>

* Allow running trufflehog from the run page

Co-authored-by: hxnyk <[email protected]>

* Add option to view help docs

Co-authored-by: mcastorina <[email protected]>

* comment out unused styles and remove unused types

* Capitalize H in TruffleHog

* remove unneeded fmt.Sprintf

---------

Co-authored-by: mcastorina <[email protected]>
2023-08-09 13:13:55 -07:00

138 lines
3.7 KiB
Go

package wizard_intro
import (
"fmt"
"io"
"strings"
"github.com/charmbracelet/bubbles/key"
"github.com/charmbracelet/bubbles/list"
tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/lipgloss"
"github.com/trufflesecurity/trufflehog/v3/pkg/tui/common"
)
// Item represents a single item in the selector.
type Item int
// ID implements selector.IdentifiableItem.
func (i Item) ID() string {
return i.String()
}
// Title returns the item title. Implements list.DefaultItem.
func (i Item) Title() string { return i.String() }
// Description returns the item description. Implements list.DefaultItem.
func (i Item) Description() string { return "" }
// FilterValue implements list.Item.
func (i Item) FilterValue() string { return i.Title() }
// Command returns the item Command view.
func (i Item) Command() string {
return i.Title()
}
// ItemDelegate is the delegate for the item.
type ItemDelegate struct {
common *common.Common
}
// Width returns the item width.
func (d ItemDelegate) Width() int {
width := d.common.Styles.MenuItem.GetHorizontalFrameSize() + d.common.Styles.MenuItem.GetWidth()
return width
}
// Height returns the item height. Implements list.ItemDelegate.
func (d ItemDelegate) Height() int {
height := d.common.Styles.MenuItem.GetVerticalFrameSize() + d.common.Styles.MenuItem.GetHeight()
return height
}
// Spacing returns the spacing between items. Implements list.ItemDelegate.
func (d ItemDelegate) Spacing() int { return 1 }
// Update implements list.ItemDelegate.
func (d ItemDelegate) Update(msg tea.Msg, m *list.Model) tea.Cmd {
idx := m.Index()
item, ok := m.SelectedItem().(Item)
if !ok {
return nil
}
switch msg := msg.(type) {
case tea.KeyMsg:
switch {
case key.Matches(msg, d.common.KeyMap.Copy):
d.common.Copy.Copy(item.Command())
return m.SetItem(idx, item)
}
}
return nil
}
// Render implements list.ItemDelegate.
func (d ItemDelegate) Render(w io.Writer, m list.Model, index int, listItem list.Item) {
i := listItem.(Item)
s := strings.Builder{}
var matchedRunes []int
// Conditions
var (
isSelected = index == m.Index()
isFiltered = m.FilterState() == list.Filtering || m.FilterState() == list.FilterApplied
)
styles := d.common.Styles.RepoSelector.Normal
if isSelected {
styles = d.common.Styles.RepoSelector.Active
}
title := i.Title()
title = common.TruncateString(title, m.Width()-styles.Base.GetHorizontalFrameSize())
// if i.repo.IsPrivate() {
// title += " 🔒"
// }
if isSelected {
title += " "
}
updatedStr := " Updated"
if m.Width()-styles.Base.GetHorizontalFrameSize()-lipgloss.Width(updatedStr)-lipgloss.Width(title) <= 0 {
updatedStr = ""
}
updatedStyle := styles.Updated.Copy().
Align(lipgloss.Right).
Width(m.Width() - styles.Base.GetHorizontalFrameSize() - lipgloss.Width(title))
updated := updatedStyle.Render(updatedStr)
if isFiltered && index < len(m.VisibleItems()) {
// Get indices of matched characters
matchedRunes = m.MatchesForItem(index)
}
if isFiltered {
unmatched := styles.Title.Copy().Inline(true)
matched := unmatched.Copy().Underline(true)
title = lipgloss.StyleRunes(title, matchedRunes, matched, unmatched)
}
title = styles.Title.Render(title)
desc := i.Description()
desc = common.TruncateString(desc, m.Width()-styles.Base.GetHorizontalFrameSize())
desc = styles.Desc.Render(desc)
s.WriteString(lipgloss.JoinHorizontal(lipgloss.Bottom, title, updated))
s.WriteRune('\n')
s.WriteString(desc)
s.WriteRune('\n')
cmd := common.TruncateString(i.Command(), m.Width()-styles.Base.GetHorizontalFrameSize())
cmd = styles.Command.Render(cmd)
s.WriteString(cmd)
fmt.Fprint(w,
d.common.Zone.Mark(i.ID(),
styles.Base.Render(s.String()),
),
)
}