Merge pull request #4681 from consul/setting_switch

Use a switch control to enable/disable features
This commit is contained in:
Javi Martín
2021-09-23 13:48:57 +02:00
committed by GitHub
24 changed files with 278 additions and 197 deletions

View File

@@ -9,46 +9,6 @@
}
}
[aria-pressed] {
@include regular-button;
border-radius: $line-height;
font-weight: bold;
min-width: rem-calc(100);
position: relative;
&::after {
background: $white;
border-radius: 100%;
content: "";
display: block;
height: 1.75em;
position: absolute;
transform: translateY(-50%);
top: 50%;
width: 1.75em;
}
&[aria-pressed=true] {
background: $primary-color;
padding-right: 2.5em;
text-align: left;
&::after {
right: 0.5em;
}
}
&[aria-pressed=false] {
background: $dark-gray;
padding-left: 2.5em;
text-align: right;
&::after {
left: 0.5em;
}
}
}
dl {
@include callout-size(map-get($callout-sizes, small));
}

View File

@@ -0,0 +1,6 @@
.admin .featured-settings-form {
[aria-pressed] {
@include switch;
}
}

View File

@@ -0,0 +1,6 @@
.admin .featured-settings-table {
td {
max-width: $global-width / 3;
}
}

View File

@@ -40,3 +40,43 @@
text-decoration: underline;
}
}
@mixin switch {
@include regular-button;
border-radius: $line-height;
font-weight: bold;
min-width: rem-calc(100);
position: relative;
&::after {
background: $white;
border-radius: 100%;
content: "";
display: block;
height: 1.75em;
position: absolute;
transform: translateY(-50%);
top: 50%;
width: 1.75em;
}
&[aria-pressed=true] {
background: $primary-color;
padding-right: 2.5em;
text-align: left;
&::after {
right: 0.5em;
}
}
&[aria-pressed=false] {
background: $dark-gray;
padding-left: 2.5em;
text-align: right;
&::after {
left: 0.5em;
}
}
}

View File

@@ -1,19 +1,12 @@
<div class="card machine-learning-setting" id="<%= dom_id(setting) %>">
<div class="card-divider">
<h3 id="machine_learning_<%= kind %>"><%= t("admin.machine_learning.#{kind}") %></h3>
<h3 id="<%= dom_id(setting, :title) %>"><%= t("admin.machine_learning.#{kind}") %></h3>
</div>
<div class="card-section">
<p id="machine_learning_<%= kind %>_description"><%= t("admin.machine_learning.#{kind}_description") %></p>
<p id="<%= dom_id(setting, :description) %>"><%= t("admin.machine_learning.#{kind}_description") %></p>
<% if ml_info.present? %>
<%= form_for(setting, url: admin_setting_path(setting), method: :put) do |f| %>
<%= f.hidden_field :tab, value: "#settings", id: "setting_tab_#{kind}" %>
<%= f.hidden_field :value, value: (setting.enabled? ? "" : "active"), id: "setting_value_#{kind}" %>
<%= f.button(t("shared.#{setting.enabled? ? "yes" : "no"}"),
"aria-labelledby": "machine_learning_#{kind}",
"aria-describedby": "machine_learning_#{kind}_description",
"aria-pressed": setting.enabled?) %>
<% end %>
<%= render Admin::Settings::FeaturedSettingsFormComponent.new(setting, tab: "#settings") %>
<dl class="callout success">
<dt><strong><%= t("admin.machine_learning.last_execution") %></strong></dt>

View File

@@ -0,0 +1,6 @@
<%= form_for([:admin, feature], remote: remote?, html: { class: "featured-settings-form" }) do |f| %>
<%= f.hidden_field :tab, id: dom_id(feature, :tab), value: tab if tab %>
<%= f.hidden_field :describedby, id: dom_id(feature, :describedby), value: describedby if describedby %>
<%= f.hidden_field :value, id: dom_id(feature, :value), value: (enabled? ? "" : "active") %>
<%= f.button text, options %>
<% end %>

View File

@@ -0,0 +1,34 @@
class Admin::Settings::FeaturedSettingsFormComponent < ApplicationComponent
attr_reader :feature, :tab, :describedby
alias_method :describedby?, :describedby
delegate :enabled?, to: :feature
def initialize(feature, tab: nil, describedby: true)
@feature = feature
@tab = tab
@describedby = describedby
end
private
def text
if enabled?
t("shared.yes")
else
t("shared.no")
end
end
def options
{
data: { disable_with: text },
"aria-labelledby": dom_id(feature, :title),
"aria-describedby": (dom_id(feature, :description) if describedby?),
"aria-pressed": enabled?
}
end
def remote?
!%w[feature.map feature.remote_census feature.sdg].include?(feature.key)
end
end

View File

@@ -16,7 +16,11 @@ class Admin::SettingsController < Admin::BaseController
def update
@setting = Setting.find(params[:id])
@setting.update!(settings_params)
redirect_to request_referer, notice: t("admin.settings.flash.updated")
respond_to do |format|
format.html { redirect_to request_referer, notice: t("admin.settings.flash.updated") }
format.js
end
end
def update_map

View File

@@ -1,6 +1,6 @@
<div id="<%= dom_id(feed) %>" class="small-12 medium-6 large-4 column end">
<div class="callout">
<h3><%= t("admin.homepage.feeds.#{feed.kind}") %></h3>
<h3 id="<%= dom_id(feed.setting, :title) %>"><%= t("admin.homepage.feeds.#{feed.kind}") %></h3>
<%= render "setting", setting: feed.setting %>

View File

@@ -1,10 +1 @@
<div id="<%= dom_id(setting) %>">
<%= form_for(setting, url: admin_setting_path(setting), method: :put) do |f| %>
<%= f.hidden_field :value,
value: (setting.enabled? ? "" : "active") %>
<%= f.submit(t("admin.settings.index.features.#{setting.enabled? ? "disable" : "enable"}"),
class: "button #{setting.enabled? ? "hollow alert" : "success"}") %>
<% end %>
</div>
<%= render Admin::Settings::FeaturedSettingsFormComponent.new(setting, describedby: false) %>

View File

@@ -38,7 +38,7 @@
<div class="small-12 medium-6 large-4 column end">
<div class="callout">
<h3 class="inline-block"><%= t("settings.#{@recommendations.key}") %></h3>
<h3 id="<%= dom_id(@recommendations, :title) %>" class="inline-block"><%= t("settings.#{@recommendations.key}") %></h3>
<%= render "setting", setting: @recommendations %>
</div>
</div>

View File

@@ -1,5 +1,5 @@
<%= form_tag admin_update_content_types_path, method: :put, id: "edit_#{dom_id(setting)}" do %>
<%= hidden_field_tag "id", setting.id %>
<%= hidden_field_tag "id", setting.id, id: dom_id(setting, :id) %>
<div class="small-12 medium-6 large-8 column">
<% group = setting.content_type_group %>

View File

@@ -1,7 +0,0 @@
<%= form_for(feature, url: admin_setting_path(feature), html: { id: "edit_#{dom_id(feature)}" }) do |f| %>
<%= f.hidden_field :tab, value: tab if defined?(tab) %>
<%= f.hidden_field :value, id: dom_id(feature), value: (feature.enabled? ? "" : "active") %>
<%= f.submit(t("admin.settings.index.features.#{feature.enabled? ? "disable" : "enable"}"),
class: "button expanded #{feature.enabled? ? "hollow alert" : "success"}",
data: { confirm: t("admin.actions.confirm") }) %>
<% end %>

View File

@@ -1,38 +1,23 @@
<table>
<table class="featured-settings-table">
<thead>
<tr>
<th><%= t("admin.settings.setting") %></th>
<th><%= t("admin.settings.setting_status") %></th>
<th><%= t("admin.settings.setting_actions") %></th>
<th><%= t("admin.settings.index.features.enabled") %></th>
</tr>
</thead>
<tbody>
<% features.each do |feature| %>
<tr>
<td class="small-8">
<strong><%= t("settings.#{feature.key}") %></strong>
<td>
<strong id="<%= dom_id(feature, :title) %>"><%= t("settings.#{feature.key}") %></strong>
<br>
<span class="small">
<span class="small" id="<%= dom_id(feature, :description) %>">
<%= t("settings.#{feature.key}_description", default: t("admin.settings.no_description")) %>
</span>
</td>
<td>
<% if feature.enabled? %>
<span class="enabled">
<strong>
<%= t("admin.settings.index.features.enabled") %>
</strong>
</span>
<% else %>
<span class="disabled">
<%= t("admin.settings.index.features.disabled") %>
</span>
<% end %>
</td>
<td class="text-right">
<%= render "admin/settings/featured_settings_form", feature: feature, tab: tab %>
<%= render Admin::Settings::FeaturedSettingsFormComponent.new(feature, tab: tab) %>
</td>
</tr>
<% end %>

View File

@@ -1,7 +1,11 @@
<%= form_for(setting, url: admin_setting_path(setting), html: { id: "edit_#{dom_id(setting)}" }) do |f| %>
<%= f.hidden_field :tab, value: tab if defined?(tab) %>
<%= form_for([:admin, setting]) do |f| %>
<%= f.hidden_field :tab, id: dom_id(setting, :tab), value: tab if defined?(tab) %>
<div class="small-12 medium-6 large-8 column">
<%= f.text_area :value, label: false, id: dom_id(setting), lines: 1 %>
<%= f.text_area :value,
label: false,
id: dom_id(setting, :value),
"aria-label": strip_tags(t("settings.#{setting.key}")),
"aria-describedby": dom_id(setting, :description) %>
</div>
<div class="small-12 medium-6 large-4 column">
<%= f.submit(t("admin.settings.index.update_setting"), class: "button hollow expanded") %>

View File

@@ -11,7 +11,7 @@
<td class="small-6">
<strong><%= t("settings.#{setting.key}") %></strong>
<br>
<span class="small">
<span id="<%= dom_id(setting, :description) %>" class="small">
<%= t("settings.#{setting.key}_description", default: t("admin.settings.no_description")) %>
</span>
</td>

View File

@@ -0,0 +1,11 @@
var form = $("<%= j render Admin::Settings::FeaturedSettingsFormComponent.new(
@setting,
tab: params[:setting][:tab],
describedby: params[:setting][:describedby]
) %>");
$("#" + form.attr("id")).html(form.html()).find("[type='submit']").focus();
<% if @setting.type == "feature" || @setting.type == "process" %>
$("#side_menu").html("<%= j render Admin::MenuComponent.new %>").foundation();
<% end %>

View File

@@ -160,7 +160,6 @@ ignore_unused:
- "admin.legislation.draft_versions.*.submit_button"
- "admin.legislation.questions.*.submit_button"
- "admin.hidden_comments.index.hidden_*"
- "admin.settings.index.features.*"
- "admin.polls.*.submit_button"
- "admin.booths.*.submit_button"
- "admin.admin_notifications.*.submit_button"

View File

@@ -1298,10 +1298,7 @@ en:
images_and_documents: "Images and documents"
feature_flags: Features
features:
enabled: "Feature enabled"
disabled: "Feature disabled"
enable: "Enable"
disable: "Disable"
enabled: "Enabled"
map:
title: Map configuration
help: Here you can customize the way the map is displayed to users. Drag map marker or click anywhere over the map, set desired zoom and click button "Update".
@@ -1322,9 +1319,7 @@ en:
remote_census_request_name: Request Data
remote_census_response_name: Response Data
setting: Feature
setting_actions: Actions
setting_name: Setting
setting_status: Status
setting_value: Value
no_description: "No description"
shared:

View File

@@ -1297,10 +1297,7 @@ es:
images_and_documents: "Imágenes y documentos"
feature_flags: Funcionalidades
features:
enabled: "Funcionalidad activada"
disabled: "Funcionalidad desactivada"
enable: "Activar"
disable: "Desactivar"
enabled: "Activada"
map:
title: Configuración del mapa
help: Aquí puedes personalizar la manera en la que se muestra el mapa a los usuarios. Arrastra el marcador o pulsa sobre cualquier parte del mapa, ajusta el zoom y pulsa el botón 'Actualizar'.
@@ -1321,9 +1318,7 @@ es:
remote_census_request_name: Datos Petición
remote_census_response_name: Datos Respuesta
setting: Funcionalidad
setting_actions: Acciones
setting_name: Configuración
setting_status: Estado
setting_value: Valor
no_description: "Sin descripción"
shared:

View File

@@ -0,0 +1,63 @@
require "rails_helper"
describe Admin::Settings::FeaturedSettingsFormComponent do
let(:setting) { create(:setting, key: "feature.goodness") }
let(:component) { Admin::Settings::FeaturedSettingsFormComponent.new(setting) }
it "includes an aria-labelledby attribute" do
render_inline component
expect(page).to have_button count: 1
expect(page).to have_css "button[aria-labelledby='title_setting_#{setting.id}']"
end
describe "aria-describedby attribute" do
it "is rendered by default" do
render_inline component
expect(page).to have_css "button[aria-describedby='description_setting_#{setting.id}']"
end
it "is not rendered when the describedby option is false" do
render_inline Admin::Settings::FeaturedSettingsFormComponent.new(setting, describedby: false)
expect(page).not_to have_css "[aria-describedby]"
end
end
describe "aria-pressed attribute" do
it "is true when the setting is enabled" do
setting.update!(value: "active")
render_inline component
expect(page).to have_css "button[aria-pressed='true']"
end
it "is false when the setting is disabled" do
setting.update!(value: "")
render_inline component
expect(page).to have_css "button[aria-pressed='false']"
end
end
describe "button text" do
it "reflects the status when the setting is enabled" do
setting.update!(value: "active")
render_inline component
expect(page).to have_button "Yes"
end
it "reflects the status when the setting is disabled" do
setting.update!(value: "")
render_inline component
expect(page).to have_button "No"
end
end
end

View File

@@ -15,21 +15,17 @@ describe "Admin feature flags", :admin do
end
scenario "Disable a participatory process", :show_exceptions do
setting = Setting.find_by(key: "process.budgets")
budget = create(:budget)
visit admin_settings_path
within("#settings-tabs") { click_link "Participation processes" }
within("#edit_setting_#{setting.id}") do
expect(page).to have_button "Disable"
expect(page).not_to have_button "Enable"
within("tr", text: "Participatory budgeting") do
click_button "Yes"
accept_confirm { click_button "Disable" }
expect(page).to have_button "No"
end
expect(page).to have_content "Value updated"
within("#side_menu") do
expect(page).not_to have_link "Participatory budgets"
end
@@ -46,7 +42,6 @@ describe "Admin feature flags", :admin do
scenario "Enable a disabled participatory process" do
Setting["process.budgets"] = nil
setting = Setting.find_by(key: "process.budgets")
visit admin_root_path
@@ -57,59 +52,38 @@ describe "Admin feature flags", :admin do
visit admin_settings_path
within("#settings-tabs") { click_link "Participation processes" }
within("#edit_setting_#{setting.id}") do
expect(page).to have_button "Enable"
expect(page).not_to have_button "Disable"
within("tr", text: "Participatory budgeting") do
click_button "No"
accept_confirm { click_button "Enable" }
expect(page).to have_button "Yes"
end
expect(page).to have_content "Value updated"
within("#side_menu") do
expect(page).to have_link "Participatory budgets"
end
end
scenario "Disable a feature" do
setting = Setting.find_by(key: "feature.twitter_login")
visit admin_settings_path
click_link "Features"
within("#edit_setting_#{setting.id}") do
expect(page).to have_button "Disable"
expect(page).not_to have_button "Enable"
within("tr", text: "Twitter login") do
click_button "Yes"
accept_confirm { click_button "Disable" }
end
expect(page).to have_content "Value updated"
within("#edit_setting_#{setting.id}") do
expect(page).to have_button "Enable"
expect(page).not_to have_button "Disable"
expect(page).to have_button "No"
expect(page).not_to have_button "Yes"
end
end
scenario "Enable a disabled feature" do
setting = Setting.find_by(key: "feature.map")
visit admin_settings_path
click_link "Features"
within("#edit_setting_#{setting.id}") do
expect(page).to have_button "Enable"
expect(page).not_to have_button "Disable"
within("tr", text: "Proposals and budget investments geolocation") do
click_button "No"
accept_confirm { click_button "Enable" }
end
expect(page).to have_content "Value updated"
within("#edit_setting_#{setting.id}") do
expect(page).to have_button "Disable"
expect(page).not_to have_button "Enable"
expect(page).to have_button "Yes"
expect(page).not_to have_button "No"
end
end
end

View File

@@ -33,7 +33,9 @@ describe "Homepage", :admin do
within("#widget_feed_#{proposals_feed.id}") do
select "1", from: "widget_feed_limit"
click_button "Enable"
click_button "No"
expect(page).to have_button "Yes"
end
visit root_path
@@ -52,7 +54,9 @@ describe "Homepage", :admin do
visit admin_homepage_path
within("#widget_feed_#{debates_feed.id}") do
select "2", from: "widget_feed_limit"
click_button "Enable"
click_button "No"
expect(page).to have_button "Yes"
end
visit root_path
@@ -73,12 +77,16 @@ describe "Homepage", :admin do
within("#widget_feed_#{proposals_feed.id}") do
select "3", from: "widget_feed_limit"
click_button "Enable"
click_button "No"
expect(page).to have_button "Yes"
end
within("#widget_feed_#{debates_feed.id}") do
select "3", from: "widget_feed_limit"
click_button "Enable"
click_button "No"
expect(page).to have_button "Yes"
end
visit root_path
@@ -100,7 +108,9 @@ describe "Homepage", :admin do
visit admin_homepage_path
within("#widget_feed_#{processes_feed.id}") do
select "3", from: "widget_feed_limit"
click_button "Enable"
click_button "No"
expect(page).to have_button "Yes"
end
visit root_path
@@ -153,11 +163,12 @@ describe "Homepage", :admin do
create(:proposal, tag_list: "Sport")
visit admin_homepage_path
within("#setting_#{user_recommendations.id}") do
click_button "Enable"
end
expect(page).to have_content "Value updated"
within("#edit_setting_#{user_recommendations.id}") do
click_button "No"
expect(page).to have_button "Yes"
end
login_as(user)
visit root_path

View File

@@ -14,12 +14,12 @@ describe "Admin settings", :admin do
end
scenario "Update" do
setting = create(:setting, key: "super.users.first")
create(:setting, key: "super.users.first")
visit admin_settings_path
within("#edit_setting_#{setting.id}") do
fill_in "setting_#{setting.id}", with: "Super Users of level 1"
within "tr", text: "First" do
fill_in "First", with: "Super Users of level 1"
click_button "Update"
end
@@ -173,13 +173,13 @@ describe "Admin settings", :admin do
end
scenario "On #tab-remote-census-configuration" do
remote_census_setting = create(:setting, key: "remote_census.general.whatever")
create(:setting, key: "remote_census.general.whatever")
visit admin_settings_path
find("#remote-census-tab").click
within("#edit_setting_#{remote_census_setting.id}") do
fill_in "setting_#{remote_census_setting.id}", with: "New value"
within "tr", text: "Whatever" do
fill_in "Whatever", with: "New value"
click_button "Update"
end
@@ -189,13 +189,13 @@ describe "Admin settings", :admin do
end
scenario "On #tab-configuration" do
configuration_setting = Setting.create!(key: "whatever")
Setting.create!(key: "whatever")
visit admin_settings_path
find("#tab-configuration").click
within("#edit_setting_#{configuration_setting.id}") do
fill_in "setting_#{configuration_setting.id}", with: "New value"
within "tr", text: "Whatever" do
fill_in "Whatever", with: "New value"
click_button "Update"
end
@@ -209,13 +209,13 @@ describe "Admin settings", :admin do
end
scenario "On #tab-map-configuration" do
map_setting = Setting.create!(key: "map.whatever")
Setting.create!(key: "map.whatever")
visit admin_settings_path
click_link "Map configuration"
within("#edit_setting_#{map_setting.id}") do
fill_in "setting_#{map_setting.id}", with: "New value"
within "tr", text: "Whatever" do
fill_in "Whatever", with: "New value"
click_button "Update"
end
@@ -225,13 +225,13 @@ describe "Admin settings", :admin do
end
scenario "On #tab-proposals" do
proposal_dashboard_setting = Setting.create!(key: "proposals.whatever")
Setting.create!(key: "proposals.whatever")
visit admin_settings_path
find("#proposals-tab").click
within("#edit_setting_#{proposal_dashboard_setting.id}") do
fill_in "setting_#{proposal_dashboard_setting.id}", with: "New value"
within "tr", text: "Whatever" do
fill_in "Whatever", with: "New value"
click_button "Update"
end
@@ -240,28 +240,22 @@ describe "Admin settings", :admin do
end
scenario "On #tab-participation-processes" do
process_setting = Setting.create!(key: "process.whatever")
Setting.create!(key: "process.whatever")
visit admin_settings_path
find("#participation-processes-tab").click
accept_alert do
find("#edit_setting_#{process_setting.id} .button").click
end
within("tr", text: "Whatever") { click_button "No" }
expect(page).to have_current_path(admin_settings_path)
expect(page).to have_css("div#tab-participation-processes.is-active")
end
scenario "On #tab-feature-flags" do
feature_setting = Setting.create!(key: "feature.whatever")
Setting.create!(key: "feature.whatever")
visit admin_settings_path
find("#features-tab").click
accept_alert do
find("#edit_setting_#{feature_setting.id} .button").click
end
within("tr", text: "Whatever") { click_button "No" }
expect(page).to have_current_path(admin_settings_path)
expect(page).to have_css("div#tab-feature-flags.is-active")
@@ -275,8 +269,10 @@ describe "Admin settings", :admin do
visit admin_settings_path
click_link "SDG configuration"
accept_alert do
within("tr", text: "Whatever") { click_button "Enable" }
within("tr", text: "Whatever") do
click_button "No"
expect(page).to have_button "Yes"
end
expect(page).to have_current_path(admin_settings_path)
@@ -287,32 +283,28 @@ describe "Admin settings", :admin do
describe "Skip verification" do
scenario "deactivate skip verification" do
Setting["feature.user.skip_verification"] = "true"
setting = Setting.find_by(key: "feature.user.skip_verification")
visit admin_settings_path
find("#features-tab").click
accept_alert do
find("#edit_setting_#{setting.id} .button").click
end
within("tr", text: "Skip user verification") do
click_button "Yes"
expect(page).to have_content "Value updated"
expect(page).to have_button "No"
end
end
scenario "activate skip verification" do
Setting["feature.user.skip_verification"] = nil
setting = Setting.find_by(key: "feature.user.skip_verification")
visit admin_settings_path
find("#features-tab").click
accept_alert do
find("#edit_setting_#{setting.id} .button").click
within("tr", text: "Skip user verification") do
click_button "No"
expect(page).to have_button "Yes"
end
expect(page).to have_content "Value updated"
Setting["feature.user.skip_verification"] = nil
end
end
@@ -338,5 +330,24 @@ describe "Admin settings", :admin do
"Sustainable Development Goals you must " \
'enable "SDG" on "Features" tab.'
end
scenario "is enabled right after enabling the feature" do
Setting["feature.sdg"] = false
login_as(create(:administrator).user)
visit admin_settings_path
click_link "Features"
within("tr", text: "SDG") do
click_button "No"
expect(page).to have_button "Yes"
end
click_link "SDG configuration"
expect(page).to have_css "h2", exact_text: "SDG configuration"
end
end
end