Class: ChartBase

Inherits:
Object show all
Defined in:
lib/jirametrics/chart_base.rb

Constant Summary collapse

@@chart_counter =
0

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeChartBase

Returns a new instance of ChartBase.



11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# File 'lib/jirametrics/chart_base.rb', line 11

def initialize
  @chart_colors = {
    'dark:Story' => 'green',
    'dark:Task' => 'blue',
    'dark:Bug' => 'orange',
    'dark:Defect' => 'orange',
    'dark:Spike' => '#9400D3', # dark purple
    'light:Story' => '#90EE90',
    'light:Task' => '#87CEFA',
    'light:Bug' => '#ffdab9',
    'light:Defect' => 'orange',
    'light:Epic' => '#fafad2',
    'light:Spike' => '#DDA0DD' # light purple
  }
  @canvas_width = 800
  @canvas_height = 200
  @canvas_responsive = true
end

Instance Attribute Details

#aggregated_project=(value) ⇒ Object (writeonly)

Sets the attribute aggregated_project

Parameters:

  • value

    the value to set the attribute aggregated_project to.



6
7
8
# File 'lib/jirametrics/chart_base.rb', line 6

def aggregated_project=(value)
  @aggregated_project = value
end

#all_boardsObject

Returns the value of attribute all_boards.



4
5
6
# File 'lib/jirametrics/chart_base.rb', line 4

def all_boards
  @all_boards
end

#board_idObject

Returns the value of attribute board_id.



4
5
6
# File 'lib/jirametrics/chart_base.rb', line 4

def board_id
  @board_id
end

#canvas_heightObject (readonly)

Returns the value of attribute canvas_height.



7
8
9
# File 'lib/jirametrics/chart_base.rb', line 7

def canvas_height
  @canvas_height
end

#canvas_widthObject (readonly)

Returns the value of attribute canvas_width.



7
8
9
# File 'lib/jirametrics/chart_base.rb', line 7

def canvas_width
  @canvas_width
end

#data_qualityObject

Returns the value of attribute data_quality.



4
5
6
# File 'lib/jirametrics/chart_base.rb', line 4

def data_quality
  @data_quality
end

#date_rangeObject

Returns the value of attribute date_range.



4
5
6
# File 'lib/jirametrics/chart_base.rb', line 4

def date_range
  @date_range
end

#holiday_datesObject

Returns the value of attribute holiday_dates.



4
5
6
# File 'lib/jirametrics/chart_base.rb', line 4

def holiday_dates
  @holiday_dates
end

#issuesObject

Returns the value of attribute issues.



7
8
9
# File 'lib/jirametrics/chart_base.rb', line 7

def issues
  @issues
end

#settingsObject

Returns the value of attribute settings.



4
5
6
# File 'lib/jirametrics/chart_base.rb', line 4

def settings
  @settings
end

#time_rangeObject

Returns the value of attribute time_range.



4
5
6
# File 'lib/jirametrics/chart_base.rb', line 4

def time_range
  @time_range
end

#timezone_offsetObject

Returns the value of attribute timezone_offset.



4
5
6
# File 'lib/jirametrics/chart_base.rb', line 4

def timezone_offset
  @timezone_offset
end

Instance Method Details

#aggregated_project?Boolean

Returns:

  • (Boolean)


30
31
32
# File 'lib/jirametrics/chart_base.rb', line 30

def aggregated_project?
  @aggregated_project
end

#canvas(width:, height:, responsive: true) ⇒ Object



218
219
220
221
222
# File 'lib/jirametrics/chart_base.rb', line 218

def canvas width:, height:, responsive: true
  @canvas_width = width
  @canvas_height = height
  @canvas_responsive = responsive
end

#canvas_responsive?Boolean

Returns:

  • (Boolean)


224
225
226
# File 'lib/jirametrics/chart_base.rb', line 224

def canvas_responsive?
  @canvas_responsive
end

#chart_format(object) ⇒ Object



167
168
169
170
171
172
173
174
# File 'lib/jirametrics/chart_base.rb', line 167

def chart_format object
  if object.is_a? Time
    # "2022-04-09T11:38:30-07:00"
    object.strftime '%Y-%m-%dT%H:%M:%S%z'
  else
    object.to_s
  end
end

#collapsible_issues_panel(issue_descriptions, *args) ⇒ Object



98
99
100
101
102
103
104
105
# File 'lib/jirametrics/chart_base.rb', line 98

def collapsible_issues_panel issue_descriptions, *args
  link_id = next_id
  issues_id = next_id

  issue_descriptions.sort! { |a, b| a[0].key_as_i <=> b[0].key_as_i }
  erb = ERB.new File.read "#{@html_directory}/collapsible_issues_panel.erb"
  erb.result(binding)
end

#color_for(type:, shade: :dark) ⇒ Object



60
61
62
# File 'lib/jirametrics/chart_base.rb', line 60

def color_for type:, shade: :dark
  @chart_colors["#{shade}:#{type}"] ||= random_color
end

#completed_issues_in_range(include_unstarted: false) ⇒ Object



144
145
146
147
148
149
150
151
152
153
154
# File 'lib/jirametrics/chart_base.rb', line 144

def completed_issues_in_range include_unstarted: false
  issues.select do |issue|
    cycletime = issue.board.cycletime
    stopped_time = cycletime.stopped_time(issue)
    started_time = cycletime.started_time(issue)

    stopped_time &&
      date_range.include?(stopped_time.to_date) && # Remove outside range
      (include_unstarted || (started_time && (stopped_time >= started_time)))
  end
end

#current_boardObject

Return only the board columns for the current board.



129
130
131
132
133
134
135
136
137
138
139
140
141
142
# File 'lib/jirametrics/chart_base.rb', line 129

def current_board
  if @board_id.nil?
    case @all_boards.size
    when 0
      raise 'Couldn\'t find any board configurations. Ensure one is set'
    when 1
      return @all_boards.values[0]
    else
      raise "Must set board_id so we know which to use. Multiple boards found: #{@all_boards.keys.inspect}"
    end
  end

  @all_boards[@board_id]
end

#daily_chart_dataset(date_issues_list:, color:, label:, positive: true) ⇒ Object



72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
# File 'lib/jirametrics/chart_base.rb', line 72

def daily_chart_dataset date_issues_list:, color:, label:, positive: true
  {
    type: 'bar',
    label: label,
    data: date_issues_list.collect do |date, issues|
      issues.sort! { |a, b| a.key_as_i <=> b.key_as_i }
      title = "#{label} (#{label_issues issues.size})"
      {
        x: date,
        y: positive ? issues.size : -issues.size,
        title: [title] + issues.collect { |i| "#{i.key} : #{i.summary.strip}#{" #{yield date, i}" if block_given?}" }
      }
    end,
    backgroundColor: color,
    borderRadius: positive ? 0 : 5
  }
end

#description_text(text) ⇒ Object



180
181
182
# File 'lib/jirametrics/chart_base.rb', line 180

def description_text text
  @description_text = text
end

#filter_issues(&block) ⇒ Object



228
229
230
# File 'lib/jirametrics/chart_base.rb', line 228

def filter_issues &block
  @filter_issues_block = block
end

#format_integer(number) ⇒ Object



184
185
186
# File 'lib/jirametrics/chart_base.rb', line 184

def format_integer number
  number.to_s.reverse.scan(/.{1,3}/).join(',').reverse
end

#format_status(name_or_id, board:, is_category: false) ⇒ Object



188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
# File 'lib/jirametrics/chart_base.rb', line 188

def format_status name_or_id, board:, is_category: false
  begin
    statuses = board.possible_statuses.expand_statuses([name_or_id])
  rescue RuntimeError => e
    return "<span style='color: red'>#{name_or_id}</span>" if e.message =~ /^Status not found:/

    throw e
  end
  raise "Expected exactly one match and got #{statuses.inspect} for #{name_or_id.inspect}" if statuses.size > 1

  status = statuses.first
  color = status_category_color status

  text = is_category ? status.category_name : status.name
  "<span style='color: #{color}'>#{text}</span>"
end

#header_text(text) ⇒ Object



176
177
178
# File 'lib/jirametrics/chart_base.rb', line 176

def header_text text
  @header_text = text
end

#holidays(date_range: @date_range) ⇒ Object



107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
# File 'lib/jirametrics/chart_base.rb', line 107

def holidays date_range: @date_range
  result = []
  start_date = nil
  end_date = nil

  date_range.each do |date|
    if date.saturday? || date.sunday? || holiday_dates.include?(date)
      if start_date.nil?
        start_date = date
      else
        end_date = date
      end
    elsif start_date
      result << (start_date..(end_date || start_date))
      start_date = nil
      end_date = nil
    end
  end
  result
end

#label_days(days) ⇒ Object



64
65
66
# File 'lib/jirametrics/chart_base.rb', line 64

def label_days days
  "#{days} day#{'s' unless days == 1}"
end

#label_issues(count) ⇒ Object



68
69
70
# File 'lib/jirametrics/chart_base.rb', line 68

def label_issues count
  "#{count} issue#{'s' unless count == 1}"
end


90
91
92
93
94
95
96
# File 'lib/jirametrics/chart_base.rb', line 90

def link_to_issue issue, args = {}
  attributes = { class: 'issue_key' }
    .merge(args)
    .collect { |key, value| "#{key}='#{value}'" }
    .join(' ')
  "<a href='#{issue.url}' #{attributes}>#{issue.key}</a>"
end

#next_idObject



56
57
58
# File 'lib/jirametrics/chart_base.rb', line 56

def next_id
  @@chart_counter += 1
end

#random_colorObject



214
215
216
# File 'lib/jirametrics/chart_base.rb', line 214

def random_color
  "\##{Random.bytes(3).unpack1('H*')}"
end

#render(caller_binding, file) ⇒ Object



34
35
36
37
38
39
40
41
42
43
44
45
# File 'lib/jirametrics/chart_base.rb', line 34

def render caller_binding, file
  pathname = Pathname.new(File.realpath(file))
  basename = pathname.basename.to_s
  raise "Unexpected filename #{basename.inspect}" unless basename =~ /^(.+)\.rb$/

  # Insert a incrementing chart_id so that all the chart names on the page are unique
  caller_binding.eval "chart_id='chart#{next_id}'" # chart_id=chart3

  @html_directory = "#{pathname.dirname}/html"
  erb = ERB.new File.read "#{@html_directory}/#{$1}.erb"
  erb.result(caller_binding)
end

#sprints_in_time_range(board) ⇒ Object



156
157
158
159
160
161
162
163
164
165
# File 'lib/jirametrics/chart_base.rb', line 156

def sprints_in_time_range board
  board.sprints.select do |sprint|
    sprint_end_time = sprint.completed_time || sprint.end_time
    sprint_start_time = sprint.start_time
    next false if sprint_start_time.nil?

    time_range.include?(sprint_start_time) || time_range.include?(sprint_end_time) ||
      (sprint_start_time < time_range.begin && sprint_end_time > time_range.end)
  end || []
end

#status_category_color(status) ⇒ Object



205
206
207
208
209
210
211
212
# File 'lib/jirametrics/chart_base.rb', line 205

def status_category_color status
  case status.category_name
  when nil then 'black'
  when 'To Do' then 'gray'
  when 'In Progress' then 'blue'
  when 'Done' then 'green'
  end
end

#wrap_and_render(caller_binding, file) ⇒ Object

Render the file and then wrap it with standard headers and quality checks.



48
49
50
51
52
53
54
# File 'lib/jirametrics/chart_base.rb', line 48

def wrap_and_render caller_binding, file
  result = String.new
  result << "<h1>#{@header_text}</h1>" if @header_text
  result << ERB.new(@description_text).result(caller_binding) if @description_text
  result << render(caller_binding, file)
  result
end