Module: CodeSunset::ApplicationHelper

Defined in:
app/helpers/code_sunset/application_helper.rb

Instance Method Summary collapse

Instance Method Details

#active_filter_chips_for(path) ⇒ Object



131
132
133
134
135
136
137
138
139
140
141
142
# File 'app/helpers/code_sunset/application_helper.rb', line 131

def active_filter_chips_for(path)
  filters.except(:page).each_with_object([]) do |(key, value), chips|
    next if value.blank?

    chips << {
      key: key,
      label: filter_chip_label(key),
      value: filter_chip_value(key, value),
      clear_path: filter_path_for(path, filters.except(:page, key))
    }
  end
end

#advanced_filters_open? ⇒ Boolean

Returns:

  • (Boolean)


156
157
158
# File 'app/helpers/code_sunset/application_helper.rb', line 156

def advanced_filters_open?
  filters.values_at(:plan, :org_id, :user_id, :paid_only, :exclude_internal, *configured_custom_filter_keys).any?(&:present?)
end

#analytics_notice ⇒ Object



34
35
36
# File 'app/helpers/code_sunset/application_helper.rb', line 34

def analytics_notice
  analytics_filters.raw_filter_notice
end

#configured_custom_filter_keys ⇒ Object



164
165
166
# File 'app/helpers/code_sunset/application_helper.rb', line 164

def configured_custom_filter_keys
  configured_custom_filters.keys
end

#configured_custom_filters ⇒ Object



160
161
162
# File 'app/helpers/code_sunset/application_helper.rb', line 160

def configured_custom_filters
  CodeSunset.configuration.custom_filters
end

#current_filter_value(key) ⇒ Object



30
31
32
# File 'app/helpers/code_sunset/application_helper.rb', line 30

def current_filter_value(key)
  filters[key]
end

#custom_filter_input_tag(key, definition) ⇒ Object



168
169
170
171
172
173
174
175
176
177
178
179
# File 'app/helpers/code_sunset/application_helper.rb', line 168

def custom_filter_input_tag(key, definition)
  current_value = current_filter_value(key)

  case definition[:type].to_sym
  when :boolean
    select_tag key, options_for_select([["Any", nil], ["Yes", true], ["No", false]], current_value), include_blank: false
  when :select
    select_tag key, options_for_select([["Any", nil]] + Array(definition[:options]), current_value), include_blank: false
  else
    text_field_tag key, current_value, placeholder: definition[:placeholder]
  end
end

#filter_path_for(path, values = filter_query_values) ⇒ Object



124
125
126
127
128
129
# File 'app/helpers/code_sunset/application_helper.rb', line 124

def filter_path_for(path, values = filter_query_values)
  query_values = values.reject { |_key, value| value.blank? }
  return path if query_values.empty?

  "#{path}?#{query_values.to_query}"
end

#filter_query_values(overrides = {}) ⇒ Object



120
121
122
# File 'app/helpers/code_sunset/application_helper.rb', line 120

def filter_query_values(overrides = {})
  filters.except(:page).merge(overrides).reject { |_key, value| value.blank? }
end

#filters_applied? ⇒ Boolean

Returns:

  • (Boolean)


38
39
40
# File 'app/helpers/code_sunset/application_helper.rb', line 38

def filters_applied?
  filters.except(:page).values.any?(&:present?)
end

#format_seen_at(timestamp) ⇒ Object



3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# File 'app/helpers/code_sunset/application_helper.rb', line 3

def format_seen_at(timestamp)
  return "Never" unless timestamp

  time = timestamp.in_time_zone
  relative_time = if time > Time.current
    "just now"
  else
    "#{time_ago_in_words(time)} ago"
  end

  (
    :time,
    relative_time,
    class: "cs-time",
    datetime: time.iso8601,
    title: time.strftime("%Y-%m-%d %H:%M:%S %Z")
  )
end

#human_count(value) ⇒ Object



22
23
24
# File 'app/helpers/code_sunset/application_helper.rb', line 22

def human_count(value)
  number_with_delimiter(value || 0)
end


105
106
107
108
109
110
# File 'app/helpers/code_sunset/application_helper.rb', line 105

def pagination_link_for(feature, label, page:, current:, filters: {}, rel: nil)
  classes = ["cs-pagination__link"]
  classes << "is-active" if current

  link_to label, feature_path(feature.key, filters.merge(page: page)), class: classes.join(" "), rel: rel
end

#removal_prompt_path_for(feature) ⇒ Object



112
113
114
# File 'app/helpers/code_sunset/application_helper.rb', line 112

def removal_prompt_path_for(feature)
  feature_path(feature.key, filters.merge(generate_removal_prompt: true))
end

#removal_prompt_reset_path_for(feature) ⇒ Object



116
117
118
# File 'app/helpers/code_sunset/application_helper.rb', line 116

def removal_prompt_reset_path_for(feature)
  feature_path(feature.key, filters.except(:page))
end

#removal_score_badge(feature, snapshot, label: nil) ⇒ Object



56
57
58
59
60
61
62
63
64
65
# File 'app/helpers/code_sunset/application_helper.rb', line 56

def removal_score_badge(feature, snapshot, label: nil)
  label ||= format("%.1f", snapshot&.score.to_f)

  (
    :span,
    label,
    class: "cs-score cs-score--help",
    title: removal_score_tooltip(feature, snapshot)
  )
end

#removal_score_tooltip(feature, snapshot) ⇒ Object



67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
# File 'app/helpers/code_sunset/application_helper.rb', line 67

def removal_score_tooltip(feature, snapshot)
  return "Removal score is unavailable until usage has been analyzed." unless feature && snapshot

  calculator = CodeSunset::ScoreCalculator.new(feature: feature, snapshot: snapshot)
  breakdown = calculator.breakdown

  [
    "Removal score favors features that look safer to remove.",
    "Recency: #{format('%.1f', breakdown[:recency][:score])}/#{format('%.0f', breakdown[:recency][:max])} from #{breakdown[:recency][:detail]}",
    "Volume: #{format('%.1f', breakdown[:volume][:score])}/#{format('%.0f', breakdown[:volume][:max])} from #{breakdown[:volume][:detail]}",
    "Org breadth: #{format('%.1f', breakdown[:orgs][:score])}/#{format('%.0f', breakdown[:orgs][:max])} from #{breakdown[:orgs][:detail]}",
    "Paid usage: #{format('%.1f', breakdown[:paid_usage][:score])}/#{format('%.0f', breakdown[:paid_usage][:max])} from #{breakdown[:paid_usage][:detail]}",
    "Total: #{format('%.1f', calculator.score)}/100"
  ].join("\n")
end

#render_filter_bar(form_url:, reset_url:, title: "Filters", copy: nil) ⇒ Object



144
145
146
147
148
149
150
151
152
153
154
# File 'app/helpers/code_sunset/application_helper.rb', line 144

def render_filter_bar(form_url:, reset_url:, title: "Filters", copy: nil)
  render(
    "code_sunset/shared/filter_bar",
    form_url: form_url,
    reset_url: reset_url,
    title: title,
    copy: copy,
    filters_applied: filters_applied?,
    active_chips: active_filter_chips_for(reset_url)
  )
end


42
43
44
45
46
47
48
49
50
51
52
53
54
# File 'app/helpers/code_sunset/application_helper.rb', line 42

def sidebar_nav_link(label, path, icon:)
  classes = ["cs-nav__link"]
  classes << "is-active" if current_page?(path)

  link_to path, class: classes.join(" ") do
    safe_join(
      [
        (:span, sidebar_icon(icon), class: "cs-nav__icon"),
        (:span, label, class: "cs-nav__text")
      ]
    )
  end
end

#status_badge(status) ⇒ Object



26
27
28
# File 'app/helpers/code_sunset/application_helper.rb', line 26

def status_badge(status)
  (:span, status.to_s.tr("_", " ").titleize, class: "cs-badge cs-badge--#{status}")
end

#usage_chart(points) ⇒ Object



83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
# File 'app/helpers/code_sunset/application_helper.rb', line 83

def usage_chart(points)
  return (:p, "No usage data yet.", class: "cs-subtle") if points.blank?

  labels = points.keys.map { |day| day.strftime("%b %-d") }
  values = points.values.map(&:to_i)

  (:div, class: "cs-chart-shell") do
    (
      :canvas,
      nil,
      class: "cs-chart",
      role: "img",
      aria: { label: "Feature usage trend chart" },
      data: {
        code_sunset_usage_chart: true,
        labels: labels.to_json,
        values: values.to_json
      }
    )
  end
end