|
| 1 | +package proxy |
| 2 | + |
| 3 | +import ( |
| 4 | + "fmt" |
| 5 | + "strings" |
| 6 | + |
| 7 | + "github.com/AlecAivazis/survey/v2" |
| 8 | + "github.com/charmbracelet/lipgloss" |
| 9 | + accessv1alpha1 "github.com/common-fate/sdk/gen/commonfate/access/v1alpha1" |
| 10 | + "github.com/mattn/go-runewidth" |
| 11 | +) |
| 12 | + |
| 13 | +func filterMultiToken(filterValue string, optValue string, optIndex int) bool { |
| 14 | + optValue = strings.ToLower(optValue) |
| 15 | + filters := strings.Split(strings.ToLower(filterValue), " ") |
| 16 | + for _, filter := range filters { |
| 17 | + if !strings.Contains(optValue, filter) { |
| 18 | + return false |
| 19 | + } |
| 20 | + } |
| 21 | + return true |
| 22 | +} |
| 23 | +func PromptEntitlements(entitlements []*accessv1alpha1.Entitlement, targetHeader string, roleHeader string, promptMessage string) (*accessv1alpha1.Entitlement, error) { |
| 24 | + type Column struct { |
| 25 | + Title string |
| 26 | + Width int |
| 27 | + } |
| 28 | + cols := []Column{{Title: targetHeader, Width: 40}, {Title: roleHeader, Width: 40}} |
| 29 | + var s = make([]string, 0, len(cols)) |
| 30 | + for _, col := range cols { |
| 31 | + style := lipgloss.NewStyle().Width(col.Width).MaxWidth(col.Width).Inline(true) |
| 32 | + renderedCell := style.Render(runewidth.Truncate(col.Title, col.Width, "…")) |
| 33 | + s = append(s, lipgloss.NewStyle().Bold(true).Padding(0).Render(renderedCell)) |
| 34 | + } |
| 35 | + header := lipgloss.NewStyle().PaddingLeft(2).Render(lipgloss.JoinHorizontal(lipgloss.Left, s...)) |
| 36 | + var options []string |
| 37 | + optionsMap := make(map[string]*accessv1alpha1.Entitlement) |
| 38 | + for i, entitlement := range entitlements { |
| 39 | + style := lipgloss.NewStyle().Width(cols[0].Width).MaxWidth(cols[0].Width).Inline(true) |
| 40 | + target := lipgloss.NewStyle().Bold(true).Padding(0).Render(style.Render(runewidth.Truncate(entitlement.Target.Display(), cols[0].Width, "…"))) |
| 41 | + |
| 42 | + style = lipgloss.NewStyle().Width(cols[1].Width).MaxWidth(cols[1].Width).Inline(true) |
| 43 | + role := lipgloss.NewStyle().Bold(true).Padding(0).Render(style.Render(runewidth.Truncate(entitlement.Role.Display(), cols[1].Width, "…"))) |
| 44 | + |
| 45 | + option := lipgloss.JoinHorizontal(lipgloss.Left, target, role) |
| 46 | + options = append(options, option) |
| 47 | + optionsMap[option] = entitlements[i] |
| 48 | + } |
| 49 | + |
| 50 | + originalSelectTemplate := survey.SelectQuestionTemplate |
| 51 | + survey.SelectQuestionTemplate = fmt.Sprintf(` |
| 52 | +{{- define "option"}} |
| 53 | + {{- if eq .SelectedIndex .CurrentIndex }}{{color .Config.Icons.SelectFocus.Format }}{{ .Config.Icons.SelectFocus.Text }} {{else}}{{color "default"}} {{end}} |
| 54 | + {{- .CurrentOpt.Value}}{{ if ne ($.GetDescription .CurrentOpt) "" }} - {{color "cyan"}}{{ $.GetDescription .CurrentOpt }}{{end}} |
| 55 | + {{- color "reset"}} |
| 56 | +{{end}} |
| 57 | +{{- if .ShowHelp }}{{- color .Config.Icons.Help.Format }}{{ .Config.Icons.Help.Text }} {{ .Help }}{{color "reset"}}{{"\n"}}{{end}} |
| 58 | +{{- color .Config.Icons.Question.Format }}{{ .Config.Icons.Question.Text }} {{color "reset"}} |
| 59 | +{{- color "default+hb"}}{{ .Message }}{{ .FilterMessage }}{{color "reset"}} |
| 60 | +{{- if .ShowAnswer}}{{color "cyan"}} {{.Answer}}{{color "reset"}}{{"\n"}} |
| 61 | +{{- else}} |
| 62 | + {{- " "}}{{- color "cyan"}}[Use arrows to move, type to filter{{- if and .Help (not .ShowHelp)}}, {{ .Config.HelpInput }} for more help{{end}}]{{color "reset"}} |
| 63 | + {{- "\n"}} |
| 64 | +%s{{- "\n"}} |
| 65 | + {{- range $ix, $option := .PageEntries}} |
| 66 | + {{- template "option" $.IterateOption $ix $option}} |
| 67 | + {{- end}} |
| 68 | +{{- end}}`, header) |
| 69 | + |
| 70 | + var out string |
| 71 | + err := survey.AskOne(&survey.Select{ |
| 72 | + Message: promptMessage, |
| 73 | + Options: options, |
| 74 | + Filter: filterMultiToken, |
| 75 | + }, &out) |
| 76 | + if err != nil { |
| 77 | + return nil, err |
| 78 | + } |
| 79 | + |
| 80 | + survey.SelectQuestionTemplate = originalSelectTemplate |
| 81 | + |
| 82 | + return optionsMap[out], nil |
| 83 | +} |
0 commit comments