jirametrics 2.0 → 2.12.1

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.
Files changed (75) hide show
  1. checksums.yaml +4 -4
  2. data/lib/jirametrics/aggregate_config.rb +19 -26
  3. data/lib/jirametrics/aging_work_bar_chart.rb +79 -54
  4. data/lib/jirametrics/aging_work_in_progress_chart.rb +106 -40
  5. data/lib/jirametrics/aging_work_table.rb +84 -54
  6. data/lib/jirametrics/anonymizer.rb +6 -5
  7. data/lib/jirametrics/blocked_stalled_change.rb +24 -4
  8. data/lib/jirametrics/board.rb +51 -23
  9. data/lib/jirametrics/board_config.rb +9 -4
  10. data/lib/jirametrics/board_movement_calculator.rb +155 -0
  11. data/lib/jirametrics/change_item.rb +56 -21
  12. data/lib/jirametrics/chart_base.rb +101 -61
  13. data/lib/jirametrics/columns_config.rb +4 -0
  14. data/lib/jirametrics/css_variable.rb +33 -0
  15. data/lib/jirametrics/cycletime_config.rb +59 -8
  16. data/lib/jirametrics/cycletime_histogram.rb +69 -4
  17. data/lib/jirametrics/cycletime_scatterplot.rb +11 -15
  18. data/lib/jirametrics/daily_view.rb +277 -0
  19. data/lib/jirametrics/daily_wip_by_age_chart.rb +44 -20
  20. data/lib/jirametrics/daily_wip_by_blocked_stalled_chart.rb +37 -35
  21. data/lib/jirametrics/daily_wip_by_parent_chart.rb +38 -0
  22. data/lib/jirametrics/daily_wip_chart.rb +61 -14
  23. data/lib/jirametrics/data_quality_report.rb +222 -41
  24. data/lib/jirametrics/dependency_chart.rb +54 -23
  25. data/lib/jirametrics/download_config.rb +12 -0
  26. data/lib/jirametrics/downloader.rb +86 -56
  27. data/lib/jirametrics/estimate_accuracy_chart.rb +173 -0
  28. data/lib/jirametrics/estimation_configuration.rb +25 -0
  29. data/lib/jirametrics/examples/aggregated_project.rb +22 -39
  30. data/lib/jirametrics/examples/standard_project.rb +26 -48
  31. data/lib/jirametrics/expedited_chart.rb +28 -25
  32. data/lib/jirametrics/exporter.rb +59 -32
  33. data/lib/jirametrics/file_config.rb +35 -14
  34. data/lib/jirametrics/file_system.rb +48 -3
  35. data/lib/jirametrics/flow_efficiency_scatterplot.rb +111 -0
  36. data/lib/jirametrics/groupable_issue_chart.rb +2 -6
  37. data/lib/jirametrics/grouping_rules.rb +7 -1
  38. data/lib/jirametrics/hierarchy_table.rb +4 -4
  39. data/lib/jirametrics/html/aging_work_bar_chart.erb +13 -16
  40. data/lib/jirametrics/html/aging_work_in_progress_chart.erb +28 -5
  41. data/lib/jirametrics/html/aging_work_table.erb +21 -25
  42. data/lib/jirametrics/html/cycletime_histogram.erb +83 -3
  43. data/lib/jirametrics/html/cycletime_scatterplot.erb +9 -12
  44. data/lib/jirametrics/html/daily_wip_chart.erb +17 -13
  45. data/lib/jirametrics/html/{story_point_accuracy_chart.erb → estimate_accuracy_chart.erb} +9 -4
  46. data/lib/jirametrics/html/expedited_chart.erb +10 -13
  47. data/lib/jirametrics/html/flow_efficiency_scatterplot.erb +85 -0
  48. data/lib/jirametrics/html/hierarchy_table.erb +2 -2
  49. data/lib/jirametrics/html/index.css +280 -0
  50. data/lib/jirametrics/html/index.erb +33 -39
  51. data/lib/jirametrics/html/sprint_burndown.erb +10 -14
  52. data/lib/jirametrics/html/throughput_chart.erb +10 -13
  53. data/lib/jirametrics/html_report_config.rb +110 -86
  54. data/lib/jirametrics/issue.rb +390 -109
  55. data/lib/jirametrics/issue_collection.rb +33 -0
  56. data/lib/jirametrics/jira_gateway.rb +33 -12
  57. data/lib/jirametrics/project_config.rb +276 -147
  58. data/lib/jirametrics/rules.rb +2 -2
  59. data/lib/jirametrics/self_or_issue_dispatcher.rb +2 -0
  60. data/lib/jirametrics/settings.json +11 -0
  61. data/lib/jirametrics/sprint.rb +1 -0
  62. data/lib/jirametrics/sprint_burndown.rb +59 -40
  63. data/lib/jirametrics/sprint_issue_change_data.rb +3 -3
  64. data/lib/jirametrics/status.rb +84 -19
  65. data/lib/jirametrics/status_collection.rb +86 -39
  66. data/lib/jirametrics/throughput_chart.rb +12 -4
  67. data/lib/jirametrics/user.rb +12 -0
  68. data/lib/jirametrics/value_equality.rb +2 -2
  69. data/lib/jirametrics.rb +29 -7
  70. metadata +20 -17
  71. data/lib/jirametrics/discard_changes_before.rb +0 -37
  72. data/lib/jirametrics/experimental/generator.rb +0 -210
  73. data/lib/jirametrics/experimental/info.rb +0 -77
  74. data/lib/jirametrics/html/data_quality_report.erb +0 -126
  75. data/lib/jirametrics/story_point_accuracy_chart.rb +0 -134
@@ -0,0 +1,280 @@
1
+ :root {
2
+ --body-background: white;
3
+ --default-text-color: black;
4
+ --grid-line-color: lightgray;
5
+ --warning-banner: yellow;
6
+
7
+ --cycletime-scatterplot-overall-trendline-color: gray;
8
+
9
+ --non-working-days-color: #F0F0F0;
10
+ --expedited-color: red;
11
+ --blocked-color: #FF7400;
12
+ --stalled-color: orange;
13
+ --dead-color: black;
14
+
15
+ --type-story-color: #4bc14b;
16
+ --type-task-color: blue;
17
+ --type-bug-color: orange;
18
+ --type-spike-color: #9400D3;
19
+
20
+ --status-category-todo-color: gray;
21
+ --status-category-inprogress-color: #2663ff;
22
+ --status-category-done-color: #00ff00;
23
+ --status-category-unknown-color: black;
24
+
25
+ --aging-work-bar-chart-percentage-line-color: red;
26
+ --aging-work-bar-chart-separator-color: white;
27
+
28
+ --throughput_chart_total_line_color: gray;
29
+
30
+ --aging-work-in-progress-chart-shading-color: lightgray;
31
+ --aging-work-in-progress-chart-shading-50-color: #2E8BC0; // green;
32
+ --aging-work-in-progress-chart-shading-85-color: #ADD8E6; // yellow;
33
+ --aging-work-in-progress-chart-shading-98-color: #FF8A8A; // orange;
34
+ --aging-work-in-progress-chart-shading-100-color: #FF2E2E; // red;
35
+
36
+ --aging-work-in-progress-by-age-trend-line-color: gray;
37
+
38
+ --aging-work-table-date-in-jeopardy: yellow;
39
+ --aging-work-table-date-overdue: red;
40
+
41
+ --hierarchy-table-inactive-item-text-color: gray;
42
+
43
+ --wip-chart-completed-color: #00ff00;
44
+ --wip-chart-completed-but-not-started-color: #99FF99;
45
+ --wip-chart-duration-less-than-day-color: #ffef41;
46
+ --wip-chart-duration-week-or-less-color: #dcc900;
47
+ --wip-chart-duration-two-weeks-or-less-color: #dfa000;
48
+ --wip-chart-duration-four-weeks-or-less-color: #eb7200;
49
+ --wip-chart-duration-more-than-four-weeks-color: #e70000;
50
+ --wip-chart-active-color: #326cff;
51
+ --wip-chart-border-color: gray;
52
+
53
+ --estimate-accuracy-chart-completed-fill-color: #00ff00;
54
+ --estimate-accuracy-chart-completed-border-color: green;
55
+ --estimate-accuracy-chart-active-fill-color: #FFCCCB;
56
+ --estimate-accuracy-chart-active-border-color: red;
57
+
58
+ --expedited-chart-no-longer-expedited: gray;
59
+ --expedited-chart-dot-issue-started-color: orange;
60
+ --expedited-chart-dot-issue-stopped-color: green;
61
+ --expedited-chart-dot-expedite-started-color: red;
62
+ --expedited-chart-dot-expedite-stopped-color: green;
63
+
64
+ --sprint-burndown-sprint-color-1: blue;
65
+ --sprint-burndown-sprint-color-2: orange;
66
+ --sprint-burndown-sprint-color-3: green;
67
+ --sprint-burndown-sprint-color-4: red;
68
+ --sprint-burndown-sprint-color-5: brown;
69
+
70
+ --daily-view-selected-issue-background: lightgray;
71
+ --daily-view-issue-border: green;
72
+ --daily-view-selected-issue-border: red;
73
+
74
+ }
75
+
76
+ body {
77
+ background-color: var(--body-background);
78
+ color: var(--default-text-color);
79
+ }
80
+
81
+ h1 {
82
+ border: 1px solid black;
83
+ background: lightgray;
84
+ padding-left: 0.2em;
85
+ }
86
+ dl, dd, dt {
87
+ padding: 0;
88
+ margin: 0;
89
+ }
90
+ dd {
91
+ margin-bottom: 0.4em;
92
+ }
93
+ span.highlight {
94
+ background: #FDD5B1;
95
+ }
96
+ a.issue_key {
97
+ white-space: nowrap;
98
+ }
99
+ table.standard {
100
+ th {
101
+ border-bottom: 1px solid gray;
102
+ position: sticky;
103
+ top: 0;
104
+ background: white;
105
+ }
106
+ td {
107
+ padding-left: 0.5em;
108
+ padding-right: 0.5em;
109
+ vertical-align: top;
110
+ }
111
+ tr:nth-child(odd){
112
+ background-color: #eee;
113
+ }
114
+ }
115
+
116
+ .chart {
117
+ background-color: white;
118
+ }
119
+
120
+ div.p {
121
+ margin: 0.5em 0;
122
+ padding: 0;
123
+ }
124
+
125
+ div.color_block {
126
+ display: inline-block;
127
+ width: 0.9em;
128
+ height: 0.9em;
129
+ border: 1px solid black;
130
+ }
131
+
132
+ ul.quality_report {
133
+ list-style-type: '⮕';
134
+ ::marker {
135
+ color: red;
136
+ }
137
+ li {
138
+ padding: 0.2em;
139
+ }
140
+ }
141
+
142
+ #footer {
143
+ text-align: center;
144
+ margin-top: 1em;
145
+ border-top: 1px solid gray;
146
+ }
147
+
148
+ div.daily_issue:hover {
149
+ background: var(--daily-view-selected-issue-background);
150
+ border-color: var(--daily-view-selected-issue-border);
151
+ }
152
+
153
+ div.daily_issue {
154
+ border: 1px solid var(--daily-view-issue-border);
155
+ padding: 0.5em;
156
+ .heading {
157
+ vertical-align: middle;
158
+ display: flex;
159
+ flex-wrap: wrap;
160
+ column-gap: 0.5em;
161
+ align-items: center;
162
+ }
163
+ table {
164
+ margin-left: 1em;
165
+ td {
166
+ vertical-align: top;
167
+ }
168
+ .time {
169
+ white-space: nowrap;
170
+ font-size: 0.8em;
171
+ }
172
+ }
173
+ .icon {
174
+ width: 1em;
175
+ height: 1em;
176
+ }
177
+ .account_id {
178
+ font-weight: bold;
179
+ }
180
+ .field {
181
+ border: 1px solid black;
182
+ color: white;
183
+ background: black;
184
+ padding-left: 0.2em;
185
+ padding-right: 0.2em;
186
+ border-radius: 0.2em;
187
+ }
188
+ .label {
189
+ border: 1px solid black;
190
+ padding-left: 0.2em;
191
+ padding-right: 0.2em;
192
+ border-radius: 0.2em;
193
+ }
194
+ margin-bottom: 0.5em;
195
+ }
196
+ div.child_issue:hover {
197
+ background: var(--body-background);
198
+ }
199
+ div.child_issue {
200
+ border: 1px dashed green;
201
+ margin: 0.2em;
202
+ margin-left: 1.5em;
203
+ padding: 0.5em;
204
+ }
205
+
206
+ @media screen and (prefers-color-scheme: dark) {
207
+ :root {
208
+ --warning-banner: #9F2B00;
209
+
210
+ --non-working-days-color: #2f2f2f;
211
+ --type-story-color: #6fb86f;
212
+ --type-task-color: #0021b3;
213
+ --type-bug-color: #bb5603;
214
+
215
+ --body-background: #343434;
216
+ --default-text-color: #aaa;
217
+ --grid-line-color: #424242;
218
+
219
+ --expedited-color: #b90000;
220
+ --blocked-color: #c75b02;
221
+ --stalled-color: #ae7202;
222
+ --dead-color: black;
223
+ --wip-chart-active-color: #2551c1;
224
+
225
+ --status-category-inprogress-color: #1c49bb;
226
+
227
+ --cycletime-scatterplot-overall-trendline-color: gray;
228
+
229
+ --hierarchy-table-inactive-item-text-color: #939393;
230
+
231
+ --wip-chart-completed-color: #03cb03;
232
+ --wip-chart-completed-but-not-started-color: #99FF99;
233
+ --wip-chart-duration-less-than-day-color: #d2d988;
234
+ --wip-chart-duration-week-or-less-color: #dfcd00;
235
+ --wip-chart-duration-two-weeks-or-less-color: #cf9400;
236
+ --wip-chart-duration-four-weeks-or-less-color: #c25e00;
237
+ --wip-chart-duration-more-than-four-weeks-color: #8e0000;
238
+
239
+ --daily-view-selected-issue-background: #474747;
240
+ }
241
+
242
+ h1 {
243
+ color: #e0e0e0;
244
+ background-color: #656565;
245
+ }
246
+
247
+ a[href] {
248
+ color: #1e8ad6;
249
+ }
250
+
251
+ a[href]:hover {
252
+ color: #3ba0e6;
253
+ }
254
+
255
+ .chart {
256
+ background: var(--body-background);
257
+ }
258
+
259
+ table.standard {
260
+ th {
261
+ border-bottom: 1px solid gray;
262
+ background: var(--body-background);
263
+ }
264
+ tr:nth-child(odd){
265
+ background-color: #656565;
266
+ }
267
+ }
268
+
269
+ div.color_block {
270
+ border: 1px solid lightgray;
271
+ }
272
+
273
+ div.daily_issue {
274
+ .field {
275
+ color: var(--default-text-color);
276
+ }
277
+ }
278
+ }
279
+
280
+ }
@@ -1,6 +1,7 @@
1
1
  <html>
2
2
  <head>
3
3
  <meta charset="UTF-8">
4
+ <link rel="icon" type="image/png" href="https://github.com/mikebowler/jirametrics/blob/main/favicon.png?raw=true" />
4
5
  <script src="https://cdn.jsdelivr.net/npm/moment@2.29.1/moment.js"></script>
5
6
  <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
6
7
  <script src="https://cdn.jsdelivr.net/npm/chartjs-adapter-moment@^1"></script>
@@ -17,49 +18,42 @@
17
18
  document.getElementById(issues_id).style.display = 'none'
18
19
  }
19
20
  }
21
+
22
+ function toggle_visibility(open_link_id, close_link_id, toggleable_id) {
23
+ let open_link = document.getElementById(open_link_id)
24
+ let close_link = document.getElementById(close_link_id)
25
+ let toggleable_element = document.getElementById(toggleable_id)
26
+
27
+ if(open_link.style.display == 'none') {
28
+ open_link.style.display = 'block'
29
+ close_link.style.display = 'none'
30
+ toggleable_element.style.display = 'none'
31
+ }
32
+ else {
33
+ open_link.style.display = 'none'
34
+ close_link.style.display = 'block'
35
+ toggleable_element.style.display = 'block'
36
+ }
37
+ }
38
+ // If we switch between light/dark mode then force a refresh so all charts will redraw correctly
39
+ // in the other colour scheme.
40
+ window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', event => {
41
+ location.reload()
42
+ })
20
43
  </script>
21
44
  <style>
22
- h1 {
23
- border: 1px solid black;
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>
45
+ <%= css %>
46
+ </style>
47
+ <script type="text/javascript">
48
+ Chart.defaults.color = getComputedStyle(document.documentElement).getPropertyValue('--default-text-color');
49
+ </script>
58
50
  </head>
59
51
  <body>
60
- <div>
61
- Page generated <%= (timezone_offset.nil? ? DateTime.now : DateTime.now.new_offset(timezone_offset)).strftime('%Y-%b-%d at %I:%M:%S%P') %>
62
- </div>
52
+ <noscript>
53
+ <div style="padding: 1em; background: gray; color: white; font-size: 2em;">
54
+ Javascript is currently disabled and that means that almost all of the charts in this report won't render. If you'd loaded this from a folder on SharePoint then save it locally and load it again.
55
+ </div>
56
+ </noscript>
63
57
  <%= "\n" + @sections.collect { |text, type| text if type == :header }.compact.join("\n\n") %>
64
58
  <%= "\n" + @sections.collect { |text, type| text if type == :body }.compact.join("\n\n") %>
65
59
  </body>
@@ -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: {
@@ -51,16 +56,7 @@ new Chart(document.getElementById('<%= chart_id %>').getContext('2d'), {
51
56
  },
52
57
  annotation: {
53
58
  annotations: {
54
- <% holidays().each_with_index do |range, index| %>
55
- holiday<%= index %>: {
56
- drawTime: 'beforeDraw',
57
- type: 'box',
58
- xMin: '<%= range.begin %>T00:00:00',
59
- xMax: '<%= range.end %>T23:59:59',
60
- backgroundColor: '#F0F0F0',
61
- borderColor: '#F0F0F0'
62
- },
63
- <% end %>
59
+ <%= working_days_annotation %>
64
60
  }
65
61
  }
66
62
  }
@@ -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: {
@@ -46,16 +52,7 @@ new Chart(document.getElementById('<%= chart_id %>').getContext('2d'), {
46
52
  },
47
53
  annotation: {
48
54
  annotations: {
49
- <% holidays.each_with_index do |range, index| %>
50
- holiday<%= index %>: {
51
- drawTime: 'beforeDraw',
52
- type: 'box',
53
- xMin: '<%= range.begin %>T00:00:00',
54
- xMax: '<%= range.end %>T23:59:59',
55
- backgroundColor: '#F0F0F0',
56
- borderColor: '#F0F0F0'
57
- },
58
- <% end %>
55
+ <%= working_days_annotation %>
59
56
  }
60
57
  }
61
58
  }