Module: SolidObjects::Web::Helpers
- Included in:
- Action
- Defined in:
- lib/solid_objects/web/helpers.rb,
sig/generated/lib/solid_objects/web/helpers.rbs
Overview
The methods a view may call. Everything a template prints goes through
h, because an actor id, an operation name, and an exception message are
all application supplied strings that reach this page unchanged.
Constant Summary collapse
- FORWARDED_PARAMS =
Only these survive a page link. A filter an operator set stays set when they turn the page; anything else the query string carries does not come back.
%w[actor_type actor_id status per_page].freeze
- TRUNCATION_LIMIT =
2_000
Instance Method Summary collapse
- #actor_label(record) ⇒ String
-
#chart(name, values) ⇒ String
Chart data travels in an attribute rather than an inline script block, so the page needs no script-src exception and an actor type cannot close the attribute and open a tag.
- #chart_library_integrity_attributes ⇒ String
-
#chart_library_source ⇒ String
A vendored copy is a path below the mount; a CDN copy is an absolute URL and is left alone.
- #csp_nonce ⇒ String?
- #csrf_tag ⇒ String
- #current_path ⇒ String
- #current_tab?(path) ⇒ Boolean
- #duration(seconds) ⇒ String
- #environment_name ⇒ String
-
#filter_value(allowed, default: nil) ⇒ String?
An unrecognized filter falls back to the default rather than returning nothing, so a hand edited query string cannot make a page look empty.
- #filtered_instances ⇒ Object
- #find_instance ⇒ Instance
- #form_to(path) ⇒ String
- #h(text) ⇒ String
- #instance_link(instance) ⇒ String
- #json_block(value) ⇒ String
- #lease_state(instance) ⇒ String
- #mailbox_messages(membership) ⇒ Object
- #number(value) ⇒ String
- #page_link(overrides = {}) ⇒ String
- #paginate(relation) ⇒ Paginator
- #path_to(path) ⇒ String
- #query_string(overrides = {}) ⇒ String
- #relative_time(time) ⇒ String
- #root_path ⇒ String
- #statistics ⇒ Statistics
- #status_label(status) ⇒ String
- #tabs ⇒ Hash[String, String]
- #truncate(text, limit = TRUNCATION_LIMIT) ⇒ String
Instance Method Details
#actor_label(record) ⇒ String
109 110 111 |
# File 'lib/solid_objects/web/helpers.rb', line 109 def actor_label(record) "#{h(record.actor_type)} / #{h(record.actor_id)}" end |
#chart(name, values) ⇒ String
Chart data travels in an attribute rather than an inline script block, so the page needs no script-src exception and an actor type cannot close the attribute and open a tag.
The container is not decoration. Chart.js measures a responsive canvas against its parent, so the parent has to have a height of its own; a panel that sizes to its children would grow a little on every redraw.
198 199 200 201 202 203 |
# File 'lib/solid_objects/web/helpers.rb', line 198 def chart(name, values) return "" unless Web.charts? %(<div class="chart-frame"><canvas data-chart="#{h(name)}" ) + %(data-chart-values='#{h(JSON.generate(values))}'></canvas></div>) end |
#chart_library_integrity_attributes ⇒ String
214 215 216 217 218 219 |
# File 'lib/solid_objects/web/helpers.rb', line 214 def chart_library_integrity_attributes integrity = Web.chart_library_integrity return "" unless integrity %( integrity="#{h(integrity)}" crossorigin="anonymous" referrerpolicy="no-referrer") end |
#chart_library_source ⇒ String
A vendored copy is a path below the mount; a CDN copy is an absolute URL and is left alone.
208 209 210 211 |
# File 'lib/solid_objects/web/helpers.rb', line 208 def chart_library_source url = Web.chart_library_url.to_s url.include?("//") ? url : path_to(url) end |
#csp_nonce ⇒ String?
51 52 53 |
# File 'lib/solid_objects/web/helpers.rb', line 51 def csp_nonce env[Web::NONCE_KEY] end |
#csrf_tag ⇒ String
56 57 58 |
# File 'lib/solid_objects/web/helpers.rb', line 56 def csrf_tag %(<input type="hidden" name="authenticity_token" value="#{h(env[Web::CSRF_TOKEN_KEY])}" />) end |
#current_path ⇒ String
34 35 36 |
# File 'lib/solid_objects/web/helpers.rb', line 34 def current_path request.path_info end |
#current_tab?(path) ⇒ Boolean
39 40 41 42 43 |
# File 'lib/solid_objects/web/helpers.rb', line 39 def current_tab?(path) return current_path == "/" if path == "/" current_path.start_with?(path) end |
#duration(seconds) ⇒ String
79 80 81 82 83 84 85 |
# File 'lib/solid_objects/web/helpers.rb', line 79 def duration(seconds) return "—" unless seconds return "#{h(format("%.3f", seconds))} s" if seconds < 60 h("#{(seconds / 60).floor} min #{(seconds % 60).round} s") end |
#environment_name ⇒ String
222 223 224 |
# File 'lib/solid_objects/web/helpers.rb', line 222 def environment_name ENV["RAILS_ENV"] || ENV["RACK_ENV"] || "development" end |
#filter_value(allowed, default: nil) ⇒ String?
An unrecognized filter falls back to the default rather than returning nothing, so a hand edited query string cannot make a page look empty.
156 157 158 159 |
# File 'lib/solid_objects/web/helpers.rb', line 156 def filter_value(allowed, default: nil) value = url_params("status") allowed.include?(value) ? value : default end |
#filtered_instances ⇒ Object
170 171 172 173 174 175 176 177 178 179 180 |
# File 'lib/solid_objects/web/helpers.rb', line 170 def filtered_instances relation = Instance.order(updated_at: :desc, id: :desc) actor_type = url_params("actor_type") relation = relation.where(actor_type:) unless actor_type.to_s.empty? actor_id = url_params("actor_id") return relation if actor_id.to_s.empty? relation.where( Instance.arel_table[:actor_id].matches("%#{Instance.sanitize_sql_like(actor_id)}%") ) end |
#find_instance ⇒ Instance
162 163 164 165 166 167 |
# File 'lib/solid_objects/web/helpers.rb', line 162 def find_instance instance = Instance.find_by(id: route_params(:id)) halt(404) unless instance instance end |
#form_to(path) ⇒ String
61 62 63 |
# File 'lib/solid_objects/web/helpers.rb', line 61 def form_to(path) %(<form method="post" action="#{h(path_to(path))}">#{csrf_tag}) end |
#h(text) ⇒ String
19 20 21 |
# File 'lib/solid_objects/web/helpers.rb', line 19 def h(text) ::Rack::Utils.escape_html(text.to_s) end |
#instance_link(instance) ⇒ String
114 115 116 |
# File 'lib/solid_objects/web/helpers.rb', line 114 def instance_link(instance) %(<a href="#{h(path_to("/instances/#{instance.id}"))}">#{actor_label(instance)}</a>) end |
#json_block(value) ⇒ String
88 89 90 91 92 93 94 |
# File 'lib/solid_objects/web/helpers.rb', line 88 def json_block(value) return "—" if value.nil? %(<pre class="payload">#{h(truncate(JSON.pretty_generate(value)))}</pre>) rescue JSON::GeneratorError, TypeError %(<pre class="payload">#{h(truncate(value.inspect))}</pre>) end |
#lease_state(instance) ⇒ String
135 136 137 138 139 140 141 |
# File 'lib/solid_objects/web/helpers.rb', line 135 def lease_state(instance) return "paused" if instance.paused_at return "idle" unless instance.activation_owner_id return "idle" unless instance.activation_expires_at (instance.activation_expires_at > statistics.now) ? "activated" : "expired" end |
#mailbox_messages(membership) ⇒ Object
183 184 185 186 187 188 |
# File 'lib/solid_objects/web/helpers.rb', line 183 def (membership) membership_model = (membership == "claimed") ? ClaimedMessage : ReadyMessage Message .where(id: membership_model.select(:message_id)) .order(available_at: :asc, id: :asc) end |
#number(value) ⇒ String
74 75 76 |
# File 'lib/solid_objects/web/helpers.rb', line 74 def number(value) h(value.to_i.to_s.reverse.scan(/\d{1,3}/).join(",").reverse) end |
#page_link(overrides = {}) ⇒ String
130 131 132 |
# File 'lib/solid_objects/web/helpers.rb', line 130 def page_link(overrides = {}) h("#{path_to(current_path)}#{query_string(overrides)}") end |
#paginate(relation) ⇒ Paginator
149 150 151 |
# File 'lib/solid_objects/web/helpers.rb', line 149 def paginate(relation) Paginator.new(relation:, page: url_params("page"), per_page: url_params("per_page")) end |
#path_to(path) ⇒ String
29 30 31 |
# File 'lib/solid_objects/web/helpers.rb', line 29 def path_to(path) "#{root_path}#{path}" end |
#query_string(overrides = {}) ⇒ String
119 120 121 122 123 124 125 126 127 |
# File 'lib/solid_objects/web/helpers.rb', line 119 def query_string(overrides = {}) merged = FORWARDED_PARAMS .to_h { |name| [ name, url_params(name) ] } .merge(overrides.transform_keys(&:to_s)) .reject { |_name, value| value.nil? || value.to_s.empty? } return "" if merged.empty? "?#{merged.map { |name, value| "#{::Rack::Utils.escape(name)}=#{::Rack::Utils.escape(value.to_s)}" }.join("&")}" end |
#relative_time(time) ⇒ String
66 67 68 69 70 71 |
# File 'lib/solid_objects/web/helpers.rb', line 66 def relative_time(time) return "—" unless time stamp = time.getutc.iso8601 %(<time datetime="#{stamp}" title="#{stamp}">#{h(stamp)}</time>) end |
#root_path ⇒ String
24 25 26 |
# File 'lib/solid_objects/web/helpers.rb', line 24 def root_path env["SCRIPT_NAME"].to_s end |
#statistics ⇒ Statistics
144 145 146 |
# File 'lib/solid_objects/web/helpers.rb', line 144 def statistics @statistics ||= Statistics.new end |
#status_label(status) ⇒ String
104 105 106 |
# File 'lib/solid_objects/web/helpers.rb', line 104 def status_label(status) %(<span class="status status-#{h(status)}">#{h(status)}</span>) end |
#tabs ⇒ Hash[String, String]
46 47 48 |
# File 'lib/solid_objects/web/helpers.rb', line 46 def tabs Web.tabs end |
#truncate(text, limit = TRUNCATION_LIMIT) ⇒ String
97 98 99 100 101 |
# File 'lib/solid_objects/web/helpers.rb', line 97 def truncate(text, limit = TRUNCATION_LIMIT) return text if text.length <= limit "#{text[0, limit]}…" end |