diff --git a/app/controllers/admin/proposals_controller.rb b/app/controllers/admin/proposals_controller.rb
index e76efce21..7e53d1a46 100644
--- a/app/controllers/admin/proposals_controller.rb
+++ b/app/controllers/admin/proposals_controller.rb
@@ -6,8 +6,22 @@ class Admin::ProposalsController < Admin::BaseController
has_orders %w[created_at]
+ before_action :load_proposal, except: :index
+
def show
- @proposal = Proposal.find(params[:id])
+ end
+
+ def update
+ if @proposal.update(proposal_params)
+ redirect_to admin_proposal_path(@proposal), notice: t("admin.proposals.update.notice")
+ else
+ render :show
+ end
+ end
+
+ def toggle_selection
+ @proposal.toggle :selected
+ @proposal.save!
end
private
@@ -15,4 +29,13 @@ class Admin::ProposalsController < Admin::BaseController
def resource_model
Proposal
end
+
+ def load_proposal
+ @proposal = Proposal.find(params[:id])
+ end
+
+ def proposal_params
+ params.require(:proposal).permit(:selected)
+ end
+
end
diff --git a/app/controllers/proposals_controller.rb b/app/controllers/proposals_controller.rb
index 5cc9b7e10..52c16f0e0 100644
--- a/app/controllers/proposals_controller.rb
+++ b/app/controllers/proposals_controller.rb
@@ -51,6 +51,7 @@ class ProposalsController < ApplicationController
discard_draft
discard_archived
load_retired
+ load_selected
load_featured
end
@@ -139,6 +140,10 @@ class ProposalsController < ApplicationController
end
end
+ def load_selected
+ @resources = @resources.selected if params[:selected].present?
+ end
+
def load_featured
return unless !@advanced_search_terms && @search_terms.blank? && @tag_filter.blank? && params[:retired].blank? && @current_order != "recommendations"
if Setting["feature.featured_proposals"]
diff --git a/app/helpers/proposals_helper.rb b/app/helpers/proposals_helper.rb
index 633f469a3..3cc0ba03a 100644
--- a/app/helpers/proposals_helper.rb
+++ b/app/helpers/proposals_helper.rb
@@ -64,4 +64,39 @@ module ProposalsHelper
proposals_current_view == "default" ? "minimal" : "default"
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
+
+ link_to button_text,
+ toggle_selection_admin_proposal_path(proposal),
+ remote: true,
+ method: :patch,
+ class: html_class
+ end
+
+ def css_for_proposal_info_row
+ if feature?(:allow_images)
+ if params[:selected].present?
+ "small-12 medium-9 column"
+ else
+ "small-12 medium-6 large-7 column"
+ end
+ else
+ if params[:selected].present?
+ "small-12 column"
+ else
+ "small-12 medium-9 column"
+ end
+ end
+ end
+
+ def show_proposal_votes?
+ params[:selected].blank?
+ end
end
diff --git a/app/views/admin/proposals/_form.html.erb b/app/views/admin/proposals/_form.html.erb
new file mode 100644
index 000000000..b6dc1c442
--- /dev/null
+++ b/app/views/admin/proposals/_form.html.erb
@@ -0,0 +1,9 @@
+<%= form_for [:admin, @proposal] do |f| %>
+
+ <%= render "shared/errors", resource: @proposal %>
+
+ <%= f.check_box :selected %>
+
+ <%= f.submit t("admin.proposals.form.update"), class: "button success" %>
+
+<% end %>
diff --git a/app/views/admin/proposals/_select_proposal.html.erb b/app/views/admin/proposals/_select_proposal.html.erb
new file mode 100644
index 000000000..d5d2069ab
--- /dev/null
+++ b/app/views/admin/proposals/_select_proposal.html.erb
@@ -0,0 +1 @@
+<%= link_to_toggle_proposal_selection(proposal) %>
diff --git a/app/views/admin/proposals/index.html.erb b/app/views/admin/proposals/index.html.erb
index 8a8372713..bc59de812 100644
--- a/app/views/admin/proposals/index.html.erb
+++ b/app/views/admin/proposals/index.html.erb
@@ -16,6 +16,7 @@
<%= t("admin.proposals.index.title") %> |
<%= t("admin.proposals.index.author") %> |
<%= t("admin.proposals.index.milestones") %> |
+ <%= t("admin.proposals.index.selected") %> |
@@ -26,6 +27,7 @@
<%= link_to proposal.title, admin_proposal_path(proposal) %> |
<%= proposal.author.username %> |
<%= proposal.milestones.count %> |
+ <%= render "select_proposal", proposal: proposal %> |
<% end %>
diff --git a/app/views/admin/proposals/show.html.erb b/app/views/admin/proposals/show.html.erb
index 13fbce01e..afb2379e3 100644
--- a/app/views/admin/proposals/show.html.erb
+++ b/app/views/admin/proposals/show.html.erb
@@ -26,4 +26,10 @@
<%= render "proposals/info", proposal: @proposal %>
+
+
+ <%= render "form" %>
+
+
+
<%= render "admin/milestones/milestones", milestoneable: @proposal %>
diff --git a/app/views/admin/proposals/toggle_selection.js.erb b/app/views/admin/proposals/toggle_selection.js.erb
new file mode 100644
index 000000000..4963b7b7c
--- /dev/null
+++ b/app/views/admin/proposals/toggle_selection.js.erb
@@ -0,0 +1 @@
+$("#<%= dom_id(@proposal) %> .js-select").html('<%= j render("select_proposal", proposal: @proposal) %>');
diff --git a/app/views/proposals/_proposal.html.erb b/app/views/proposals/_proposal.html.erb
index 97224172a..bad37f0ee 100644
--- a/app/views/proposals/_proposal.html.erb
+++ b/app/views/proposals/_proposal.html.erb
@@ -12,10 +12,10 @@
alt: proposal.image.title.unicode_normalize %>
-
+
<% else %>
-
+
<% end %>
<% cache [locale_and_user_status(proposal), "index", proposal, proposal.author] do %>
@@ -62,24 +62,27 @@
-
- <% if proposal.successful? %>
-
-
- <%= t("proposals.proposal.successful") %>
-
-
- <% elsif proposal.archived? %>
-
-
<%= t("proposals.proposal.supports", count: proposal.total_votes) %>
-
<%= t("proposals.proposal.archived") %>
-
- <% else %>
- <%= render "votes",
- { proposal: proposal, vote_url: vote_proposal_path(proposal, value: "yes") } %>
- <% end %>
-
+ <% if show_proposal_votes? %>
+
+ <% if proposal.successful? %>
+
+
+ <%= t("proposals.proposal.successful") %>
+
+
+ <% elsif proposal.archived? %>
+
+
<%= t("proposals.proposal.supports", count: proposal.total_votes) %>
+
<%= t("proposals.proposal.archived") %>
+
+ <% else %>
+ <%= render "votes",
+ { proposal: proposal, vote_url: vote_proposal_path(proposal, value: "yes") } %>
+ <% end %>
+
+ <% end %>
+
diff --git a/app/views/proposals/_selected.html.erb b/app/views/proposals/_selected.html.erb
new file mode 100644
index 000000000..2d8f272e2
--- /dev/null
+++ b/app/views/proposals/_selected.html.erb
@@ -0,0 +1,8 @@
+<% if params[:selected].blank? %>
+
+
+
+
+ <%= link_to t("proposals.index.selected_proposals"), proposals_path(selected: "all"), class: "small" %>
+
+<% end %>
diff --git a/app/views/proposals/index.html.erb b/app/views/proposals/index.html.erb
index fff4a7bed..5729a92c1 100644
--- a/app/views/proposals/index.html.erb
+++ b/app/views/proposals/index.html.erb
@@ -9,7 +9,13 @@
<% end %>
- <% if @search_terms || @advanced_search_terms || @tag_filter || params[:retired].present? %>
+ <% if [
+ @search_terms,
+ @advanced_search_terms,
+ @tag_filter,
+ params[:retired].present?,
+ params[:selected].present?
+ ].any? %>
@@ -29,6 +35,8 @@
<% elsif params[:retired].present? %>
<%= t("proposals.index.retired_proposals") %>
+ <% elsif params[:selected].present? %>
+ <%= t("proposals.index.selected_proposals") %>
<% end %>
@@ -69,7 +77,10 @@
- <%= render("shared/advanced_search", search_path: proposals_path(page: 1)) unless params[:retired].present? %>
+ <% unless params[:retired].present? || params[:selected].present? %>
+ <%= render "shared/advanced_search",
+ search_path: proposals_path(page: 1) %>
+ <% end %>
<%= render "shared/order_links", i18n_namespace: "proposals.index" %>
@@ -118,6 +129,7 @@
<%= render "popular" %>
<% end %>
<%= render "retired" %>
+ <%= render "selected" %>
diff --git a/config/locales/en/activerecord.yml b/config/locales/en/activerecord.yml
index 97c9431ca..142b8ecd4 100644
--- a/config/locales/en/activerecord.yml
+++ b/config/locales/en/activerecord.yml
@@ -187,6 +187,7 @@ en:
title: "Title"
question: "Question"
description: "Description"
+ selected: "Mark as selected"
terms_of_service: "Terms of service"
user:
login: "Email or username"
diff --git a/config/locales/en/admin.yml b/config/locales/en/admin.yml
index c03001722..4376979ba 100644
--- a/config/locales/en/admin.yml
+++ b/config/locales/en/admin.yml
@@ -1239,10 +1239,16 @@ en:
title: Proposals
id: ID
author: Author
+ select: Select
+ selected: Selected
milestones: Milestones
no_proposals: There are no proposals.
show:
create_question: Add this proposal to a poll to be voted
+ form:
+ update: Update proposal
+ update:
+ notice: Proposal updated successfully
hidden_proposals:
index:
filter: Filter
diff --git a/config/locales/en/general.yml b/config/locales/en/general.yml
index 820319ae6..021d120f1 100644
--- a/config/locales/en/general.yml
+++ b/config/locales/en/general.yml
@@ -376,6 +376,7 @@ en:
error: "An error has occured. Please go to 'My account' page to manually disable recommendations for proposals"
retired_proposals: Retired proposals
retired_proposals_link: "Proposals retired by the author"
+ selected_proposals: Selected proposals
retired_links:
all: All
duplicated: Duplicated
diff --git a/config/locales/es/activerecord.yml b/config/locales/es/activerecord.yml
index 13dd8783c..66a187114 100644
--- a/config/locales/es/activerecord.yml
+++ b/config/locales/es/activerecord.yml
@@ -187,6 +187,7 @@ es:
title: "Título"
question: "Pregunta"
description: "Descripción"
+ selected: "Marcar como seleccionada"
terms_of_service: "Términos de servicio"
user:
login: "Email o nombre de usuario"
diff --git a/config/locales/es/admin.yml b/config/locales/es/admin.yml
index 0e6a91fc0..7f63504aa 100644
--- a/config/locales/es/admin.yml
+++ b/config/locales/es/admin.yml
@@ -1239,9 +1239,15 @@ es:
id: ID
author: Autor
milestones: Hitos
+ select: Seleccionar
+ selected: Seleccionada
no_proposals: No hay propuestas.
show:
create_question: Añadir esta propuesta a una votación para ser votada
+ form:
+ update: Actualizar propuesta ciudadana
+ update:
+ notice: Propuesta actualizada correctamente
hidden_proposals:
index:
filter: Filtro
diff --git a/config/locales/es/general.yml b/config/locales/es/general.yml
index deb858d95..76f88587a 100644
--- a/config/locales/es/general.yml
+++ b/config/locales/es/general.yml
@@ -376,6 +376,7 @@ es:
error: "Ha ocurrido un error. Por favor dirígete al apartado 'Mi cuenta' para desactivar las recomendaciones manualmente"
retired_proposals: Propuestas retiradas
retired_proposals_link: "Propuestas retiradas por sus autores"
+ selected_proposals: Propuestas seleccionadas
retired_links:
all: Todas
duplicated: Duplicadas
diff --git a/config/routes/admin.rb b/config/routes/admin.rb
index 917f1447c..1e67bcc5e 100644
--- a/config/routes/admin.rb
+++ b/config/routes/admin.rb
@@ -29,7 +29,8 @@ namespace :admin do
end
end
- resources :proposals, only: [:index, :show] do
+ resources :proposals, only: [:index, :show, :update] do
+ member { patch :toggle_selection }
resources :milestones, controller: "proposal_milestones"
resources :progress_bars, except: :show, controller: "proposal_progress_bars"
end
diff --git a/spec/features/admin/proposals_spec.rb b/spec/features/admin/proposals_spec.rb
index affc723f7..92685b139 100644
--- a/spec/features/admin/proposals_spec.rb
+++ b/spec/features/admin/proposals_spec.rb
@@ -10,6 +10,7 @@ feature "Admin proposals" do
"admin_proposal_path"
context "Index" do
+
scenario "Search" do
create(:proposal, title: "Make Pluto a planet again")
create(:proposal, title: "Build a monument to honour CONSUL developers")
@@ -26,6 +27,29 @@ feature "Admin proposals" do
expect(page).to have_content "Make Pluto a planet again"
expect(page).not_to have_content "Build a monument"
end
+
+ scenario "Select a proposal", :js do
+ proposal = create(:proposal)
+
+ visit admin_proposals_path
+
+ within("#proposal_#{proposal.id}") { click_link "Select" }
+
+ within("#proposal_#{proposal.id}") { expect(page).to have_link "Selected" }
+ expect(proposal.reload.selected?).to be true
+ end
+
+ scenario "Unselect a proposal", :js do
+ proposal = create(:proposal, :selected)
+
+ visit admin_proposals_path
+
+ within("#proposal_#{proposal.id}") { click_link "Selected" }
+
+ within("#proposal_#{proposal.id}") { expect(page).to have_link "Select" }
+ expect(proposal.reload.selected?).to be false
+ end
+
end
context "Show" do
@@ -55,5 +79,32 @@ feature "Admin proposals" do
expect(page).to have_link "Add this proposal to a poll to be voted"
end
end
+
+ scenario "Select a proposal" do
+ proposal = create(:proposal)
+
+ visit admin_proposal_path(proposal)
+
+ check "Mark as selected"
+ click_button "Update proposal"
+
+ expect(page).to have_content "Proposal updated successfully"
+ expect(find_field("Mark as selected")).to be_checked
+ expect(proposal.reload.selected?).to be true
+ end
+
+ scenario "Unselect a proposal" do
+ proposal = create(:proposal, :selected)
+
+ visit admin_proposal_path(proposal)
+
+ uncheck "Mark as selected"
+ click_button "Update proposal"
+
+ expect(page).to have_content "Proposal updated successfully"
+ expect(find_field("Mark as selected")).not_to be_checked
+ expect(proposal.reload.selected?).to be false
+ end
+
end
end
diff --git a/spec/features/proposals_spec.rb b/spec/features/proposals_spec.rb
index 5162dae30..74669a661 100644
--- a/spec/features/proposals_spec.rb
+++ b/spec/features/proposals_spec.rb
@@ -118,6 +118,25 @@ feature "Proposals" do
end
end
+ context "Index" do
+ scenario "Lists selected proposals" do
+ selected_proposal = create(:proposal, :selected)
+ unselected_proposal = create(:proposal)
+
+ visit proposals_path
+
+ expect(page).to have_selector("#proposals .proposal", count: 2)
+ expect(page).to have_content selected_proposal.title
+ expect(page).to have_content unselected_proposal.title
+
+ click_link "Selected proposals"
+
+ expect(page).to have_selector("#proposals .proposal", count: 1)
+ expect(page).to have_content selected_proposal.title
+ expect(page).not_to have_content unselected_proposal.title
+ end
+ end
+
scenario "Show" do
proposal = create(:proposal)