Class: ThroughputChart
Constant Summary
Constants inherited
from ChartBase
ChartBase::LABEL_POSITIONS
Instance Attribute Summary collapse
Attributes inherited from ChartBase
#aggregated_project, #all_boards, #atlassian_document_format, #board_id, #canvas_height, #canvas_width, #data_quality, #date_range, #file_system, #fix_versions, #holiday_dates, #issues, #settings, #time_range, #timezone_offset, #x_axis_title, #y_axis_title
Instance Method Summary
collapse
#group_issues, #grouping_rules, #init_configuration_block
Methods inherited from ChartBase
#aggregated_project?, #before_run, #call_before_run, #canvas, #canvas_responsive?, #chart_format, #collapsible_issues_panel, #color_block, #color_for, #completed_issues_in_range, #current_board, #cycletime, #cycletime_for_issue, #daily_chart_dataset, #date_annotation, #describe_non_working_days, #description_text, #format_integer, #format_status, #header_text, #holidays, #html_directory, #icon_span, #label_days, #label_hours, #label_issues, #label_minutes, #link_to_issue, #next_id, #normalize_annotation_datetime, #not_visible_text, #random_color, #render, #render_axis_title, #render_top_text, #seam_end, #seam_start, #stagger_label_positions, #status_category_color, #to_human_readable, #working_days_annotation, #wrap_and_render
Constructor Details
Returns a new instance of ThroughputChart.
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
# File 'lib/jirametrics/throughput_chart.rb', line 10
def initialize block
super()
'Throughput Chart'
description_text <<-TEXT
<div>Throughput data is very useful for#{' '}
<a href="https://blog.mikebowler.ca/2024/06/02/probabilistic-forecasting/">probabilistic forecasting</a>,
to determine when we'll be done. Try it now with the
<a href="<%= throughput_forecaster_url %>" target="_blank" rel="noopener noreferrer">
Focused Objective throughput forecaster,</a> to see how long it would take to complete all of the
<%= @not_started_count %> items you currently have in your backlog.
</div>
#{describe_non_working_days}
TEXT
@x_axis_title = nil
@y_axis_title = 'Count of items'
init_configuration_block(block) do
grouping_rules { |issue, rule| default_grouping_rules(issue, rule) }
end
end
|
Instance Attribute Details
#possible_statuses ⇒ Object
Returns the value of attribute possible_statuses.
8
9
10
|
# File 'lib/jirametrics/throughput_chart.rb', line 8
def possible_statuses
@possible_statuses
end
|
Instance Method Details
#calculate_custom_periods ⇒ Object
82
83
84
85
86
87
88
|
# File 'lib/jirametrics/throughput_chart.rb', line 82
def calculate_custom_periods
last_days = @issue_periods.values.compact.uniq.sort
last_days.each_with_index.map do |last_day, i|
first_day = i.zero? ? @date_range.begin : last_days[i - 1] + 1
first_day..last_day
end
end
|
#calculate_time_periods ⇒ Object
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
|
# File 'lib/jirametrics/throughput_chart.rb', line 63
def calculate_time_periods
first_day = @date_range.begin
first_day = case first_day.wday
when 0 then first_day + 1
when 1 then first_day
else first_day + (8 - first_day.wday)
end
periods = []
loop do
last_day = first_day + 6
return periods unless @date_range.include? last_day
periods << (first_day..last_day)
first_day = last_day + 1
end
end
|
#default_grouping_rules(issue, rule) ⇒ Object
58
59
60
61
|
# File 'lib/jirametrics/throughput_chart.rb', line 58
def default_grouping_rules issue, rule
rule.label = issue.type
rule.color = color_for type: issue.type
end
|
#run ⇒ Object
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
|
# File 'lib/jirametrics/throughput_chart.rb', line 32
def run
@not_started_count = issues.count { |issue| issue.started_stopped_times.first.nil? }
completed_issues = completed_issues_in_range include_unstarted: true
rules_to_issues = group_issues completed_issues
data_sets = []
total_data_set = weekly_throughput_dataset(
completed_issues: completed_issues,
label: 'Totals',
color: CssVariable['--throughput_chart_total_line_color'],
dashed: true
)
@throughput_samples = total_data_set[:data].collect { |d| d[:y] }
data_sets << total_data_set if rules_to_issues.size > 1
rules_to_issues.each_key do |rules|
data_sets << weekly_throughput_dataset(
completed_issues: rules_to_issues[rules], label: rules.label, color: rules.color,
label_hint: rules.label_hint
)
end
wrap_and_render(binding, __FILE__)
end
|
#throughput_dataset(periods:, completed_issues:, label_hint: nil) ⇒ Object
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
|
# File 'lib/jirametrics/throughput_chart.rb', line 120
def throughput_dataset periods:, completed_issues:, label_hint: nil
custom_mode = @issue_periods&.values&.any?
periods.collect do |period|
closed_issues = completed_issues.filter_map do |issue|
stop_date = issue.started_stopped_dates.last
next unless stop_date
if custom_mode
[stop_date, issue] if @issue_periods[issue] == period.end
elsif period.include?(stop_date)
[stop_date, issue]
end
end
date_label = "on #{period.end}"
date_label = "between #{period.begin} and #{period.end}" unless period.begin == period.end
with_label_hint = label_hint ? " with #{label_hint}" : ''
{
y: closed_issues.size,
x: "#{period.end}T23:59:59",
title: ["#{closed_issues.size} items closed#{with_label_hint} #{date_label}"] +
closed_issues.collect do |_stop_date, issue|
hint = @issue_hints&.fetch(issue, nil)
"#{issue.key} : #{issue.summary}#{" #{hint}" if hint}"
end
}
end
end
|
#throughput_forecaster_url ⇒ Object
108
109
110
111
112
113
114
115
116
117
118
|
# File 'lib/jirametrics/throughput_chart.rb', line 108
def throughput_forecaster_url
params = {
throughputMode: 'data',
samplesText: @throughput_samples.join(','),
storyLow: @not_started_count,
storyHigh: @not_started_count
}
query = params.map { |k, v| "#{k}=#{CGI.escape(v.to_s)}" }.join('&')
"https://focusedobjective.com/throughput?#{query}"
end
|
#weekly_throughput_dataset(completed_issues:, label:, color:, dashed: false, label_hint: nil) ⇒ Object
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
|
# File 'lib/jirametrics/throughput_chart.rb', line 90
def weekly_throughput_dataset completed_issues:, label:, color:, dashed: false, label_hint: nil
periods = @issue_periods&.values&.any? ? calculate_custom_periods : calculate_time_periods
result = {
label: label,
label_hint: label_hint,
data: throughput_dataset(
periods: periods, completed_issues: completed_issues, label_hint: label_hint
),
fill: false,
showLine: true,
borderColor: color,
lineTension: 0.4,
backgroundColor: color
}
result['borderDash'] = [10, 5] if dashed
result
end
|