From 3d8187d283bc550e93f243ccdeece26f7b2684b2 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Mon, 20 Oct 2025 14:53:03 +0000
Subject: [PATCH 1/3] Initial plan
From 46d8e40c0ff5ab114230fe49b4b41396c1f31ffc Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Mon, 20 Oct 2025 14:59:56 +0000
Subject: [PATCH 2/3] Add Strava webhook configuration UI
Co-authored-by: apdarr <3004606+apdarr@users.noreply.github.com>
---
app/controllers/plans_controller.rb | 14 ++++++-
app/views/plans/_form.html.erb | 8 ++++
app/views/plans/index.html.erb | 14 +++++++
app/views/plans/show.html.erb | 58 +++++++++++++++++++++++++++++
config/routes.rb | 1 +
5 files changed, 93 insertions(+), 2 deletions(-)
diff --git a/app/controllers/plans_controller.rb b/app/controllers/plans_controller.rb
index 79758e3..c971476 100644
--- a/app/controllers/plans_controller.rb
+++ b/app/controllers/plans_controller.rb
@@ -1,5 +1,5 @@
class PlansController < ApplicationController
- before_action :set_plan, only: %i[ show edit update destroy processing_status edit_workouts update_workouts create_blank_schedule ]
+ before_action :set_plan, only: %i[ show edit update destroy processing_status edit_workouts update_workouts create_blank_schedule enable_webhook_sync ]
# GET /plans or /plans.json
def index
@@ -104,6 +104,16 @@ def processing_status
end
end
+ # PATCH /plans/1/enable_webhook_sync
+ def enable_webhook_sync
+ if @plan.respond_to?(:webhook_enabled=)
+ @plan.update(webhook_enabled: true)
+ redirect_to plans_path, notice: "Strava activity sync has been enabled for this plan."
+ else
+ redirect_to plans_path, alert: "Webhook sync is not available yet. Database migration pending."
+ end
+ end
+
private
# Use callbacks to share common setup or constraints between actions.
def set_plan
@@ -112,7 +122,7 @@ def set_plan
# Only allow a list of trusted parameters through.
def plan_params
- params.require(:plan).permit(:length, :race_date, :plan_type, photos: [])
+ params.require(:plan).permit(:length, :race_date, :plan_type, :webhook_enabled, photos: [])
end
# Create blank activities for a custom plan
diff --git a/app/views/plans/_form.html.erb b/app/views/plans/_form.html.erb
index 6a9b217..ad6a3dd 100644
--- a/app/views/plans/_form.html.erb
+++ b/app/views/plans/_form.html.erb
@@ -33,6 +33,14 @@
<%= form.date_field :race_date, class: "form-input" %>
+
+
+ <% if @plan.respond_to?(:webhook_enabled?) && @plan.webhook_enabled? %>
+
+
+
+
+
+
+
Strava Activity Sync Enabled
+
New Strava activities will be automatically synced and matched to workouts in this plan.
+
+
+
+ <% end %>
+
<%= link_to "Edit plan", edit_plan_path(@plan), class: "btn-soft" %>
<% if @plan.custom? %>
@@ -52,6 +66,50 @@
+
+ <% if @plan.respond_to?(:webhook_enabled?) && @plan.webhook_enabled? %>
+ <%
+ # This will check for unmatched activities when the database supports it
+ # For now, showing placeholder that will be populated when webhook is implemented
+ unmatched_activities = @plan.activities.where(matched_workout_id: nil).where.not(strava_id: nil) rescue []
+ %>
+ <% if unmatched_activities.any? %>
+
+
+
+
+
+
+
Unmatched Strava Activities
+
The following activities couldn't be automatically matched to workouts in your plan. You can link them manually or dismiss them.
+
+
+ <% unmatched_activities.limit(5).each do |activity| %>
+
+
+
+ <%= activity.start_date_local.strftime("%b %d, %Y") %>
+ <%= activity.distance %> mi
+
+
<%= activity.description.presence || "No description" %>
+
+
+ <%= button_to "Link", "#",
+ method: :post,
+ class: "btn-soft text-xs px-3 py-1" %>
+ <%= button_to "Dismiss", "#",
+ method: :delete,
+ class: "btn-ghost text-xs px-3 py-1 text-slate-500" %>
+
+
+ <% end %>
+
+
+
+
+ <% end %>
+ <% end %>
+
diff --git a/config/routes.rb b/config/routes.rb
index c49256d..87c3319 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -11,6 +11,7 @@
patch :update_workouts
post :create_blank_schedule
get :processing_status
+ patch :enable_webhook_sync
end
end
resources :activities
From bafea10c2ef3366dd0cc68497de7c9906c058a5d Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Mon, 20 Oct 2025 15:01:48 +0000
Subject: [PATCH 3/3] Add tests for webhook UI components
Co-authored-by: apdarr <3004606+apdarr@users.noreply.github.com>
---
test/controllers/plans_controller_test.rb | 21 ++++++++
test/system/plans_test.rb | 63 +++++++++++++++++++++++
2 files changed, 84 insertions(+)
diff --git a/test/controllers/plans_controller_test.rb b/test/controllers/plans_controller_test.rb
index 1e1163e..baef734 100644
--- a/test/controllers/plans_controller_test.rb
+++ b/test/controllers/plans_controller_test.rb
@@ -25,6 +25,7 @@ class PlansControllerTest < ActionDispatch::IntegrationTest
test "should get new" do
get new_plan_url
assert_response :success
+ assert_select "input[type=checkbox][name='plan[webhook_enabled]']"
end
test "should create plan" do
@@ -90,4 +91,24 @@ class PlansControllerTest < ActionDispatch::IntegrationTest
assert_redirected_to plans_url
end
+
+ test "should enable webhook sync" do
+ skip "Requires webhook_enabled column in database" unless @plan.respond_to?(:webhook_enabled)
+
+ patch enable_webhook_sync_plan_url(@plan)
+
+ @plan.reload
+ assert @plan.webhook_enabled
+ assert_redirected_to plans_url
+ assert_equal "Strava activity sync has been enabled for this plan.", flash[:notice]
+ end
+
+ test "should handle enable webhook sync when column doesn't exist" do
+ skip "Only applicable when webhook_enabled column doesn't exist" if @plan.respond_to?(:webhook_enabled)
+
+ patch enable_webhook_sync_plan_url(@plan)
+
+ assert_redirected_to plans_url
+ assert_match /not available yet/, flash[:alert]
+ end
end
diff --git a/test/system/plans_test.rb b/test/system/plans_test.rb
index 1f32261..5f04934 100644
--- a/test/system/plans_test.rb
+++ b/test/system/plans_test.rb
@@ -215,4 +215,67 @@ def login!
# Should navigate to edit workouts page
assert_current_path edit_workouts_plan_path(Plan.last)
end
+
+ test "should show webhook sync checkbox on new plan form" do
+ visit new_plan_path
+
+ # Verify webhook sync checkbox exists
+ assert_selector "input[type='checkbox'][name='plan[webhook_enabled]']"
+ assert_selector "label", text: "Enable Strava Activity Sync"
+ assert_text "Automatically sync new Strava activities"
+ end
+
+ test "should create plan with webhook enabled" do
+ skip "Requires webhook_enabled column in database" unless Plan.column_names.include?("webhook_enabled")
+
+ visit new_plan_path
+
+ assert_selector "form"
+ fill_in "plan[length]", with: 12
+ fill_in "plan[race_date]", with: (Date.current + 3.months).strftime("%Y-%m-%d")
+
+ # Enable webhook sync
+ check "plan[webhook_enabled]"
+
+ click_on "Create Plan"
+ assert_text "Plan was successfully created"
+
+ plan = Plan.last
+ assert plan.webhook_enabled
+ end
+
+ test "should show enable sync button for plans without webhook" do
+ skip "Requires webhook_enabled column in database" unless Plan.column_names.include?("webhook_enabled")
+
+ # Create a plan without webhook enabled
+ plan = Plan.create!(
+ length: 12,
+ race_date: Date.current + 3.months,
+ plan_type: "template",
+ webhook_enabled: false
+ )
+
+ visit plans_path
+
+ # Should show Enable Sync button
+ assert_selector "input[type='submit'][value='Enable Sync']"
+ end
+
+ test "should show webhook status on plan show page" do
+ skip "Requires webhook_enabled column in database" unless Plan.column_names.include?("webhook_enabled")
+
+ # Create a plan with webhook enabled
+ plan = Plan.create!(
+ length: 12,
+ race_date: Date.current + 3.months,
+ plan_type: "template",
+ webhook_enabled: true
+ )
+
+ visit plan_path(plan)
+
+ # Should show webhook sync status
+ assert_text "Strava Activity Sync Enabled"
+ assert_text "New Strava activities will be automatically synced"
+ end
end