commit a41d4f9531907e42cc088ba85bbb1a13d150c89c
parent def222fd39720544427000bf6ea72c0ddd6241cc
Author: Jack Mordaunt <jackmordaunt@gmail.com>
Date: Tue, 3 Nov 2020 18:40:42 +0800
refactor: add progress / regress semantics
Diffstat:
| M | cmd/kanban/main.go | | | 30 | ++++++------------------------ |
| M | kanban.go | | | 101 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------------- |
2 files changed, 75 insertions(+), 56 deletions(-)
diff --git a/cmd/kanban/main.go b/cmd/kanban/main.go
@@ -32,7 +32,7 @@ func main() {
ui := &UI{
Window: w,
Th: th,
- Engine: &kanban.Engine{
+ Kanban: &kanban.Kanban{
Stages: []kanban.Stage{
{
Name: "Todo",
@@ -91,7 +91,7 @@ type (
// this object.
type UI struct {
*app.Window
- Engine *kanban.Engine
+ Kanban *kanban.Kanban
Th *material.Theme
Panels []Panel
TicketStates Map
@@ -130,30 +130,12 @@ func (ui *UI) Update(gtx C) {
for _, state := range ui.TicketStates.List() {
state := (*Ticket)(state)
if state.NextButton.Clicked() {
- if err := func() error {
- next, err := ui.Engine.NextStage(state.Stage)
- if err != nil {
- return fmt.Errorf("getting next stage: %w", err)
- }
- if err := ui.Engine.Move(next, state.Ticket.ID); err != nil {
- return fmt.Errorf("moving ticket: %s", err)
- }
- return nil
- }(); err != nil {
+ if err := ui.Kanban.Progress(state.ID); err != nil {
fmt.Printf("error: %s\n", err)
}
}
if state.PrevButton.Clicked() {
- if err := func() error {
- next, err := ui.Engine.PreviousStage(state.Stage)
- if err != nil {
- return fmt.Errorf("getting previous stage: %w", err)
- }
- if err := ui.Engine.Move(next, state.Ticket.ID); err != nil {
- return fmt.Errorf("moving ticket: %s", err)
- }
- return nil
- }(); err != nil {
+ if err := ui.Kanban.Regress(state.ID); err != nil {
fmt.Printf("error: %s\n", err)
}
}
@@ -164,7 +146,7 @@ func (ui *UI) Update(gtx C) {
fmt.Printf("error: %s", err)
return
}
- if err := ui.Engine.Assign(ui.TicketForm.Stage, ticket); err != nil {
+ if err := ui.Kanban.Assign(ui.TicketForm.Stage, ticket); err != nil {
fmt.Printf("error: %s", err)
return
}
@@ -186,7 +168,7 @@ func (ui *UI) Layout(gtx C) D {
for kk := range ui.Panels {
panel := &ui.Panels[kk]
panels[kk] = layout.Flexed(1, func(gtx C) D {
- stage, _ := ui.Engine.Stage(panel.Label)
+ stage, _ := ui.Kanban.Stage(panel.Label)
var cards = make([]layout.ListElement, len(stage.Tickets))
for ii, ticket := range stage.Tickets {
id := ticket.ID.String()
diff --git a/kanban.go b/kanban.go
@@ -5,31 +5,31 @@ import (
"strconv"
)
-// Kanban engine that drives the model.
-type Engine struct {
+// Kanban manipulates the model.
+type Kanban struct {
Stages []Stage
}
// ListStages returns a list of stages.
-func (eng Engine) ListStages() ([]Stage, error) {
- return eng.Stages, nil
+func (k Kanban) ListStages() ([]Stage, error) {
+ return k.Stages, nil
}
// NextStage returns the stage that follows the specified one.
-func (eng Engine) NextStage(current string) (string, error) {
- for ii, stage := range eng.Stages {
- if stage.Name == current && ii < len(eng.Stages)-1 {
- return eng.Stages[ii+1].Name, nil
+func (k Kanban) NextStage(current string) (string, error) {
+ for ii, stage := range k.Stages {
+ if stage.Name == current && ii < len(k.Stages)-1 {
+ return k.Stages[ii+1].Name, nil
}
}
return current, fmt.Errorf("no more stages after: %q", current)
}
// NextStage returns the stage that preceeds the specified one.
-func (eng Engine) PreviousStage(current string) (string, error) {
- for ii, stage := range eng.Stages {
+func (k Kanban) PreviousStage(current string) (string, error) {
+ for ii, stage := range k.Stages {
if stage.Name == current && ii > 0 {
- return eng.Stages[ii-1].Name, nil
+ return k.Stages[ii-1].Name, nil
}
}
return current, fmt.Errorf("no more stages before: %q", current)
@@ -37,25 +37,25 @@ func (eng Engine) PreviousStage(current string) (string, error) {
// Stage returns a stage by the given name.
// Creates an empty stage if it doesn't exist.
-func (eng *Engine) Stage(name string) (Stage, error) {
- for _, stage := range eng.Stages {
+func (k *Kanban) Stage(name string) (Stage, error) {
+ for _, stage := range k.Stages {
if stage.Name == name {
return stage, nil
}
}
- eng.Stages = append(eng.Stages, Stage{Name: name})
- return eng.Stages[len(eng.Stages)-1], nil
+ k.Stages = append(k.Stages, Stage{Name: name})
+ return k.Stages[len(k.Stages)-1], nil
}
-func (eng *Engine) Move(stage string, ticket ID) error {
+func (k *Kanban) Move(stage string, ticket ID) error {
var found *Ticket
- for ii := range eng.Stages {
- stage := eng.Stages[ii]
+ for ii := range k.Stages {
+ stage := k.Stages[ii]
for kk := range stage.Tickets {
t := stage.Tickets[kk]
if t.ID == ticket {
found = &t
- if err := eng.Delete(ticket); err != nil {
+ if err := k.Delete(ticket); err != nil {
return err
}
break
@@ -65,28 +65,65 @@ func (eng *Engine) Move(stage string, ticket ID) error {
if found == nil {
return fmt.Errorf("ticket %q does not exist", ticket)
}
- return eng.Assign(stage, *found)
+ return k.Assign(stage, *found)
}
-func (eng *Engine) Assign(stage string, ticket Ticket) error {
- ticket.ID = eng.nextID()
- for ii := range eng.Stages {
- s := &eng.Stages[ii]
+// Progress a ticket to the next stage.
+func (k *Kanban) Progress(ticket ID) error {
+ stage, err := k.StageFor(ticket)
+ if err != nil {
+ return err
+ }
+ next, err := k.NextStage(stage)
+ if err != nil {
+ return err
+ }
+ return k.Move(next, ticket)
+}
+
+// Regress a ticket to the previous stage.
+func (k *Kanban) Regress(ticket ID) error {
+ stage, err := k.StageFor(ticket)
+ if err != nil {
+ return err
+ }
+ next, err := k.PreviousStage(stage)
+ if err != nil {
+ return err
+ }
+ return k.Move(next, ticket)
+}
+
+func (k *Kanban) StageFor(ticket ID) (string, error) {
+ for _, s := range k.Stages {
+ for _, t := range s.Tickets {
+ if t.ID == ticket {
+ return s.Name, nil
+ }
+ }
+ }
+ return "", fmt.Errorf("ticket %q does not exist", ticket)
+}
+
+func (k *Kanban) Assign(stage string, ticket Ticket) error {
+ ticket.ID = k.nextID()
+ for ii := range k.Stages {
+ s := &k.Stages[ii]
if s.Name == stage {
s.Tickets = append(s.Tickets, ticket)
return nil
}
}
- eng.Stages = append(eng.Stages, Stage{
+ k.Stages = append(k.Stages, Stage{
Name: stage,
Tickets: []Ticket{ticket},
})
return nil
}
-func (eng *Engine) Delete(ticket ID) error {
- for kk := range eng.Stages {
- s := &eng.Stages[kk]
+func (k *Kanban) Delete(ticket ID) error {
+ for kk := range k.Stages {
+ s := &k.Stages[kk]
for ii := range s.Tickets {
if s.Tickets[ii].ID == ticket {
s.Tickets = append(s.Tickets[:ii], s.Tickets[ii+1:]...)
@@ -97,8 +134,8 @@ func (eng *Engine) Delete(ticket ID) error {
return nil
}
-func (eng *Engine) Update(ticket Ticket) error {
- for _, s := range eng.Stages {
+func (k *Kanban) Update(ticket Ticket) error {
+ for _, s := range k.Stages {
for ii := range s.Tickets {
if s.Tickets[ii].ID == ticket.ID {
s.Tickets[ii] = ticket
@@ -109,9 +146,9 @@ func (eng *Engine) Update(ticket Ticket) error {
return nil
}
-func (eng *Engine) nextID() ID {
+func (k *Kanban) nextID() ID {
var max int
- for _, stage := range eng.Stages {
+ for _, stage := range k.Stages {
for _, t := range stage.Tickets {
if int(t.ID) > max {
max = int(t.ID)