|
@@ -2,9 +2,7 @@
|
|
|
//
|
|
//
|
|
|
// TODO enable collection recursing (i.e, embeded collections)
|
|
// TODO enable collection recursing (i.e, embeded collections)
|
|
|
//
|
|
//
|
|
|
-// TODO enable scroll/viewport logic on issues!!!
|
|
|
|
|
-
|
|
|
|
|
-// TODO connect WriteIssue to createIssue widget
|
|
|
|
|
|
|
+// TODO enable scroll/viewport logic
|
|
|
//
|
|
//
|
|
|
// While the package remains in v0.0.X releases, this TUI may be undocumented.
|
|
// While the package remains in v0.0.X releases, this TUI may be undocumented.
|
|
|
package issues
|
|
package issues
|
|
@@ -154,6 +152,8 @@ func (m Model) View() string {
|
|
|
// ----------------------------------------------------------------------------
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
// interface definition for widgets
|
|
// interface definition for widgets
|
|
|
|
|
+//
|
|
|
|
|
+// TODO add keyhelp func to widget interface
|
|
|
type widget interface {
|
|
type widget interface {
|
|
|
render() tea.Msg
|
|
render() tea.Msg
|
|
|
}
|
|
}
|
|
@@ -168,14 +168,16 @@ type inputField struct {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// widget for creating an issue
|
|
// widget for creating an issue
|
|
|
|
|
+//
|
|
|
|
|
+// TODO invoke editor for descriptions
|
|
|
type createIssue struct {
|
|
type createIssue struct {
|
|
|
inputFields []inputField
|
|
inputFields []inputField
|
|
|
Path string
|
|
Path string
|
|
|
selected int
|
|
selected int
|
|
|
- Err error // behaviour undefined
|
|
|
|
|
|
|
+ Err error // not implemented
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-func initialInputModel(path string, placeholder string) createIssue {
|
|
|
|
|
|
|
+func initialCreateIssueModel(path string, placeholder string) createIssue {
|
|
|
spawnInput := func(f bool) textinput.Model {
|
|
spawnInput := func(f bool) textinput.Model {
|
|
|
ti := textinput.New()
|
|
ti := textinput.New()
|
|
|
ti.Placeholder = placeholder
|
|
ti.Placeholder = placeholder
|
|
@@ -258,13 +260,25 @@ func (ci createIssue) update(msg tea.Msg) (createIssue, tea.Cmd) {
|
|
|
if ci.selected == len(ci.inputFields) { // confirm create
|
|
if ci.selected == len(ci.inputFields) { // confirm create
|
|
|
ci.selected++
|
|
ci.selected++
|
|
|
} else if ci.selected == len(ci.inputFields)+1 { // confirmed
|
|
} else if ci.selected == len(ci.inputFields)+1 { // confirmed
|
|
|
- cmds = append(cmds, tea.Quit)
|
|
|
|
|
|
|
+ cmds = append(cmds, ci.create)
|
|
|
} else {
|
|
} else {
|
|
|
incrementSelected()
|
|
incrementSelected()
|
|
|
}
|
|
}
|
|
|
case "esc": // cancel
|
|
case "esc": // cancel
|
|
|
cmds = append(cmds, tea.Quit)
|
|
cmds = append(cmds, tea.Quit)
|
|
|
}
|
|
}
|
|
|
|
|
+ case createResult:
|
|
|
|
|
+ cmds = append(cmds, ci.write(Issue(msg)))
|
|
|
|
|
+ case writeResult:
|
|
|
|
|
+ switch value := msg.(type) {
|
|
|
|
|
+ case bool:
|
|
|
|
|
+ if !value {
|
|
|
|
|
+ } else {
|
|
|
|
|
+ cmds = append(cmds, tea.Quit)
|
|
|
|
|
+ }
|
|
|
|
|
+ case error:
|
|
|
|
|
+ panic(value)
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
for i, ti := range ci.inputFields {
|
|
for i, ti := range ci.inputFields {
|
|
@@ -403,5 +417,72 @@ func (m Model) load() tea.Msg {
|
|
|
return collection
|
|
return collection
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- return initialInputModel(m.Path, "lorem ipsum")
|
|
|
|
|
|
|
+ return initialCreateIssueModel(m.Path, "lorem ipsum")
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+type createResult Issue
|
|
|
|
|
+
|
|
|
|
|
+// A widget for creating issues
|
|
|
|
|
+//
|
|
|
|
|
+// TODO implement description field in createIssue.create cmd
|
|
|
|
|
+func (ci createIssue) create() tea.Msg {
|
|
|
|
|
+ data := make(map[string]string)
|
|
|
|
|
+ commaSplit := func(t string) []string {
|
|
|
|
|
+ s := strings.Split(t, ",")
|
|
|
|
|
+ for i, v := range s {
|
|
|
|
|
+ s[i] = strings.TrimLeft(v, " \t\n")
|
|
|
|
|
+ s[i] = strings.TrimRight(s[i], " \t\n")
|
|
|
|
|
+
|
|
|
|
|
+ s[i] = parseHumanToPath(s[i])
|
|
|
|
|
+ }
|
|
|
|
|
+ return s
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ for _, field := range ci.inputFields {
|
|
|
|
|
+ data[field.title] = field.input.Value()
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ var newIssue = Issue{
|
|
|
|
|
+ Path: ci.Path,
|
|
|
|
|
+ Tags: VariadicField{Path: "/tags"},
|
|
|
|
|
+ Blockedby: VariadicField{Path: "/blockedby"},
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ for key, value := range data {
|
|
|
|
|
+ switch key {
|
|
|
|
|
+ case "title":
|
|
|
|
|
+ newIssue.Title = value
|
|
|
|
|
+ case "status":
|
|
|
|
|
+ newIssue.Status = Field{Path: "/status", Data: value}
|
|
|
|
|
+ case "description":
|
|
|
|
|
+ newIssue.Description = Field{Path: "/description", Data: value}
|
|
|
|
|
+ case "tags":
|
|
|
|
|
+ splitTags := commaSplit(value)
|
|
|
|
|
+ for _, tag := range splitTags {
|
|
|
|
|
+ newIssue.Tags.Fields = append(newIssue.Tags.Fields, Field{Path: tag})
|
|
|
|
|
+ }
|
|
|
|
|
+ case "blockers":
|
|
|
|
|
+ splitBlockedby := commaSplit(value)
|
|
|
|
|
+ for _, blocker := range splitBlockedby {
|
|
|
|
|
+ newIssue.Blockedby.Fields = append(
|
|
|
|
|
+ newIssue.Blockedby.Fields, Field{Path: blocker},
|
|
|
|
|
+ )
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return createResult(newIssue)
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+type writeResult any
|
|
|
|
|
+
|
|
|
|
|
+// Wraps a cmd func, passes an initialized Issue to WriteIssue()
|
|
|
|
|
+func (ci createIssue) write(issue Issue) tea.Cmd {
|
|
|
|
|
+ return func() tea.Msg {
|
|
|
|
|
+ result, err := WriteIssue(issue, false)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return writeResult(err)
|
|
|
|
|
+ }
|
|
|
|
|
+ return writeResult(result)
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|