class Kennel::Models::Dashboard
Constants
- DEFAULTS
- READONLY_ATTRIBUTES
- REQUEST_DEFAULTS
- SUPPORTED_DEFINITION_OPTIONS
- TRACKING_FIELD
- WIDGET_DEFAULTS
Public Class Methods
api_resource()
click to toggle source
# File lib/kennel/models/dashboard.rb, line 84 def api_resource "dashboard" end
normalize(expected, actual)
click to toggle source
Calls superclass method
# File lib/kennel/models/dashboard.rb, line 88 def normalize(expected, actual) super ignore_default expected, actual, DEFAULTS ignore_default expected, actual, reflow_type: "auto" if expected[:layout_type] == "ordered" widgets_pairs(expected, actual).each do |pair| pair.each { |w| sort_conditional_formats w } ignore_widget_defaults(*pair) ignore_request_defaults(*pair) pair.each { |widget| widget&.delete(:id) } # ids are kinda random so we always discard them end end
parse_url(url)
click to toggle source
# File lib/kennel/models/dashboard.rb, line 171 def self.parse_url(url) url[/\/dashboard\/([a-z\d-]+)/, 1] end
url(id)
click to toggle source
# File lib/kennel/models/dashboard.rb, line 167 def self.url(id) Utils.path_to_url "/dashboard/#{id}" end
Private Class Methods
ignore_defaults(expected, actual, defaults)
click to toggle source
# File lib/kennel/models/dashboard.rb, line 125 def ignore_defaults(expected, actual, defaults) [expected.size, actual.size].max.times do |i| ignore_default expected[i] || {}, actual[i] || {}, defaults end end
ignore_request_defaults(expected, actual)
click to toggle source
discard styles/conditional_formats/aggregator if nothing would change when we applied (both are default or nil)
# File lib/kennel/models/dashboard.rb, line 119 def ignore_request_defaults(expected, actual) a_r = actual&.dig(:definition, :requests) || [] e_r = expected&.dig(:definition, :requests) || [] ignore_defaults e_r, a_r, REQUEST_DEFAULTS end
ignore_widget_defaults(expected, actual)
click to toggle source
# File lib/kennel/models/dashboard.rb, line 111 def ignore_widget_defaults(expected, actual) types = [expected&.dig(:definition, :type), actual&.dig(:definition, :type)].uniq.compact return unless types.size == 1 return unless defaults = WIDGET_DEFAULTS[types.first] ignore_default expected&.[](:definition) || {}, actual&.[](:definition) || {}, defaults end
sort_conditional_formats(widget)
click to toggle source
conditional_formats ordering is randomly changed by datadog, compare a stable ordering
# File lib/kennel/models/dashboard.rb, line 105 def sort_conditional_formats(widget) if formats = widget&.dig(:definition, :conditional_formats) widget[:definition][:conditional_formats] = formats.sort_by(&:hash) end end
widgets_pairs(*pair)
click to toggle source
expand nested widgets into expected/actual pairs for default resolution
- a, e
-
-> [[a-w, e-w], [a-w1-w1, e-w1-w1], …]
# File lib/kennel/models/dashboard.rb, line 133 def widgets_pairs(*pair) result = [pair.map { |d| d[:widgets] || [] }] slots = result[0].map(&:size).max slots.times do |i| nested = pair.map { |d| d.dig(:widgets, i, :definition, :widgets) || [] } result << nested if nested.any?(&:any?) end result.flat_map { |a, e| [a.size, e.size].max.times.map { |i| [a[i], e[i]] } } end
Public Instance Methods
as_json()
click to toggle source
# File lib/kennel/models/dashboard.rb, line 144 def as_json return @json if @json all_widgets = render_definitions(definitions) + widgets expand_q all_widgets @json = { layout_type: layout_type, title: "#{title}#{LOCK}", description: description, template_variables: render_template_variables, template_variable_presets: template_variable_presets, widgets: all_widgets } @json[:reflow_type] = reflow_type if reflow_type # setting nil breaks create with "ordered" @json[:id] = id if id validate_json(@json) if validate @json end
resolve_linked_tracking_ids!(id_map, **args)
click to toggle source
# File lib/kennel/models/dashboard.rb, line 175 def resolve_linked_tracking_ids!(id_map, **args) widgets = as_json[:widgets].flat_map { |w| [w, *w.dig(:definition, :widgets) || []] } widgets.each do |widget| next unless definition = widget[:definition] case definition[:type] when "uptime" if ids = definition[:monitor_ids] definition[:monitor_ids] = ids.map do |id| tracking_id?(id) ? (resolve_link(id, :monitor, id_map, **args) || id) : id end end when "alert_graph" if (id = definition[:alert_id]) && tracking_id?(id) definition[:alert_id] = (resolve_link(id, :monitor, id_map, **args) || id).to_s end when "slo" if (id = definition[:slo_id]) && tracking_id?(id) definition[:slo_id] = (resolve_link(id, :slo, id_map, **args) || id).to_s end end end end
Private Instance Methods
expand_q(widgets)
click to toggle source
creates queries from metadata to avoid having to keep q and expression in sync
{q: :metadata, metadata: [{expression: “sum:bar”, alias_name: “foo”}, …], } -> {q: “sum:bar, …”, metadata: …, }
# File lib/kennel/models/dashboard.rb, line 208 def expand_q(widgets) widgets = widgets.flat_map { |w| w.dig(:definition, :widgets) || w } # expand groups widgets.each do |w| w.dig(:definition, :requests)&.each do |request| next unless request.is_a?(Hash) && request[:q] == :metadata request[:q] = request.fetch(:metadata).map { |m| m.fetch(:expression) }.join(", ") end end end
render_definitions(definitions)
click to toggle source
# File lib/kennel/models/dashboard.rb, line 228 def render_definitions(definitions) definitions.map do |title, type, display_type, queries, options = {}, too_many_args = nil| if title.is_a?(Hash) && !type title # user gave a full widget, just use it else # validate inputs if too_many_args || (!title || !type || !queries || !options.is_a?(Hash)) raise ArgumentError, "Expected exactly 5 arguments for each definition (title, type, display_type, queries, options)" end if (SUPPORTED_DEFINITION_OPTIONS | options.keys) != SUPPORTED_DEFINITION_OPTIONS raise ArgumentError, "Supported options are: #{SUPPORTED_DEFINITION_OPTIONS.map(&:inspect).join(", ")}" end # build definition requests = Array(queries).map do |q| request = { q: q } request[:display_type] = display_type if display_type request end { definition: { title: title, type: type, requests: requests, **options } } end end end
tracking_id?(id)
click to toggle source
# File lib/kennel/models/dashboard.rb, line 200 def tracking_id?(id) id.is_a?(String) && id.include?(":") end
validate_json(data)
click to toggle source
Calls superclass method
Kennel::OptionalValidations#validate_json
# File lib/kennel/models/dashboard.rb, line 218 def validate_json(data) super validate_template_variables data # Avoid diff from datadog presets sorting. presets = data[:template_variable_presets] invalid! "template_variable_presets must be sorted by name" if presets && presets != presets.sort_by { |p| p[:name] } end