jirametrics 2.0.1 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/jirametrics/aggregate_config.rb +1 -1
- data/lib/jirametrics/aging_work_bar_chart.rb +18 -13
- data/lib/jirametrics/aging_work_in_progress_chart.rb +8 -6
- data/lib/jirametrics/aging_work_table.rb +21 -16
- data/lib/jirametrics/anonymizer.rb +6 -5
- data/lib/jirametrics/chart_base.rb +35 -19
- data/lib/jirametrics/css_variable.rb +33 -0
- data/lib/jirametrics/cycletime_scatterplot.rb +8 -9
- data/lib/jirametrics/daily_wip_by_age_chart.rb +43 -17
- data/lib/jirametrics/daily_wip_by_blocked_stalled_chart.rb +32 -17
- data/lib/jirametrics/daily_wip_by_parent_chart.rb +42 -0
- data/lib/jirametrics/daily_wip_chart.rb +67 -6
- data/lib/jirametrics/data_quality_report.rb +1 -1
- data/lib/jirametrics/dependency_chart.rb +18 -14
- data/lib/jirametrics/downloader.rb +13 -11
- data/lib/jirametrics/examples/aggregated_project.rb +17 -20
- data/lib/jirametrics/examples/standard_project.rb +10 -18
- data/lib/jirametrics/expedited_chart.rb +17 -15
- data/lib/jirametrics/exporter.rb +26 -20
- data/lib/jirametrics/grouping_rules.rb +7 -1
- data/lib/jirametrics/html/aging_work_bar_chart.erb +12 -6
- data/lib/jirametrics/html/aging_work_in_progress_chart.erb +8 -2
- data/lib/jirametrics/html/aging_work_table.erb +11 -19
- data/lib/jirametrics/html/cycletime_histogram.erb +9 -3
- data/lib/jirametrics/html/cycletime_scatterplot.erb +10 -4
- data/lib/jirametrics/html/daily_wip_chart.erb +18 -5
- data/lib/jirametrics/html/expedited_chart.erb +11 -5
- data/lib/jirametrics/html/hierarchy_table.erb +1 -1
- data/lib/jirametrics/html/index.css +186 -0
- data/lib/jirametrics/html/index.erb +8 -36
- data/lib/jirametrics/html/sprint_burndown.erb +11 -6
- data/lib/jirametrics/html/story_point_accuracy_chart.erb +9 -4
- data/lib/jirametrics/html/throughput_chart.erb +11 -5
- data/lib/jirametrics/html_report_config.rb +28 -3
- data/lib/jirametrics/issue.rb +5 -3
- data/lib/jirametrics/jira_gateway.rb +5 -2
- data/lib/jirametrics/project_config.rb +14 -19
- data/lib/jirametrics/settings.json +7 -0
- data/lib/jirametrics/sprint_burndown.rb +10 -4
- data/lib/jirametrics/status_collection.rb +1 -1
- data/lib/jirametrics/story_point_accuracy_chart.rb +20 -10
- data/lib/jirametrics/throughput_chart.rb +10 -2
- data/lib/jirametrics.rb +2 -0
- metadata +7 -3
@@ -1,20 +1,3 @@
|
|
1
|
-
<h1>Aging Work Table</h1>
|
2
|
-
<p>
|
3
|
-
This chart shows all active (started but not completed) work, ordered from oldest at the top to
|
4
|
-
newest at the bottom.
|
5
|
-
</p>
|
6
|
-
<p>
|
7
|
-
If there are expedited items that haven't yet started then they're at the bottom of the table. By the
|
8
|
-
very definition of expedited, if we haven't started them already, we'd better get on that.
|
9
|
-
</p>
|
10
|
-
<p>
|
11
|
-
<% if age_cutoff > 0 %>
|
12
|
-
Items less than <%= label_days age_cutoff %> old have been excluded from this chart to provide more
|
13
|
-
focus on the older items. The exception are items that are either expedited or blocked - these are
|
14
|
-
shown no matter how old they are.
|
15
|
-
<% end %>
|
16
|
-
</p>
|
17
|
-
|
18
1
|
<table class='standard'>
|
19
2
|
<thead>
|
20
3
|
<tr>
|
@@ -31,14 +14,23 @@
|
|
31
14
|
</tr>
|
32
15
|
</thead>
|
33
16
|
<tbody>
|
17
|
+
<% show_age_cutoff_bar_at = age_cutoff %>
|
34
18
|
<% aging_issues.each do |issue| %>
|
19
|
+
<% issue_age = issue.board.cycletime.age(issue, today: @today) %>
|
20
|
+
<% if show_age_cutoff_bar_at && issue_age&.<(show_age_cutoff_bar_at) %>
|
21
|
+
<tr><th colspan=100 style="text-align: left; padding-top: 1em;">
|
22
|
+
The items below are less than <%= label_days age_cutoff %> old, and are only on this report
|
23
|
+
because they're either expedited or blocked.
|
24
|
+
</th></tr>
|
25
|
+
<% show_age_cutoff_bar_at = nil %>
|
26
|
+
<% end %>
|
35
27
|
<tr>
|
36
|
-
<td style="text-align: right;"><%=
|
28
|
+
<td style="text-align: right;"><%= issue_age || 'Not started' %></td>
|
37
29
|
<td><%= expedited_text(issue) %></td>
|
38
30
|
<td><%= blocked_text(issue) %></td>
|
39
31
|
<td>
|
40
32
|
<% parent_hierarchy(issue).each_with_index do |parent, index| %>
|
41
|
-
<% color =
|
33
|
+
<% color = parent != issue ? "var(--hierarchy-table-inactive-item-text-color)" : 'var(--default-text-color)' %>
|
42
34
|
<div style="padding-left: <%= index %>em; color: <%= color %>">
|
43
35
|
<span style="white-space: nowrap;">
|
44
36
|
<img src="<%= parent.type_icon_url %>" title="<%= parent.type %>"/>
|
@@ -1,4 +1,4 @@
|
|
1
|
-
<div>
|
1
|
+
<div class="chart">
|
2
2
|
<canvas id="<%= chart_id %>" width="<%= canvas_width %>" height="<%= canvas_height %>"></canvas>
|
3
3
|
</div>
|
4
4
|
<script>
|
@@ -17,14 +17,20 @@ new Chart(document.getElementById('<%= chart_id %>').getContext('2d'),
|
|
17
17
|
title: {
|
18
18
|
display: true,
|
19
19
|
text: 'Cycletime in days'
|
20
|
-
}
|
20
|
+
},
|
21
|
+
grid: {
|
22
|
+
color: <%= CssVariable['--grid-line-color'].to_json %>
|
23
|
+
},
|
21
24
|
},
|
22
25
|
y: {
|
23
26
|
stacked: true,
|
24
27
|
title: {
|
25
28
|
display: true,
|
26
29
|
text: 'Number of items that had that cycletime'
|
27
|
-
}
|
30
|
+
},
|
31
|
+
grid: {
|
32
|
+
color: <%= CssVariable['--grid-line-color'].to_json %>
|
33
|
+
},
|
28
34
|
}
|
29
35
|
},
|
30
36
|
plugins: {
|
@@ -1,4 +1,4 @@
|
|
1
|
-
<div>
|
1
|
+
<div class="chart">
|
2
2
|
<canvas id="<%= chart_id %>" width="<%= canvas_width %>" height="<%= canvas_height %>"></canvas>
|
3
3
|
</div>
|
4
4
|
<script>
|
@@ -20,6 +20,9 @@ new Chart(document.getElementById('<%= chart_id %>').getContext('2d'), {
|
|
20
20
|
display: true,
|
21
21
|
labelString: 'Date Completed'
|
22
22
|
},
|
23
|
+
grid: {
|
24
|
+
color: <%= CssVariable['--grid-line-color'].to_json %>
|
25
|
+
},
|
23
26
|
min: "<%= date_range.begin.to_s %>",
|
24
27
|
max: "<%= (date_range.end + 1).to_s %>"
|
25
28
|
},
|
@@ -34,6 +37,9 @@ new Chart(document.getElementById('<%= chart_id %>').getContext('2d'), {
|
|
34
37
|
display: true,
|
35
38
|
text: 'Cycle time in days'
|
36
39
|
},
|
40
|
+
grid: {
|
41
|
+
color: <%= CssVariable['--grid-line-color'].to_json %>
|
42
|
+
},
|
37
43
|
}
|
38
44
|
},
|
39
45
|
plugins: {
|
@@ -53,8 +59,8 @@ new Chart(document.getElementById('<%= chart_id %>').getContext('2d'), {
|
|
53
59
|
type: 'box',
|
54
60
|
xMin: '<%= range.begin %>T00:00:00',
|
55
61
|
xMax: '<%= range.end %>T23:59:59',
|
56
|
-
backgroundColor: '
|
57
|
-
borderColor: '
|
62
|
+
backgroundColor: <%= CssVariable.new('--non-working-days-color').to_json %>,
|
63
|
+
borderColor: <%= CssVariable.new('--non-working-days-color').to_json %>
|
58
64
|
},
|
59
65
|
<% end %>
|
60
66
|
|
@@ -64,7 +70,7 @@ new Chart(document.getElementById('<%= chart_id %>').getContext('2d'), {
|
|
64
70
|
type: 'line',
|
65
71
|
yMin: <%= percent %>,
|
66
72
|
yMax: <%= percent %>,
|
67
|
-
borderColor:
|
73
|
+
borderColor: <%= color.to_json %>,
|
68
74
|
borderWidth: 1,
|
69
75
|
drawTime: 'beforeDraw'
|
70
76
|
},
|
@@ -1,4 +1,4 @@
|
|
1
|
-
<div>
|
1
|
+
<div class="chart">
|
2
2
|
<canvas id="<%= chart_id %>" width="<%= canvas_width %>" height="<%= canvas_height %>"></canvas>
|
3
3
|
</div>
|
4
4
|
<script>
|
@@ -20,7 +20,10 @@ new Chart(document.getElementById('<%= chart_id %>').getContext('2d'),
|
|
20
20
|
time: {
|
21
21
|
unit: 'day'
|
22
22
|
},
|
23
|
-
stacked: true
|
23
|
+
stacked: true,
|
24
|
+
grid: {
|
25
|
+
color: <%= CssVariable['--grid-line-color'].to_json %>
|
26
|
+
},
|
24
27
|
},
|
25
28
|
y: {
|
26
29
|
stacked: true,
|
@@ -32,7 +35,9 @@ new Chart(document.getElementById('<%= chart_id %>').getContext('2d'),
|
|
32
35
|
display: true,
|
33
36
|
text: 'Count of items'
|
34
37
|
},
|
35
|
-
|
38
|
+
grid: {
|
39
|
+
color: <%= CssVariable['--grid-line-color'].to_json %>
|
40
|
+
},
|
36
41
|
}
|
37
42
|
},
|
38
43
|
plugins: {
|
@@ -51,11 +56,19 @@ new Chart(document.getElementById('<%= chart_id %>').getContext('2d'),
|
|
51
56
|
type: 'box',
|
52
57
|
xMin: '<%= range.begin %>T00:00:00',
|
53
58
|
xMax: '<%= range.end %>T23:59:59',
|
54
|
-
backgroundColor: '
|
55
|
-
borderColor: '
|
59
|
+
backgroundColor: <%= CssVariable.new('--non-working-days-color').to_json %>,
|
60
|
+
borderColor: <%= CssVariable.new('--non-working-days-color').to_json %>
|
56
61
|
},
|
57
62
|
<% end %>
|
58
63
|
}
|
64
|
+
},
|
65
|
+
legend: {
|
66
|
+
labels: {
|
67
|
+
filter: function(item, chart) {
|
68
|
+
// Logic to remove a particular legend item goes here
|
69
|
+
return !item.text.includes('Trendline');
|
70
|
+
}
|
71
|
+
}
|
59
72
|
}
|
60
73
|
}
|
61
74
|
}
|
@@ -1,4 +1,4 @@
|
|
1
|
-
<div>
|
1
|
+
<div class="chart">
|
2
2
|
<canvas id="<%= chart_id %>" width="<%= canvas_width %>" height="<%= canvas_height %>"></canvas>
|
3
3
|
</div>
|
4
4
|
<script>
|
@@ -24,7 +24,10 @@ new Chart(document.getElementById('<%= chart_id %>').getContext('2d'), {
|
|
24
24
|
labelString: 'Date Completed'
|
25
25
|
},
|
26
26
|
min: "<%= date_range.begin.to_s %>",
|
27
|
-
max: "<%= date_range.end.to_s %>"
|
27
|
+
max: "<%= date_range.end.to_s %>",
|
28
|
+
grid: {
|
29
|
+
color: <%= CssVariable['--grid-line-color'].to_json %>
|
30
|
+
},
|
28
31
|
},
|
29
32
|
y: {
|
30
33
|
scaleLabel: {
|
@@ -35,7 +38,10 @@ new Chart(document.getElementById('<%= chart_id %>').getContext('2d'), {
|
|
35
38
|
display: true,
|
36
39
|
text: 'Age in days'
|
37
40
|
},
|
38
|
-
min: 0
|
41
|
+
min: 0,
|
42
|
+
grid: {
|
43
|
+
color: <%= CssVariable['--grid-line-color'].to_json %>
|
44
|
+
},
|
39
45
|
}
|
40
46
|
},
|
41
47
|
plugins: {
|
@@ -55,8 +61,8 @@ new Chart(document.getElementById('<%= chart_id %>').getContext('2d'), {
|
|
55
61
|
type: 'box',
|
56
62
|
xMin: '<%= range.begin %>T00:00:00',
|
57
63
|
xMax: '<%= range.end %>T23:59:59',
|
58
|
-
backgroundColor: '
|
59
|
-
borderColor: '
|
64
|
+
backgroundColor: <%= CssVariable.new('--non-working-days-color').to_json %>,
|
65
|
+
borderColor: <%= CssVariable.new('--non-working-days-color').to_json %>
|
60
66
|
},
|
61
67
|
<% end %>
|
62
68
|
}
|
@@ -14,7 +14,7 @@
|
|
14
14
|
<tr>
|
15
15
|
<td style="text-align: right;"><%= issue.board.cycletime.age(issue, today: @today) || 'Not started' %></td>
|
16
16
|
<td>
|
17
|
-
<% color = (node.children?
|
17
|
+
<% color = "var(--hierarchy-table-#{ 'in' if node.children? }active-item-text-color)" %>
|
18
18
|
<span style="padding-left: <%= depth - 1 %>em;" />
|
19
19
|
<span style="white-space: nowrap;">
|
20
20
|
<img src="<%= issue.type_icon_url %>" title="<%= issue.type %>"/>
|
@@ -0,0 +1,186 @@
|
|
1
|
+
:root {
|
2
|
+
--body-background: white;
|
3
|
+
--default-text-color: black;
|
4
|
+
--grid-line-color: lightgray;
|
5
|
+
|
6
|
+
--cycletime-scatterplot-overall-trendline-color: gray;
|
7
|
+
|
8
|
+
--non-working-days-color: #F0F0F0;
|
9
|
+
--expedited-color: red;
|
10
|
+
--blocked-color: #FF7400;
|
11
|
+
--stalled-color: orange;
|
12
|
+
--dead-color: black;
|
13
|
+
|
14
|
+
--type-story-color: #4bc14b;
|
15
|
+
--type-task-color: blue;
|
16
|
+
--type-bug-color: orange;
|
17
|
+
--type-spike-color: #9400D3;
|
18
|
+
|
19
|
+
--status-category-todo-color: gray;
|
20
|
+
--status-category-inprogress-color: #2663ff;
|
21
|
+
--status-category-done-color: #00ff00;
|
22
|
+
|
23
|
+
--aging-work-bar-chart-percentage-line-color: red;
|
24
|
+
--aging-work-bar-chart-separator-color: white;
|
25
|
+
|
26
|
+
--throughput_chart_total_line_color: gray;
|
27
|
+
|
28
|
+
--aging-work-in-progress-chart-shading-color: lightgray;
|
29
|
+
--aging-work-in-progress-by-age-trend-line-color: gray;
|
30
|
+
|
31
|
+
--hierarchy-table-inactive-item-text-color: gray;
|
32
|
+
|
33
|
+
--wip-chart-completed-color: #00ff00;
|
34
|
+
--wip-chart-completed-but-not-started-color: #99FF99;
|
35
|
+
--wip-chart-duration-less-than-day-color: #ffef41;
|
36
|
+
--wip-chart-duration-week-or-less-color: #dcc900;
|
37
|
+
--wip-chart-duration-two-weeks-or-less-color: #dfa000;
|
38
|
+
--wip-chart-duration-four-weeks-or-less-color: #eb7200;
|
39
|
+
--wip-chart-duration-more-than-four-weeks-color: #e70000;
|
40
|
+
--wip-chart-active-color: #326cff;
|
41
|
+
--wip-chart-border-color: gray;
|
42
|
+
|
43
|
+
--estimate-accuracy-chart-completed-fill-color: #00ff00;
|
44
|
+
--estimate-accuracy-chart-completed-border-color: green;
|
45
|
+
--estimate-accuracy-chart-active-fill-color: #FFCCCB;
|
46
|
+
--estimate-accuracy-chart-active-border-color: red;
|
47
|
+
|
48
|
+
--expedited-chart-no-longer-expedited: gray;
|
49
|
+
--expedited-chart-dot-issue-started-color: orange;
|
50
|
+
--expedited-chart-dot-issue-stopped-color: green;
|
51
|
+
--expedited-chart-dot-expedite-started-color: red;
|
52
|
+
--expedited-chart-dot-expedite-stopped-color: green;
|
53
|
+
|
54
|
+
--sprint-burndown-sprint-color-1: blue;
|
55
|
+
--sprint-burndown-sprint-color-2: orange;
|
56
|
+
--sprint-burndown-sprint-color-3: green;
|
57
|
+
--sprint-burndown-sprint-color-4: red;
|
58
|
+
--sprint-burndown-sprint-color-5: brown;
|
59
|
+
|
60
|
+
|
61
|
+
}
|
62
|
+
|
63
|
+
body {
|
64
|
+
background-color: var(--body-background);
|
65
|
+
color: var(--default-text-color);
|
66
|
+
}
|
67
|
+
|
68
|
+
h1 {
|
69
|
+
border: 1px solid black;
|
70
|
+
background: lightgray;
|
71
|
+
padding-left: 0.2em;
|
72
|
+
}
|
73
|
+
dl, dd, dt {
|
74
|
+
padding: 0;
|
75
|
+
margin: 0;
|
76
|
+
}
|
77
|
+
dd {
|
78
|
+
margin-bottom: 0.4em;
|
79
|
+
}
|
80
|
+
span.highlight {
|
81
|
+
background: #FDD5B1;
|
82
|
+
}
|
83
|
+
a.issue_key {
|
84
|
+
white-space: nowrap;
|
85
|
+
}
|
86
|
+
table.standard {
|
87
|
+
th {
|
88
|
+
border-bottom: 1px solid gray;
|
89
|
+
position: sticky;
|
90
|
+
top: 0;
|
91
|
+
background: white;
|
92
|
+
}
|
93
|
+
td {
|
94
|
+
padding-left: 0.5em;
|
95
|
+
padding-right: 0.5em;
|
96
|
+
vertical-align: top;
|
97
|
+
}
|
98
|
+
tr:nth-child(odd){
|
99
|
+
background-color: #eee;
|
100
|
+
}
|
101
|
+
}
|
102
|
+
.quality_note_bullet {
|
103
|
+
color: red;
|
104
|
+
}
|
105
|
+
|
106
|
+
.chart {
|
107
|
+
background-color: white;
|
108
|
+
}
|
109
|
+
|
110
|
+
div.p {
|
111
|
+
margin: 0.5em 0;
|
112
|
+
padding: 0;
|
113
|
+
}
|
114
|
+
|
115
|
+
div.color_block {
|
116
|
+
display: inline-block;
|
117
|
+
width: 0.9em;
|
118
|
+
height: 0.9em;
|
119
|
+
border: 1px solid black;
|
120
|
+
}
|
121
|
+
|
122
|
+
@media screen and (prefers-color-scheme: dark) {
|
123
|
+
:root {
|
124
|
+
--non-working-days-color: #2f2f2f;
|
125
|
+
--type-story-color: #6fb86f;
|
126
|
+
--type-task-color: #0021b3;
|
127
|
+
--type-bug-color: #bb5603;
|
128
|
+
|
129
|
+
--body-background: #343434;
|
130
|
+
--default-text-color: #aaa;
|
131
|
+
--grid-line-color: #424242;
|
132
|
+
|
133
|
+
--expedited-color: #b90000;
|
134
|
+
--blocked-color: #c75b02;
|
135
|
+
--stalled-color: #ae7202;
|
136
|
+
--dead-color: black;
|
137
|
+
--wip-chart-active-color: #2551c1;
|
138
|
+
|
139
|
+
--aging-work-in-progress-chart-shading-color: #b4b4b4;
|
140
|
+
|
141
|
+
--status-category-inprogress-color: #1c49bb;
|
142
|
+
|
143
|
+
--cycletime-scatterplot-overall-trendline-color: gray;
|
144
|
+
|
145
|
+
--hierarchy-table-inactive-item-text-color: #939393;
|
146
|
+
|
147
|
+
--wip-chart-completed-color: #03cb03;
|
148
|
+
--wip-chart-completed-but-not-started-color: #99FF99;
|
149
|
+
--wip-chart-duration-less-than-day-color: #d2d988;
|
150
|
+
--wip-chart-duration-week-or-less-color: #dfcd00;
|
151
|
+
--wip-chart-duration-two-weeks-or-less-color: #cf9400;
|
152
|
+
--wip-chart-duration-four-weeks-or-less-color: #c25e00;
|
153
|
+
--wip-chart-duration-more-than-four-weeks-color: #8e0000;
|
154
|
+
}
|
155
|
+
|
156
|
+
h1 {
|
157
|
+
color: #e0e0e0;
|
158
|
+
background-color: #656565;
|
159
|
+
}
|
160
|
+
|
161
|
+
a[href] {
|
162
|
+
color: #1e8ad6;
|
163
|
+
}
|
164
|
+
|
165
|
+
a[href]:hover {
|
166
|
+
color: #3ba0e6;
|
167
|
+
}
|
168
|
+
|
169
|
+
.chart {
|
170
|
+
background: var(--body-background);
|
171
|
+
}
|
172
|
+
|
173
|
+
table.standard {
|
174
|
+
th {
|
175
|
+
border-bottom: 1px solid gray;
|
176
|
+
background: var(--body-background);
|
177
|
+
}
|
178
|
+
tr:nth-child(odd){
|
179
|
+
background-color: #656565;
|
180
|
+
}
|
181
|
+
}
|
182
|
+
|
183
|
+
div.color_block {
|
184
|
+
border: 1px solid lightgray;
|
185
|
+
}
|
186
|
+
}
|
@@ -17,44 +17,16 @@
|
|
17
17
|
document.getElementById(issues_id).style.display = 'none'
|
18
18
|
}
|
19
19
|
}
|
20
|
+
// If we switch between light/dark mode then force a refresh so all charts will redraw correctly
|
21
|
+
// in the other colour scheme.
|
22
|
+
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', event => {
|
23
|
+
location.reload()
|
24
|
+
})
|
25
|
+
|
20
26
|
</script>
|
21
27
|
<style>
|
22
|
-
|
23
|
-
|
24
|
-
background: lightgray;
|
25
|
-
padding-left: 0.2em;
|
26
|
-
}
|
27
|
-
dl, dd, dt {
|
28
|
-
padding: 0;
|
29
|
-
margin: 0;
|
30
|
-
}
|
31
|
-
dd {
|
32
|
-
margin-bottom: 0.4em;
|
33
|
-
}
|
34
|
-
span.highlight {
|
35
|
-
background: #FDD5B1;
|
36
|
-
}
|
37
|
-
a.issue_key {
|
38
|
-
white-space: nowrap;
|
39
|
-
}
|
40
|
-
table.standard thead tr th {
|
41
|
-
border-bottom: 1px solid gray;
|
42
|
-
position: sticky;
|
43
|
-
top: 0;
|
44
|
-
background: white;
|
45
|
-
}
|
46
|
-
table.standard tbody tr td {
|
47
|
-
padding-left: 0.5em;
|
48
|
-
padding-right: 0.5em;
|
49
|
-
vertical-align: top;
|
50
|
-
}
|
51
|
-
table.standard tbody tr:nth-child(odd){
|
52
|
-
background-color: #eee;
|
53
|
-
}
|
54
|
-
.quality_note_bullet {
|
55
|
-
color: red;
|
56
|
-
}
|
57
|
-
</style>
|
28
|
+
<%= css %>
|
29
|
+
</style>
|
58
30
|
</head>
|
59
31
|
<body>
|
60
32
|
<div>
|
@@ -1,6 +1,6 @@
|
|
1
1
|
<h2>Burndown by <%= y_axis_title %></h2>
|
2
2
|
|
3
|
-
<div>
|
3
|
+
<div class="chart">
|
4
4
|
<canvas id="<%= chart_id %>" width="<%= canvas_width %>" height="<%= canvas_height %>"></canvas>
|
5
5
|
</div>
|
6
6
|
<script>
|
@@ -26,8 +26,10 @@ new Chart(document.getElementById('<%= chart_id %>').getContext('2d'), {
|
|
26
26
|
labelString: 'Date'
|
27
27
|
},
|
28
28
|
min: "<%= date_range.begin.to_s %>",
|
29
|
-
max: "<%= (date_range.end + 1).to_s %>"
|
30
|
-
|
29
|
+
max: "<%= (date_range.end + 1).to_s %>",
|
30
|
+
grid: {
|
31
|
+
color: <%= CssVariable['--grid-line-color'].to_json %>
|
32
|
+
},
|
31
33
|
},
|
32
34
|
y: {
|
33
35
|
scaleLabel: {
|
@@ -38,7 +40,10 @@ new Chart(document.getElementById('<%= chart_id %>').getContext('2d'), {
|
|
38
40
|
display: true,
|
39
41
|
text: "<%= y_axis_title %>"
|
40
42
|
},
|
41
|
-
min: 0.0
|
43
|
+
min: 0.0,
|
44
|
+
grid: {
|
45
|
+
color: <%= CssVariable['--grid-line-color'].to_json %>
|
46
|
+
},
|
42
47
|
}
|
43
48
|
},
|
44
49
|
plugins: {
|
@@ -57,8 +62,8 @@ new Chart(document.getElementById('<%= chart_id %>').getContext('2d'), {
|
|
57
62
|
type: 'box',
|
58
63
|
xMin: '<%= range.begin %>T00:00:00',
|
59
64
|
xMax: '<%= range.end %>T23:59:59',
|
60
|
-
backgroundColor: '
|
61
|
-
borderColor: '
|
65
|
+
backgroundColor: <%= CssVariable.new('--non-working-days-color').to_json %>,
|
66
|
+
borderColor: <%= CssVariable.new('--non-working-days-color').to_json %>
|
62
67
|
},
|
63
68
|
<% end %>
|
64
69
|
}
|
@@ -1,4 +1,4 @@
|
|
1
|
-
<div>
|
1
|
+
<div class="chart">
|
2
2
|
<canvas id="<%= chart_id %>" width="<%= canvas_width %>" height="<%= canvas_height %>"></canvas>
|
3
3
|
</div>
|
4
4
|
<script>
|
@@ -24,8 +24,10 @@ new Chart(document.getElementById('<%= chart_id %>').getContext('2d'), {
|
|
24
24
|
display: true,
|
25
25
|
text: "Cycletime (days)"
|
26
26
|
},
|
27
|
-
min: 0
|
28
|
-
|
27
|
+
min: 0,
|
28
|
+
grid: {
|
29
|
+
color: <%= CssVariable['--grid-line-color'].to_json %>
|
30
|
+
},
|
29
31
|
},
|
30
32
|
y: {
|
31
33
|
type: "<%= @y_axis_type %>",
|
@@ -40,7 +42,10 @@ new Chart(document.getElementById('<%= chart_id %>').getContext('2d'), {
|
|
40
42
|
display: true,
|
41
43
|
text: "<%= @y_axis_label %>"
|
42
44
|
},
|
43
|
-
min: 0.0
|
45
|
+
min: 0.0,
|
46
|
+
grid: {
|
47
|
+
color: <%= CssVariable['--grid-line-color'].to_json %>
|
48
|
+
},
|
44
49
|
}
|
45
50
|
},
|
46
51
|
plugins: {
|
@@ -1,5 +1,5 @@
|
|
1
1
|
|
2
|
-
<div>
|
2
|
+
<div class="chart">
|
3
3
|
<canvas id="<%= chart_id %>" width="<%= canvas_width %>" height="<%= canvas_height %>"></canvas>
|
4
4
|
</div>
|
5
5
|
<script>
|
@@ -23,7 +23,10 @@ new Chart(document.getElementById('<%= chart_id %>').getContext('2d'), {
|
|
23
23
|
scaleLabel: {
|
24
24
|
display: true,
|
25
25
|
labelString: 'Date Completed'
|
26
|
-
}
|
26
|
+
},
|
27
|
+
grid: {
|
28
|
+
color: <%= CssVariable['--grid-line-color'].to_json %>
|
29
|
+
},
|
27
30
|
},
|
28
31
|
y: {
|
29
32
|
scaleLabel: {
|
@@ -33,7 +36,10 @@ new Chart(document.getElementById('<%= chart_id %>').getContext('2d'), {
|
|
33
36
|
display: true,
|
34
37
|
text: 'Count of items'
|
35
38
|
},
|
36
|
-
min: 0
|
39
|
+
min: 0,
|
40
|
+
grid: {
|
41
|
+
color: <%= CssVariable['--grid-line-color'].to_json %>
|
42
|
+
},
|
37
43
|
},
|
38
44
|
},
|
39
45
|
plugins: {
|
@@ -52,8 +58,8 @@ new Chart(document.getElementById('<%= chart_id %>').getContext('2d'), {
|
|
52
58
|
type: 'box',
|
53
59
|
xMin: '<%= range.begin %>T00:00:00',
|
54
60
|
xMax: '<%= range.end %>T23:59:59',
|
55
|
-
backgroundColor: '
|
56
|
-
borderColor: '
|
61
|
+
backgroundColor: <%= CssVariable.new('--non-working-days-color').to_json %>,
|
62
|
+
borderColor: <%= CssVariable.new('--non-working-days-color').to_json %>
|
57
63
|
},
|
58
64
|
<% end %>
|
59
65
|
}
|
@@ -26,6 +26,11 @@ class HtmlReportConfig
|
|
26
26
|
end
|
27
27
|
end
|
28
28
|
|
29
|
+
# Mostly this is its own method so it can be called from the config
|
30
|
+
def included_projects
|
31
|
+
@file_config.project_config.aggregate_config.included_projects
|
32
|
+
end
|
33
|
+
|
29
34
|
def run
|
30
35
|
instance_eval(&@block)
|
31
36
|
|
@@ -36,11 +41,21 @@ class HtmlReportConfig
|
|
36
41
|
|
37
42
|
File.open @file_config.output_filename, 'w' do |file|
|
38
43
|
html_directory = "#{Pathname.new(File.realpath(__FILE__)).dirname}/html"
|
39
|
-
|
44
|
+
css = load_css html_directory: html_directory
|
45
|
+
erb = ERB.new File.read(File.join(html_directory, 'index.erb'))
|
40
46
|
file.puts erb.result(binding)
|
41
47
|
end
|
42
48
|
end
|
43
49
|
|
50
|
+
def load_css html_directory:
|
51
|
+
base_css = File.read(File.join(html_directory, 'index.css'))
|
52
|
+
extra_css_filename = settings['include_css']
|
53
|
+
return base_css unless extra_css_filename && File.exist?(extra_css_filename)
|
54
|
+
|
55
|
+
@file_config.project_config.exporter.file_system.log("including css from file: #{extra_css_filename}")
|
56
|
+
base_css << "\n\n" << File.read(extra_css_filename)
|
57
|
+
end
|
58
|
+
|
44
59
|
def board_id id = nil
|
45
60
|
@board_id = id unless id.nil?
|
46
61
|
@board_id
|
@@ -92,6 +107,10 @@ class HtmlReportConfig
|
|
92
107
|
execute_chart DailyWipByBlockedStalledChart.new
|
93
108
|
end
|
94
109
|
|
110
|
+
def daily_wip_by_parent_chart &block
|
111
|
+
execute_chart DailyWipByParentChart.new block
|
112
|
+
end
|
113
|
+
|
95
114
|
def throughput_chart &block
|
96
115
|
execute_chart ThroughputChart.new(block)
|
97
116
|
end
|
@@ -109,7 +128,8 @@ class HtmlReportConfig
|
|
109
128
|
end
|
110
129
|
|
111
130
|
def html string, type: :body
|
112
|
-
|
131
|
+
allowed_types = %i[body header]
|
132
|
+
raise "Unexpected type: #{type} allowed_types: #{allowed_types.inspect}" unless allowed_types.include? type
|
113
133
|
|
114
134
|
@sections << [string, type]
|
115
135
|
end
|
@@ -145,13 +165,18 @@ class HtmlReportConfig
|
|
145
165
|
execute_chart DependencyChart.new block
|
146
166
|
end
|
147
167
|
|
168
|
+
# have an explicit method here so that index.erb can call 'settings' just as any other erb can.
|
169
|
+
def settings
|
170
|
+
@file_config.project_config.settings
|
171
|
+
end
|
172
|
+
|
148
173
|
def execute_chart chart, &after_init_block
|
149
174
|
project_config = @file_config.project_config
|
150
175
|
|
151
176
|
chart.issues = issues
|
152
177
|
chart.time_range = project_config.time_range
|
153
178
|
chart.timezone_offset = timezone_offset
|
154
|
-
chart.settings =
|
179
|
+
chart.settings = settings
|
155
180
|
|
156
181
|
chart.all_boards = project_config.all_boards
|
157
182
|
chart.board_id = find_board_id if chart.respond_to? :board_id=
|
data/lib/jirametrics/issue.rb
CHANGED
@@ -30,7 +30,8 @@ class Issue
|
|
30
30
|
fabricate_change(field_name: 'status'),
|
31
31
|
fabricate_change(field_name: 'priority')
|
32
32
|
].compact + @changes
|
33
|
-
rescue
|
33
|
+
rescue # rubocop:disable Style/RescueStandardError
|
34
|
+
# All we're doing is adding information to the existing exception and letting it propogate up
|
34
35
|
raise "Unable to initialize #{raw['key']}"
|
35
36
|
end
|
36
37
|
|
@@ -252,7 +253,7 @@ class Issue
|
|
252
253
|
end
|
253
254
|
|
254
255
|
blocked_link_texts = settings['blocked_link_text']
|
255
|
-
stalled_threshold = settings['
|
256
|
+
stalled_threshold = settings['stalled_threshold_days']
|
256
257
|
|
257
258
|
blocking_issue_keys = []
|
258
259
|
|
@@ -283,8 +284,9 @@ class Issue
|
|
283
284
|
blocking_status = change.value
|
284
285
|
end
|
285
286
|
elsif change.link?
|
287
|
+
# Example: "This issue is satisfied by ANON-30465"
|
286
288
|
unless /^This issue (?<link_text>.+) (?<issue_key>.+)$/ =~ (change.value || change.old_value)
|
287
|
-
puts "Can't parse link text: #{change.value || change.old_value}"
|
289
|
+
puts "Issue(#{key}) Can't parse link text: #{change.value || change.old_value}"
|
288
290
|
next
|
289
291
|
end
|
290
292
|
|