From aa288f4f32b023bd93b046533aee3ec523077f1f Mon Sep 17 00:00:00 2001 From: Ryan Kulp Date: Sun, 9 Aug 2026 19:38:28 -0400 Subject: [PATCH] Update statuspage plugin from core repo --- README.md | 1 + lib/statuspage/statuspage.rb | 83 +++++++++++++++++++ lib/statuspage/views/full.html.erb | 5 ++ lib/statuspage/views/half_horizontal.html.erb | 5 ++ lib/statuspage/views/half_vertical.html.erb | 5 ++ lib/statuspage/views/quadrant.html.erb | 5 ++ .../views/shared/_calendar_star.html.erb | 1 + lib/statuspage/views/shared/_hexagon.html.erb | 1 + lib/statuspage/views/shared/_layout.html.erb | 44 ++++++++++ .../views/shared/_shield_warning.html.erb | 1 + .../views/shared/_title_bar.html.erb | 5 ++ 11 files changed, 156 insertions(+) create mode 100644 lib/statuspage/statuspage.rb create mode 100644 lib/statuspage/views/full.html.erb create mode 100644 lib/statuspage/views/half_horizontal.html.erb create mode 100644 lib/statuspage/views/half_vertical.html.erb create mode 100644 lib/statuspage/views/quadrant.html.erb create mode 100644 lib/statuspage/views/shared/_calendar_star.html.erb create mode 100644 lib/statuspage/views/shared/_hexagon.html.erb create mode 100644 lib/statuspage/views/shared/_layout.html.erb create mode 100644 lib/statuspage/views/shared/_shield_warning.html.erb create mode 100644 lib/statuspage/views/shared/_title_bar.html.erb diff --git a/README.md b/README.md index 9f17e98..043a831 100644 --- a/README.md +++ b/README.md @@ -26,6 +26,7 @@ community Recipes: - [Parcel](/lib/parcel) - [RSS Feed](/lib/rss_feed) - [Shopify](/lib/shopify) +- [Statuspage](/lib/statuspage) - [Stock Price](/lib/stock_price) - [Tempest Weather Station](/lib/tempest_weather_station) - [Todoist](/lib/todoist) diff --git a/lib/statuspage/statuspage.rb b/lib/statuspage/statuspage.rb new file mode 100644 index 0000000..028784a --- /dev/null +++ b/lib/statuspage/statuspage.rb @@ -0,0 +1,83 @@ +module Plugins + class Statuspage < Base + + def locals + { pages: } + end + + private + + # NOTE: only works with pages hosted on statuspage.io + def pages + content = { 'incidents' => [], 'scheduled' => [] } + items.each do |item| + next unless item.is_a?(Hash) && item[:date] + + if item[:date] > DateTime.now + item[:icon] = 'calendar_star' + content['scheduled'] << item + else + item[:icon] = item[:date] > 24.hours.ago ? 'shield_warning' : 'hexagon' + content['incidents'] << item + end + end + + content + end + + # rubocop:disable Security/Open + def items + page_urls.map do |url| + URI.open(url, open_timeout: 5) do |rss| + feed = RSS::Parser.parse(rss, validate: false) + latest_post = feed&.items&.first + + if latest_post.nil? + { + content: 'Unsupported status page', + site_name: url + } + elsif latest_post.is_a?(RSS::Atom::Feed::Entry) + { + title: latest_post&.title&.content, + date: latest_post&.published&.content, + content: latest_post&.content&.content, + site_name: feed&.title&.content + } + else + { + title: latest_post&.title, + date: latest_post&.pubDate, + content: latest_post&.description, # not used, just in case + site_name: feed&.channel&.title&.split('Status')&.first&.squish # => 'Prompt.io' + } + end + end + rescue OpenURI::HTTPError, RSS::NotWellFormedError, Errno::ENOENT + nil + rescue URI::InvalidURIError, SocketError, Resolv::ResolvError, Net::OpenTimeout, Net::ReadTimeout, + OpenSSL::SSL::SSLError, Errno::EHOSTUNREACH, Errno::ECONNREFUSED, Errno::EPIPE => e + handle_erroring_state(e.message) + nil + rescue RuntimeError => e + raise unless e.message.include?('redirection forbidden') + + handle_erroring_state(e.message) + nil + end.compact + end + # rubocop:enable Security/Open + + def page_urls + line_separated_string_to_array(settings['page_urls']).map do |base_url| + next unless base_url.include?('http') # IDEA: extract RssFeed > validate_uri() + + if ['/history.rss', '/feed'].any? { |pattern| base_url.include?(pattern) } + base_url + else + base_url.chomp('/').concat('/history.rss') + end + end.compact # ignores skipped / malformed URLs + end + end +end diff --git a/lib/statuspage/views/full.html.erb b/lib/statuspage/views/full.html.erb new file mode 100644 index 0000000..6ced291 --- /dev/null +++ b/lib/statuspage/views/full.html.erb @@ -0,0 +1,5 @@ +
+ <%= render "plugins/statuspage/shared/layout", pages: pages, always_columns: true, overflow_counter: true, large_text: true %> + + <%= render "plugins/statuspage/shared/title_bar", instance_name: instance_name %> +
diff --git a/lib/statuspage/views/half_horizontal.html.erb b/lib/statuspage/views/half_horizontal.html.erb new file mode 100644 index 0000000..bcc1853 --- /dev/null +++ b/lib/statuspage/views/half_horizontal.html.erb @@ -0,0 +1,5 @@ +
+ <%= render "plugins/statuspage/shared/layout", pages: pages, clamp_details: true, always_columns: true %> + + <%= render "plugins/statuspage/shared/title_bar", instance_name: instance_name %> +
diff --git a/lib/statuspage/views/half_vertical.html.erb b/lib/statuspage/views/half_vertical.html.erb new file mode 100644 index 0000000..33bdbdb --- /dev/null +++ b/lib/statuspage/views/half_vertical.html.erb @@ -0,0 +1,5 @@ +
+ <%= render "plugins/statuspage/shared/layout", pages: pages, overflow_counter: true %> + + <%= render "plugins/statuspage/shared/title_bar", instance_name: instance_name %> +
diff --git a/lib/statuspage/views/quadrant.html.erb b/lib/statuspage/views/quadrant.html.erb new file mode 100644 index 0000000..908ca3f --- /dev/null +++ b/lib/statuspage/views/quadrant.html.erb @@ -0,0 +1,5 @@ +
+ <%= render "plugins/statuspage/shared/layout", pages: pages %> + + <%= render "plugins/statuspage/shared/title_bar", instance_name: instance_name %> +
diff --git a/lib/statuspage/views/shared/_calendar_star.html.erb b/lib/statuspage/views/shared/_calendar_star.html.erb new file mode 100644 index 0000000..88f4c78 --- /dev/null +++ b/lib/statuspage/views/shared/_calendar_star.html.erb @@ -0,0 +1 @@ + diff --git a/lib/statuspage/views/shared/_hexagon.html.erb b/lib/statuspage/views/shared/_hexagon.html.erb new file mode 100644 index 0000000..410d9c8 --- /dev/null +++ b/lib/statuspage/views/shared/_hexagon.html.erb @@ -0,0 +1 @@ + diff --git a/lib/statuspage/views/shared/_layout.html.erb b/lib/statuspage/views/shared/_layout.html.erb new file mode 100644 index 0000000..0dd3e49 --- /dev/null +++ b/lib/statuspage/views/shared/_layout.html.erb @@ -0,0 +1,44 @@ +<% groups = (pages || {}).to_a.first(2) %> +<% always_columns = local_assigns[:always_columns] == true %> +<% large_text = local_assigns[:large_text] == true %> +<% heading_label_class = large_text ? "label lg:label--large" : "label" %> +<% title_class = large_text ? "title title--small lg:title--base" : "title title--small" %> + +
+
+ <% groups.each_with_index do |(type, items), index| %> + <% section_items = Array(items) %> +
+
+
+ <%= type.to_s.titleize %> +
+ +
+
+ <% section_items.each do |item| %> +
+
+
+
+ <%= render "plugins/statuspage/shared/#{item[:icon]}", classes: (local_assigns[:icon_classes] || "w--6 h--6") %> + <%= item[:site_name] %> +
+ data-clamp="1"<% end %>> + <% if type.to_s == 'scheduled' %> + Scheduled: <%= l(item[:date].to_date, format: "%B %d, %Y") %> + <% elsif type.to_s == 'incidents' %> + Last Incident: <%= localized_time_ago(item[:date]) %> + <% end %> + + data-clamp="1"<% end %>><%= item[:title] %> +
+
+ <% end %> +
+
+
+
+ <% end %> +
+
diff --git a/lib/statuspage/views/shared/_shield_warning.html.erb b/lib/statuspage/views/shared/_shield_warning.html.erb new file mode 100644 index 0000000..59c7358 --- /dev/null +++ b/lib/statuspage/views/shared/_shield_warning.html.erb @@ -0,0 +1 @@ + diff --git a/lib/statuspage/views/shared/_title_bar.html.erb b/lib/statuspage/views/shared/_title_bar.html.erb new file mode 100644 index 0000000..5939e98 --- /dev/null +++ b/lib/statuspage/views/shared/_title_bar.html.erb @@ -0,0 +1,5 @@ +
+ <%= image_tag plugin_image_path("statuspage--render.svg"), class: "image image--adaptive", alt: "Statuspage" %> +

Statuspage

+ <%= instance_name %> +