kanban

Kanban client in Gio
Log | Files | Refs | README | LICENSE

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:
Mcmd/kanban/main.go | 30++++++------------------------
Mkanban.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)