diff --git a/frontend/src/stimulus/controllers/poll-for-changes.controller.ts b/frontend/src/stimulus/controllers/poll-for-changes.controller.ts index 9be894e96238..fac59aa36734 100644 --- a/frontend/src/stimulus/controllers/poll-for-changes.controller.ts +++ b/frontend/src/stimulus/controllers/poll-for-changes.controller.ts @@ -38,7 +38,7 @@ export default class PollForChangesController extends ApplicationController { updatedAt: String, }; - declare updatedAtValue:string; + declare referenceValue:string; declare urlValue:string; declare intervalValue:number; @@ -58,7 +58,7 @@ export default class PollForChangesController extends ApplicationController { } async triggerTurboStream():Promise { - await fetch(`${this.urlValue}?updatedAt=${this.updatedAtValue}`, { + await fetch(`${this.urlValue}?reference=${this.referenceValue}`, { headers: { Accept: 'text/vnd.turbo-stream.html', }, diff --git a/modules/meeting/app/components/meetings/header_component.html.erb b/modules/meeting/app/components/meetings/header_component.html.erb index 8219e286ac8c..487d164bbf54 100644 --- a/modules/meeting/app/components/meetings/header_component.html.erb +++ b/modules/meeting/app/components/meetings/header_component.html.erb @@ -3,7 +3,7 @@ render(Primer::OpenProject::PageHeader.new( data: { controller: "poll-for-changes", - poll_for_changes_updated_at_value: @meeting.updated_at.iso8601, + poll_for_changes_reference_value: @meeting.changed_hash, poll_for_changes_url_value: check_for_updates_meeting_path(@meeting), poll_for_changes_interval_value: check_for_updates_interval, } diff --git a/modules/meeting/app/controllers/meetings_controller.rb b/modules/meeting/app/controllers/meetings_controller.rb index ab5fc91a73c5..dcd4751c1373 100644 --- a/modules/meeting/app/controllers/meetings_controller.rb +++ b/modules/meeting/app/controllers/meetings_controller.rb @@ -76,10 +76,10 @@ def show end def check_for_updates - if Time.zone.parse(params[:updatedAt]) < @meeting.updated_at.change(usec: 0) - respond_with_flash(Meetings::UpdateFlashComponent.new(meeting: @meeting)) - else + if params[:updatedAt] == @meeting.changed_hash head :no_content + else + respond_with_flash(Meetings::UpdateFlashComponent.new(meeting: @meeting)) end end diff --git a/modules/meeting/app/models/meeting.rb b/modules/meeting/app/models/meeting.rb index 9116281ae333..5c663a9b369f 100644 --- a/modules/meeting/app/models/meeting.rb +++ b/modules/meeting/app/models/meeting.rb @@ -110,6 +110,25 @@ class Meeting < ApplicationRecord closed: 5 } + ## + # Cache key for detecting changes to be shown to the user + def changed_hash + sql = <<~SQL + SELECT MAX(meeting_agenda_items.updated_at), MAX(meeting_sections.updated_at), MAX(meetings.lock_version) FROM meetings + LEFT JOIN meeting_agenda_items ON meeting_agenda_items.meeting_id = meetings.id + LEFT JOIN meeting_sections ON meeting_sections.meeting_id = meetings.id + WHERE meetings.id = :id + SQL + + parts = ActiveRecord::Base + .connection + .exec_query(OpenProject::SqlSanitization.sanitize(sql, id:)) + .rows + .flatten + + OpenProject::Cache::CacheKey.expand(parts) + end + ## # Return the computed start_time when changed def start_time