diff --git a/app/controllers/accountable_sparklines_controller.rb b/app/controllers/accountable_sparklines_controller.rb index bebc211f..832b0a09 100644 --- a/app/controllers/accountable_sparklines_controller.rb +++ b/app/controllers/accountable_sparklines_controller.rb @@ -17,6 +17,9 @@ class AccountableSparklinesController < ApplicationController end render layout: false + rescue => e + Rails.logger.error "Accountable sparkline error for #{@accountable&.name}: #{e.message}" + render partial: "accountable_sparklines/error", layout: false end private diff --git a/app/controllers/accounts_controller.rb b/app/controllers/accounts_controller.rb index 904be2b5..d3fbb00e 100644 --- a/app/controllers/accounts_controller.rb +++ b/app/controllers/accounts_controller.rb @@ -24,6 +24,9 @@ class AccountsController < ApplicationController def sparkline render layout: false + rescue => e + Rails.logger.error "Sparkline error for account #{@account.id}: #{e.message}" + render partial: "accounts/sparkline_error", layout: false end private diff --git a/app/javascript/controllers/turbo_frame_timeout_controller.js b/app/javascript/controllers/turbo_frame_timeout_controller.js new file mode 100644 index 00000000..a81b3dde --- /dev/null +++ b/app/javascript/controllers/turbo_frame_timeout_controller.js @@ -0,0 +1,42 @@ +import { Controller } from "@hotwired/stimulus" + +// Connects to data-controller="turbo-frame-timeout" +export default class extends Controller { + static values = { timeout: { type: Number, default: 10000 } } + + connect() { + this.timeoutId = setTimeout(() => { + this.handleTimeout() + }, this.timeoutValue) + + // Listen for successful frame loads to clear timeout + this.element.addEventListener("turbo:frame-load", this.clearTimeout.bind(this)) + } + + disconnect() { + this.clearTimeout() + } + + clearTimeout() { + if (this.timeoutId) { + clearTimeout(this.timeoutId) + this.timeoutId = null + } + } + + handleTimeout() { + // Replace loading content with error state + this.element.innerHTML = ` +
Timeout
+Error
+Error
+