Merge pull request #5498 from consuldemocracy/toggle_switch

Use a switch control to toggle selections
This commit is contained in:
Javi Martín
2024-10-28 14:19:58 +01:00
committed by GitHub
52 changed files with 966 additions and 436 deletions

View File

@@ -80,9 +80,6 @@
App.ColumnsSelector.toggleColumn(event); App.ColumnsSelector.toggleColumn(event);
} }
}); });
$(".column-selectable").on("inserted", function() {
App.ColumnsSelector.initColumns();
});
}, },
destroy: function() { destroy: function() {
$("#js-columns-selector-wrapper").children(":not(#column_selector_item_template)").remove(); $("#js-columns-selector-wrapper").children(":not(#column_selector_item_template)").remove();

View File

@@ -0,0 +1,19 @@
.admin .admin-budget-investments {
td {
&[data-field=supports],
&[data-field=valuation_finished],
&[data-field=visible_to_valuators],
&[data-field=selected],
&[data-field=incompatible] {
text-align: center;
}
&:not([data-field=id], [data-field=title], [data-field=supports]) {
font-size: $small-font-size;
}
}
.toggle-switch [aria-pressed] {
font-size: inherit;
}
}

View File

@@ -85,7 +85,7 @@
@include regular-button; @include regular-button;
border-radius: $line-height; border-radius: $line-height;
font-weight: bold; font-weight: bold;
min-width: rem-calc(100); min-width: 6em;
position: relative; position: relative;
&::after { &::after {

View File

@@ -0,0 +1,64 @@
<div id="investments" class="admin-budget-investments">
<%= link_to t("admin.budget_investments.index.download_current_selection"),
admin_budget_budget_investments_path(csv_params),
class: "float-right small clear" %>
<% if params[:advanced_filters].include?("winners") %>
<%= render Admin::Budgets::CalculateWinnersButtonComponent.new(budget, from_investments: true) %>
<% end %>
<% if investments.any? %>
<h3 class="inline-block"><%= page_entries_info investments %></h3>
<%= render "admin/shared/columns_selector",
cookie: "investments-columns",
default: %w[id title supports admin valuator geozone feasibility price valuation_finished visible_to_valuators selected incompatible] %>
<br>
<%= render "filters_description", i18n_namespace: "admin.budget_investments.index" %>
<table class="table-for-mobile column-selectable">
<thead>
<tr>
<th><%= link_to_investments_sorted_by :id %></th>
<th data-field="title"><%= link_to_investments_sorted_by :title %></th>
<th data-field="supports"><%= link_to_investments_sorted_by :supports %></th>
<th data-field="admin"><%= t("admin.budget_investments.index.list.admin") %></th>
<th data-field="author">
<%= t("admin.budget_investments.index.list.author") %>
</th>
<th data-field="valuator">
<%= t("admin.budget_investments.index.list.valuation_group") %> /
<%= t("admin.budget_investments.index.list.valuator") %>
</th>
<th data-field="geozone"><%= t("admin.budget_investments.index.list.geozone") %></th>
<th data-field="feasibility"><%= t("admin.budget_investments.index.list.feasibility") %></th>
<% if budget.show_money? %>
<th data-field="price"><%= t("admin.budget_investments.index.list.price") %></th>
<% end %>
<th data-field="valuation_finished">
<%= t("admin.budget_investments.index.list.valuation_finished") %>
</th>
<th data-field="visible_to_valuators">
<%= t("admin.budget_investments.index.list.visible_to_valuators") %>
</th>
<th data-field="selected"><%= t("admin.budget_investments.index.list.selected") %></th>
<% if params[:advanced_filters]&.include?("selected") %>
<th data-field="incompatible"><%= t("admin.budget_investments.index.list.incompatible") %></th>
<% end %>
</tr>
</thead>
<tbody>
<% investments.each do |investment| %>
<%= render Admin::BudgetInvestments::RowComponent.new(investment) %>
<% end %>
</tbody>
</table>
<%= paginate investments %>
<% else %>
<div class="callout primary clear">
<%= t("admin.budget_investments.index.no_budget_investments") %>
</div>
<% end %>
</div>

View File

@@ -0,0 +1,30 @@
class Admin::BudgetInvestments::InvestmentsComponent < ApplicationComponent
attr_reader :budget, :investments
use_helpers :set_direction, :set_sorting_icon
def initialize(budget, investments)
@budget = budget
@investments = investments
end
private
def csv_params
csv_params = params.clone.merge(format: :csv)
csv_params = csv_params.to_unsafe_h.transform_keys(&:to_sym)
csv_params.delete(:page)
csv_params
end
def link_to_investments_sorted_by(column)
direction = set_direction(params[:direction])
icon = set_sorting_icon(direction, column)
translation = t("admin.budget_investments.index.list.#{column}")
link_to(
safe_join([translation, tag.span(class: "icon-sortable #{icon}")]),
admin_budget_budget_investments_path(sort_by: column, direction: direction)
)
end
end

View File

@@ -0,0 +1,57 @@
<tr id="<%= dom_id(investment) %>" class="budget_investment">
<td class="text-right" data-field="id">
<strong><%= investment.id %></strong>
</td>
<td data-field="title">
<%= link_to investment.title, investment_path, target: "_blank" %>
</td>
<td data-field="supports">
<%= investment.total_votes %>
</td>
<td data-field="admin">
<%= administrator_info %>
</td>
<td data-field="author">
<%= investment.author.name %>
</td>
<td data-field="valuator">
<%= valuators_info %>
</td>
<td data-field="geozone">
<%= investment.heading.name %>
</td>
<td data-field="feasibility">
<%= t("admin.budget_investments.index.feasibility.#{investment.feasibility}") %>
</td>
<% if budget.show_money? %>
<td data-field="price">
<%= investment.formatted_price %>
</td>
<% end %>
<td data-field="valuation_finished">
<%= investment.valuation_finished? ? t("shared.yes") : t("shared.no") %>
</td>
<td data-field="visible_to_valuators">
<%= render Admin::BudgetInvestments::ToggleVisibleToValuatorsComponent.new(investment) %>
</td>
<td data-field="selected">
<%= render Admin::BudgetInvestments::ToggleSelectionComponent.new(investment) %>
</td>
<% if params[:advanced_filters]&.include?("selected") %>
<td data-field="incompatible">
<%= investment.incompatible? ? t("shared.yes") : t("shared.no") %>
</td>
<% end %>
</tr>

View File

@@ -0,0 +1,38 @@
class Admin::BudgetInvestments::RowComponent < ApplicationComponent
attr_reader :investment
def initialize(investment)
@investment = investment
end
private
def budget
investment.budget
end
def investment_path
admin_budget_budget_investment_path(budget_id: budget.id,
id: investment.id,
params: Budget::Investment.filter_params(params).to_h)
end
def administrator_info
if investment.administrator.present?
tag.span(investment.administrator.description_or_name,
title: t("admin.budget_investments.index.assigned_admin"))
else
t("admin.budget_investments.index.no_admin_assigned")
end
end
def valuators_info
valuators = [investment.assigned_valuation_groups, investment.assigned_valuators].compact
if valuators.present?
valuators.join(", ")
else
t("admin.budget_investments.index.no_valuators_assigned")
end
end
end

View File

@@ -0,0 +1,5 @@
<% if can?(action, investment) %>
<%= render Admin::ToggleSwitchComponent.new(action, investment, pressed: selected?, **options) %>
<% elsif selected? %>
<%= selected_text %>
<% end %>

View File

@@ -0,0 +1,50 @@
class Admin::BudgetInvestments::ToggleSelectionComponent < ApplicationComponent
attr_reader :investment
use_helpers :can?
delegate :selected?, to: :investment
def initialize(investment)
@investment = investment
end
private
def selected_text
t("admin.budget_investments.index.selected")
end
def action
if selected?
:deselect
else
:select
end
end
def path
url_for({
controller: "admin/budget_investments",
action: action,
budget_id: investment.budget,
id: investment,
filter: params[:filter],
sort_by: params[:sort_by],
min_total_supports: params[:min_total_supports],
max_total_supports: params[:max_total_supports],
advanced_filters: params[:advanced_filters],
page: params[:page]
})
end
def options
{
"aria-label": label,
form_class: "toggle-selection",
path: path
}
end
def label
t("admin.actions.label", action: t("admin.actions.select"), name: investment.title)
end
end

View File

@@ -0,0 +1,5 @@
<% if can?(:admin_update, investment) %>
<%= render Admin::ToggleSwitchComponent.new(action, investment, pressed: visible_to_valuators?, **options) %>
<% else %>
<%= text %>
<% end %>

View File

@@ -0,0 +1,38 @@
class Admin::BudgetInvestments::ToggleVisibleToValuatorsComponent < ApplicationComponent
attr_reader :investment
use_helpers :can?
delegate :visible_to_valuators?, to: :investment
def initialize(investment)
@investment = investment
end
private
def action
if visible_to_valuators?
:hide_from_valuators
else
:show_to_valuators
end
end
def text
if visible_to_valuators?
t("shared.yes")
else
t("shared.no")
end
end
def options
{
"aria-label": label,
form_class: "visible-to-valuators"
}
end
def label
t("admin.actions.show_to_valuators", name: investment.title)
end
end

View File

@@ -0,0 +1 @@
<%= render Admin::ToggleSwitchComponent.new(action, proposal, pressed: selected?, **options) %>

View File

@@ -0,0 +1,31 @@
class Admin::Proposals::ToggleSelectionComponent < ApplicationComponent
attr_reader :proposal
def initialize(proposal)
@proposal = proposal
end
private
def action
if selected?
:deselect
else
:select
end
end
def selected?
proposal.selected?
end
def options
{
"aria-label": label
}
end
def label
t("admin.actions.label", action: t("admin.actions.select"), name: proposal.title)
end
end

View File

@@ -1 +1 @@
<%= render Admin::ActionComponent.new(action, record, **default_options.merge(options)) %> <%= render Admin::ActionComponent.new(action, record, **html_options) %>

View File

@@ -25,7 +25,11 @@ class Admin::ToggleSwitchComponent < ApplicationComponent
method: :patch, method: :patch,
remote: true, remote: true,
"aria-pressed": pressed?, "aria-pressed": pressed?,
form_class: "toggle-switch" form_class: "toggle-switch #{options[:form_class]}".strip
} }
end end
def html_options
default_options.merge(options.except(:form_class))
end
end end

View File

@@ -6,19 +6,18 @@ class Admin::BudgetInvestmentsController < Admin::BaseController
feature_flag :budgets feature_flag :budgets
has_orders %w[oldest], only: [:show, :edit] has_orders %w[oldest], only: [:show, :edit]
has_filters %w[all], only: [:index, :toggle_selection] has_filters %w[all], only: :index
before_action :load_budget before_action :load_budget
before_action :load_investment, only: [:show, :edit, :update, :toggle_selection] before_action :load_investment, except: [:index]
before_action :load_ballot, only: [:show, :index] before_action :load_ballot, only: [:show, :index]
before_action :parse_valuation_filters before_action :parse_valuation_filters
before_action :load_investments, only: [:index, :toggle_selection] before_action :load_investments, only: :index
def index def index
load_tags load_tags
respond_to do |format| respond_to do |format|
format.html format.html
format.js
format.csv do format.csv do
send_data Budget::Investment::Exporter.new(@investments).to_csv, send_data Budget::Investment::Exporter.new(@investments).to_csv,
filename: "budget_investments.csv" filename: "budget_investments.csv"
@@ -40,8 +39,6 @@ class Admin::BudgetInvestmentsController < Admin::BaseController
def update def update
authorize! :admin_update, @investment authorize! :admin_update, @investment
respond_to do |format|
format.html do
if @investment.update(budget_investment_params) if @investment.update(budget_investment_params)
redirect_to admin_budget_budget_investment_path(@budget, redirect_to admin_budget_budget_investment_path(@budget,
@investment, @investment,
@@ -55,17 +52,44 @@ class Admin::BudgetInvestmentsController < Admin::BaseController
end end
end end
format.json do def show_to_valuators
@investment.update!(budget_investment_params) authorize! :admin_update, @investment
end @investment.update!(visible_to_valuators: true)
respond_to do |format|
format.html { redirect_to request.referer, notice: t("flash.actions.update.budget_investment") }
format.js { render :toggle_visible_to_valuators }
end end
end end
def toggle_selection def hide_from_valuators
authorize! :toggle_selection, @investment authorize! :admin_update, @investment
@investment.toggle :selected @investment.update!(visible_to_valuators: false)
@investment.save!
load_investments respond_to do |format|
format.html { redirect_to request.referer, notice: t("flash.actions.update.budget_investment") }
format.js { render :toggle_visible_to_valuators }
end
end
def select
authorize! :select, @investment
@investment.update!(selected: true)
respond_to do |format|
format.html { redirect_to request.referer, notice: t("flash.actions.update.budget_investment") }
format.js { render :toggle_selection }
end
end
def deselect
authorize! :deselect, @investment
@investment.update!(selected: false)
respond_to do |format|
format.html { redirect_to request.referer, notice: t("flash.actions.update.budget_investment") }
format.js { render :toggle_selection }
end
end end
private private
@@ -96,7 +120,7 @@ class Admin::BudgetInvestmentsController < Admin::BaseController
def allowed_params def allowed_params
attributes = [:external_url, :heading_id, :administrator_id, :tag_list, attributes = [:external_url, :heading_id, :administrator_id, :tag_list,
:valuation_tag_list, :incompatible, :visible_to_valuators, :selected, :valuation_tag_list, :incompatible, :selected,
:milestone_tag_list, valuator_ids: [], valuator_group_ids: []] :milestone_tag_list, valuator_ids: [], valuator_group_ids: []]
[*attributes, translation_params(Budget::Investment)] [*attributes, translation_params(Budget::Investment)]
end end

View File

@@ -8,8 +8,21 @@ class Admin::Legislation::ProposalsController < Admin::Legislation::BaseControll
@proposals = @proposals.send("sort_by_#{@current_order}").page(params[:page]) @proposals = @proposals.send("sort_by_#{@current_order}").page(params[:page])
end end
def toggle_selection def select
@proposal.toggle :selected @proposal.update!(selected: true)
@proposal.save!
respond_to do |format|
format.html { redirect_to request.referer, notice: t("flash.actions.update.proposal") }
format.js { render :toggle_selection }
end
end
def deselect
@proposal.update!(selected: false)
respond_to do |format|
format.html { redirect_to request.referer, notice: t("flash.actions.update.proposal") }
format.js { render :toggle_selection }
end
end end
end end

View File

@@ -19,9 +19,22 @@ class Admin::ProposalsController < Admin::BaseController
end end
end end
def toggle_selection def select
@proposal.toggle :selected @proposal.update!(selected: true)
@proposal.save!
respond_to do |format|
format.html { redirect_to request.referer, notice: t("flash.actions.update.proposal") }
format.js { render :toggle_selection }
end
end
def deselect
@proposal.update!(selected: false)
respond_to do |format|
format.html { redirect_to request.referer, notice: t("flash.actions.update.proposal") }
format.js { render :toggle_selection }
end
end end
private private

View File

@@ -3,18 +3,6 @@ module BudgetInvestmentsHelper
params.map { |af| t("admin.budget_investments.index.filters.#{af}") }.join(", ") params.map { |af| t("admin.budget_investments.index.filters.#{af}") }.join(", ")
end end
def link_to_investments_sorted_by(column)
direction = set_direction(params[:direction])
icon = set_sorting_icon(direction, column)
translation = t("admin.budget_investments.index.list.#{column}")
link_to(
safe_join([translation, tag.span(class: "icon-sortable #{icon}")]),
admin_budget_budget_investments_path(sort_by: column, direction: direction)
)
end
def set_sorting_icon(direction, sort_by) def set_sorting_icon(direction, sort_by)
if sort_by.to_s == params[:sort_by] if sort_by.to_s == params[:sort_by]
if direction == "desc" if direction == "desc"

View File

@@ -1,11 +1,4 @@
module BudgetsHelper module BudgetsHelper
def csv_params
csv_params = params.clone.merge(format: :csv)
csv_params = csv_params.to_unsafe_h.transform_keys(&:to_sym)
csv_params.delete(:page)
csv_params
end
def namespaced_budget_investment_path(investment, options = {}) def namespaced_budget_investment_path(investment, options = {})
case namespace case namespace
when "management" when "management"

View File

@@ -64,25 +64,6 @@ module ProposalsHelper
proposals_current_view == "default" ? "minimal" : "default" proposals_current_view == "default" ? "minimal" : "default"
end end
def link_to_toggle_proposal_selection(proposal)
if proposal.selected?
button_text = t("admin.proposals.index.selected")
html_class = "button expanded"
else
button_text = t("admin.proposals.index.select")
html_class = "button hollow expanded"
end
case proposal.class.to_s
when "Proposal"
path = toggle_selection_admin_proposal_path(proposal)
when "Legislation::Proposal"
path = toggle_selection_admin_legislation_process_proposal_path(proposal.process, proposal)
end
link_to button_text, path, remote: true, method: :patch, class: html_class
end
def css_for_proposal_info_row(proposal) def css_for_proposal_info_row(proposal)
if proposal.image.present? if proposal.image.present?
if params[:selected].present? if params[:selected].present?

View File

@@ -71,10 +71,13 @@ module Abilities
can [:read, :create, :update, :destroy], Budget::Group can [:read, :create, :update, :destroy], Budget::Group
can [:read, :create, :update, :destroy], Budget::Heading can [:read, :create, :update, :destroy], Budget::Heading
can [:hide, :admin_update, :toggle_selection], Budget::Investment can [:hide, :admin_update], Budget::Investment
can [:valuate, :comment_valuation], Budget::Investment can [:valuate, :comment_valuation], Budget::Investment
cannot [:admin_update, :toggle_selection, :valuate, :comment_valuation], cannot [:admin_update, :valuate, :comment_valuation],
Budget::Investment, budget: { phase: "finished" } Budget::Investment, budget: { phase: "finished" }
can [:select, :deselect], Budget::Investment do |investment|
investment.feasible? && investment.valuation_finished? && !investment.budget.finished?
end
can :create, Budget::ValuatorAssignment can :create, Budget::ValuatorAssignment

View File

@@ -1,64 +0,0 @@
<%= link_to t("admin.budget_investments.index.download_current_selection"),
admin_budget_budget_investments_path(csv_params),
class: "float-right small clear" %>
<% if params[:advanced_filters].include?("winners") %>
<%= render Admin::Budgets::CalculateWinnersButtonComponent.new(@budget, from_investments: true) %>
<% end %>
<% if @investments.any? %>
<h3 class="inline-block"><%= page_entries_info @investments %></h3>
<%= render "admin/shared/columns_selector",
cookie: "investments-columns",
default: %w[id title supports admin valuator geozone feasibility price valuation_finished visible_to_valuators selected incompatible] %>
<br>
<%= render "filters_description", i18n_namespace: "admin.budget_investments.index" %>
<table class="table-for-mobile column-selectable">
<thead>
<tr>
<th><%= link_to_investments_sorted_by :id %></th>
<th data-field="title"><%= link_to_investments_sorted_by :title %></th>
<th data-field="supports"><%= link_to_investments_sorted_by :supports %></th>
<th data-field="admin"><%= t("admin.budget_investments.index.list.admin") %></th>
<th data-field="author">
<%= t("admin.budget_investments.index.list.author") %>
</th>
<th data-field="valuator">
<%= t("admin.budget_investments.index.list.valuation_group") %> /
<%= t("admin.budget_investments.index.list.valuator") %>
</th>
<th data-field="geozone"><%= t("admin.budget_investments.index.list.geozone") %></th>
<th data-field="feasibility"><%= t("admin.budget_investments.index.list.feasibility") %></th>
<% if @budget.show_money? %>
<th data-field="price"><%= t("admin.budget_investments.index.list.price") %></th>
<% end %>
<th data-field="valuation_finished">
<%= t("admin.budget_investments.index.list.valuation_finished") %>
</th>
<th data-field="visible_to_valuators">
<%= t("admin.budget_investments.index.list.visible_to_valuators") %>
</th>
<th data-field="selected"><%= t("admin.budget_investments.index.list.selected") %></th>
<% if params[:advanced_filters]&.include?("selected") %>
<th data-field="incompatible"><%= t("admin.budget_investments.index.list.incompatible") %></th>
<% end %>
</tr>
</thead>
<tbody>
<% @investments.each do |investment| %>
<tr id="<%= dom_id(investment) %>" class="budget_investment">
<%= render "/admin/budget_investments/select_investment", investment: investment %>
</tr>
<% end %>
</tbody>
</table>
<%= paginate @investments %>
<% else %>
<div class="callout primary clear">
<%= t("admin.budget_investments.index.no_budget_investments") %>
</div>
<% end %>

View File

@@ -1,109 +0,0 @@
<td class="text-right" data-field="id">
<strong><%= investment.id %></strong>
</td>
<td data-field="title">
<%= link_to investment.title,
admin_budget_budget_investment_path(budget_id: @budget.id,
id: investment.id,
params: Budget::Investment.filter_params(params).to_h),
target: "_blank" %>
</td>
<td class="text-center" data-field="supports">
<%= investment.total_votes %>
</td>
<td class="small" data-field="admin">
<% if investment.administrator.present? %>
<span title="<%= t("admin.budget_investments.index.assigned_admin") %>">
<%= investment.administrator.description_or_name %>
</span>
<% else %>
<%= t("admin.budget_investments.index.no_admin_assigned") %>
<% end %>
</td>
<td class="small" data-field="author">
<%= investment.author.name %>
</td>
<td class="small" data-field="valuator">
<% valuators = [investment.assigned_valuation_groups, investment.assigned_valuators].compact %>
<% no_valuators_assigned = t("admin.budget_investments.index.no_valuators_assigned") %>
<%= valuators.present? ? valuators.join(", ") : no_valuators_assigned %>
</td>
<td class="small" data-field="geozone">
<%= investment.heading.name %>
</td>
<td class="small" data-field="feasibility">
<%= t("admin.budget_investments.index.feasibility.#{investment.feasibility}") %>
</td>
<% if @budget.show_money? %>
<td class="small" data-field="price">
<%= investment.formatted_price %>
</td>
<% end %>
<td class="small text-center" data-field="valuation_finished">
<%= investment.valuation_finished? ? t("shared.yes") : t("shared.no") %>
</td>
<td class="small text-center" data-field="visible_to_valuators">
<% if can?(:admin_update, investment) %>
<%= form_for [:admin, investment.budget, investment], remote: true, format: :json do |f| %>
<%= f.check_box :visible_to_valuators,
label: false,
class: "js-submit-on-change",
id: "budget_investment_visible_to_valuators" %>
<% end %>
<% else %>
<%= investment.visible_to_valuators? ? t("shared.yes") : t("shared.no") %>
<% end %>
</td>
<td id="selection" class="small text-center" data-field="selected">
<% if investment.selected? %>
<%= link_to_if can?(:toggle_selection, investment),
t("admin.budget_investments.index.selected"),
toggle_selection_admin_budget_budget_investment_path(
@budget,
investment,
filter: params[:filter],
sort_by: params[:sort_by],
min_total_supports: params[:min_total_supports],
max_total_supports: params[:max_total_supports],
advanced_filters: params[:advanced_filters],
page: params[:page]
),
method: :patch,
remote: true,
class: "button small expanded" %>
<% elsif investment.feasible? && investment.valuation_finished? %>
<% if can?(:toggle_selection, investment) %>
<%= link_to t("admin.budget_investments.index.select"),
toggle_selection_admin_budget_budget_investment_path(
@budget,
investment,
filter: params[:filter],
sort_by: params[:sort_by],
min_total_supports: params[:min_total_supports],
max_total_supports: params[:max_total_supports],
advanced_filters: params[:advanced_filters],
page: params[:page]
),
method: :patch,
remote: true,
class: "button small hollow expanded" %>
<% end %>
<% end %>
</td>
<% if params[:advanced_filters]&.include?("selected") %>
<td class="small text-center" data-field="incompatible">
<%= investment.incompatible? ? t("shared.yes") : t("shared.no") %>
</td>
<% end %>

View File

@@ -12,6 +12,4 @@
<%= render "/shared/filter_subnav", i18n_namespace: "admin.budget_investments.index" %> <%= render "/shared/filter_subnav", i18n_namespace: "admin.budget_investments.index" %>
<div id="investments"> <%= render Admin::BudgetInvestments::InvestmentsComponent.new(@budget, @investments) %>
<%= render "investments" %>
</div>

View File

@@ -1 +0,0 @@
$("#investments").html("<%= j render("admin/budget_investments/investments") %>");

View File

@@ -1 +1,4 @@
$("#<%= dom_id(@investment) %>").html("<%= j render("select_investment", investment: @investment) %>").trigger("inserted"); <%= render "admin/shared/toggle_switch",
record: @investment,
form_class: "toggle-selection",
new_content: render(Admin::BudgetInvestments::ToggleSelectionComponent.new(@investment)) %>

View File

@@ -0,0 +1,4 @@
<%= render "admin/shared/toggle_switch",
record: @investment,
form_class: "visible-to-valuators",
new_content: render(Admin::BudgetInvestments::ToggleVisibleToValuatorsComponent.new(@investment)) %>

View File

@@ -1,5 +1,3 @@
var replacement = $("<%= j render Admin::BudgetPhases::ToggleEnabledComponent.new(@phase) %>"); <%= render "admin/shared/toggle_switch",
var form = $("#<%= dom_id(@phase) %> .toggle-switch"); record: @phase,
new_content: render(Admin::BudgetPhases::ToggleEnabledComponent.new(@phase)) %>
form.replaceWith(replacement);
replacement.find("[type='submit']").focus();

View File

@@ -19,7 +19,7 @@
<td class="text-center"><%= proposal.id %></td> <td class="text-center"><%= proposal.id %></td>
<td><%= proposal.title %></td> <td><%= proposal.title %></td>
<td class="text-center"><%= proposal.votes_score %></td> <td class="text-center"><%= proposal.votes_score %></td>
<td class="select"><%= render "select_proposal", proposal: proposal %></td> <td><%= render Admin::Proposals::ToggleSelectionComponent.new(proposal) %></td>
</tr> </tr>
<% end %> <% end %>
</tbody> </tbody>

View File

@@ -1 +0,0 @@
<%= link_to_toggle_proposal_selection(proposal) %>

View File

@@ -1 +1,3 @@
$("#<%= dom_id(@proposal) %> .select").html("<%= j render("select_proposal", proposal: @proposal) %>"); <%= render "admin/shared/toggle_switch",
record: @proposal,
new_content: render(Admin::Proposals::ToggleSelectionComponent.new(@proposal)) %>

View File

@@ -1 +0,0 @@
<%= link_to_toggle_proposal_selection(proposal) %>

View File

@@ -27,7 +27,7 @@
<td><%= link_to proposal.title, admin_proposal_path(proposal) %></td> <td><%= link_to proposal.title, admin_proposal_path(proposal) %></td>
<td><%= proposal.author.username %></td> <td><%= proposal.author.username %></td>
<td><%= proposal.milestones.count %></td> <td><%= proposal.milestones.count %></td>
<td class="js-select"><%= render "select_proposal", proposal: proposal %></td> <td><%= render Admin::Proposals::ToggleSelectionComponent.new(proposal) %></td>
</tr> </tr>
<% end %> <% end %>
</tbody> </tbody>

View File

@@ -1 +1,3 @@
$("#<%= dom_id(@proposal) %> .js-select").html("<%= j render("select_proposal", proposal: @proposal) %>"); <%= render "admin/shared/toggle_switch",
record: @proposal,
new_content: render(Admin::Proposals::ToggleSelectionComponent.new(@proposal)) %>

View File

@@ -0,0 +1,5 @@
var new_toggle_switch = $("<%= j new_content %>");
var current_toggle_switch = $("#<%= dom_id(record) %> .<%= local_assigns[:form_class] || "toggle-switch" %>");
current_toggle_switch.replaceWith(new_toggle_switch);
new_toggle_switch.find("[type='submit']").focus();

View File

@@ -24,7 +24,7 @@ module ActionDispatch::Routing::UrlFor
end end
def namespaced_polymorphic_path(namespace, resource, options = {}) def namespaced_polymorphic_path(namespace, resource, options = {})
if %w[Budget::Group Budget::Heading Legislation::DraftVersion Legislation::Question if %w[Budget::Group Budget::Heading Legislation::DraftVersion Legislation::Proposal Legislation::Question
Poll::Booth Poll::BoothAssignment Poll::Officer Poll::Question Poll::Question::Option Poll::Booth Poll::BoothAssignment Poll::Officer Poll::Question Poll::Question::Option
Poll::Question::Option::Video Poll::Shift SDG::LocalTarget].include?(resource.class.name) Poll::Question::Option::Video Poll::Shift SDG::LocalTarget].include?(resource.class.name)
resolve = resolve_for(resource) resolve = resolve_for(resource)

View File

@@ -16,6 +16,8 @@ en:
unmark_featured: Unmark featured unmark_featured: Unmark featured
edit: Edit edit: Edit
configure: Configure configure: Configure
select: Select
show_to_valuators: "Show %{name} to valuators"
officing_booth: officing_booth:
title: "You are officing the booth located at %{booth}. If this is not correct, do not continue and call the help phone number. Thank you." title: "You are officing the booth located at %{booth}. If this is not correct, do not continue and call the help phone number. Thank you."
banners: banners:
@@ -268,7 +270,6 @@ en:
unfeasible: "Unfeasible" unfeasible: "Unfeasible"
undecided: "Undecided" undecided: "Undecided"
selected: "Selected" selected: "Selected"
select: "Select"
list: list:
id: ID id: ID
title: Title title: Title
@@ -1294,7 +1295,6 @@ en:
title: Proposals title: Proposals
id: ID id: ID
author: Author author: Author
select: Select
selected: Selected selected: Selected
milestones: Milestones milestones: Milestones
no_proposals: There are no proposals. no_proposals: There are no proposals.

View File

@@ -16,6 +16,8 @@ es:
unmark_featured: Quitar destacado unmark_featured: Quitar destacado
edit: Editar edit: Editar
configure: Configurar configure: Configurar
select: Seleccionar
show_to_valuators: "Mostrar %{name} a evaluadores"
officing_booth: officing_booth:
title: "Estás ahora mismo en la mesa ubicada en %{booth}. Si esto no es correcto no sigas adelante y llama al teléfono de incidencias. Gracias." title: "Estás ahora mismo en la mesa ubicada en %{booth}. Si esto no es correcto no sigas adelante y llama al teléfono de incidencias. Gracias."
banners: banners:
@@ -268,7 +270,6 @@ es:
unfeasible: "Inviable" unfeasible: "Inviable"
undecided: "Sin decidir" undecided: "Sin decidir"
selected: "Seleccionado" selected: "Seleccionado"
select: "Seleccionar"
list: list:
id: ID id: ID
title: Título title: Título
@@ -1295,7 +1296,6 @@ es:
id: ID id: ID
author: Autor author: Autor
milestones: Hitos milestones: Hitos
select: Seleccionar
selected: Seleccionada selected: Seleccionada
no_proposals: No hay propuestas. no_proposals: No hay propuestas.
show: show:

View File

@@ -32,7 +32,11 @@ namespace :admin do
resources :debates, only: [:index, :show] resources :debates, only: [:index, :show]
resources :proposals, only: [:index, :show, :update] do resources :proposals, only: [:index, :show, :update] do
member { patch :toggle_selection } member do
patch :select
patch :deselect
end
resources :milestones, controller: "proposal_milestones" resources :milestones, controller: "proposal_milestones"
resources :progress_bars, except: :show, controller: "proposal_progress_bars" resources :progress_bars, except: :show, controller: "proposal_progress_bars"
end end
@@ -62,7 +66,12 @@ namespace :admin do
end end
resources :budget_investments, only: [:index, :show, :edit, :update] do resources :budget_investments, only: [:index, :show, :edit, :update] do
member { patch :toggle_selection } member do
patch :select
patch :deselect
patch :show_to_valuators
patch :hide_from_valuators
end
resources :audits, only: :show, controller: "budget_investment_audits" resources :audits, only: :show, controller: "budget_investment_audits"
resources :milestones, controller: "budget_investment_milestones" resources :milestones, controller: "budget_investment_milestones"
@@ -232,7 +241,10 @@ namespace :admin do
resources :processes do resources :processes do
resources :questions resources :questions
resources :proposals do resources :proposals do
member { patch :toggle_selection } member do
patch :select
patch :deselect
end
end end
resources :draft_versions resources :draft_versions
resources :milestones resources :milestones

View File

@@ -0,0 +1,66 @@
require "rails_helper"
describe Admin::BudgetInvestments::ToggleSelectionComponent, :admin do
context "open budget" do
let(:budget) { create(:budget) }
it "is not rendered for not-yet-evaluated investments" do
unfeasible_investment = create(:budget_investment, :unfeasible, budget: budget)
feasible_investment = create(:budget_investment, :feasible, budget: budget)
render_inline Admin::BudgetInvestments::ToggleSelectionComponent.new(unfeasible_investment)
expect(page).not_to be_rendered
render_inline Admin::BudgetInvestments::ToggleSelectionComponent.new(feasible_investment)
expect(page).not_to be_rendered
end
it "renders a button to select unselected evaluated investments" do
valuation_finished_investment = create(:budget_investment, :feasible, :finished, budget: budget)
render_inline Admin::BudgetInvestments::ToggleSelectionComponent.new(valuation_finished_investment)
expect(page).to have_button count: 1
expect(page).to have_button exact_text: "No"
expect(page).to have_css "button[aria-pressed='false']"
end
it "renders a button to deselect selected investments" do
selected_investment = create(:budget_investment, :selected, budget: budget)
render_inline Admin::BudgetInvestments::ToggleSelectionComponent.new(selected_investment)
expect(page).to have_button count: 1
expect(page).to have_button exact_text: "Yes"
expect(page).to have_css "button[aria-pressed='true']"
end
end
context "finished budget" do
let(:budget) { create(:budget, :finished) }
it "is not rendered for unselected investments" do
unfeasible_investment = create(:budget_investment, :unfeasible, budget: budget)
feasible_investment = create(:budget_investment, :feasible, budget: budget)
valuation_finished_investment = create(:budget_investment, :feasible, :finished, budget: budget)
render_inline Admin::BudgetInvestments::ToggleSelectionComponent.new(unfeasible_investment)
expect(page).not_to be_rendered
render_inline Admin::BudgetInvestments::ToggleSelectionComponent.new(feasible_investment)
expect(page).not_to be_rendered
render_inline Admin::BudgetInvestments::ToggleSelectionComponent.new(valuation_finished_investment)
expect(page).not_to be_rendered
end
it "renders plain text for selected investments" do
selected_investment = create(:budget_investment, :selected, budget: budget)
render_inline Admin::BudgetInvestments::ToggleSelectionComponent.new(selected_investment)
expect(page).to have_content "Selected"
expect(page).not_to have_button
end
end
end

View File

@@ -0,0 +1,21 @@
require "rails_helper"
describe Admin::BudgetInvestments::ToggleVisibleToValuatorsComponent, :admin do
describe "aria-pressed attribute" do
it "is true for investments visible to valuators" do
investment = create(:budget_investment, :visible_to_valuators)
render_inline Admin::BudgetInvestments::ToggleVisibleToValuatorsComponent.new(investment)
expect(page).to have_css "[aria-pressed=true]"
end
it "is true for investments invisible to valuators" do
investment = create(:budget_investment, :invisible_to_valuators)
render_inline Admin::BudgetInvestments::ToggleVisibleToValuatorsComponent.new(investment)
expect(page).to have_css "[aria-pressed=false]"
end
end
end

View File

@@ -0,0 +1,21 @@
require "rails_helper"
describe Admin::Proposals::ToggleSelectionComponent, :admin do
describe "aria-pressed attribute" do
it "is true for selected proposals" do
proposal = create(:proposal, :selected)
render_inline Admin::Proposals::ToggleSelectionComponent.new(proposal)
expect(page).to have_css "button[aria-pressed='true']"
end
it "is false for not selected proposals" do
proposal = create(:proposal)
render_inline Admin::Proposals::ToggleSelectionComponent.new(proposal)
expect(page).to have_css "button[aria-pressed='false']"
end
end
end

View File

@@ -23,18 +23,139 @@ describe Admin::BudgetInvestmentsController, :admin do
end end
end end
describe "PATCH update" do describe "PATCH show_to_valuators" do
it "does not redirect on AJAX requests" do let(:investment) { create(:budget_investment, :invisible_to_valuators) }
investment = create(:budget_investment)
patch :update, params: { it "marks the investment as visible to valuators" do
id: investment, expect do
budget_id: investment.budget, patch :show_to_valuators, xhr: true, params: { id: investment, budget_id: investment.budget }
format: :json, end.to change { investment.reload.visible_to_valuators? }.from(false).to(true)
budget_investment: { visible_to_valuators: true }
}
expect(response).not_to be_redirect expect(response).to be_successful
end
it "does not modify investments visible to valuators" do
investment.update!(visible_to_valuators: true)
expect do
patch :show_to_valuators, xhr: true, params: { id: investment, budget_id: investment.budget }
end.not_to change { investment.reload.visible_to_valuators? }
end
it "redirects admins without JavaScript to the same page" do
request.env["HTTP_REFERER"] = admin_budget_budget_investments_path(investment.budget)
patch :show_to_valuators, params: { id: investment, budget_id: investment.budget }
expect(response).to redirect_to admin_budget_budget_investments_path(investment.budget)
expect(flash[:notice]).to eq "Investment project updated successfully."
end
end
describe "PATCH hide_from_valuators" do
let(:investment) { create(:budget_investment, :visible_to_valuators) }
it "marks the investment as visible to valuators" do
expect do
patch :hide_from_valuators, xhr: true, params: { id: investment, budget_id: investment.budget }
end.to change { investment.reload.visible_to_valuators? }.from(true).to(false)
expect(response).to be_successful
end
it "does not modify investments visible to valuators" do
investment.update!(visible_to_valuators: false)
expect do
patch :hide_from_valuators, xhr: true, params: { id: investment, budget_id: investment.budget }
end.not_to change { investment.reload.visible_to_valuators? }
end
it "redirects admins without JavaScript to the same page" do
request.env["HTTP_REFERER"] = admin_budget_budget_investments_path(investment.budget)
patch :hide_from_valuators, params: { id: investment, budget_id: investment.budget }
expect(response).to redirect_to admin_budget_budget_investments_path(investment.budget)
expect(flash[:notice]).to eq "Investment project updated successfully."
end
end
describe "PATCH select" do
let(:investment) { create(:budget_investment, :feasible, :finished) }
it "selects the investment" do
expect do
patch :select, xhr: true, params: { id: investment, budget_id: investment.budget }
end.to change { investment.reload.selected? }.from(false).to(true)
expect(response).to be_successful
end
it "does not modify already selected investments" do
investment.update!(selected: true)
expect do
patch :select, xhr: true, params: { id: investment, budget_id: investment.budget }
end.not_to change { investment.reload.selected? }
end
it "uses the select/deselect authorization rules" do
investment.update!(valuation_finished: false)
patch :select, xhr: true, params: { id: investment, budget_id: investment.budget }
expect(flash[:alert]).to eq "You do not have permission to carry out the action " \
"'select' on Investment."
expect(investment).not_to be_selected
end
it "redirects admins without JavaScript to the same page" do
request.env["HTTP_REFERER"] = admin_budget_budget_investments_path(investment.budget)
patch :select, params: { id: investment, budget_id: investment.budget }
expect(response).to redirect_to admin_budget_budget_investments_path(investment.budget)
expect(flash[:notice]).to eq "Investment project updated successfully."
end
end
describe "PATCH deselect" do
let(:investment) { create(:budget_investment, :feasible, :finished, :selected) }
it "deselects the investment" do
expect do
patch :deselect, xhr: true, params: { id: investment, budget_id: investment.budget }
end.to change { investment.reload.selected? }.from(true).to(false)
expect(response).to be_successful
end
it "does not modify non-selected investments" do
investment.update!(selected: false)
expect do
patch :deselect, xhr: true, params: { id: investment, budget_id: investment.budget }
end.not_to change { investment.reload.selected? }
end
it "uses the select/deselect authorization rules" do
investment.update!(valuation_finished: false)
patch :deselect, xhr: true, params: { id: investment, budget_id: investment.budget }
expect(flash[:alert]).to eq "You do not have permission to carry out the action " \
"'deselect' on Investment."
expect(investment).to be_selected
end
it "redirects admins without JavaScript to the same page" do
request.env["HTTP_REFERER"] = admin_budget_budget_investments_path(investment.budget)
patch :deselect, params: { id: investment, budget_id: investment.budget }
expect(response).to redirect_to admin_budget_budget_investments_path(investment.budget)
expect(flash[:notice]).to eq "Investment project updated successfully."
end end
end end
end end

View File

@@ -0,0 +1,61 @@
require "rails_helper"
describe Admin::Legislation::ProposalsController, :admin do
describe "PATCH select" do
let(:proposal) { create(:legislation_proposal) }
it "selects the proposal" do
expect do
patch :select, xhr: true, params: { id: proposal.id, process_id: proposal.process.id }
end.to change { proposal.reload.selected? }.from(false).to(true)
expect(response).to be_successful
end
it "does not modify already selected proposals" do
proposal.update!(selected: true)
expect do
patch :select, xhr: true, params: { id: proposal.id, process_id: proposal.process.id }
end.not_to change { proposal.reload.selected? }
end
it "redirects admins without JavaScript to the same page" do
request.env["HTTP_REFERER"] = admin_proposals_path
patch :select, params: { id: proposal.id, process_id: proposal.process.id }
expect(response).to redirect_to admin_proposals_path
expect(flash[:notice]).to eq "Proposal updated successfully."
end
end
describe "PATCH deselect" do
let(:proposal) { create(:legislation_proposal, :selected) }
it "deselects the proposal" do
expect do
patch :deselect, xhr: true, params: { id: proposal.id, process_id: proposal.process.id }
end.to change { proposal.reload.selected? }.from(true).to(false)
expect(response).to be_successful
end
it "does not modify non-selected proposals" do
proposal.update!(selected: false)
expect do
patch :deselect, xhr: true, params: { id: proposal.id, process_id: proposal.process.id }
end.not_to change { proposal.reload.selected? }
end
it "redirects admins without JavaScript to the same page" do
request.env["HTTP_REFERER"] = admin_proposals_path
patch :deselect, params: { id: proposal.id, process_id: proposal.process.id }
expect(response).to redirect_to admin_proposals_path
expect(flash[:notice]).to eq "Proposal updated successfully."
end
end
end

View File

@@ -0,0 +1,61 @@
require "rails_helper"
describe Admin::ProposalsController, :admin do
describe "PATCH select" do
let(:proposal) { create(:proposal) }
it "selects the proposal" do
expect do
patch :select, xhr: true, params: { id: proposal.id }
end.to change { proposal.reload.selected? }.from(false).to(true)
expect(response).to be_successful
end
it "does not modify already selected proposals" do
proposal.update!(selected: true)
expect do
patch :select, xhr: true, params: { id: proposal.id }
end.not_to change { proposal.reload.selected? }
end
it "redirects admins without JavaScript to the same page" do
request.env["HTTP_REFERER"] = admin_proposals_path
patch :select, params: { id: proposal.id }
expect(response).to redirect_to admin_proposals_path
expect(flash[:notice]).to eq "Proposal updated successfully."
end
end
describe "PATCH deselect" do
let(:proposal) { create(:proposal, :selected) }
it "deselects the proposal" do
expect do
patch :deselect, xhr: true, params: { id: proposal.id }
end.to change { proposal.reload.selected? }.from(true).to(false)
expect(response).to be_successful
end
it "does not modify non-selected proposals" do
proposal.update!(selected: false)
expect do
patch :deselect, xhr: true, params: { id: proposal.id }
end.not_to change { proposal.reload.selected? }
end
it "redirects admins without JavaScript to the same page" do
request.env["HTTP_REFERER"] = admin_proposals_path
patch :deselect, params: { id: proposal.id }
expect(response).to redirect_to admin_proposals_path
expect(flash[:notice]).to eq "Proposal updated successfully."
end
end
end

View File

@@ -177,5 +177,9 @@ FactoryBot.define do
trait :hidden do trait :hidden do
hidden_at { Time.current } hidden_at { Time.current }
end end
trait :selected do
selected { true }
end
end end
end end

View File

@@ -115,7 +115,11 @@ describe Abilities::Administrator do
it { should_not be_able_to(:admin_update, finished_investment) } it { should_not be_able_to(:admin_update, finished_investment) }
it { should_not be_able_to(:valuate, finished_investment) } it { should_not be_able_to(:valuate, finished_investment) }
it { should_not be_able_to(:comment_valuation, finished_investment) } it { should_not be_able_to(:comment_valuation, finished_investment) }
it { should_not be_able_to(:toggle_selection, finished_investment) }
it { should be_able_to([:select, :deselect], create(:budget_investment, :feasible, :finished)) }
it { should_not be_able_to([:select, :deselect], create(:budget_investment, :feasible, :open)) }
it { should_not be_able_to([:select, :deselect], create(:budget_investment, :unfeasible, :finished)) }
it { should_not be_able_to([:select, :deselect], finished_investment) }
it { should be_able_to(:destroy, proposal_image) } it { should be_able_to(:destroy, proposal_image) }
it { should be_able_to(:destroy, proposal_document) } it { should be_able_to(:destroy, proposal_document) }

View File

@@ -43,21 +43,6 @@ describe "Admin budget investments", :admin do
expect(page).not_to have_content("") expect(page).not_to have_content("")
end end
scenario "If budget is finished do not show 'Selected' button" do
finished_budget = create(:budget, :finished)
budget_investment = create(:budget_investment, budget: finished_budget, cached_votes_up: 77)
visit admin_budget_budget_investments_path(budget_id: finished_budget.id)
within("#budget_investment_#{budget_investment.id}") do
expect(page).to have_content(budget_investment.title)
expect(page).to have_content(budget_investment.heading.name)
expect(page).to have_content(budget_investment.id)
expect(page).to have_content(budget_investment.total_votes)
expect(page).not_to have_link("Selected")
end
end
scenario "Display admin and valuator assignments" do scenario "Display admin and valuator assignments" do
olga = create(:user, username: "Olga") olga = create(:user, username: "Olga")
miriam = create(:user, username: "Miriam") miriam = create(:user, username: "Miriam")
@@ -1422,62 +1407,19 @@ describe "Admin budget investments", :admin do
expect(page).not_to have_content(feasible_vf_bi.title) expect(page).not_to have_content(feasible_vf_bi.title)
end end
scenario "Showing the selection buttons" do
visit admin_budget_budget_investments_path(budget)
within("#budget_investment_#{unfeasible_bi.id}") do
expect(page).not_to have_link("Select")
expect(page).not_to have_link("Selected")
end
within("#budget_investment_#{feasible_bi.id}") do
expect(page).not_to have_link("Select")
expect(page).not_to have_link("Selected")
end
within("#budget_investment_#{feasible_vf_bi.id}") do
expect(page).to have_link("Select")
expect(page).not_to have_link("Selected")
end
within("#budget_investment_#{selected_bi.id}") do
expect(page).not_to have_link("Select")
expect(page).to have_link("Selected")
end
end
scenario "Show only selected text when budget is finished" do
budget.update!(phase: "finished")
visit admin_budget_budget_investments_path(budget)
within("#budget_investment_#{unfeasible_bi.id} #selection") do
expect(page).not_to have_content("Select")
expect(page).not_to have_content("Selected")
end
within("#budget_investment_#{feasible_bi.id} #selection") do
expect(page).not_to have_content("Select")
expect(page).not_to have_content("Selected")
end
within("#budget_investment_#{feasible_vf_bi.id} #selection") do
expect(page).not_to have_content("Select")
expect(page).not_to have_content("Selected")
end
within("#budget_investment_#{selected_bi.id} #selection") do
expect(page).not_to contain_exactly("Select")
expect(page).to have_content("Selected")
end
end
scenario "Selecting an investment" do scenario "Selecting an investment" do
visit admin_budget_budget_investments_path(budget) visit admin_budget_budget_investments_path(budget)
within("#budget_investment_#{feasible_vf_bi.id}") do expect(page).to have_content "Unfeasible project"
click_link("Select")
expect(page).to have_link("Selected") within("tr", text: "Feasible, VF project") do
within("[data-field=selected]") do
expect(page).to have_content "No"
click_button "Select Feasible, VF project"
expect(page).to have_content "Yes"
end
end end
click_link "Advanced filters" click_link "Advanced filters"
@@ -1485,9 +1427,12 @@ describe "Admin budget investments", :admin do
within("#advanced_filters") { check("Selected") } within("#advanced_filters") { check("Selected") }
click_button("Filter") click_button("Filter")
within("#budget_investment_#{feasible_vf_bi.id}") do expect(page).not_to have_content "Unfeasible project"
expect(page).not_to have_link("Select")
expect(page).to have_link("Selected") within("tr", text: "Feasible, VF project") do
within("[data-field=selected]") do
expect(page).to have_content "Yes"
end
end end
end end
@@ -1500,21 +1445,26 @@ describe "Admin budget investments", :admin do
expect(page).to have_content("There are 2 investments") expect(page).to have_content("There are 2 investments")
within("#budget_investment_#{selected_bi.id}") do within("tr", text: "Selected project") do
click_link("Selected") within("[data-field=selected]") do
expect(page).to have_content "Yes"
expect(page).to have_link("Select") click_button "Select Selected project"
expect(page).to have_content "No"
end
end end
click_button("Filter") click_button "Filter"
expect(page).not_to have_content(selected_bi.title) expect(page).not_to have_content "Selected project"
expect(page).to have_content("There is 1 investment") expect(page).to have_content "There is 1 investment"
visit admin_budget_budget_investments_path(budget) visit admin_budget_budget_investments_path(budget)
within("#budget_investment_#{selected_bi.id}") do within("tr", text: "Selected project") do
expect(page).to have_link("Select") within("[data-field=selected]") do
expect(page).not_to have_link("Selected") expect(page).to have_content "No"
end
end end
end end
@@ -1526,10 +1476,12 @@ describe "Admin budget investments", :admin do
visit admin_budget_budget_investments_path(budget) visit admin_budget_budget_investments_path(budget)
within("#budget_investment_#{selected_bi.id}") do within("tr", text: "Selected project") do
click_link("Selected") within("[data-field=selected]") do
click_button "Select Selected project"
expect(page).to have_link "Select" expect(page).to have_content "No"
end
end end
click_link("Next") click_link("Next")
@@ -1545,8 +1497,8 @@ describe "Admin budget investments", :admin do
let(:heading) { create(:budget_heading, budget: budget) } let(:heading) { create(:budget_heading, budget: budget) }
let(:investment1) { create(:budget_investment, heading: heading) } let(:investment1) { create(:budget_investment, heading: heading, title: "Investment 1") }
let(:investment2) { create(:budget_investment, heading: heading) } let(:investment2) { create(:budget_investment, heading: heading, title: "Investment 2") }
scenario "Mark as visible to valuator" do scenario "Mark as visible to valuator" do
investment1.valuators << valuator investment1.valuators << valuator
@@ -1559,17 +1511,22 @@ describe "Admin budget investments", :admin do
check "Under valuation" check "Under valuation"
click_button "Filter" click_button "Filter"
within("#budget_investment_#{investment1.id}") do within("tr", text: "Investment 1") do
check "budget_investment_visible_to_valuators" within("[data-field=visible_to_valuators]") do
expect(page).to have_content "No"
click_button "Show Investment 1 to valuators"
expect(page).to have_content "Yes"
end
end end
visit admin_budget_budget_investments_path(budget) refresh
click_link "Advanced filters"
check "Under valuation"
click_button "Filter"
within("#budget_investment_#{investment1.id}") do within("tr", text: "Investment 1") do
expect(find("#budget_investment_visible_to_valuators")).to be_checked within("[data-field=visible_to_valuators]") do
expect(page).to have_content "Yes"
end
end end
end end
@@ -1608,18 +1565,22 @@ describe "Admin budget investments", :admin do
check "Under valuation" check "Under valuation"
click_button "Filter" click_button "Filter"
within("#budget_investment_#{investment1.id}") do within("tr", text: "Investment 1") do
uncheck "budget_investment_visible_to_valuators" within("[data-field=visible_to_valuators]") do
expect(page).to have_content "Yes"
click_button "Show Investment 1 to valuators"
expect(page).to have_content "No"
end
end end
visit admin_budget_budget_investments_path(budget) refresh
click_link "Advanced filters" within("tr", text: "Investment 1") do
check "Under valuation" within("[data-field=visible_to_valuators]") do
click_button "Filter" expect(page).to have_content "No"
end
within("#budget_investment_#{investment1.id}") do
expect(find("#budget_investment_visible_to_valuators")).not_to be_checked
end end
end end
@@ -1631,42 +1592,44 @@ describe "Admin budget investments", :admin do
visit admin_budget_budget_investments_path(budget) visit admin_budget_budget_investments_path(budget)
within "tr", text: "Visible" do within "tr", text: "Visible" do
within "td[data-field=visible_to_valuators]" do within "[data-field=visible_to_valuators]" do
expect(page).to have_text "Yes" expect(page).to have_text "Yes"
expect(page).not_to have_field "budget_investment_visible_to_valuators" expect(page).not_to have_button
end end
end end
within "tr", text: "Invisible" do within "tr", text: "Invisible" do
within "td[data-field=visible_to_valuators]" do within "[data-field=visible_to_valuators]" do
expect(page).to have_text "No" expect(page).to have_text "No"
expect(page).not_to have_field "budget_investment_visible_to_valuators" expect(page).not_to have_button
end end
end end
end end
scenario "Showing the valuating checkbox" do scenario "Showing the valuating checkbox" do
investment1 = create(:budget_investment, :with_administrator, :with_valuator, :visible_to_valuators, investment1.valuators << valuator
budget: budget) investment2.valuators << valuator
investment2 = create(:budget_investment, :with_administrator, :with_valuator, :invisible_to_valuators, investment1.update!(administrator: admin, visible_to_valuators: true)
budget: budget) investment2.update!(administrator: admin, visible_to_valuators: false)
visit admin_budget_budget_investments_path(budget) visit admin_budget_budget_investments_path(budget)
expect(page).to have_css("#budget_investment_visible_to_valuators")
click_link "Advanced filters" click_link "Advanced filters"
check "Under valuation" check "Under valuation"
click_button "Filter" click_button "Filter"
within("#budget_investment_#{investment1.id}") do within "tr", text: "Investment 1" do
valuating_checkbox = find("#budget_investment_visible_to_valuators") within "[data-field=visible_to_valuators]" do
expect(valuating_checkbox).to be_checked expect(page).to have_content "Yes"
expect(page).to have_css "button[aria-pressed='true']"
end
end end
within("#budget_investment_#{investment2.id}") do within "tr", text: "Investment 2" do
valuating_checkbox = find("#budget_investment_visible_to_valuators") within "[data-field=visible_to_valuators]" do
expect(valuating_checkbox).not_to be_checked expect(page).to have_content "No"
expect(page).to have_css "button[aria-pressed='false']"
end
end end
end end
@@ -1676,8 +1639,14 @@ describe "Admin budget investments", :admin do
visit admin_budget_budget_investments_path(budget) visit admin_budget_budget_investments_path(budget)
within("#budget_investment_#{investment1.id}") do within "tr", text: "Investment 1" do
check "budget_investment_visible_to_valuators" within "[data-field=visible_to_valuators]" do
expect(page).to have_content "No"
click_button "Show Investment 1 to valuators"
expect(page).to have_content "Yes"
end
end end
visit edit_admin_budget_budget_investment_path(budget, investment1) visit edit_admin_budget_budget_investment_path(budget, investment1)
@@ -1867,13 +1836,18 @@ describe "Admin budget investments", :admin do
within("#js-columns-selector-wrapper") { uncheck "Title" } within("#js-columns-selector-wrapper") { uncheck "Title" }
within("#budget_investment_#{investment.id}") do within("#budget_investment_#{investment.id}") do
click_link "Selected" within("[data-field=selected]") do
expect(page).to have_content "Yes"
expect(page).to have_link "Select" click_button "Select Don't display me, please!"
expect(page).not_to have_content "Don't display me, please!"
expect(page).to have_content "No"
end end
end end
expect(page).not_to have_content "Don't display me, please!"
end
scenario "When restoring the page from browser history renders columns selectors only once" do scenario "When restoring the page from browser history renders columns selectors only once" do
visit admin_budget_budget_investments_path(budget) visit admin_budget_budget_investments_path(budget)

View File

@@ -11,18 +11,18 @@ describe "Admin collaborative legislation", :admin do
expect(page).to have_content(proposal.title) expect(page).to have_content(proposal.title)
expect(page).to have_content(proposal.id) expect(page).to have_content(proposal.id)
expect(page).to have_content(proposal.cached_votes_score) expect(page).to have_content(proposal.cached_votes_score)
expect(page).to have_content("Select") expect(page).to have_content("No")
end end
end end
scenario "Selecting legislation proposals" do scenario "Selecting legislation proposals" do
proposal = create(:legislation_proposal, cached_votes_score: 10) proposal = create(:legislation_proposal, title: "Add more accessibility tests")
visit admin_legislation_process_proposals_path(proposal.legislation_process_id) visit admin_legislation_process_proposals_path(proposal.legislation_process_id)
click_link "Select" click_button "Select Add more accessibility tests"
within "#legislation_proposal_#{proposal.id}" do within "#legislation_proposal_#{proposal.id}" do
expect(page).to have_content("Selected") expect(page).to have_content "Yes"
end end
end end

View File

@@ -22,31 +22,39 @@ describe "Admin proposals", :admin do
end end
scenario "Select a proposal" do scenario "Select a proposal" do
proposal = create(:proposal) proposal = create(:proposal, title: "Forbid door-to-door sales")
visit admin_proposals_path visit admin_proposals_path
within("#proposal_#{proposal.id}") { click_link "Select" } within("#proposal_#{proposal.id}") do
expect(page).to have_content "No"
within("#proposal_#{proposal.id}") { expect(page).to have_link "Selected" } click_button "Select Forbid door-to-door sales"
expect(page).to have_content "Yes"
end
refresh refresh
within("#proposal_#{proposal.id}") { expect(page).to have_link "Selected" } within("#proposal_#{proposal.id}") { expect(page).to have_content "Yes" }
end end
scenario "Unselect a proposal" do scenario "Unselect a proposal" do
proposal = create(:proposal, :selected) proposal = create(:proposal, :selected, title: "Allow door-to-door sales")
visit admin_proposals_path visit admin_proposals_path
within("#proposal_#{proposal.id}") { click_link "Selected" } within("#proposal_#{proposal.id}") do
expect(page).to have_content "Yes"
within("#proposal_#{proposal.id}") { expect(page).to have_link "Select" } click_button "Select Allow door-to-door sales"
expect(page).to have_content "No"
end
refresh refresh
within("#proposal_#{proposal.id}") { expect(page).to have_link "Select" } within("#proposal_#{proposal.id}") { expect(page).to have_content "No" }
end end
end end

View File

@@ -1,13 +0,0 @@
require "rails_helper"
describe "investment row" do
it "uses a JSON request to update visible to valuators" do
investment = create(:budget_investment)
@budget = investment.budget
sign_in(create(:administrator).user)
render "admin/budget_investments/select_investment", investment: investment
expect(rendered).to have_css "form[action$='json'] input[name$='[visible_to_valuators]']"
end
end