Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion rocketpool-cli/service/config/addon-gww.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ func (configPage *AddonGwwPage) createContent() {

// Set up the form items
configPage.enabledBox = createParameterizedCheckbox(enabledParam)
configPage.otherParams = createParameterizedFormItems(otherParams, configPage.layout.descriptionBox)
configPage.otherParams = createParameterizedFormItems(otherParams, configPage.layout)

// Map the parameters to the form items in the layout
configPage.layout.mapParameterizedFormItems(configPage.enabledBox)
Expand Down
2 changes: 1 addition & 1 deletion rocketpool-cli/service/config/addon-rescuenode.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ func (configPage *AddonRescueNodePage) createContent() {

// Set up the form items
configPage.enabledBox = createParameterizedCheckbox(enabledParam)
configPage.otherParams = createParameterizedFormItems(otherParams, configPage.layout.descriptionBox)
configPage.otherParams = createParameterizedFormItems(otherParams, configPage.layout)

// Map the parameters to the form items in the layout
configPage.layout.mapParameterizedFormItems(configPage.enabledBox)
Expand Down
226 changes: 77 additions & 149 deletions rocketpool-cli/service/config/config-form.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,33 +13,82 @@ import (

// A form item linked to a Parameter
type parameterizedFormItem struct {
parameter *cfgtypes.Parameter
item tview.FormItem
parameter *cfgtypes.Parameter
item tview.FormItem
onCommitError func(message string)
}

func (pfi *parameterizedFormItem) reportCommitError(message string) {
if pfi.onCommitError != nil {
pfi.onCommitError(message)
}
}

func (pfi *parameterizedFormItem) clearCommitError() {
if pfi.onCommitError != nil {
pfi.onCommitError("")
}
}

func (pfi *parameterizedFormItem) commit() {
switch pfi.item.(type) {
case *tview.Checkbox:
pfi.parameter.Value = pfi.item.(*tview.Checkbox).IsChecked()
pfi.clearCommitError()
case *tview.InputField:
var err error
inputField := pfi.item.(*tview.InputField)
switch pfi.parameter.Type {
case cfgtypes.ParameterType_Int:
pfi.parameter.Value, err = strconv.ParseInt(inputField.GetText(), 0, 0)
if err != nil {
pfi.reportCommitError(fmt.Sprintf("INVALID INTEGER VALUE FOR %s", pfi.parameter.Name))
return
}
case cfgtypes.ParameterType_Uint:
pfi.parameter.Value, err = strconv.ParseUint(inputField.GetText(), 0, 0)
if err != nil {
pfi.reportCommitError(fmt.Sprintf("INVALID UNSIGNED INTEGER VALUE FOR %s", pfi.parameter.Name))
return
}
case cfgtypes.ParameterType_Uint16:
pfi.parameter.Value, err = strconv.ParseUint(inputField.GetText(), 0, 16)
if err != nil {
pfi.reportCommitError(fmt.Sprintf("INVALID VALUE FOR %s (MUST BE 0–65535)", pfi.parameter.Name))
return
}
case cfgtypes.ParameterType_String, cfgtypes.ParameterType_Float:
pfi.parameter.Value = strings.TrimSpace(inputField.GetText())
default:
panic(fmt.Sprintf("Unknown parameter type for text field %v", pfi.parameter.Type))
}
pfi.clearCommitError()
default:
panic(fmt.Sprintf("Unknown form item type %v", pfi.item))
}
}

// Create a list of form items based on a set of parameters
func createParameterizedFormItems(params []*cfgtypes.Parameter, descriptionBox *tview.TextView) []*parameterizedFormItem {
func createParameterizedFormItems(params []*cfgtypes.Parameter, layout *standardLayout) []*parameterizedFormItem {
formItems := []*parameterizedFormItem{}
for _, param := range params {
var item *parameterizedFormItem
switch param.Type {
case cfgtypes.ParameterType_Bool:
item = createParameterizedCheckbox(param)
case cfgtypes.ParameterType_Int:
case cfgtypes.ParameterType_Int, cfgtypes.ParameterType_Uint, cfgtypes.ParameterType_Uint16:
item = createParameterizedIntField(param)
case cfgtypes.ParameterType_Uint:
item = createParameterizedUintField(param)
case cfgtypes.ParameterType_Uint16:
item = createParameterizedUint16Field(param)
case cfgtypes.ParameterType_String:
case cfgtypes.ParameterType_String, cfgtypes.ParameterType_Float:
item = createParameterizedStringField(param)
case cfgtypes.ParameterType_Choice:
item = createParameterizedDropDown(param, descriptionBox)
case cfgtypes.ParameterType_Float:
item = createParameterizedStringField(param)
item = createParameterizedDropDown(param, layout.descriptionBox)
default:
panic(fmt.Sprintf("Unknown parameter type %v", param))
}
if layout != nil {
item.onCommitError = layout.showCommitError
layout.setItemNavCapture(item)
}
formItems = append(formItems, item)
}

Expand All @@ -50,142 +99,44 @@ func createParameterizedFormItems(params []*cfgtypes.Parameter, descriptionBox *
func createParameterizedCheckbox(param *cfgtypes.Parameter) *parameterizedFormItem {
item := tview.NewCheckbox().
SetLabel(param.Name).
SetChecked(param.Value == true).
SetChangedFunc(func(checked bool) {
param.Value = checked
})
item.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey {
switch event.Key() {
case tcell.KeyDown, tcell.KeyTab:
return tcell.NewEventKey(tcell.KeyTab, 0, 0)
case tcell.KeyUp, tcell.KeyBacktab:
return tcell.NewEventKey(tcell.KeyBacktab, 0, 0)
default:
return event
}
})

return &parameterizedFormItem{
SetChecked(param.Value == true)
out := &parameterizedFormItem{
parameter: param,
item: item,
}
}

// Create a standard int field
func createParameterizedIntField(param *cfgtypes.Parameter) *parameterizedFormItem {
item := tview.NewInputField().
SetLabel(param.Name).
SetAcceptanceFunc(tview.InputFieldInteger)
item.SetDoneFunc(func(key tcell.Key) {
if key == tcell.KeyEscape {
item.SetText("")
} else {
value, err := strconv.ParseInt(item.GetText(), 0, 0)
if err != nil {
// TODO: show error modal?
item.SetText("")
} else {
param.Value = int(value)
}
}
})
item.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey {
switch event.Key() {
case tcell.KeyDown, tcell.KeyTab:
return tcell.NewEventKey(tcell.KeyTab, 0, 0)
case tcell.KeyUp, tcell.KeyBacktab:
return tcell.NewEventKey(tcell.KeyBacktab, 0, 0)
default:
return event
}
item.SetChangedFunc(func(checked bool) {
out.commit()
})

return &parameterizedFormItem{
parameter: param,
item: item,
}
return out
}

// Create a standard uint field
func createParameterizedUintField(param *cfgtypes.Parameter) *parameterizedFormItem {
// Create a standard int field
func createParameterizedIntField(param *cfgtypes.Parameter) *parameterizedFormItem {
item := tview.NewInputField().
SetLabel(param.Name).
SetAcceptanceFunc(tview.InputFieldInteger)
item.SetDoneFunc(func(key tcell.Key) {
if key == tcell.KeyEscape {
item.SetText("")
} else {
value, err := strconv.ParseUint(item.GetText(), 0, 0)
if err != nil {
// TODO: show error modal?
item.SetText("")
} else {
param.Value = int(value)
}
}
})
item.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey {
switch event.Key() {
case tcell.KeyDown, tcell.KeyTab:
return tcell.NewEventKey(tcell.KeyTab, 0, 0)
case tcell.KeyUp, tcell.KeyBacktab:
return tcell.NewEventKey(tcell.KeyBacktab, 0, 0)
default:
return event
}
})

return &parameterizedFormItem{
out := &parameterizedFormItem{
parameter: param,
item: item,
}
}

// Create a standard uint16 field
func createParameterizedUint16Field(param *cfgtypes.Parameter) *parameterizedFormItem {
item := tview.NewInputField().
SetLabel(param.Name).
SetAcceptanceFunc(tview.InputFieldInteger)
item.SetDoneFunc(func(key tcell.Key) {
if key == tcell.KeyEscape {
item.SetText("")
} else {
value, err := strconv.ParseUint(item.GetText(), 0, 16)
if err != nil {
// TODO: show error modal?
item.SetText("")
} else {
param.Value = int(value)
}
}
})
item.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey {
switch event.Key() {
case tcell.KeyDown, tcell.KeyTab:
return tcell.NewEventKey(tcell.KeyTab, 0, 0)
case tcell.KeyUp, tcell.KeyBacktab:
return tcell.NewEventKey(tcell.KeyBacktab, 0, 0)
default:
return event
}
out.commit()
})

return &parameterizedFormItem{
parameter: param,
item: item,
}
return out
}

// Create a standard string field
func createParameterizedStringField(param *cfgtypes.Parameter) *parameterizedFormItem {
item := tview.NewInputField().
SetLabel(param.Name)
out := &parameterizedFormItem{
parameter: param,
item: item,
}
item.SetDoneFunc(func(key tcell.Key) {
if key == tcell.KeyEscape {
item.SetText("")
} else {
param.Value = strings.TrimSpace(item.GetText())
}
out.commit()
})
item.SetAcceptanceFunc(func(textToCheck string, lastChar rune) bool {
if param.MaxLength > 0 {
Expand All @@ -196,21 +147,8 @@ func createParameterizedStringField(param *cfgtypes.Parameter) *parameterizedFor
// TODO: regex support
return true
})
item.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey {
switch event.Key() {
case tcell.KeyDown, tcell.KeyTab:
return tcell.NewEventKey(tcell.KeyTab, 0, 0)
case tcell.KeyUp, tcell.KeyBacktab:
return tcell.NewEventKey(tcell.KeyBacktab, 0, 0)
default:
return event
}
})

return &parameterizedFormItem{
parameter: param,
item: item,
}
return out
}

// Create a standard choice field
Expand All @@ -233,16 +171,6 @@ func createParameterizedDropDown(param *cfgtypes.Parameter, descriptionBox *tvie
descriptionBox.SetText(descriptions[index])
})
item.SetTextOptions(" ", " ", "", "", "")
item.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey {
switch event.Key() {
case tcell.KeyDown, tcell.KeyTab:
return tcell.NewEventKey(tcell.KeyTab, 0, 0)
case tcell.KeyUp, tcell.KeyBacktab:
return tcell.NewEventKey(tcell.KeyBacktab, 0, 0)
default:
return event
}
})
list := item.GetList()
list.SetSelectedBackgroundColor(tcell.Color46)
list.SetSelectedTextColor(tcell.ColorBlack)
Expand Down
13 changes: 13 additions & 0 deletions rocketpool-cli/service/config/form.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ type Form struct {

// An optional function which is called when the form item changes.
changed func(index int)

// When set, navigation between form items is blocked while this returns true.
navigationBlocked func() bool
}

// NewForm returns a new form.
Expand Down Expand Up @@ -355,6 +358,13 @@ func (f *Form) SetCancelFunc(callback func()) *Form {
return f
}

// SetNavigationBlocked sets a callback that blocks Tab/Enter/Backtab navigation
// between form items while it returns true.
func (f *Form) SetNavigationBlocked(blocked func() bool) *Form {
f.navigationBlocked = blocked
return f
}

// SetChangedFunc sets a handler which is called when the user moves to
// another field in the form.
func (f *Form) SetChangedFunc(callback func(index int)) *Form {
Expand Down Expand Up @@ -574,6 +584,9 @@ func (f *Form) Focus(delegate func(p tview.Primitive)) {
f.focusedElement = 0
}
handler := func(key tcell.Key) {
if f.navigationBlocked != nil && f.navigationBlocked() {
return
}
switch key {
case tcell.KeyTab, tcell.KeyEnter:
f.focusedElement++
Expand Down
2 changes: 1 addition & 1 deletion rocketpool-cli/service/config/settings-alerting.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ func (configPage *AlertingConfigPage) createContent() {
configPage.layout.setupEscapeReturnHomeHandler(configPage.mainDisplay, configPage.homePage)

// Set up the UI components
allItems := createParameterizedFormItems(configPage.masterConfig.Alertmanager.GetParameters(), configPage.layout.descriptionBox)
allItems := createParameterizedFormItems(configPage.masterConfig.Alertmanager.GetParameters(), configPage.layout)

// Map the config parameters to the UI form items:
configPage.layout.mapParameterizedFormItems(allItems...)
Expand Down
4 changes: 2 additions & 2 deletions rocketpool-cli/service/config/settings-commit-boost.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,8 @@ func (configPage *CommitBoostConfigPage) createContent() {
}
externalParams := []*cfgtypes.Parameter{&configPage.masterConfig.CommitBoost.ExternalUrl}

configPage.localItems = createParameterizedFormItems(localParams, configPage.layout.descriptionBox)
configPage.externalItems = createParameterizedFormItems(externalParams, configPage.layout.descriptionBox)
configPage.localItems = createParameterizedFormItems(localParams, configPage.layout)
configPage.externalItems = createParameterizedFormItems(externalParams, configPage.layout)

// Relay checkboxes - using CommitBoost's own relay parameters
configPage.flashbotsBox = createParameterizedCheckbox(&configPage.masterConfig.CommitBoost.FlashbotsRelay)
Expand Down
22 changes: 11 additions & 11 deletions rocketpool-cli/service/config/settings-consensus.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,17 +65,17 @@ func (configPage *ConsensusConfigPage) createContent() {
configPage.ccModeDropdown = createParameterizedDropDown(&configPage.masterConfig.ConsensusClientMode, configPage.layout.descriptionBox)
configPage.ccDropdown = createParameterizedDropDown(&configPage.masterConfig.ConsensusClient, configPage.layout.descriptionBox)
configPage.externalCcDropdown = createParameterizedDropDown(&configPage.masterConfig.ExternalConsensusClient, configPage.layout.descriptionBox)
configPage.ccCommonItems = createParameterizedFormItems(configPage.masterConfig.ConsensusCommon.GetParameters(), configPage.layout.descriptionBox)
configPage.lighthouseItems = createParameterizedFormItems(configPage.masterConfig.Lighthouse.GetParameters(), configPage.layout.descriptionBox)
configPage.lodestarItems = createParameterizedFormItems(configPage.masterConfig.Lodestar.GetParameters(), configPage.layout.descriptionBox)
configPage.nimbusItems = createParameterizedFormItems(configPage.masterConfig.Nimbus.GetParameters(), configPage.layout.descriptionBox)
configPage.prysmItems = createParameterizedFormItems(configPage.masterConfig.Prysm.GetParameters(), configPage.layout.descriptionBox)
configPage.tekuItems = createParameterizedFormItems(configPage.masterConfig.Teku.GetParameters(), configPage.layout.descriptionBox)
configPage.externalLighthouseItems = createParameterizedFormItems(configPage.masterConfig.ExternalLighthouse.GetParameters(), configPage.layout.descriptionBox)
configPage.externalNimbusItems = createParameterizedFormItems(configPage.masterConfig.ExternalNimbus.GetParameters(), configPage.layout.descriptionBox)
configPage.externalLodestarItems = createParameterizedFormItems(configPage.masterConfig.ExternalLodestar.GetParameters(), configPage.layout.descriptionBox)
configPage.externalPrysmItems = createParameterizedFormItems(configPage.masterConfig.ExternalPrysm.GetParameters(), configPage.layout.descriptionBox)
configPage.externalTekuItems = createParameterizedFormItems(configPage.masterConfig.ExternalTeku.GetParameters(), configPage.layout.descriptionBox)
configPage.ccCommonItems = createParameterizedFormItems(configPage.masterConfig.ConsensusCommon.GetParameters(), configPage.layout)
configPage.lighthouseItems = createParameterizedFormItems(configPage.masterConfig.Lighthouse.GetParameters(), configPage.layout)
configPage.lodestarItems = createParameterizedFormItems(configPage.masterConfig.Lodestar.GetParameters(), configPage.layout)
configPage.nimbusItems = createParameterizedFormItems(configPage.masterConfig.Nimbus.GetParameters(), configPage.layout)
configPage.prysmItems = createParameterizedFormItems(configPage.masterConfig.Prysm.GetParameters(), configPage.layout)
configPage.tekuItems = createParameterizedFormItems(configPage.masterConfig.Teku.GetParameters(), configPage.layout)
configPage.externalLighthouseItems = createParameterizedFormItems(configPage.masterConfig.ExternalLighthouse.GetParameters(), configPage.layout)
configPage.externalNimbusItems = createParameterizedFormItems(configPage.masterConfig.ExternalNimbus.GetParameters(), configPage.layout)
configPage.externalLodestarItems = createParameterizedFormItems(configPage.masterConfig.ExternalLodestar.GetParameters(), configPage.layout)
configPage.externalPrysmItems = createParameterizedFormItems(configPage.masterConfig.ExternalPrysm.GetParameters(), configPage.layout)
configPage.externalTekuItems = createParameterizedFormItems(configPage.masterConfig.ExternalTeku.GetParameters(), configPage.layout)

// Map the parameters to the form items in the layout
configPage.layout.mapParameterizedFormItems(configPage.ccModeDropdown, configPage.ccDropdown, configPage.externalCcDropdown)
Expand Down
Loading
Loading