-
Notifications
You must be signed in to change notification settings - Fork 81
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add planning board to triage party!! #269
Open
tejal29
wants to merge
13
commits into
google:master
Choose a base branch
from
tejal29:add_planning_board
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
13 commits
Select commit
Hold shift + click to select a range
f150e2f
Add planning board view with relevant columns than Collection
tejal29 1041380
skaffold dev is running
tejal29 c68c02e
wip
tejal29 731f5df
add planning board
tejal29 13a8610
Add name and description to swimlane
tejal29 f1c9970
fix license and some other config
tejal29 857cfb9
fix lints
tejal29 8eedb05
css lint
tejal29 f777ff7
maybe this is it
tejal29 fb71380
address code review comments
tejal29 b382f5c
more fixes and some changed to README
tejal29 630d6d0
move skaffold config to Q4 and remove in progress as the logic is inc…
tejal29 81efbf4
sort milestones by due date
tejal29 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -125,7 +125,7 @@ Use the drop-down labelled `Solo` on the top-right of any page to enable multi-p | |
|
||
NOTE: Multi-player works best if the "Resolution" field of each rule has a clear action to resolve the item and remove it from the list. | ||
|
||
## Kanban mode (NEW) | ||
## Kanban mode | ||
|
||
![kanban mode](docs/images/kanban.png) | ||
|
||
|
@@ -141,6 +141,28 @@ Best practices for designing a useful Kanban dashboard: | |
* If a collection should be displayed in Kanban form by default, specify `display: kanban` in its configuration. | ||
* For velocity measurements and time estimate support, create a rule named `__velocity__` containing recently closed issues to include. See the example configuration. | ||
|
||
## Planning Board mode (NEW) | ||
![planning mode](docs/images/planning.png) | ||
|
||
In v1.5.0, pages can now be displayed as a SCRUM dashboard. | ||
The columns are based on the feature or Objective(O) the issue belongs to. Use rules to define features. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How about 'objective' instead of 'Objective(O)'? |
||
The rows are swim-lanes based on the target milestones. | ||
To see a real-world example: | ||
|
||
* [skaffold planning dashboard](http://tinyurl.com/skaffold-planning) | ||
* [skaffold planning config](https://github.com/google/triage-party/blob/master/config/examples/skaffold.yaml#L142) | ||
|
||
In the above example, skaffold has 2 Objectives and 2 features defined | ||
The two objectives are | ||
1) Simply onbaording and make inner devloop faster | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we can remove these two lines |
||
2) Extensibility | ||
|
||
Best practices for designing a useful Planning dashboard: | ||
|
||
* Rules should be designed and ordered in a way that represents progress: `Not started` -> `Started` -> `Under Review` -> `Completed` | ||
* Rules work best when they are mutually excusive (no issue matches multiple rules) | ||
* If a collection should be displayed in Planning form by default, specify `display: planning` in its configuration. | ||
|
||
## Data freshness | ||
|
||
![age screenshot](docs/images/age.png) | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,166 @@ | ||
// Copyright 2020 Google Inc. | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
package site | ||
|
||
import ( | ||
"fmt" | ||
"html/template" | ||
"net/http" | ||
"path/filepath" | ||
"sort" | ||
"strings" | ||
"time" | ||
|
||
"github.com/google/triage-party/pkg/hubbub" | ||
"github.com/google/triage-party/pkg/provider" | ||
"github.com/google/triage-party/pkg/triage" | ||
"k8s.io/klog/v2" | ||
) | ||
|
||
const ( | ||
unplanned = "Unplanned" | ||
) | ||
|
||
// Planning shows a view of a collection. | ||
tejal29 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
// Planning board can be used planning Sprints and futures releases | ||
// categorized in swimlanes defining a feature or Objective. | ||
// The planning board gives a view of all planned milestones with issues | ||
// versus the current or selected milestone in the Kanban Board. | ||
// It also highlights all new incoming issues not assigned to a milestone. | ||
|
||
func (h *Handlers) Planning() http.HandlerFunc { | ||
fmap := template.FuncMap{ | ||
"toJS": toJS, | ||
"toYAML": toYAML, | ||
"toJSfunc": toJSfunc, | ||
"toDays": toDays, | ||
"HumanDuration": humanDuration, | ||
"UnixNano": unixNano, | ||
"getAssignees": getAssignees, | ||
"unAssignedOrAvatar": unAssignedOrAvatar, | ||
"Class": className, | ||
"isUnplanned": isUnplanned, | ||
} | ||
|
||
t := template.Must(template.New("planning").Funcs(fmap).ParseFiles( | ||
filepath.Join(h.baseDir, "planning.tmpl"), | ||
filepath.Join(h.baseDir, "base.tmpl"), | ||
)) | ||
|
||
return func(w http.ResponseWriter, r *http.Request) { | ||
klog.Infof("GET %s: %v", r.URL.Path, r.Header) | ||
|
||
id := strings.TrimPrefix(r.URL.Path, "/p/") | ||
|
||
p, err := h.collectionPage(r.Context(), id, isRefresh(r)) | ||
if err != nil { | ||
http.Error(w, fmt.Sprintf("planning page for %q: %v", id, err), 500) | ||
klog.Errorf("page: %v", err) | ||
|
||
return | ||
} | ||
|
||
if p.CollectionResult.RuleResults != nil { | ||
p.Description = p.Collection.Description | ||
p.Swimlanes = groupByState(p.CollectionResult.RuleResults) | ||
} | ||
|
||
err = t.ExecuteTemplate(w, "base", p) | ||
|
||
if err != nil { | ||
klog.Errorf("tmpl: %v", err) | ||
return | ||
} | ||
} | ||
} | ||
|
||
// unAssignedOrAvatar is used in a sticky note and hence | ||
// wrapping "unAssigned | ||
func unAssignedOrAvatar(u *provider.User) template.HTML { | ||
if u.GetLogin() == unassigned { | ||
return `🤷` | ||
} | ||
return avatar(u) | ||
} | ||
|
||
func getAssignees(co *hubbub.Conversation) []*provider.User { | ||
if co.Assignees == nil || len(co.Assignees) == 0 { | ||
return []*provider.User{{Login: &unassigned}} | ||
} | ||
return co.Assignees | ||
} | ||
|
||
func groupByState(results []*triage.RuleResult) []*Swimlane { | ||
milestones := []time.Time{} | ||
milestoneDueOnMap := map[time.Time]string{} | ||
lanes := map[string]*Swimlane{ | ||
unplanned: { | ||
Name: unplanned, | ||
Columns: make([]*triage.RuleResult, len(results)), | ||
}, | ||
} | ||
seen := map[int]struct{}{} | ||
for i, r := range results { | ||
for _, co := range r.Items { | ||
if _, ok := seen[co.ID]; ok { | ||
continue | ||
} | ||
seen[co.ID] = struct{}{} | ||
var state string | ||
if co.Milestone == nil { | ||
state = unplanned | ||
} else { | ||
state = *co.Milestone.Title | ||
} | ||
if lanes[state] == nil { | ||
ts := co.Milestone.GetDueOn() | ||
milestones = append(milestones, ts) | ||
milestoneDueOnMap[ts] = state | ||
lanes[state] = &Swimlane{ | ||
Name: state, | ||
Description: fmt.Sprintf("Due on %s-%d (%d/%d) open", | ||
ts.Month().String(), ts.Day(), co.Milestone.GetOpenIssues(), | ||
co.Milestone.GetOpenIssues()+co.Milestone.GetClosedIssues()), | ||
URL: *co.Milestone.HTMLURL, | ||
Columns: make([]*triage.RuleResult, len(results)), | ||
} | ||
} | ||
if lanes[state].Columns[i] == nil { | ||
lanes[state].Columns[i] = &triage.RuleResult{ | ||
Rule: r.Rule, | ||
Items: []*hubbub.Conversation{}, | ||
} | ||
} | ||
lanes[state].Columns[i].Items = append(lanes[state].Columns[i].Items, co) | ||
lanes[state].Issues++ | ||
} | ||
} | ||
|
||
sl := []*Swimlane{lanes[unplanned]} | ||
|
||
// sort lanes as per due date. | ||
sort.Slice(milestones, func(i, j int) bool { | ||
return milestones[i].Before(milestones[j]) | ||
}) | ||
|
||
for _, k := range milestones { | ||
sl = append(sl, lanes[milestoneDueOnMap[k]]) | ||
} | ||
return sl | ||
} | ||
|
||
func isUnplanned(name string) bool { | ||
return name == unplanned | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe Scrum is the correct capitalization