Class: PredictabilityEngine::Report

Inherits:
Object
  • Object
show all
Includes:
Constants
Defined in:
lib/predictability_engine/report.rb,
lib/predictability_engine/report/constants.rb,
lib/predictability_engine/report/text_renderer.rb,
lib/predictability_engine/report/image_generator.rb

Overview

rubocop:disable Metrics/ClassLength

Defined Under Namespace

Modules: Constants, ImageGenerator, TextRenderer

Constant Summary collapse

PRIORITY_SORT =
lambda do |values|
  values.sort_by { |v| [Constants::PRIORITY_ORDER.index(v) || Constants::PRIORITY_ORDER.size, v] }
end
FACETS =
[
  { key: :priority, label: 'Priority', accessor: :priority, dirname: 'priorities',
    sort: PRIORITY_SORT },
  { key: :type, label: 'Type', accessor: :type, dirname: 'types',
    sort: lambda(&:sort) }
].freeze

Constants included from Constants

Constants::CHART_CONFIG, Constants::DEFAULT_FORECAST_HISTORY, Constants::DEFAULT_HISTORICAL_RANGE, Constants::DEFAULT_SIZE, Constants::FONT_BOLD_PATHS, Constants::FONT_PATHS, Constants::FORMAT_CONFIG, Constants::PRIORITY_ORDER, Constants::RESOLUTION_CONFIG

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(items, title: 'Predictability Report', percentiles: PredictabilityEngine::DEFAULT_PERCENTILES, type: nil, priority: nil) ⇒ Report

Returns a new instance of Report.



25
26
27
28
29
30
31
32
33
# File 'lib/predictability_engine/report.rb', line 25

def initialize(items, title: 'Predictability Report', percentiles: PredictabilityEngine::DEFAULT_PERCENTILES,
               type: nil, priority: nil)
  @type = type
  @priority = priority
  @items = filter_by_facets(items)
  @title = title
  @percentiles = percentiles
  @images_path = nil
end

Instance Attribute Details

#images_pathObject (readonly)

Returns the value of attribute images_path.



23
24
25
# File 'lib/predictability_engine/report.rb', line 23

def images_path
  @images_path
end

#itemsObject (readonly)

Returns the value of attribute items.



23
24
25
# File 'lib/predictability_engine/report.rb', line 23

def items
  @items
end

#percentilesObject (readonly)

Returns the value of attribute percentiles.



23
24
25
# File 'lib/predictability_engine/report.rb', line 23

def percentiles
  @percentiles
end

#priorityObject (readonly)

Returns the value of attribute priority.



23
24
25
# File 'lib/predictability_engine/report.rb', line 23

def priority
  @priority
end

#titleObject (readonly)

Returns the value of attribute title.



23
24
25
# File 'lib/predictability_engine/report.rb', line 23

def title
  @title
end

#typeObject (readonly)

Returns the value of attribute type.



23
24
25
# File 'lib/predictability_engine/report.rb', line 23

def type
  @type
end

Class Method Details

.facet_values(items, facet) ⇒ Object



48
49
50
51
# File 'lib/predictability_engine/report.rb', line 48

def self.facet_values(items, facet)
  raw = items.map { |i| i.public_send(facet[:accessor]) || 'Unspecified' }.uniq
  facet[:sort].call(raw)
end

.generate_all(items) ⇒ Object



35
36
37
38
39
40
41
42
43
44
45
46
# File 'lib/predictability_engine/report.rb', line 35

def self.generate_all(items)
  reports = { all: new(items, title: 'Full Predictability Dashboard') }
  FACETS.each do |facet|
    values = facet_values(items, facet)
    next unless values.size > 1

    reports[facet[:key]] = values.to_h do |val|
      [val, new(items, title: "Dashboard: #{val}", facet[:key] => val)]
    end
  end
  reports
end

Instance Method Details

#generate_chart_images(base_dir) ⇒ Object



64
65
66
# File 'lib/predictability_engine/report.rb', line 64

def generate_chart_images(base_dir, **)
  @images_path = ImageGenerator.generate(self, base_dir, **)
end

#pdf_viewport_size(format, landscape) ⇒ Object



110
111
112
113
114
115
116
117
118
119
# File 'lib/predictability_engine/report.rb', line 110

def pdf_viewport_size(format, landscape)
  res = RESOLUTION_CONFIG[format.to_s.downcase]
  if res
    return landscape ? res : [res[1], res[0]]
  end

  sizes = { 'A4' => [794, 1123], 'A3' => [1123, 1587] }
  w, h = sizes[format.to_s.upcase] || sizes[DEFAULT_SIZE.to_s.upcase]
  landscape ? [h, w] : [w, h]
end

#playwright_binObject



88
89
90
91
92
93
94
95
96
97
98
99
100
# File 'lib/predictability_engine/report.rb', line 88

def playwright_bin
  root = File.expand_path('../..', __dir__)
  unless ENV['PLAYWRIGHT_BROWSERS_PATH']
    require 'etc'
    real_home = begin
      Etc.getpwuid.dir
    rescue StandardError
      Dir.home
    end
    ENV['PLAYWRIGHT_BROWSERS_PATH'] = File.expand_path('.cache/ms-playwright', real_home)
  end
  File.exist?("#{root}/node_modules/.bin/playwright") ? "#{root}/node_modules/.bin/playwright" : 'npx playwright'
end

#playwright_chromium_launch_optsObject



102
103
104
105
106
107
108
# File 'lib/predictability_engine/report.rb', line 102

def playwright_chromium_launch_opts
  exe = ENV.fetch('PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH', nil)
  return {} unless exe

  # System Chromium (e.g. Alpine apk) needs --no-sandbox in Docker containers.
  { executablePath: exe, chromiumSandbox: false }
end

#render(format, layout: nil, color: false, **extra_opts) ⇒ Object

Raises:

  • (ArgumentError)


53
54
55
56
57
58
59
60
61
62
# File 'lib/predictability_engine/report.rb', line 53

def render(format, layout: nil, color: false, **extra_opts)
  config = find_format_config(format)&.last
  method_name = "render_#{find_format_config(format)&.first || format.to_sym}"
  raise ArgumentError, "Unsupported format: #{format}" unless respond_to?(method_name, true)

  opts = { layout: effective_layout(layout, config), color: color }.merge(extra_opts)
  opts[:format] = config[:format] if config&.key?(:format)
  opts[:landscape] = config[:landscape] if config&.key?(:landscape)
  send(method_name, **opts)
end

#render_html(layout: :landscape, sub_reports: nil) ⇒ Object



68
69
70
71
72
73
74
75
76
77
# File 'lib/predictability_engine/report.rb', line 68

def render_html(layout: :landscape, sub_reports: nil, **)
  charts = CHART_CONFIG.map do |id, cfg|
    chart = VegaVisualizer.send(cfg[:vega] || id, @items,
                                title: nil,
                                percentiles: @percentiles)
    { title: cfg[:title], chart: chart }
  end
  Visualizer.to_full_html(charts, @items, title: @title, layout: layout, percentiles: @percentiles,
                                          sub_reports: sub_reports)
end


121
122
123
124
# File 'lib/predictability_engine/report.rb', line 121

def render_image_link(chart_id, fmt)
  rel_path = "images/#{chart_id}.png"
  fmt == :confluence ? "!#{rel_path}!" : "![](#{rel_path})"
end

#with_report_temp_html(layout: :landscape) ⇒ Object



79
80
81
82
83
84
85
86
# File 'lib/predictability_engine/report.rb', line 79

def with_report_temp_html(layout: :landscape)
  temp_html = "tmp/report_#{object_id}.html"
  FileUtils.mkdir_p('tmp')
  File.write(temp_html, render_html(layout: layout))
  yield temp_html
ensure
  FileUtils.rm_f(temp_html) if temp_html
end