From 0c2f4e76e132a197c96a9763c13c02f8eb1ff83c Mon Sep 17 00:00:00 2001 From: Katya Sarmiento <5871075+Kitkatnik@users.noreply.github.com> Date: Mon, 27 Apr 2026 02:18:47 -0400 Subject: [PATCH 1/2] Show slot description and Edit link on admin Volunteer Slots page Surface the existing ScheduleItem description under each slot title and add an Edit button (linking to the canonical schedule item edit form) next to View, mirroring the admin/schedule_items index pattern. --- app/views/admin/volunteer_slots/index.html.erb | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/app/views/admin/volunteer_slots/index.html.erb b/app/views/admin/volunteer_slots/index.html.erb index b69edb0..c4aec10 100644 --- a/app/views/admin/volunteer_slots/index.html.erb +++ b/app/views/admin/volunteer_slots/index.html.erb @@ -25,7 +25,12 @@ <% @slots.each do |slot| %> <% state = slot.volunteer_state %> - <%= slot.title %> + +
<%= slot.title %>
+ <% if slot.description.present? %> +
<%= slot.description %>
+ <% end %> + <%= ScheduleItem::DAY_META.dig(slot.day, :label) %>
<%= slot.time_label %> @@ -43,7 +48,10 @@ - <%= link_to "View", admin_volunteer_slot_path(slot), class: "btn btn-muted" %> +
+ <%= link_to "View", admin_volunteer_slot_path(slot), class: "btn btn-muted" %> + <%= link_to "Edit", edit_admin_schedule_item_path(slot), class: "btn btn-muted" %> +
<% end %> From ab5825efba4e9e64f5867685c1515e888dbc8617 Mon Sep 17 00:00:00 2001 From: Katya Sarmiento <5871075+Kitkatnik@users.noreply.github.com> Date: Mon, 27 Apr 2026 10:11:12 -0400 Subject: [PATCH 2/2] Volunteer slot edit: cancel returns to last page, drop tabs from show MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cancel button on the schedule_items form now uses a same-origin return_to param (validated to start with '/' and not '//') passed by the volunteer slots index/show Edit links, persisted via a hidden field so it survives validation re-renders. Falls back to the schedule items index when no return_to is set. Also removes the "By person / By slot" tabs nav from the volunteer slot show page — those tabs are an index-level affordance. --- app/views/admin/schedule_items/_form.html.erb | 11 +++++++++- .../admin/volunteer_slots/index.html.erb | 2 +- app/views/admin/volunteer_slots/show.html.erb | 4 +--- config/brakeman.ignore | 20 +++++++++++++++++++ 4 files changed, 32 insertions(+), 5 deletions(-) diff --git a/app/views/admin/schedule_items/_form.html.erb b/app/views/admin/schedule_items/_form.html.erb index ee9d5dc..0890050 100644 --- a/app/views/admin/schedule_items/_form.html.erb +++ b/app/views/admin/schedule_items/_form.html.erb @@ -8,10 +8,19 @@ <% end %> +<% + raw_return_to = params[:return_to].to_s + return_to = (raw_return_to.start_with?("/") && !raw_return_to.start_with?("//")) ? raw_return_to : nil +%> +
<%= form_with model: [ :admin, schedule_item ], class: "space-y-4", data: { controller: "embassy-settings" } do |f| %> + <% if return_to %> + <%= hidden_field_tag :return_to, return_to %> + <% end %> +
<%= f.label :title, class: "label" %> <%= f.text_field :title, required: true, class: "input" %> @@ -157,7 +166,7 @@
<%= f.submit class: "btn btn-navy" %> - <%= link_to "Cancel", admin_schedule_items_path, class: "btn btn-muted" %> + <%= link_to "Cancel", return_to || admin_schedule_items_path, class: "btn btn-muted" %>
<% end %>
diff --git a/app/views/admin/volunteer_slots/index.html.erb b/app/views/admin/volunteer_slots/index.html.erb index c4aec10..9decd53 100644 --- a/app/views/admin/volunteer_slots/index.html.erb +++ b/app/views/admin/volunteer_slots/index.html.erb @@ -50,7 +50,7 @@
<%= link_to "View", admin_volunteer_slot_path(slot), class: "btn btn-muted" %> - <%= link_to "Edit", edit_admin_schedule_item_path(slot), class: "btn btn-muted" %> + <%= link_to "Edit", edit_admin_schedule_item_path(slot, return_to: admin_volunteer_slots_path), class: "btn btn-muted" %>
diff --git a/app/views/admin/volunteer_slots/show.html.erb b/app/views/admin/volunteer_slots/show.html.erb index 2d31b2c..2322376 100644 --- a/app/views/admin/volunteer_slots/show.html.erb +++ b/app/views/admin/volunteer_slots/show.html.erb @@ -26,10 +26,8 @@
-<%= render "admin/volunteers/tabs" %> -
- <%= link_to "Edit slot", edit_admin_schedule_item_path(@slot), class: "btn btn-muted" %> + <%= link_to "Edit slot", edit_admin_schedule_item_path(@slot, return_to: admin_volunteer_slot_path(@slot)), class: "btn btn-muted" %>

diff --git a/config/brakeman.ignore b/config/brakeman.ignore index 35f2c49..26a0c70 100644 --- a/config/brakeman.ignore +++ b/config/brakeman.ignore @@ -40,6 +40,26 @@ "confidence": "Weak", "cwe_id": [79], "note": "admin_ticket_url is built by the User model as a hard-coded https://dashboard.tito.io/... string with a Tito-issued slug. The slug is alphanumeric/dashes from the Tito API; the scheme is fixed. /admin is behind require_admin! so only admins reach this view. Low risk." + }, + { + "warning_type": "Cross-Site Scripting", + "warning_code": 4, + "fingerprint": "2c22f666bfc341d1ca35845661e7544b651646a9f0b4ce6ec496f84a7e3bc298", + "check_name": "LinkToHref", + "message": "Unsafe parameter value in `link_to` href", + "file": "app/views/admin/schedule_items/_form.html.erb", + "line": 169, + "link": "https://brakemanscanner.org/docs/warning_types/link_to_href", + "code": "link_to(\"Cancel\", ((params[:return_to].to_s or nil) or admin_schedule_items_path), :class => \"btn btn-muted\")", + "render_path": null, + "location": { + "type": "template", + "template": "admin/schedule_items/_form" + }, + "user_input": "params[:return_to].to_s", + "confidence": "High", + "cwe_id": [79], + "note": "return_to is validated above the form: only same-origin paths pass (must start with '/' and not '//'), blocking external redirects, javascript:, data:, etc. The whole admin namespace is gated by require_admin!, so reaching this view already requires an authenticated admin. Static analysis can't trace through the start_with? check, but the runtime guard is sound." } ], "brakeman_version": "8.0.4"