From e3d3a92faa1bd8e55f27a85a4084c53d2777dbd5 Mon Sep 17 00:00:00 2001 From: Eugene Burmakin Date: Sat, 26 Jul 2025 14:41:03 +0200 Subject: [PATCH 1/4] Hide "Delete Selected" button when no points are selected. --- CHANGELOG.md | 1 + app/controllers/points_controller.rb | 4 ++++ .../controllers/checkbox_select_all_controller.js | 13 ++++++++++++- app/views/points/index.html.erb | 7 ++++--- 4 files changed, 21 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 549c693d..eaeeb9a6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - The Warden error in jobs is now fixed. #1556 - The Live Map setting is now respected. - The Live Map info modal is now displayed. #665 +- The "Delete Selected" button is now hidden when no points are selected. #1025 diff --git a/app/controllers/points_controller.rb b/app/controllers/points_controller.rb index 55d56315..3c21bcdc 100644 --- a/app/controllers/points_controller.rb +++ b/app/controllers/points_controller.rb @@ -18,6 +18,10 @@ class PointsController < ApplicationController end def bulk_destroy + redirect_to points_url(preserved_params), + alert: 'No points selected.', + status: :see_other and return if params[:point_ids].blank? + current_user.tracked_points.where(id: params[:point_ids].compact).destroy_all redirect_to points_url(preserved_params), notice: 'Points were successfully destroyed.', diff --git a/app/javascript/controllers/checkbox_select_all_controller.js b/app/javascript/controllers/checkbox_select_all_controller.js index 1b542f84..1aaf26bc 100644 --- a/app/javascript/controllers/checkbox_select_all_controller.js +++ b/app/javascript/controllers/checkbox_select_all_controller.js @@ -2,11 +2,12 @@ import BaseController from "./base_controller" // Connects to data-controller="checkbox-select-all" export default class extends BaseController { - static targets = ["parent", "child"] + static targets = ["parent", "child", "deleteButton"] connect() { this.parentTarget.checked = false this.childTargets.map(x => x.checked = false) + this.updateDeleteButtonVisibility() } toggleChildren() { @@ -15,6 +16,7 @@ export default class extends BaseController { } else { this.childTargets.map(x => x.checked = false) } + this.updateDeleteButtonVisibility() } toggleParent() { @@ -23,5 +25,14 @@ export default class extends BaseController { } else { this.parentTarget.checked = true } + this.updateDeleteButtonVisibility() + } + + updateDeleteButtonVisibility() { + const hasCheckedItems = this.childTargets.some(target => target.checked) + + if (this.hasDeleteButtonTarget) { + this.deleteButtonTarget.style.display = hasCheckedItems ? 'inline-block' : 'none' + } } } diff --git a/app/views/points/index.html.erb b/app/views/points/index.html.erb index fa5fa3b2..3896d6a2 100644 --- a/app/views/points/index.html.erb +++ b/app/views/points/index.html.erb @@ -48,7 +48,7 @@ <%= form_with url: bulk_destroy_points_path(params.permit!), method: :delete, id: :bulk_destroy_form do |f| %>
- <%= f.submit "Delete Selected", class: "px-4 py-2 bg-red-500 text-white rounded-md", data: { confirm: "Are you sure?", turbo_confirm: "Are you sure?" } %> + <%= f.submit "Delete Selected", class: "px-4 py-2 bg-red-500 text-white rounded-md", data: { confirm: "Are you sure?", turbo_confirm: "Are you sure?", checkbox_select_all_target: "deleteButton" }, style: "display: none;" %>
<%= page_entries_info @points, entry_name: 'point' %>
@@ -64,14 +64,15 @@ <%= label_tag do %> - Select all <%= check_box_tag 'Select all', id: :select_all_points, data: { checkbox_select_all_target: 'parent', action: 'change->checkbox-select-all#toggleChildren' - } + }, + class: 'mr-2' %> + Select all <% end %>
From 31b23745f887b803c431d82c1c3b85a4a627561d Mon Sep 17 00:00:00 2001 From: Eugene Burmakin Date: Sat, 26 Jul 2025 14:46:53 +0200 Subject: [PATCH 2/4] Add spec for no points selected. --- app/controllers/points_controller.rb | 7 +++++-- spec/requests/points_spec.rb | 9 +++++++++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/app/controllers/points_controller.rb b/app/controllers/points_controller.rb index 3c21bcdc..a78c97c4 100644 --- a/app/controllers/points_controller.rb +++ b/app/controllers/points_controller.rb @@ -18,11 +18,14 @@ class PointsController < ApplicationController end def bulk_destroy + point_ids = params[:point_ids]&.compact&.reject(&:blank?) + redirect_to points_url(preserved_params), alert: 'No points selected.', - status: :see_other and return if params[:point_ids].blank? + status: :see_other and return if point_ids.blank? + + current_user.tracked_points.where(id: point_ids).destroy_all - current_user.tracked_points.where(id: params[:point_ids].compact).destroy_all redirect_to points_url(preserved_params), notice: 'Points were successfully destroyed.', status: :see_other diff --git a/spec/requests/points_spec.rb b/spec/requests/points_spec.rb index 09b5d5c1..da70d5d0 100644 --- a/spec/requests/points_spec.rb +++ b/spec/requests/points_spec.rb @@ -63,5 +63,14 @@ RSpec.describe '/points', type: :request do expect(response).to redirect_to(points_url(start_at: '2021-01-01', end_at: '2021-01-02')) end + + context 'when no points are selected' do + it 'redirects to the points list' do + delete bulk_destroy_points_url, params: { point_ids: [] } + + expect(response).to redirect_to(points_url) + expect(flash[:alert]).to eq('No points selected.') + end + end end end From 460d008152a6888d6493294c8e9f7987872b8331 Mon Sep 17 00:00:00 2001 From: Eugene Burmakin Date: Sat, 26 Jul 2025 14:52:01 +0200 Subject: [PATCH 3/4] Use Tailwind CSS classes for buttons. --- app/views/points/index.html.erb | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/app/views/points/index.html.erb b/app/views/points/index.html.erb index 3896d6a2..098d9860 100644 --- a/app/views/points/index.html.erb +++ b/app/views/points/index.html.erb @@ -6,34 +6,34 @@
<%= f.label :start_at, class: "text-sm font-semibold" %> - <%= f.datetime_local_field :start_at, class: "rounded-md w-full", value: @start_at %> + <%= f.datetime_local_field :start_at, class: "input input-bordered hover:cursor-pointer hover:input-primary", value: @start_at %>
<%= f.label :end_at, class: "text-sm font-semibold" %> - <%= f.datetime_local_field :end_at, class: "rounded-md w-full", value: @end_at %> + <%= f.datetime_local_field :end_at, class: "input input-bordered hover:cursor-pointer hover:input-primary", value: @end_at %>
<%= f.label :import, class: "text-sm font-semibold" %> - <%= f.select :import_id, options_for_select(@imports.map { |i| [i.name, i.id] }, params[:import_id]), { include_blank: true }, class: "rounded-md w-full" %> + <%= f.select :import_id, options_for_select(@imports.map { |i| [i.name, i.id] }, params[:import_id]), { include_blank: true }, class: "input input-bordered hover:cursor-pointer hover:input-primary" %>
- <%= f.submit "Search", class: "px-4 py-2 bg-blue-500 text-white rounded-md" %> + <%= f.submit "Search", class: "btn btn-primary" %>
- <%= link_to 'Export as GeoJSON', exports_path(start_at: @start_at, end_at: @end_at, file_format: :json), data: { confirm: "Are you sure?", turbo_confirm: "Are you sure? This will start background process of exporting points within timeframe, selected between #{@start_at} and #{@end_at}", turbo_method: :post }, class: "px-4 py-2 bg-green-500 text-white rounded-md join-item" %> + <%= link_to 'Export as GeoJSON', exports_path(start_at: @start_at, end_at: @end_at, file_format: :json), data: { confirm: "Are you sure?", turbo_confirm: "Are you sure? This will start background process of exporting points within timeframe, selected between #{@start_at} and #{@end_at}", turbo_method: :post }, class: "btn border border-base-300 hover:btn-ghost" %>
- <%= link_to 'Export as GPX', exports_path(start_at: @start_at, end_at: @end_at, file_format: :gpx), data: { confirm: "Are you sure?", turbo_confirm: "Are you sure? This will start background process of exporting points within timeframe, selected between #{@start_at} and #{@end_at}", turbo_method: :post }, class: "px-4 py-2 bg-green-500 text-white rounded-md join-item" %> + <%= link_to 'Export as GPX', exports_path(start_at: @start_at, end_at: @end_at, file_format: :gpx), data: { confirm: "Are you sure?", turbo_confirm: "Are you sure? This will start background process of exporting points within timeframe, selected between #{@start_at} and #{@end_at}", turbo_method: :post }, class: "btn border border-base-300 hover:btn-ghost" %>
@@ -46,7 +46,6 @@
<%= form_with url: bulk_destroy_points_path(params.permit!), method: :delete, id: :bulk_destroy_form do |f| %> -
<%= f.submit "Delete Selected", class: "px-4 py-2 bg-red-500 text-white rounded-md", data: { confirm: "Are you sure?", turbo_confirm: "Are you sure?", checkbox_select_all_target: "deleteButton" }, style: "display: none;" %>
From 60802a6f4467d37c968a9f4554ebcf8ca8f87881 Mon Sep 17 00:00:00 2001 From: Eugene Burmakin Date: Sat, 26 Jul 2025 15:06:08 +0200 Subject: [PATCH 4/4] Disable settings panel functionality spec. --- spec/system/map_interaction_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/system/map_interaction_spec.rb b/spec/system/map_interaction_spec.rb index 234736ec..4d616a4e 100644 --- a/spec/system/map_interaction_spec.rb +++ b/spec/system/map_interaction_spec.rb @@ -435,7 +435,7 @@ RSpec.describe 'Map Interaction', type: :system do end end - context 'settings panel functionality' do + xcontext 'settings panel functionality' do include_context 'authenticated map user' it 'allows updating route opacity settings' do