Module: RoundhouseUi::TagsHelper
- Defined in:
- app/helpers/roundhouse_ui/tags_helper.rb
Overview
Renders host-defined job tags (see ADR 0002). Resolution is memoized for the life of the request: a page can render hundreds of rows, and ErrorGroups scans up to DEFAULT_SCAN_LIMIT entries, so the host's resolver must not be called once per row when it only varies by class.
Instance Method Summary collapse
-
#any_filter?(query, tag, queue = rh_filter.queue) ⇒ Boolean
Any filter active? Bulk-on-match is filter-gated, so this decides whether the bulk bar renders at all — and which empty-state copy is honest.
- #filter_description(query, tag, queue = rh_filter.queue) ⇒ Object
-
#like_description ⇒ Object
"find more like this", said back to you.
-
#rh_filter ⇒ Object
Human description of the active filter set, so a bulk confirm names every constraint that will be applied — not just the text query.
-
#tag_badge(key, value) ⇒ Object
Value only — the key is near-constant down a column, so repeating it is noise.
-
#tag_badges(tags) ⇒ Object
Pills for a resolved tag Hash.
-
#tag_cache ⇒ Object
The per-request memo handed to Tags.for, shared with JobSetBrowsing so a class (or job) resolved while scanning is not resolved again when its badge renders.
-
#tag_cell(tags) ⇒ Object
Cell contents.
-
#tag_column? ⇒ Boolean
Tags get their own table column rather than an inline badge: class names vary wildly in length, so inline badges land at ragged x-positions and can't be scanned down.
-
#tag_column_label ⇒ Object
Header for that column.
-
#tag_vocabulary ⇒ Object
Values offered as filter chips where no counts are available.
-
#tags_for(entry) ⇒ Object
Tags for one job entry, as a { "key" => "value" } Hash.
-
#tags_for_class(klass) ⇒ Object
Tags for a class name alone — used by grouped Errors, where every entry in a group shares a class, so a class-derived tag is constant for the group.
Instance Method Details
#any_filter?(query, tag, queue = rh_filter.queue) ⇒ Boolean
Any filter active? Bulk-on-match is filter-gated, so this decides whether the bulk bar renders at all — and which empty-state copy is honest. Delegates to the concern's predicate where it is available, so the button the view offers and the scope the route enforces cannot drift apart. They did: this returned true only for the view, while bulk_all had no gate at all.
115 116 117 118 119 120 |
# File 'app/helpers/roundhouse_ui/tags_helper.rb', line 115 def any_filter?(query, tag, queue = rh_filter.queue) return controller.send(:bulk_filter_present?, query, tag) if controller.respond_to?(:bulk_filter_present?, true) query.present? || !tag.nil? || queue.present? || rh_filter.klass.present? || rh_filter.error.present? end |
#filter_description(query, tag, queue = rh_filter.queue) ⇒ Object
88 89 90 91 92 93 94 95 |
# File 'app/helpers/roundhouse_ui/tags_helper.rb', line 88 def filter_description(query, tag, queue = rh_filter.queue) parts = [] parts << "matching “#{query}”" if query.present? parts << "tagged #{tag[0]}: #{tag[1]}" if tag parts << "in queue #{queue}" if queue.present? parts << like_description if rh_filter.klass.present? || rh_filter.error.present? parts.join(" and ") end |
#like_description ⇒ Object
"find more like this", said back to you. The wording has to be exact about what it selected, because the bulk Delete sitting next to it acts on precisely this set and nothing wider.
100 101 102 103 104 105 106 107 108 |
# File 'app/helpers/roundhouse_ui/tags_helper.rb', line 100 def like_description # Either half stands on its own. "every Timeout::Error, whatever the class" # is a question worth asking, so clearing the class must not take the error # with it — which is what it used to do. return "failing with #{rh_filter.error}" if rh_filter.klass.blank? return "like #{rh_filter.klass}" if rh_filter.error.blank? "like #{rh_filter.klass} failing with #{rh_filter.error}" end |
#rh_filter ⇒ Object
Human description of the active filter set, so a bulk confirm names every
constraint that will be applied — not just the text query.
Every active constraint must appear here. A confirm that names only the
text query while a queue or tag also narrows the set understates what is
about to be destroyed.
filter is the controller's parse, reached through the helper. One source for
the prose, the predicate and the pill — a description built from a second
reading of the filter is a description that can disagree with what was applied.
84 85 86 |
# File 'app/helpers/roundhouse_ui/tags_helper.rb', line 84 def rh_filter controller.respond_to?(:filter, true) ? controller.send(:filter) : RoundhouseUi::FilterQuery.none end |
#tag_badge(key, value) ⇒ Object
Value only — the key is near-constant down a column, so repeating it is noise. It stays in the tooltip for hosts with more than one dimension.
124 125 126 |
# File 'app/helpers/roundhouse_ui/tags_helper.rb', line 124 def tag_badge(key, value) content_tag(:span, value, class: "rh-pill rh-pill-tag", title: "#{key}: #{value}") end |
#tag_badges(tags) ⇒ Object
Pills for a resolved tag Hash. Renders nothing when there are no tags, so every call site can be unconditional.
34 35 36 37 38 |
# File 'app/helpers/roundhouse_ui/tags_helper.rb', line 34 def tag_badges() return if .blank? safe_join(.map { |key, value| tag_badge(key, value) }, " ") end |
#tag_cache ⇒ Object
The per-request memo handed to Tags.for, shared with JobSetBrowsing so a class (or job) resolved while scanning is not resolved again when its badge renders. Tags.for chooses the key: class name normally, jid in per-job mode.
11 12 13 |
# File 'app/helpers/roundhouse_ui/tags_helper.rb', line 11 def tag_cache @rh_tag_cache ||= {} end |
#tag_cell(tags) ⇒ Object
Cell contents. Stacks when a host defines more than one dimension.
55 56 57 58 59 |
# File 'app/helpers/roundhouse_ui/tags_helper.rb', line 55 def tag_cell() return content_tag(:span, "—", class: "rh-sub") if .blank? tag_badges() end |
#tag_column? ⇒ Boolean
Tags get their own table column rather than an inline badge: class names vary wildly in length, so inline badges land at ragged x-positions and can't be scanned down. Only worth a column when a host configured tags.
43 44 45 |
# File 'app/helpers/roundhouse_ui/tags_helper.rb', line 43 def tag_column? RoundhouseUi..present? end |
#tag_column_label ⇒ Object
Header for that column. With the usual single dimension this is the tag's own name ("squad"); with several there's no one right label.
49 50 51 52 |
# File 'app/helpers/roundhouse_ui/tags_helper.rb', line 49 def tag_column_label keys = Tags.filters&.keys keys&.one? ? keys.first.titleize : "Tags" end |
#tag_vocabulary ⇒ Object
Values offered as filter chips where no counts are available. Prefers the host's declared vocabulary, so the chips stay put as you filter; falls back to whatever the visible rows happen to carry, which at least beats nothing but shifts as you page.
65 66 67 68 69 70 71 72 73 74 |
# File 'app/helpers/roundhouse_ui/tags_helper.rb', line 65 def tag_vocabulary declared = Tags.filters return declared if declared.present? seen = Hash.new { |h, k| h[k] = [] } Array(@jobs).each do |job| (job).each { |key, value| seen[key] << value unless seen[key].include?(value) } end seen.transform_values(&:sort) end |
#tags_for(entry) ⇒ Object
Tags for one job entry, as a { "key" => "value" } Hash.
16 17 18 19 20 |
# File 'app/helpers/roundhouse_ui/tags_helper.rb', line 16 def (entry) return Tags::EMPTY unless RoundhouseUi. Tags.for(klass: entry.klass, item: entry.item, cache: tag_cache) end |
#tags_for_class(klass) ⇒ Object
Tags for a class name alone — used by grouped Errors, where every entry in a group shares a class, so a class-derived tag is constant for the group. Passes no payload, so a per-job resolver correctly declines rather than attributing one job's tags to the whole group.
26 27 28 29 30 |
# File 'app/helpers/roundhouse_ui/tags_helper.rb', line 26 def (klass) return Tags::EMPTY unless RoundhouseUi. Tags.for(klass: klass, item: {}, cache: tag_cache) end |