Repository navigation
Conversation
31674ea to
bebdc0d
Compare
There was a problem hiding this comment.
🟡 Changes recommended
The chart lacks an accessible representation of its historical data, and its frontend drawing behavior needs focused tests.
3 open findings
What changed in this PR
Adds a sprint velocity widget showing committed/completed story points and an average baseline across up to seven sprints.
Changes:
- Adds historical velocity calculation and reporting UI.
- Introduces an Angular bar chart and average-line plugin.
- Adds backend, component, and feature coverage.
| File | Description |
|---|---|
modules/backlogs/spec/models/backlogs/velocity_spec.rb |
Tests velocity calculations. |
modules/backlogs/spec/features/backlogs/sprint_reports/velocity_chart_widget_spec.rb |
Tests widget integration. |
modules/backlogs/spec/features/backlogs/sprint_reports/show_spec.rb |
Verifies widget ordering. |
modules/backlogs/spec/components/backlogs/sprint_reports/widgets/velocity_chart_spec.rb |
Tests rendered chart data. |
modules/backlogs/config/locales/en.yml |
Adds velocity labels. |
modules/backlogs/app/views/backlogs/sprint_reports/show.html.erb |
Adds the widget to reports. |
modules/backlogs/app/models/backlogs/velocity.rb |
Calculates sprint velocity data. |
modules/backlogs/app/components/backlogs/sprint_reports/widgets/velocity_chart.rb |
Builds widget data and summaries. |
modules/backlogs/app/components/backlogs/sprint_reports/widgets/velocity_chart.html.erb |
Renders the widget. |
frontend/src/app/features/backlogs/velocity-chart.component.ts |
Configures the bar chart. |
frontend/src/app/features/backlogs/velocity-chart.component.html |
Provides the chart canvas. |
frontend/src/app/features/backlogs/plugin.average-line.ts |
Draws the average baseline. |
frontend/src/app/app.module.ts |
Registers the custom element. |
🧠 Review effort: Balanced
Give feedback about Copilot approvals in this survey to enter a drawing for a $150 gift card.
|
Warning Flaky specs
🤖 Ask Copilot to investigateCopy the prompt below into a new comment on this PR to delegate the investigation to GitHub Copilot. It will look into the flakiness and open a separate pull request with you as reviewer. |
ulferts
left a comment
There was a problem hiding this comment.
I am not done with the review. I haven't read the tests yet and I also need to thoroughly test the changes in the application. Whether you @EinLama want to start addressing the topics is up to you.
But from my first glimpses, I think this is behaving nicely. I personally liked rendering a table for screen reader. The code structure is 'boring', in a good way. Everything is where I would expect it to be.
Todos
Visual
Average line number font
The number on the average line should be in bold and at least according to the figma files look just like the ones in each bar:
Figma:
Low numbers and disabling a data set
When having a bar with very low numbers e.g. 0 and disabling the other data set, the number overlaps the sprint name
Empty space above bars
Probably depending on the data, there is as much empty space in the chart as there is filled one. From what I remember, it is not easy to get ChartJS to use a less wasteful approach but it could be worth a try. In the Burndown chart a suggestedMax is provided
This is probably the result of combining grace: '10%' and maxTicksLimit: 3.
Unclear average line semantics
For a user, it might be unclear, what the line showing the average of the completed story points means. The line has no description and is displayed both when the 'Completed' data set is enabled but also when it is disabled:
This is more a product question than a technical one. In a meeting we discussed the option to let the line work just like the other data sets. If that happens, there would be a legend explaining what it does.
Average line when disabling both data sets
This is maybe a non issue, maybe a nitpick: when disabling both data sets, the graph is empty with a small y-axis visible. In it, the average line is then not displayed:
| @@ -0,0 +1,33 @@ | |||
| <div class="position-relative" style="height: 320px"> | |||
There was a problem hiding this comment.
We'll need to extract this hard wired height into a class to then be used by all the charts on the reports page. The Burndown PR does it admittedly with a name that is not generic.
Probably to be done after merging both PRs.
|
|
||
| function truncate(label:string):string { | ||
| return label.length > MAX_LABEL_LENGTH ? `${label.slice(0, MAX_LABEL_LENGTH - 1).trimEnd()}…` : label; | ||
| } |
There was a problem hiding this comment.
This code should probably be shared with other charts so it should be extracted.
One could also work on measuring the text that is rendered and trim when necessary. That would allow more flexibility when showing the charts on wider screens vs on narrow ones. But I would be ok with this coming at a later stage when we feel it necessary.
| end | ||
|
|
||
| def breakdowns | ||
| @breakdowns ||= sprints.map { SprintWorkPackageBreakdown.new(sprint: it, project:) } |
There was a problem hiding this comment.
This leads to four queries being fired per sprint displayed so 28 max (as snapshot_block does two queries each count and sum). Of those, only half are used.
The WorkPackages::JournalTimeline can do it in a single query and could be applied here. If used, it will also:
- apply visibility at the time of querying. E.g. a work package moved out of the project would still be counted. WorkPackage.at_timestamp(...).visible does not do that AFAIK.
- because of the above, with Burndown using
WorkPackages::JournalTimelineI expect the widgets to show different values potentially. The discrepancy would also apply to the Overview widget.
Using WorkPackages::JournalTimeline here and in SprintWorkPackageBreakdown.snapshot_block would resolve those discrepancies.
There was a problem hiding this comment.
Yes, I too think it would make sense to apply the JournalTimeline to SprintWorkPackageBreakdown, too. This would also keep this (velocity) chart and the work package overview widget in sync. If they used two different mechanics to count work packages, a user would see different numbers for the same metric in some edge cases.
ulferts
left a comment
There was a problem hiding this comment.
Only some small additions to what I have commented on yesterday. They lean more towards asking product. The other parts are nitpicks.
Todo
Average factoring in current sprint
This is more of a specification question - we need to discuss this with Product. The chart currently factors in the current sprint as well when calculating the average. Naturally, at the beginning of a sprint, that number is low, reducing the average without any actual reason. I think we should not factor in the current sprint in the average.
Average if there is no predecessor
Again a question for Product: We might want to display no average if there is no previous sprint. This looks off:
Omitting the dashed line and the mentioning of the average in the header would be one option. We could also think about not showing the chart at all if there is no previous sprint.
30ff1a7 to
5483925
Compare
We discussed both of these today and both were agreed upon. We will not factor in the current sprint for calculating the average. Additionally, when there's no average to show (there's no previous sprint), we don't show the dotted line and legend and we also don't show the title caption about the average. |
7ec5d77 to
86f7d28
Compare
Copy/pasted from the wrong file. Oopsie!
To keep it in line with the latest Burndown chart changes (to be merged)
…present Same for the finish date(s)
Use the updated `order_by_date` scope here. This ensures that sprints without a date are ignored and the sprint order matches other places in the application.
86f7d28 to
06755de
Compare
1. only consider the preceding sprints when calculating the average 2. when there is no average (no preceding sprints), hide it



Ticket
https://community.openproject.org/wp/AGILE-66
What are you trying to accomplish?
Show a chart for the (at most) past 6 sprints plus the currently viewed sprint and their velocity.
Screenshots
What approach did you choose and why?
Introduced a new POR class
Velocitywhich, much likeSprintWorkPackageBreakdowncontains all the logic to collect the relevant sprints and calculate their velocity. To do this,Velocitymakes use ofSprintWorkPackageBreakdown, as that class already provides counts for committed and completed work packages and their story points.The chart itself only renders the given data. Worth mentioning here is the introduction of a the
AverageLinePluginthat will render a dashed line across the diagram. It is used to render an average baseline through the chart. It could be useful for other charts, too.Apart from making use of the plugin, the chart overrides the default primer colors to match the design's colors. It works well in both light and dark mode.
For now, only story points are supported as a metric. Other estimation units will be added in AGILE-457.
AI involvement
Collaborative – AI generated a substantial part of the code; I reviewed and understand every line.
Merge checklist