Merge pull request #5488 from consuldemocracy/check_all_none

Add buttons to check/uncheck all locales
This commit is contained in:
Javi Martín
2024-06-06 17:28:51 +02:00
committed by GitHub
39 changed files with 255 additions and 215 deletions

View File

@@ -10,6 +10,7 @@
//= link stat_graphs.js
//= link dashboard_graphs.js
//= link dashboard_poster.css
//= link noscript.css
//= link print.css
//= link pdf_fonts.css
//= link_tree ../../../vendor/assets/images

View File

@@ -2,20 +2,22 @@
"use strict";
App.CheckAllNone = {
initialize: function() {
$("[data-check-all]").on("click", function(e) {
var target_name;
e.preventDefault();
e.stopPropagation();
target_name = $(this).data("check-all");
$("[name='" + target_name + "']").prop("checked", true);
});
$("[data-check-none]").on("click", function(e) {
var target_name;
e.preventDefault();
e.stopPropagation();
target_name = $(this).data("check-none");
$("[name='" + target_name + "']").prop("checked", false);
$(".check-all-none button").on("click", function() {
var fields = App.CheckAllNone.associated_fields($(this));
if ($(this).data("check-all")) {
fields.prop("checked", true);
} else if ($(this).data("check-none")) {
fields.prop("checked", false);
}
});
},
associated_fields: function(element) {
if (element.data("field-name")) {
return $("[name='" + element.data("field-name") + "']");
} else {
return $("[type='checkbox']", element.closest("fieldset"));
}
}
};
}).call(this);

View File

@@ -22,27 +22,19 @@
@import "mixins/*";
@import "admin";
@import "advanced_search";
@import "annotator_overrides";
@import "autocomplete_overrides";
@import "avatar";
@import "banner";
@import "comments_count";
@import "datepicker_overrides";
@import "layout";
@import "participation";
@import "milestones";
@import "pages";
@import "dashboard";
@import "in_favor_against";
@import "legislation";
@import "legislation_process";
@import "legislation_process_form";
@import "map_location";
@import "moderation_actions";
@import "notification_item";
@import "community";
@import "search_results_summary";
@import "stats";
@import "sticky_overrides";
@import "tags";
@@ -60,6 +52,7 @@
@import "sdg/**/*";
@import "sdg_management/*";
@import "sdg_management/**/*";
@import "shared/**/*";
@import "subscriptions";
@import "widgets/**/*";

View File

@@ -1,43 +1,3 @@
// Table of Contents
//
// 01. Sidebar menu
// 02. Legislation cards
//
// 01. Sidebar menu
// -----------------
.legislation-categories {
.menu.simple {
border-bottom: 0;
list-style: none;
padding-left: 0;
margin-left: 0;
margin-top: 0;
@include breakpoint(medium) {
margin: 1.5rem 0;
}
li {
display: block;
cursor: pointer;
margin-bottom: 1rem;
@include breakpoint(medium) {
margin-bottom: 2rem;
max-width: 80%;
}
&.is-active {
font-weight: 700;
}
}
}
}
// 02. Legislation cards
// -----------------
.legislation {
margin: 0 0 $line-height;
border: 1px solid;

View File

@@ -0,0 +1,9 @@
.admin {
.tabs-content > .tabs-panel {
display: block;
}
}
.check-all-none {
display: none;
}

View File

@@ -0,0 +1,16 @@
.check-all-none {
list-style-type: none;
margin-#{$global-left}: 0;
button {
@include link;
}
li {
display: inline-block;
+ li::before {
@include vertical-separator;
}
}
}

View File

@@ -23,6 +23,10 @@
<legend><%= attribute_name(:enabled) %></legend>
<p class="help-text"><%= t("admin.locales.enabled_help_text") %></p>
<% if many_available_locales? %>
<%= render Shared::CheckAllNoneComponent.new %>
<% end %>
<div class="collection-check-boxes">
<%= f.collection_check_boxes(
:enabled,

View File

@@ -1,4 +1,4 @@
<h2><%= t("moderation.#{i18n_namespace}.index.title") %></h2>
<%= header %>
<%= render "shared/filter_subnav", i18n_namespace: "moderation.#{i18n_namespace}.index" %>
@@ -9,12 +9,7 @@
<% end %>
<%= form_tag form_path, method: :put do %>
<p class="float-left js-check">
<%= t("shared.check") %>:
<%= link_to t("shared.check_all"), "#", data: { check_all: field_name } %>
|
<%= link_to t("shared.check_none"), "#", data: { check_none: field_name } %>
</p>
<%= render Shared::CheckAllNoneComponent.new(field_name) %>
<%= content %>

View File

@@ -1,4 +1,5 @@
class Moderation::Shared::IndexComponent < ApplicationComponent
include Header
attr_reader :records
def initialize(records)
@@ -7,6 +8,10 @@ class Moderation::Shared::IndexComponent < ApplicationComponent
private
def title
t("moderation.#{i18n_namespace}.index.title")
end
def i18n_namespace
table_name
end

View File

@@ -1,6 +1,6 @@
<% provide :main_class, "moderation-users-index" %>
<h2><%= t("moderation.users.index.title") %></h2>
<%= header %>
<%= render Admin::SearchComponent.new(label: t("moderation.users.index.search_placeholder")) %>

View File

@@ -1,4 +1,5 @@
class Moderation::Users::IndexComponent < ApplicationComponent
include Header
attr_reader :users
def initialize(users)
@@ -7,6 +8,10 @@ class Moderation::Users::IndexComponent < ApplicationComponent
private
def title
t("moderation.users.index.title")
end
def status(user)
t("admin.activity.show.actions.#{activity_action(user)}")
end

View File

@@ -0,0 +1,12 @@
<ul class="check-all-none">
<li>
<%= button_tag t("shared.check_all"),
type: "button",
data: { field_name: field_name, check_all: true } %>
</li>
<li>
<%= button_tag t("shared.check_none"),
type: "button",
data: { field_name: field_name, check_none: true } %>
</li>
</ul>

View File

@@ -0,0 +1,7 @@
class Shared::CheckAllNoneComponent < ApplicationComponent
attr_reader :field_name
def initialize(field_name = nil)
@field_name = field_name
end
end

View File

@@ -11,3 +11,6 @@
<%= javascript_include_tag "application", "data-turbolinks-track" => "reload" %>
<%= csrf_meta_tags %>
<%= favicon_link_tag image_path_for("favicon.ico") %>
<noscript>
<%= stylesheet_link_tag "noscript" %>
</noscript>

View File

@@ -1,7 +0,0 @@
<noscript>
<style type="text/css">
.admin .tabs-content > .tabs-panel {
display: block;
}
</style>
</noscript>

View File

@@ -2,7 +2,6 @@
<html <%= common_html_attributes %>>
<head>
<%= render "layouts/common_head", default_title: "Admin" %>
<%= render "layouts/no_script" %>
<%= content_for :head %>
</head>

View File

@@ -1,5 +1,5 @@
<%= render Moderation::Shared::IndexComponent.new(@budget_investments) do %>
<table class="clear">
<table>
<thead>
<tr>
<th><%= t("moderation.budget_investments.index.headers.budget_investment") %></th>

View File

@@ -1,5 +1,5 @@
<%= render Moderation::Shared::IndexComponent.new(@comments) do %>
<table class="clear">
<table>
<thead>
<tr>
<th><%= t("moderation.comments.index.headers.comment") %></th>

View File

@@ -1,5 +1,5 @@
<%= render Moderation::Shared::IndexComponent.new(@debates) do %>
<table class="clear">
<table>
<thead>
<tr>
<th><%= t("moderation.debates.index.headers.debate") %></th>

View File

@@ -1,5 +1,5 @@
<%= render Moderation::Shared::IndexComponent.new(@proposal_notifications) do %>
<table class="clear">
<table>
<thead>
<tr>
<th><%= t("moderation.proposal_notifications.index.headers.proposal_notification") %></th>

View File

@@ -1,5 +1,5 @@
<%= render Moderation::Shared::IndexComponent.new(@proposals) do %>
<table class="clear">
<table>
<thead>
<tr>
<th><%= t("moderation.proposals.index.headers.proposal") %></th>

View File

@@ -674,9 +674,8 @@ en:
author_deleted: User deleted
email_deleted: Email deleted
back: Go back
check: Select
check_all: All
check_none: None
check_all: Select all
check_none: Select none
collective: Collective
flag: Flag as inappropriate
follow: "Follow"

View File

@@ -674,9 +674,8 @@ es:
author_deleted: Usuario eliminado
email_deleted: Email eliminado
back: Volver
check: Seleccionar
check_all: Todos
check_none: Ninguno
check_all: Seleccionar todos
check_none: Seleccionar ninguno
collective: Colectivo
flag: Denunciar como inapropiado
follow: "Seguir"

View File

@@ -5,10 +5,9 @@ describe Admin::Locales::FormComponent do
let(:enabled_locales) { %i[en nl] }
let(:locales_settings) { Setting::LocalesSettings.new(default: default_locale, enabled: enabled_locales) }
let(:component) { Admin::Locales::FormComponent.new(locales_settings) }
describe "default language selector" do
before { allow(I18n).to receive(:available_locales).and_return(%i[de en es nl]) }
describe "default language selector" do
it "renders radio buttons when there are only a few locales" do
render_inline component
@@ -34,4 +33,24 @@ describe Admin::Locales::FormComponent do
selected: "Nederlands"
end
end
describe "buttons to check all/none" do
it "is not rendered when there are only a few locales" do
render_inline component
expect(page).not_to have_button "Select all"
expect(page).not_to have_button "Select none"
end
it "is rendered when there are many locales" do
allow(component).to receive(:select_field_threshold).and_return(3)
render_inline component
page.find(:fieldset, "Enabled languages") do |fieldset|
expect(fieldset).to have_button "Select all"
expect(fieldset).to have_button "Select none"
end
end
end
end

View File

@@ -0,0 +1,41 @@
require "rails_helper"
describe Shared::CheckAllNoneComponent do
it "generates a data-field-name attribute when a field name is given" do
render_inline Shared::CheckAllNoneComponent.new("ids[]")
expect(page).to have_button count: 2
page.find("li:first-child") do |check_all|
expect(check_all).to have_button "Select all"
expect(check_all).to have_css "button[type='button'][data-field-name='ids[]'][data-check-all]"
expect(check_all).not_to have_css "[data-check-none]"
end
page.find("li:last-child") do |check_none|
expect(check_none).to have_button "Select none"
expect(check_none).to have_css "button[type='button'][data-field-name='ids[]'][data-check-none]"
expect(check_none).not_to have_css "[data-check-all]"
end
end
it "does not generate a data-field-name attribute when no field name is given" do
render_inline Shared::CheckAllNoneComponent.new
expect(page).to have_button count: 2
page.find("li:first-child") do |check_all|
expect(check_all).to have_button "Select all"
expect(check_all).to have_css "button[type='button'][data-check-all]"
expect(check_all).not_to have_css "[data-check-none]"
expect(check_all).not_to have_css "[data-field-name]"
end
page.find("li:last-child") do |check_none|
expect(check_none).to have_button "Select none"
expect(check_none).to have_css "button[type='button'][data-check-none]"
expect(check_none).not_to have_css "[data-check-all]"
expect(check_none).not_to have_css "[data-field-name]"
end
end
end

View File

@@ -51,4 +51,22 @@ describe "Locales management", :admin do
expect(page).not_to have_link "English"
end
end
scenario "select all/none" do
allow_any_instance_of(Admin::Locales::FormComponent).to receive(:many_available_locales?).and_return(true)
visit admin_locales_path
within_fieldset "Enabled languages" do
expect(page).to have_field type: :checkbox
click_button "Select all"
expect(all(:checkbox)).to all(be_checked)
click_button "Select none"
all(:checkbox).each { |checkbox| expect(checkbox).not_to be_checked }
end
end
end

View File

@@ -53,10 +53,7 @@ describe "Moderate budget investments" do
describe "When an investment has been selected for moderation" do
before do
visit moderation_budget_investments_path
within(".menu.simple") do
click_link "All"
end
within("#investment_#{investment.id}") do
check "budget_investment_#{investment.id}_check"
@@ -108,16 +105,17 @@ describe "Moderate budget investments" do
create_list(:budget_investment, 2, heading: heading, author: create(:user))
visit moderation_budget_investments_path
click_link "All"
within(".js-check") { click_link "All" }
expect(page).to have_field type: :checkbox, count: 3
expect(all("input[type=checkbox]")).to all(be_checked)
within(".check-all-none") { click_button "Select all" }
within(".js-check") { click_link "None" }
expect(all(:checkbox)).to all(be_checked)
all("input[type=checkbox]").each do |checkbox|
expect(checkbox).not_to be_checked
end
within(".check-all-none") { click_button "Select none" }
all(:checkbox).each { |checkbox| expect(checkbox).not_to be_checked }
end
scenario "remembering page, filter and order" do
@@ -139,35 +137,25 @@ describe "Moderate budget investments" do
scenario "Current filter is properly highlighted" do
visit moderation_budget_investments_path
expect(page).not_to have_link("Pending")
expect(page).to have_link("All")
expect(page).to have_link("Marked as viewed")
visit moderation_budget_investments_path(filter: "all")
within(".menu.simple") do
expect(page).not_to have_link("All")
expect(page).to have_link("Pending")
expect(page).to have_link("Marked as viewed")
end
visit moderation_budget_investments_path(filter: "pending_flag_review")
within(".menu.simple") do
expect(page).to have_link("All")
expect(page).not_to have_link("Pending")
expect(page).to have_link("Marked as viewed")
end
visit moderation_budget_investments_path(filter: "with_ignored_flag")
within(".menu.simple") do
expect(page).to have_link("All")
expect(page).to have_link("Pending")
expect(page).not_to have_link("Marked as viewed")
end
end
scenario "Filtering investments" do
create(:budget_investment, heading: heading, title: "Books investment")

View File

@@ -74,9 +74,7 @@ describe "Moderate comments" do
before do
visit moderation_comments_path
within(".menu.simple") do
click_link "All"
end
within("#comment_#{comment.id}") do
check "comment_#{comment.id}_check"
@@ -128,16 +126,17 @@ describe "Moderate comments" do
create_list(:comment, 2)
visit moderation_comments_path
click_link "All"
within(".js-check") { click_link "All" }
expect(page).to have_field type: :checkbox, count: 2
expect(all("input[type=checkbox]")).to all(be_checked)
within(".check-all-none") { click_button "Select all" }
within(".js-check") { click_link "None" }
expect(all(:checkbox)).to all(be_checked)
all("input[type=checkbox]").each do |checkbox|
expect(checkbox).not_to be_checked
end
within(".check-all-none") { click_button "Select none" }
all(:checkbox).each { |checkbox| expect(checkbox).not_to be_checked }
end
scenario "remembering page, filter and order" do
@@ -164,26 +163,20 @@ describe "Moderate comments" do
expect(page).to have_link("Marked as viewed")
visit moderation_comments_path(filter: "all")
within(".menu.simple") do
expect(page).not_to have_link("All")
expect(page).to have_link("Pending")
expect(page).to have_link("Marked as viewed")
end
visit moderation_comments_path(filter: "pending_flag_review")
within(".menu.simple") do
expect(page).to have_link("All")
expect(page).not_to have_link("Pending")
expect(page).to have_link("Marked as viewed")
end
visit moderation_comments_path(filter: "with_ignored_flag")
within(".menu.simple") do
expect(page).to have_link("All")
expect(page).to have_link("Pending")
expect(page).not_to have_link("Marked as viewed")
end
end
scenario "Filtering comments" do
create(:comment, body: "Regular comment")

View File

@@ -47,9 +47,7 @@ describe "Moderate debates" do
before do
visit moderation_debates_path
within(".menu.simple") do
click_link "All"
end
within("#debate_#{debate.id}") do
check "debate_#{debate.id}_check"
@@ -97,16 +95,17 @@ describe "Moderate debates" do
create_list(:debate, 2)
visit moderation_debates_path
click_link "All"
within(".js-check") { click_link "All" }
expect(page).to have_field type: :checkbox, count: 2
expect(all("input[type=checkbox]")).to all(be_checked)
within(".check-all-none") { click_button "Select all" }
within(".js-check") { click_link "None" }
expect(all(:checkbox)).to all(be_checked)
all("input[type=checkbox]").each do |checkbox|
expect(checkbox).not_to be_checked
end
within(".check-all-none") { click_button "Select none" }
all(:checkbox).each { |checkbox| expect(checkbox).not_to be_checked }
end
scenario "remembering page, filter and order" do
@@ -133,26 +132,20 @@ describe "Moderate debates" do
expect(page).to have_link("Marked as viewed")
visit moderation_debates_path(filter: "all")
within(".menu.simple") do
expect(page).not_to have_link("All")
expect(page).to have_link("Pending")
expect(page).to have_link("Marked as viewed")
end
visit moderation_debates_path(filter: "pending_flag_review")
within(".menu.simple") do
expect(page).to have_link("All")
expect(page).not_to have_link("Pending")
expect(page).to have_link("Marked as viewed")
end
visit moderation_debates_path(filter: "with_ignored_flag")
within(".menu.simple") do
expect(page).to have_link("All")
expect(page).to have_link("Pending")
expect(page).not_to have_link("Marked as viewed")
end
end
scenario "Filtering debates" do
create(:debate, title: "Regular debate")

View File

@@ -55,9 +55,7 @@ describe "Moderate proposal notifications" do
before do
visit moderation_proposal_notifications_path
within(".menu.simple") do
click_link "All"
end
within("#proposal_notification_#{proposal_notification.id}") do
check "proposal_notification_#{proposal_notification.id}_check"
@@ -108,16 +106,17 @@ describe "Moderate proposal notifications" do
create_list(:proposal_notification, 2)
visit moderation_proposal_notifications_path
click_link "All"
within(".js-check") { click_link "All" }
expect(page).to have_field type: :checkbox, count: 2
expect(all("input[type=checkbox]")).to all(be_checked)
within(".check-all-none") { click_button "Select all" }
within(".js-check") { click_link "None" }
expect(all(:checkbox)).to all(be_checked)
all("input[type=checkbox]").each do |checkbox|
expect(checkbox).not_to be_checked
end
within(".check-all-none") { click_button "Select none" }
all(:checkbox).each { |checkbox| expect(checkbox).not_to be_checked }
end
scenario "remembering page, filter and order" do
@@ -144,26 +143,20 @@ describe "Moderate proposal notifications" do
expect(page).to have_link("Mark as viewed")
visit moderation_proposal_notifications_path(filter: "all")
within(".menu.simple") do
expect(page).not_to have_link("All")
expect(page).to have_link("Pending review")
expect(page).to have_link("Mark as viewed")
end
visit moderation_proposal_notifications_path(filter: "pending_review")
within(".menu.simple") do
expect(page).to have_link("All")
expect(page).not_to have_link("Pending review")
expect(page).to have_link("Mark as viewed")
end
visit moderation_proposal_notifications_path(filter: "ignored")
within(".menu.simple") do
expect(page).to have_link("All")
expect(page).to have_link("Pending review")
expect(page).not_to have_link("Marked as viewed")
end
end
scenario "Filtering proposals" do
proposal = create(:proposal)

View File

@@ -46,9 +46,7 @@ describe "Moderate proposals" do
describe "When a proposal has been selected for moderation" do
before do
visit moderation_proposals_path
within(".menu.simple") do
click_link "All"
end
within("#proposal_#{proposal.id}") do
check "proposal_#{proposal.id}_check"
@@ -96,16 +94,17 @@ describe "Moderate proposals" do
create_list(:proposal, 2)
visit moderation_proposals_path
click_link "All"
within(".js-check") { click_link "All" }
expect(page).to have_field type: :checkbox, count: 3
expect(all("input[type=checkbox]")).to all(be_checked)
within(".check-all-none") { click_button "Select all" }
within(".js-check") { click_link "None" }
expect(all(:checkbox)).to all(be_checked)
all("input[type=checkbox]").each do |checkbox|
expect(checkbox).not_to be_checked
end
within(".check-all-none") { click_button "Select none" }
all(:checkbox).each { |checkbox| expect(checkbox).not_to be_checked }
end
scenario "remembering page, filter and order" do
@@ -132,26 +131,20 @@ describe "Moderate proposals" do
expect(page).to have_link("Mark as viewed")
visit moderation_proposals_path(filter: "all")
within(".menu.simple") do
expect(page).not_to have_link("All")
expect(page).to have_link("Pending review")
expect(page).to have_link("Mark as viewed")
end
visit moderation_proposals_path(filter: "pending_flag_review")
within(".menu.simple") do
expect(page).to have_link("All")
expect(page).not_to have_link("Pending")
expect(page).to have_link("Mark as viewed")
end
visit moderation_proposals_path(filter: "with_ignored_flag")
within(".menu.simple") do
expect(page).to have_link("All")
expect(page).to have_link("Pending review")
expect(page).not_to have_link("Marked as viewed")
end
end
scenario "Filtering proposals" do
create(:proposal, title: "Regular proposal")