Erstellung Created vs resolved Chart - #24862
Conversation
|
All contributors have signed the CLA ✍️ ✅ |
|
I have read the CLA Document and I hereby sign the CLA |
|
|
||
| calculate_series series_data | ||
|
|
||
| result = calculate_series series_data |
EinLama
left a comment
There was a problem hiding this comment.
Hey @AileenK13 , thank you for this PR. It renders a useful chart and already has a lot going for it 👏 well done!
Before we can merge it, there is some feedback that should be addressed. Also, some tests (we call them specs) should be added. I know that this is already on your todo-list, just listing it here for the sake of completeness.
The CI uncovered some issues during an automatic check (linting, style, etc.), please have a look at these, too. I didn't add an additional review comment for most of these and let them stand for themselves.
I know that this is a lot of feedback. Please inquire further when something is unclear or you require support 👍
Thank you for your work 🙇
| #++ | ||
|
|
||
| module OpenProject::Backlogs::CreatedResolved | ||
| class Series < Array |
There was a problem hiding this comment.
Although you can, one should never inherit from built-in classes such as Array and Hash. Due to hardcoded rules imposed by the Ruby interpreter, this will end badly eventually.
There's a nice screencast by Avdi Grimm about this topic where he explains it in much detail.
This class can stay mostly the same, but delegate to a member variable which is an array:
I'd also store the allowed units in a constant, fine-grain the raised exception to be an ArgumentError and give information about the allowed values in the error message so that the user has a chance to pass the correct value here:
class Series
UNITS = %i[workpackages hours].freeze
attr_reader :unit, :name, :data
attr_accessor :display
def initialize(unit, name, *args)
@unit = unit.to_sym
@name = name.to_sym
@data = Array.new(args)
@display = display
raise ArgumentError, "Unsupported unit: '#{@unit}' - should be one of: #{UNITS.join(', ')}" unless UNITS.include?(@unit)
end
endBe aware that callers of this class will have to call @series.data instead of series in order to access the Array values.
| def calculate_series(series_data) | ||
| series_data.collect_names.each do |c| | ||
| # need to differentiate between hours and sp | ||
| make_series c.to_sym, series_data.unit_for(c), series_data[c].to_a.sort_by(&:first).map(&:last) |
There was a problem hiding this comment.
When a method call gets a bit more elaborate, it's a good idea to include the optional parenthesis around the method arguments to make it more readable.
For parameters that are more elaborate, move them to their own variable definition:
| make_series c.to_sym, series_data.unit_for(c), series_data[c].to_a.sort_by(&:first).map(&:last) | |
| data = series_data[c].to_a.sort_by(&:first).map(&:last) | |
| make_series(c.to_sym, series_data.unit_for(c), data) |
|
|
||
| def calculate_series(series_data) | ||
| series_data.collect_names.each do |c| | ||
| # need to differentiate between hours and sp |
There was a problem hiding this comment.
I think this comment can be removed. We don't care about hours and story points here. This is a leftover from the burndown chart.
| private | ||
|
|
||
| def make_date_series(sprint) | ||
| @days = if sprint.start_date && sprint.finish_date |
There was a problem hiding this comment.
There is Sprint#date_range_set? for this purpose:
| @days = if sprint.start_date && sprint.finish_date | |
| @days = if sprint.date_range_set? |
| def determine_max | ||
| @max = { | ||
| workpackages: @available_series.values.select { |s| s.unit == :workpackages }.flatten.compact.reject(&:nan?).max || 0.0, | ||
| hours: @available_series.values.select { |s| s.unit == :hours }.flatten.compact.reject(&:nan?).max || 0.0 |
There was a problem hiding this comment.
I think nobody is using hours here, this is a leftover from the burndown chart. You should be able to delete this line 🤔
| } | ||
|
|
||
| const PRIMER_COLORS = [ | ||
| 'red', // (strong, but not first to avoid clash with orange) |
There was a problem hiding this comment.
This will override the colors not only for the created vs. resolved chart, but also for most others.
I am not sure whether this is what we want. Also, the comment here no longer speaks the truth. It states that red should not be the first color - but it is. 😁
I'll have to double check which order we exactly want here. For now, it would be good to revert this change and define the colors directly on the created vs. resolved chart instead.
That should be possible by setting backgroundColor and borderColor on each dataset of the created vs. resolved chart component. We could fetch the color from the CSS definition there, for example:
getCSSVariable(`--display-red-scale-2`) // for a muted color tone (perhaps background)
getCSSVariable(`--display-red-scale-4`) // for a shiny color tone (perhaps border)
I haven't tested this. I hope it works 🤞🏻
| #++ | ||
|
|
||
| module OpenProject::Backlogs::CreatedResolved | ||
| class SeriesRawData < Hash |
There was a problem hiding this comment.
Same here - instead of inheriting of Hash, hold an instance and delegate to it.
| const data = JSON.parse(this.chartData()) as ChartData<'line'>; | ||
| return data; |
There was a problem hiding this comment.
| const data = JSON.parse(this.chartData()) as ChartData<'line'>; | |
| return data; | |
| return JSON.parse(this.chartData()) as ChartData<'line'>; |
|
|
||
| def dataseries(created_resolved) | ||
| created_resolved.series.map do |s| | ||
| Rails.logger.info ">>> DEBUG series: #{s.inspect}" |
There was a problem hiding this comment.
Stale debug comment, should be removed before merge.
| determine_max | ||
| end | ||
|
|
||
| attr_reader :days, :sprint_id, :max, :created, :resolved |
There was a problem hiding this comment.
Neither :created nor :resolved are used anywhere. These getters can be deleted.
Ticket
https://community.openproject.org/wp/AGILE-60
What are you trying to accomplish?
Creating a “Created vs. Resolved” Graph for the Sprint Report
Screenshots
What approach did you choose and why?
Based on the burndown chart, another widget was developed that displays the tasks created and completed during a sprint.
Merge checklist