permission.go

  1package dialog
  2
  3import (
  4	"github.com/charmbracelet/bubbles/key"
  5	tea "github.com/charmbracelet/bubbletea"
  6	"github.com/charmbracelet/lipgloss"
  7	"github.com/kujtimiihoxha/termai/internal/permission"
  8	"github.com/kujtimiihoxha/termai/internal/tui/components/core"
  9	"github.com/kujtimiihoxha/termai/internal/tui/layout"
 10	"github.com/kujtimiihoxha/termai/internal/tui/styles"
 11	"github.com/kujtimiihoxha/termai/internal/tui/util"
 12
 13	"github.com/charmbracelet/huh"
 14)
 15
 16type PermissionAction string
 17
 18// Permission responses
 19const (
 20	PermissionAllow           PermissionAction = "allow"
 21	PermissionAllowForSession PermissionAction = "allow_session"
 22	PermissionDeny            PermissionAction = "deny"
 23)
 24
 25// PermissionResponseMsg represents the user's response to a permission request
 26type PermissionResponseMsg struct {
 27	Permission permission.PermissionRequest
 28	Action     PermissionAction
 29}
 30
 31// Width and height constants for the dialog
 32var (
 33	permissionWidth  = 60
 34	permissionHeight = 10
 35)
 36
 37// PermissionDialog interface for permission dialog component
 38type PermissionDialog interface {
 39	tea.Model
 40	layout.Sizeable
 41	layout.Bindings
 42}
 43
 44// permissionDialogCmp is the implementation of PermissionDialog
 45type permissionDialogCmp struct {
 46	form       *huh.Form
 47	content    string
 48	width      int
 49	height     int
 50	permission permission.PermissionRequest
 51}
 52
 53func (p *permissionDialogCmp) Init() tea.Cmd {
 54	return nil
 55}
 56
 57func (p *permissionDialogCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
 58	var cmds []tea.Cmd
 59
 60	// Process the form
 61	form, cmd := p.form.Update(msg)
 62	if f, ok := form.(*huh.Form); ok {
 63		p.form = f
 64		cmds = append(cmds, cmd)
 65	}
 66
 67	if p.form.State == huh.StateCompleted {
 68		// Get the selected action
 69		action := p.form.GetString("action")
 70
 71		// Close the dialog and return the response
 72		return p, tea.Batch(
 73			util.CmdHandler(core.DialogCloseMsg{}),
 74			util.CmdHandler(PermissionResponseMsg{Action: PermissionAction(action), Permission: p.permission}),
 75		)
 76	}
 77
 78	return p, tea.Batch(cmds...)
 79}
 80
 81func (p *permissionDialogCmp) View() string {
 82	contentStyle := lipgloss.NewStyle().
 83		Width(p.width).
 84		Padding(1, 0).
 85		Foreground(styles.Text).
 86		Align(lipgloss.Center)
 87
 88	return lipgloss.JoinVertical(
 89		lipgloss.Center,
 90		contentStyle.Render(p.content),
 91		p.form.View(),
 92	)
 93}
 94
 95func (p *permissionDialogCmp) GetSize() (int, int) {
 96	return p.width, p.height
 97}
 98
 99func (p *permissionDialogCmp) SetSize(width int, height int) {
100	p.width = width
101	p.height = height
102}
103
104func (p *permissionDialogCmp) BindingKeys() []key.Binding {
105	return p.form.KeyBinds()
106}
107
108func newPermissionDialogCmp(permission permission.PermissionRequest, content string) PermissionDialog {
109	// Create a note field for displaying the content
110
111	// Create select field for the permission options
112	selectOption := huh.NewSelect[string]().
113		Key("action").
114		Options(
115			huh.NewOption("Allow", string(PermissionAllow)),
116			huh.NewOption("Allow for this session", string(PermissionAllowForSession)),
117			huh.NewOption("Deny", string(PermissionDeny)),
118		).
119		Title("Permission Request")
120
121	// Apply theme
122	theme := styles.HuhTheme()
123
124	// Setup form width and height
125	form := huh.NewForm(huh.NewGroup(selectOption)).
126		WithWidth(permissionWidth - 2).
127		WithShowHelp(false).
128		WithTheme(theme).
129		WithShowErrors(false)
130
131	// Focus the form for immediate interaction
132	selectOption.Focus()
133
134	return &permissionDialogCmp{
135		permission: permission,
136		form:       form,
137		content:    content,
138		width:      permissionWidth,
139		height:     permissionHeight,
140	}
141}
142
143// NewPermissionDialogCmd creates a new permission dialog command
144func NewPermissionDialogCmd(permission permission.PermissionRequest, content string) tea.Cmd {
145	permDialog := newPermissionDialogCmp(permission, content)
146
147	// Create the dialog layout
148	dialogPane := layout.NewSinglePane(
149		permDialog.(*permissionDialogCmp),
150		layout.WithSignlePaneSize(permissionWidth+2, permissionHeight+2),
151		layout.WithSinglePaneBordered(true),
152		layout.WithSinglePaneFocusable(true),
153		layout.WithSinglePaneActiveColor(styles.Blue),
154		layout.WithSignlePaneBorderText(map[layout.BorderPosition]string{
155			layout.TopMiddleBorder: " Permission Required ",
156		}),
157	)
158
159	// Focus the dialog
160	dialogPane.Focus()
161
162	// Return the dialog command
163	return util.CmdHandler(core.DialogMsg{
164		Content: dialogPane,
165	})
166}
167