Merge pull request #2950 from consul/backport-improve_index_legislation_proposals

Allow select winner legislation proposals
This commit is contained in:
Javier Martín
2018-10-05 12:59:28 +02:00
committed by GitHub
25 changed files with 254 additions and 8 deletions

View File

@@ -887,6 +887,13 @@
} }
} }
.legislation-proposals {
.votes {
min-height: $line-height * 8;
}
}
.proposal-show .votes, .proposal-show .votes,
.debate-show .votes { .debate-show .votes {
border: 0; border: 0;

View File

@@ -1,7 +1,16 @@
class Admin::Legislation::ProposalsController < Admin::Legislation::BaseController class Admin::Legislation::ProposalsController < Admin::Legislation::BaseController
has_orders %w[id title supports], only: :index
load_and_authorize_resource :process, class: "Legislation::Process" load_and_authorize_resource :process, class: "Legislation::Process"
load_and_authorize_resource :proposal, class: "Legislation::Proposal", through: :process load_and_authorize_resource :proposal, class: "Legislation::Proposal", through: :process
def index def index
@proposals = @proposals.send("sort_by_#{@current_order}").page(params[:page])
end
def toggle_selection
@proposal.toggle :selected
@proposal.save!
end end
end end

View File

@@ -1,5 +1,7 @@
class Legislation::ProcessesController < Legislation::BaseController class Legislation::ProcessesController < Legislation::BaseController
has_filters %w{open next past}, only: :index has_filters %w[open next past], only: :index
has_filters %w[random winners], only: :proposals
load_and_authorize_resource load_and_authorize_resource
before_action :set_random_seed, only: :proposals before_action :set_random_seed, only: :proposals
@@ -91,7 +93,9 @@ class Legislation::ProcessesController < Legislation::BaseController
@proposals = ::Legislation::Proposal.where(process: @process) @proposals = ::Legislation::Proposal.where(process: @process)
@proposals = @proposals.search(params[:search]) if params[:search].present? @proposals = @proposals.search(params[:search]) if params[:search].present?
@proposals = @proposals.order('random()').page(params[:page])
@current_filter = "winners" if params[:filter].blank? && @proposals.winners.any?
@proposals = @proposals.send(@current_filter).page(params[:page])
if @process.proposals_phase.started? || (current_user && current_user.administrator?) if @process.proposals_phase.started? || (current_user && current_user.administrator?)
legislation_proposal_votes(@proposals) legislation_proposal_votes(@proposals)

View File

@@ -10,4 +10,20 @@ module LegislationHelper
def new_legislation_proposal_link_text(process) def new_legislation_proposal_link_text(process)
t("proposals.index.start_proposal") t("proposals.index.start_proposal")
end end
def link_to_toggle_legislation_proposal_selection(proposal)
if proposal.selected?
button_text = t("admin.legislation.proposals.index.selected")
html_class = 'button expanded'
else
button_text = t("admin.legislation.proposals.index.select")
html_class = 'button hollow expanded'
end
link_to button_text,
toggle_selection_admin_legislation_process_proposal_path(proposal.process, proposal),
remote: true,
method: :patch,
class: html_class
end
end end

View File

@@ -45,9 +45,15 @@ class Legislation::Proposal < ActiveRecord::Base
scope :sort_by_confidence_score, -> { reorder(confidence_score: :desc) } scope :sort_by_confidence_score, -> { reorder(confidence_score: :desc) }
scope :sort_by_created_at, -> { reorder(created_at: :desc) } scope :sort_by_created_at, -> { reorder(created_at: :desc) }
scope :sort_by_most_commented, -> { reorder(comments_count: :desc) } scope :sort_by_most_commented, -> { reorder(comments_count: :desc) }
scope :sort_by_title, -> { reorder(title: :asc) }
scope :sort_by_id, -> { reorder(id: :asc) }
scope :sort_by_supports, -> { reorder(cached_votes_up: :desc) }
scope :sort_by_random, -> { reorder("RANDOM()") } scope :sort_by_random, -> { reorder("RANDOM()") }
scope :sort_by_flags, -> { order(flags_count: :desc, updated_at: :desc) } scope :sort_by_flags, -> { order(flags_count: :desc, updated_at: :desc) }
scope :last_week, -> { where("proposals.created_at >= ?", 7.days.ago)} scope :last_week, -> { where("proposals.created_at >= ?", 7.days.ago)}
scope :selected, -> { where(selected: true) }
scope :random, -> { sort_by_random }
scope :winners, -> { selected.sort_by_confidence_score }
def to_param def to_param
"#{id}-#{title}".parameterize "#{id}-#{title}".parameterize

View File

@@ -0,0 +1,29 @@
<% if proposals.any? %>
<h3><%= page_entries_info proposals %></h3>
<%= render 'shared/wide_order_selector', i18n_namespace: "admin.legislation.processes.proposals" %>
<table class="stack" id="legislation_proposals_list">
<thead>
<tr>
<th class="text-center"><%= t("admin.legislation.proposals.index.id") %></th>
<th><%= t("admin.legislation.proposals.index.title") %></th>
<th class="text-center"><%= t("admin.legislation.proposals.index.supports") %></th>
<th><%= t("admin.legislation.proposals.index.selected") %></th>
</tr>
</thead>
<tbody>
<% proposals.each do |proposal| %>
<tr id="<%= dom_id(proposal) %>" class="legislation_proposal">
<td class="text-center"><%= proposal.id %></td>
<td><%= proposal.title %></td>
<td class="text-center"><%= proposal.cached_votes_up %></td>
<td class="select"><%= render "select_proposal", proposal: proposal %></td>
</tr>
<% end %>
</tbody>
</table>
<%= paginate proposals %>
<% end %>

View File

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

View File

@@ -11,4 +11,5 @@
<%= render 'admin/legislation/processes/subnav', process: @process, active: 'proposals' %> <%= render 'admin/legislation/processes/subnav', process: @process, active: 'proposals' %>
<%= render 'form' %> <%= render 'form' %>
<%= render 'proposals', proposals: @proposals %>
</div> </div>

View File

@@ -0,0 +1 @@
$("#<%= dom_id(@proposal) %> .select").html('<%= j render("select_proposal", proposal: @proposal) %>');

View File

@@ -3,6 +3,7 @@
<div class="row"> <div class="row">
<div class="small-12 medium-9 column"> <div class="small-12 medium-9 column">
<div class="legislation-proposals"> <div class="legislation-proposals">
<%= render 'shared/filter_subnav', i18n_namespace: "legislation.processes.proposals" %>
<% if proposals.empty? %> <% if proposals.empty? %>
<div class="callout primary"> <div class="callout primary">
<p><%= t("legislation.processes.proposals.empty_proposals") %></p> <p><%= t("legislation.processes.proposals.empty_proposals") %></p>

View File

@@ -39,8 +39,6 @@
</div> </div>
<% end %> <% end %>
</div> </div>
<% else %>
<p><%= t("legislation.proposals.closed") %></p>
<% end %> <% end %>
<span class="total-votes"> <span class="total-votes">

View File

@@ -2,6 +2,7 @@
# #
# i18n_namespace: for example "moderation.debates.index" # i18n_namespace: for example "moderation.debates.index"
%> %>
<% if @valid_orders.present? && @valid_orders.count > 1 %> <% if @valid_orders.present? && @valid_orders.count > 1 %>
<div class="wide-order-selector small-12 medium-8"> <div class="wide-order-selector small-12 medium-8">
<form> <form>

View File

@@ -139,6 +139,8 @@ ignore_unused:
- 'admin.activity.show.filter*' - 'admin.activity.show.filter*'
- 'admin.legislation.processes.index.filter*' - 'admin.legislation.processes.index.filter*'
- 'admin.legislation.processes.*.submit_button' - 'admin.legislation.processes.*.submit_button'
- 'admin.legislation.processes.proposals.orders.*'
- 'admin.legislation.processes.proposals.select_order'
- 'admin.legislation.draft_versions.*.submit_button' - 'admin.legislation.draft_versions.*.submit_button'
- 'admin.legislation.questions.*.submit_button' - 'admin.legislation.questions.*.submit_button'
- 'admin.comments.index.hidden_*' - 'admin.comments.index.hidden_*'
@@ -176,6 +178,7 @@ ignore_unused:
- 'notifications.notification.action.*' - 'notifications.notification.action.*'
- 'legislation.processes.index.filter*' - 'legislation.processes.index.filter*'
- 'legislation.processes.index.section_header.*' - 'legislation.processes.index.section_header.*'
- 'legislation.processes.proposals.filters.*'
- 'helpers.page_entries_info.*' # kaminari - 'helpers.page_entries_info.*' # kaminari
- 'views.pagination.*' # kaminari - 'views.pagination.*' # kaminari
- 'shared.suggest.*' - 'shared.suggest.*'

View File

@@ -76,6 +76,9 @@ en:
legislation/process: legislation/process:
one: "Process" one: "Process"
other: "Processes" other: "Processes"
legislation/proposal:
one: "Proposal"
other: "Proposals"
legislation/draft_versions: legislation/draft_versions:
one: "Draft version" one: "Draft version"
other: "Draft versions" other: "Draft versions"

View File

@@ -394,6 +394,12 @@ en:
back: Back back: Back
title: Create new collaborative legislation process title: Create new collaborative legislation process
submit_button: Create process submit_button: Create process
proposals:
select_order: Sort by
orders:
id: Id
title: Title
supports: Supports
process: process:
title: Process title: Process
comments: Comments comments: Comments
@@ -411,6 +417,11 @@ en:
index: index:
title: Proposals title: Proposals
back: Back back: Back
id: Id
title: Title
supports: Supports
select: Select
selected: Selected
form: form:
custom_categories: Categories custom_categories: Categories
custom_categories_description: Categories that users can select creating the proposal. custom_categories_description: Categories that users can select creating the proposal.

View File

@@ -52,6 +52,9 @@ en:
more_info: More information and context more_info: More information and context
proposals: proposals:
empty_proposals: There are no proposals empty_proposals: There are no proposals
filters:
random: Random
winners: Selected
debate: debate:
empty_questions: There aren't any questions empty_questions: There aren't any questions
participate: Participate in the debate participate: Participate in the debate
@@ -120,4 +123,3 @@ en:
form: form:
tags_label: "Categories" tags_label: "Categories"
not_verified: "For vote proposals %{verify_account}." not_verified: "For vote proposals %{verify_account}."
closed: "This process has been closed and can not receive votes."

View File

@@ -76,6 +76,9 @@ es:
legislation/process: legislation/process:
one: "Proceso" one: "Proceso"
other: "Procesos" other: "Procesos"
legislation/proposal:
one: "Propuesta"
other: "Propuestas"
legislation/draft_versions: legislation/draft_versions:
one: "Versión borrador" one: "Versión borrador"
other: "Versiones borrador" other: "Versiones borrador"

View File

@@ -395,6 +395,12 @@ es:
back: Volver back: Volver
title: Crear nuevo proceso de legislación colaborativa title: Crear nuevo proceso de legislación colaborativa
submit_button: Crear proceso submit_button: Crear proceso
proposals:
select_order: Ordenar por
orders:
id: Id
title: Título
supports: Apoyos
process: process:
title: Proceso title: Proceso
comments: Comentarios comments: Comentarios
@@ -412,6 +418,11 @@ es:
index: index:
title: Propuestas title: Propuestas
back: Volver back: Volver
id: Id
title: Título
supports: Apoyos
select: Seleccionar
selected: Seleccionado
form: form:
custom_categories: Categorías custom_categories: Categorías
custom_categories_description: Categorías que el usuario puede seleccionar al crear la propuesta. custom_categories_description: Categorías que el usuario puede seleccionar al crear la propuesta.

View File

@@ -52,6 +52,9 @@ es:
more_info: Más información y contexto more_info: Más información y contexto
proposals: proposals:
empty_proposals: No hay propuestas empty_proposals: No hay propuestas
filters:
random: Aleatorias
winners: Seleccionadas
debate: debate:
empty_questions: No hay preguntas empty_questions: No hay preguntas
participate: Realiza tus aportaciones al debate previo participando en los siguientes temas. participate: Realiza tus aportaciones al debate previo participando en los siguientes temas.
@@ -120,4 +123,3 @@ es:
form: form:
tags_label: "Categorías" tags_label: "Categorías"
not_verified: "Para votar propuestas %{verify_account}." not_verified: "Para votar propuestas %{verify_account}."
closed: "Este proceso se ha cerrado y ya no puede recoger votos."

View File

@@ -194,7 +194,9 @@ namespace :admin do
namespace :legislation do namespace :legislation do
resources :processes do resources :processes do
resources :questions resources :questions
resources :proposals resources :proposals do
member { patch :toggle_selection }
end
resources :draft_versions resources :draft_versions
end end
end end

View File

@@ -6,6 +6,7 @@ section "Creating legislation proposals" do
summary: Faker::Lorem.paragraph, summary: Faker::Lorem.paragraph,
author: User.all.sample, author: User.all.sample,
process: Legislation::Process.all.sample, process: Legislation::Process.all.sample,
terms_of_service: '1') terms_of_service: '1',
selected: rand <= 1.0 / 3)
end end
end end

View File

@@ -0,0 +1,5 @@
class AddSelectedToLegislationProposals < ActiveRecord::Migration
def change
add_column :legislation_proposals, :selected, :boolean
end
end

View File

@@ -687,6 +687,7 @@ ActiveRecord::Schema.define(version: 20180924071722) do
t.datetime "updated_at", null: false t.datetime "updated_at", null: false
t.integer "cached_votes_total", default: 0 t.integer "cached_votes_total", default: 0
t.integer "cached_votes_down", default: 0 t.integer "cached_votes_down", default: 0
t.boolean "selected"
end end
add_index "legislation_proposals", ["legislation_process_id"], name: "index_legislation_proposals_on_legislation_process_id", using: :btree add_index "legislation_proposals", ["legislation_process_id"], name: "index_legislation_proposals_on_legislation_process_id", using: :btree

View File

@@ -0,0 +1,85 @@
require 'rails_helper'
feature 'Admin legislation processes' do
background do
admin = create(:administrator)
login_as(admin.user)
end
context "Index" do
scenario 'Displaying legislation proposals' do
proposal = create(:legislation_proposal, cached_votes_up: 10)
visit admin_legislation_process_proposals_path(proposal.legislation_process_id)
within "#legislation_proposal_#{proposal.id}" do
expect(page).to have_content(proposal.title)
expect(page).to have_content(proposal.id)
expect(page).to have_content(proposal.cached_votes_up)
expect(page).to have_content('Select')
end
end
scenario 'Selecting legislation proposals', :js do
proposal = create(:legislation_proposal, cached_votes_up: 10)
visit admin_legislation_process_proposals_path(proposal.legislation_process_id)
click_link 'Select'
within "#legislation_proposal_#{proposal.id}" do
expect(page).to have_content('Selected')
end
end
scenario 'Sorting legislation proposals by title', js: true do
process = create(:legislation_process)
create(:legislation_proposal, title: 'bbbb', legislation_process_id: process.id)
create(:legislation_proposal, title: 'aaaa', legislation_process_id: process.id)
create(:legislation_proposal, title: 'cccc', legislation_process_id: process.id)
visit admin_legislation_process_proposals_path(process.id)
select "Title", from: "order-selector-participation"
within('#legislation_proposals_list') do
within all('.legislation_proposal')[0] { expect(page).to have_content('aaaa') }
within all('.legislation_proposal')[1] { expect(page).to have_content('bbbb') }
within all('.legislation_proposal')[2] { expect(page).to have_content('cccc') }
end
end
scenario 'Sorting legislation proposals by supports', js: true do
process = create(:legislation_process)
create(:legislation_proposal, cached_votes_up: 10, legislation_process_id: process.id)
create(:legislation_proposal, cached_votes_up: 30, legislation_process_id: process.id)
create(:legislation_proposal, cached_votes_up: 20, legislation_process_id: process.id)
visit admin_legislation_process_proposals_path(process.id)
select "Supports", from: "order-selector-participation"
within('#legislation_proposals_list') do
within all('.legislation_proposal')[0] { expect(page).to have_content('30') }
within all('.legislation_proposal')[1] { expect(page).to have_content('20') }
within all('.legislation_proposal')[2] { expect(page).to have_content('10') }
end
end
scenario 'Sorting legislation proposals by Id', js: true do
process = create(:legislation_process)
proposal1 = create(:legislation_proposal, title: 'bbbb', legislation_process_id: process.id)
proposal2 = create(:legislation_proposal, title: 'aaaa', legislation_process_id: process.id)
proposal3 = create(:legislation_proposal, title: 'cccc', legislation_process_id: process.id)
visit admin_legislation_process_proposals_path(process.id, order: :title)
select "Id", from: "order-selector-participation"
within('#legislation_proposals_list') do
within all('.legislation_proposal')[0] { expect(page).to have_content(proposal1.id) }
within all('.legislation_proposal')[1] { expect(page).to have_content(proposal2.id) }
within all('.legislation_proposal')[2] { expect(page).to have_content(proposal3.id) }
end
end
end
end

View File

@@ -64,6 +64,49 @@ feature 'Legislation Proposals' do
expect(legislation_proposals_order).to eq(first_page_proposals_order) expect(legislation_proposals_order).to eq(first_page_proposals_order)
end end
context 'Selected filter' do
scenario 'apperars even if there are not any selected poposals' do
create(:legislation_proposal, legislation_process_id: process.id)
visit legislation_process_proposals_path(process)
expect(page).to have_content('Selected')
end
scenario 'defaults to winners if there are selected proposals' do
create(:legislation_proposal, legislation_process_id: process.id)
create(:legislation_proposal, legislation_process_id: process.id, selected: true)
visit legislation_process_proposals_path(process)
expect(page).to have_link('Random')
expect(page).not_to have_link('Selected')
expect(page).to have_content('Selected')
end
scenario 'defaults to random if the current process does not have selected proposals' do
create(:legislation_proposal, legislation_process_id: process.id)
create(:legislation_proposal, selected: true)
visit legislation_process_proposals_path(process)
expect(page).to have_link('Selected')
expect(page).not_to have_link('Random')
expect(page).to have_content('Random')
end
scenario 'filters correctly' do
proposal1 = create(:legislation_proposal, legislation_process_id: process.id)
proposal2 = create(:legislation_proposal, legislation_process_id: process.id, selected: true)
visit legislation_process_proposals_path(process, filter: "random")
click_link 'Selected'
expect(page).to have_css("div#legislation_proposal_#{proposal2.id}")
expect(page).not_to have_css("div#legislation_proposal_#{proposal1.id}")
end
end
def legislation_proposals_order def legislation_proposals_order
all("[id^='legislation_proposal_']").collect { |e| e[:id] } all("[id^='legislation_proposal_']").collect { |e| e[:id] }
end end