From 0a46307bb8487394c4f9e9b0032d196b1eb13fff Mon Sep 17 00:00:00 2001 From: moveson Date: Thu, 20 Aug 2026 11:39:01 -0600 Subject: [PATCH 1/2] Warn when a private event group's times feed projections New events default to use_for_projections = true, which is right for real events being set up pre-publication but silently includes test events with unrealistic times. Surface the combination at the three moments it matters: - The event form shows an inline warning under the checkbox when the event group is concealed - The setup and setup summary pages show a warning callout listing the projectable events with links to their edit forms - The Take Private confirmation adds a sentence noting the group's events will keep feeding projections unless unchecked Follow-up to #2229/#2231; see also #2169. Co-Authored-By: Claude Fable 5 --- app/helpers/event_groups_helper.rb | 10 ++- .../_projections_warning.html.erb | 21 +++++ .../_setup_summary_status.html.erb | 2 + app/views/event_groups/setup.html.erb | 2 + app/views/events/_form.html.erb | 9 +++ config/locales/views.en.yml | 6 +- spec/helpers/event_groups_helper_spec.rb | 32 ++++++++ .../concealed_projections_warning_spec.rb | 78 +++++++++++++++++++ 8 files changed, 157 insertions(+), 3 deletions(-) create mode 100644 app/views/event_groups/_projections_warning.html.erb create mode 100644 spec/helpers/event_groups_helper_spec.rb create mode 100644 spec/system/event_group_construction/concealed_projections_warning_spec.rb diff --git a/app/helpers/event_groups_helper.rb b/app/helpers/event_groups_helper.rb index 554721ade..bcaa14a98 100644 --- a/app/helpers/event_groups_helper.rb +++ b/app/helpers/event_groups_helper.rb @@ -30,12 +30,18 @@ def button_to_event_group_make_public(view_object) end def button_to_event_group_make_private(view_object) + sentences = [t("event_groups.setup.make_private_confirm", event_group_name: view_object.event_group_name)] + if view_object.events.any?(&:use_for_projections?) + sentences << t("event_groups.setup.make_private_projections_addendum") + end + sentences << t("event_groups.setup.confirm_proceed") + confirm = sentences.join(" ") + button_to "Take Private", organization_event_group_path(view_object.organization, view_object.event_group, event_group: { concealed: true }), method: :patch, - data: { turbo_confirm: t("event_groups.setup.make_private_confirm", - event_group_name: view_object.event_group_name) }, + data: { turbo_confirm: confirm }, class: "btn btn-outline-success" end diff --git a/app/views/event_groups/_projections_warning.html.erb b/app/views/event_groups/_projections_warning.html.erb new file mode 100644 index 000000000..cf7238638 --- /dev/null +++ b/app/views/event_groups/_projections_warning.html.erb @@ -0,0 +1,21 @@ +<%# locals: (presenter:) -%> + +<% projectable_events = presenter.event_group.concealed? ? presenter.events.select(&:use_for_projections?) : [] %> +<% if projectable_events.present? %> + +<% end %> diff --git a/app/views/event_groups/_setup_summary_status.html.erb b/app/views/event_groups/_setup_summary_status.html.erb index d7fc29b3e..93b21db40 100644 --- a/app/views/event_groups/_setup_summary_status.html.erb +++ b/app/views/event_groups/_setup_summary_status.html.erb @@ -23,6 +23,8 @@ <% end %> + <%= render "projections_warning", presenter: presenter %> + + <%= render "projections_warning", presenter: @presenter %> + <%= render "event_overview_cards", presenter: @presenter %> diff --git a/app/views/events/_form.html.erb b/app/views/events/_form.html.erb index 1aacc8fac..f5e83a301 100644 --- a/app/views/events/_form.html.erb +++ b/app/views/events/_form.html.erb @@ -206,6 +206,15 @@ data-bs-placement="bottom" data-bs-original-title="When checked, this event's split times help power pacing plans and live projections for events on this course, even if this event is not public. Uncheck if this event's times are unreliable (for example, unrealistic test data or serious timing problems) and should not influence predictions."> <%= form.check_box :use_for_projections %> + <% if presenter.event_group.concealed? %> +
+

+ This Event Group is private, but this Event's times will still feed pacing plans + and projections for its Course while the box above is checked. If this Event + contains test data or unrealistic times, uncheck the box. +

+
+ <% end %> diff --git a/config/locales/views.en.yml b/config/locales/views.en.yml index 08d0628ee..2d692bb8d 100644 --- a/config/locales/views.en.yml +++ b/config/locales/views.en.yml @@ -32,12 +32,16 @@ en: enable_live_confirm: "NOTE: This will enable live entry actions for %{event_group_name}, and will also enable live follower notifications by email and SMS text when new times are added. Are you sure you want to proceed?" disable_live_confirm: "NOTE: This will suspend all live entry actions for %{event_group_name}, including any that may be in process, and will disable live follower notifications by email and SMS text when new times are added. Are you sure you want to proceed?" make_public_confirm: "NOTE: This will make %{event_group_name} visible to the public, including all related entrants. Are you sure you want to proceed?" - make_private_confirm: "NOTE: This will conceal %{event_group_name} from the public, including all related entrants. Are you sure you want to proceed?" + make_private_confirm: "NOTE: This will conceal %{event_group_name} from the public, including all related entrants." + make_private_projections_addendum: "Even while private, this group's Events will continue to feed pacing plans and projections for their Courses unless you uncheck \"Use this event's times for projections\" on each Event." + confirm_proceed: "Are you sure you want to proceed?" group_is_public_main: "Congratulations, your Event Group is public!" group_is_public_detail: "Results and Follow pages are now available for your entrants to view." group_is_private_main: "Your Event Group is still private" group_is_private_detail: "Once your Events and Courses are ready and you have Entrants loaded, click the \"Go Public\" button to make your Event Group visible to the public." + projections_warning_main: "This private group's times feed projections" + projections_warning_detail: "This Event Group is not public, but times from the Events listed here will still feed pacing plans and projections for their Courses. That is usually what you want for real events being set up. If an Event contains test data or unrealistic times, uncheck \"Use this event's times for projections\" on that Event:" group_is_live_main: "Your Event Group is available for Live Entry" group_is_live_detail: "You can now access the Live Entry view and use OST Remote and RaceResult RFID integration to record times." diff --git a/spec/helpers/event_groups_helper_spec.rb b/spec/helpers/event_groups_helper_spec.rb new file mode 100644 index 000000000..1c010e013 --- /dev/null +++ b/spec/helpers/event_groups_helper_spec.rb @@ -0,0 +1,32 @@ +require "rails_helper" + +RSpec.describe EventGroupsHelper do + describe "#button_to_event_group_make_private" do + subject(:html) { helper.button_to_event_group_make_private(view_object) } + + let(:event_group) { event_groups(:sum) } + let(:view_object) do + instance_double(EventGroupSetupPresenter, + organization: event_group.organization, + event_group: event_group, + event_group_name: event_group.name, + events: event_group.events.to_a) + end + + context "when any event feeds projections" do + it "includes the projections addendum before the confirmation question" do + expect(html).to include("continue to feed pacing plans") + expect(html).to include("Are you sure you want to proceed?") + end + end + + context "when no events feed projections" do + before { event_group.events.each { |event| event.update_column(:use_for_projections, false) } } + + it "omits the projections addendum" do + expect(html).not_to include("continue to feed pacing plans") + expect(html).to include("Are you sure you want to proceed?") + end + end + end +end diff --git a/spec/system/event_group_construction/concealed_projections_warning_spec.rb b/spec/system/event_group_construction/concealed_projections_warning_spec.rb new file mode 100644 index 000000000..a967eec8f --- /dev/null +++ b/spec/system/event_group_construction/concealed_projections_warning_spec.rb @@ -0,0 +1,78 @@ +require "rails_helper" + +RSpec.describe "warnings when a concealed event group feeds projections", :js, type: :system do + let(:admin) { users(:admin_user) } + let(:event_group) { event_groups(:sum) } + let(:event) { event_group.events.first } + + before { login_as admin, scope: :user } + + describe "the event group setup page" do + context "when the event group is concealed and its events feed projections" do + before { event_group.update_column(:concealed, true) } + + scenario "shows the warning with links to the events" do + visit setup_event_group_path(event_group) + + expect(page).to have_content("This private group's times feed projections") + expect(page).to have_link(event.guaranteed_short_name, href: edit_event_group_event_path(event_group, event)) + end + end + + context "when the event group is visible" do + scenario "does not show the warning" do + visit setup_event_group_path(event_group) + + expect(page).to have_content(event_group.name) + expect(page).not_to have_content("This private group's times feed projections") + end + end + + context "when the event group is concealed but no events feed projections" do + before do + event_group.update_column(:concealed, true) + event_group.events.each { |e| e.update_column(:use_for_projections, false) } + end + + scenario "does not show the warning" do + visit setup_event_group_path(event_group) + + expect(page).to have_content(event_group.name) + expect(page).not_to have_content("This private group's times feed projections") + end + end + end + + describe "the setup summary page" do + context "when the event group is concealed and its events feed projections" do + before { event_group.update_column(:concealed, true) } + + scenario "shows the warning" do + visit setup_summary_event_group_path(event_group) + + expect(page).to have_content("This private group's times feed projections") + end + end + end + + describe "the edit event page" do + context "when the event group is concealed" do + before { event_group.update_column(:concealed, true) } + + scenario "shows the inline projections warning" do + visit edit_event_group_event_path(event_group, event) + + expect(page).to have_content("This Event Group is private, but this Event's times will still feed") + end + end + + context "when the event group is visible" do + scenario "does not show the inline projections warning" do + visit edit_event_group_event_path(event_group, event) + + expect(page).to have_content("Use this event's times for projections") + expect(page).not_to have_content("this Event's times will still feed") + end + end + end +end From 0f9515adc0350eb6caed89882b832094dd894f20 Mon Sep 17 00:00:00 2001 From: moveson Date: Thu, 20 Aug 2026 11:43:38 -0600 Subject: [PATCH 2/2] Reword event form projections warning Co-Authored-By: Claude Fable 5 --- app/views/events/_form.html.erb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/events/_form.html.erb b/app/views/events/_form.html.erb index f5e83a301..2e596609d 100644 --- a/app/views/events/_form.html.erb +++ b/app/views/events/_form.html.erb @@ -211,7 +211,7 @@

This Event Group is private, but this Event's times will still feed pacing plans and projections for its Course while the box above is checked. If this Event - contains test data or unrealistic times, uncheck the box. + contains (or is expected to contain) test data or unrealistic times, uncheck the box.

<% end %>