Skip to content

Commit

Permalink
fix dialog and optional value handling // add examples and descriptio…
Browse files Browse the repository at this point in the history
…n to concept.json spec
  • Loading branch information
redradrat committed Nov 7, 2021
1 parent 7dc5e4b commit fd6709c
Show file tree
Hide file tree
Showing 3 changed files with 143 additions and 27 deletions.
50 changes: 41 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ Mandatory Values
? instanceName (string) [? for help]
```

As this is our first time rendering this, a dialog will pop up, asking us for values.
As this is our first time rendering this, a dialog will open up, asking us for values.
So for now we will comply with what this pesky dialog wants.

```
Expand Down Expand Up @@ -132,7 +132,7 @@ will be reused, if this file is detected. You can even pass a specific file with
───────┴────────────────────────────────────────────────────────────────────
```

When we now execute our render command again, we will see that kable automatically
When we now run our render command again, we will see that kable automatically
detects the `renderinfo.json` file in the output path, and reuses it's values.

```
Expand Down Expand Up @@ -232,7 +232,7 @@ When rendering via `kable render` a dialog will ask the user about the defined i

Examples of how to define aforementioned inputs in your concept.json file:

```
```json
{
"apiVersion": 1,
"type": "jsonnet",
Expand All @@ -243,19 +243,19 @@ Examples of how to define aforementioned inputs in your concept.json file:
// HERE WE CAN DEFINE INPUTS

"string": {
"type": "string",
"type": "string"
},

"int": {
"type": "int",
"type": "int"
},

"bool": {
"type": "bool",
"type": "bool"
},

"map": {
"type": "map",
"type": "map"
},

"selection": {
Expand All @@ -264,11 +264,43 @@ Examples of how to define aforementioned inputs in your concept.json file:
"Option 1",
"Option 2"
]
},
}

},
"optional": {...},
"optional": {

// ANOTHER SECTION OF INPUTS THAT ARE NOT MANDATORY

"string": {
"type": "string"
},
...
}
}
}
```

There is the possibility to add a description and example to each required input.

```json
{
"apiVersion": 1,
"type": "jsonnet",
"metadata": {
...
},
"inputs": {
"mandatory": {
// HERE WE CAN DEFINE INPUTS

"string": {
"type": "string",
"description": "This text describes the purpose of the input.",
"example": "examplevalue"
},
...
}
}
}
```

Expand Down
114 changes: 98 additions & 16 deletions cmd/inputDialog.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,11 @@ import (
"encoding/json"
"errors"
"fmt"
"os"
"sort"
"strings"

"github.com/AlecAivazis/survey/v2/terminal"

"github.com/fatih/color"

Expand All @@ -13,6 +17,11 @@ import (
"github.com/redradrat/kable/pkg/concepts"
)

var (
cursor *terminal.Cursor
hl = color.New(color.Bold, color.Underline).Sprintf
)

type InputDialog struct {
inputs concepts.ConceptInputs
}
Expand All @@ -24,7 +33,7 @@ func NewInputDialog(inputs concepts.ConceptInputs) InputDialog {
func (id InputDialog) RunInputDialog() (*concepts.RenderValues, error) {
values := concepts.RenderValues{}
if len(id.inputs.Mandatory) != 0 {
PrintMsg("Mandatory Values")
PrintMsg(hl("\nMandatory Values"))
keys := getSortedMapKeys(id.inputs.Mandatory)
for _, key := range keys {
value, err := getValue(key, id.inputs.Mandatory[key])
Expand All @@ -36,17 +45,42 @@ func (id InputDialog) RunInputDialog() (*concepts.RenderValues, error) {
}

if len(id.inputs.Optional) != 0 {
PrintMsg("Optional Values")
keys := getSortedMapKeys(id.inputs.Optional)
for _, key := range keys {
value, err := getValue(key, id.inputs.Optional[key])
if err != nil {
return nil, err

optConfirm := false
optPrompt := &survey.Confirm{
Message: "Provide values for optional inputs?",
}
if err := survey.AskOne(optPrompt, &optConfirm); err != nil {
return nil, err
}
erasePreviousLine()

// Only go into optional values if the users want's to
if optConfirm {
PrintMsg(hl("\nOptional Values"))
keys := getSortedMapKeys(id.inputs.Optional)
for _, key := range keys {
valConfirm := false
valPrompt := &survey.Confirm{
Message: fmt.Sprintf("Provide value for %s?", key),
Help: breakEvery60chars(id.inputs.Optional[key].Description),
}
if err := survey.AskOne(valPrompt, &valConfirm); err != nil {
return nil, err
}
if valConfirm {
erasePreviousLine()
value, err := getValue(key, id.inputs.Optional[key])
if err != nil {
return nil, err
}
values[key] = value
}
}
values[key] = value
}
}

fmt.Println()
return &values, nil
}

Expand All @@ -61,25 +95,38 @@ func getSortedMapKeys(values map[string]concepts.InputType) []string {

func getValue(name string, input concepts.InputType) (concepts.ValueType, error) {

var helpText string
if input.Description != "" {
helpText = helpText + breakEvery60chars(input.Description) + "\n\n"
}
if input.Example != "" {
helpText = helpText + "Example: " + input.Example
}

var value concepts.ValueType
switch input.Type {
case concepts.ConceptStringInputType:

if helpText == "" {
helpText = "example: test"
}
val := ""
prompt := &survey.Input{
Message: name + color.CyanString(" (string)"),
Help: "example: test",
Help: helpText,
}
if err := survey.AskOne(prompt, &val); err != nil {
return nil, err
}

value = concepts.StringValueType(val)
case concepts.ConceptIntInputType:
if helpText == "" {
helpText = "example: 3"
}
var val int
prompt := &survey.Input{
Message: name + color.CyanString(" (integer)"),
Help: "example: 3",
Help: helpText,
}
if err := survey.AskOne(prompt, &val); err != nil {
return nil, err
Expand All @@ -90,30 +137,33 @@ func getValue(name string, input concepts.InputType) (concepts.ValueType, error)
var val bool
prompt := &survey.Confirm{
Message: name + color.CyanString(" (boolean)"),
Help: helpText,
}
if err := survey.AskOne(prompt, &val); err != nil {
return nil, err
}

value = concepts.BoolValueType(val)
case concepts.ConceptSelectionInputType:

val := ""
var val string
prompt := &survey.Select{
Message: name,
Message: name + color.CyanString(" (select)"),
Options: input.Options,
Help: helpText,
}
if err := survey.AskOne(prompt, &val); err != nil {
return nil, err
}

value = concepts.StringValueType(val)
case concepts.ConceptMapInputType:

if helpText == "" {
helpText = "example: {'foo':'bar'}"
}
val := ""
prompt := &survey.Input{
Message: name + color.CyanString(" (map)"),
Help: "example: {'foo':'bar'}",
Help: helpText,
}
if err := survey.AskOne(prompt, &val); err != nil {
return nil, err
Expand All @@ -129,3 +179,35 @@ func getValue(name string, input concepts.InputType) (concepts.ValueType, error)
}
return value, nil
}

func breakEvery60chars(in string) string {
if len(in) <= 60 {
return in
}
var chunks []string
chunk := make([]rune, 60)
len := 0
for _, r := range in {
chunk[len] = r
len++
if len == 60 {
chunks = append(chunks, string(chunk))
len = 0
}
}
if len > 0 {
chunks = append(chunks, string(chunk[:len]))
}
return strings.Join(chunks, "\n")
}

func erasePreviousLine() {
if cursor == nil {
cursor = &terminal.Cursor{
In: os.Stdin,
Out: os.Stdout,
}
}
cursor.PreviousLine(1)
terminal.EraseLine(os.Stdout, terminal.ERASE_LINE_ALL)
}
6 changes: 4 additions & 2 deletions pkg/concepts/concepts.go
Original file line number Diff line number Diff line change
Expand Up @@ -195,8 +195,10 @@ func (ci ConceptInputs) All() map[string]InputType {
}

type InputType struct {
Type InputTypeIdentifier `json:"type"`
Options []string `json:"options,omitempty"`
Type InputTypeIdentifier `json:"type"`
Description string `json:"description"`
Example string `json:"example"`
Options []string `json:"options,omitempty"`
}

type InputTypeIdentifier string
Expand Down

0 comments on commit fd6709c

Please sign in to comment.