Remove obsolete questions index in the admin area
We removed the link to this page in commit 83e8d6035 because poll
questions don't really make sense without a poll.
However, this page also contained information about successful
proposals, which might be interesting so administrators don't have to
navigate to the public area in order to find and create questions based
on successful proposals.
So we're keeping the part about successful proposals and linking it from
the proposals part of the admin area.
Note we're using translation keys like `successful_proposals_tab`, which
don't make sense anymore, for the successful proposals. We're doing so
because we've already got translations for these keys and, if we renamed
them, we'd lose the existing translations and our translators would have
to add them again.
Also note we're changing one poll question test a little bit so we
create the question from a successful proposal using the new page. There
are other tests checking how to create a question from the
admin/proposals#show action and other tests checking what happens when
accessing a successful proposal in the admin section, so we don't lose
any test coverage by changing an existing test instead of adding a new
one.
Finally, note that we've removing the `search` method in poll question
because we no longer use it. This currently makes the
`author_visible_name` database column useless; we aren't removing it
right now because we don't want to risk a possible data loss in a patch
release (we're about to release version 2.3.1), but we might remove it
in the future.
This commit is contained in:
@@ -1,11 +0,0 @@
|
|||||||
.admin .poll-questions-filter {
|
|
||||||
$gap: 0.5em;
|
|
||||||
@include flex-with-gap($gap);
|
|
||||||
align-items: flex-end;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
|
|
||||||
[type="submit"] {
|
|
||||||
@include regular-button;
|
|
||||||
margin-left: $gap;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
<%= form_tag "", method: :get, class: "poll-questions-filter" do %>
|
|
||||||
<div class="filter">
|
|
||||||
<%= label_tag :poll_id, t("admin.questions.index.filter_poll") %>
|
|
||||||
<%= select_tag "poll_id", poll_select_options, prompt: t("polls.all") %>
|
|
||||||
</div>
|
|
||||||
<%= submit_tag t("shared.filter") %>
|
|
||||||
<% end %>
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
class Admin::Poll::Questions::FilterComponent < ApplicationComponent
|
|
||||||
attr_reader :polls
|
|
||||||
use_helpers :current_path_with_query_params
|
|
||||||
|
|
||||||
def initialize(polls)
|
|
||||||
@polls = polls
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
def poll_select_options
|
|
||||||
options_from_collection_for_select(polls, :id, :name, params[:poll_id])
|
|
||||||
end
|
|
||||||
end
|
|
||||||
@@ -1,6 +1,8 @@
|
|||||||
<% provide :main_class, "admin-proposals-index" %>
|
<% provide :main_class, "admin-proposals-index" %>
|
||||||
|
|
||||||
<%= header %>
|
<%= header do %>
|
||||||
|
<%= successful_proposals_link %>
|
||||||
|
<% end %>
|
||||||
|
|
||||||
<% if proposals.any? %>
|
<% if proposals.any? %>
|
||||||
<%= render Admin::SearchComponent.new(label: t("admin.shared.search.label.proposals")) %>
|
<%= render Admin::SearchComponent.new(label: t("admin.shared.search.label.proposals")) %>
|
||||||
|
|||||||
@@ -9,4 +9,12 @@ class Admin::Proposals::IndexComponent < ApplicationComponent
|
|||||||
def title
|
def title
|
||||||
t("admin.proposals.index.title")
|
t("admin.proposals.index.title")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def successful_proposals_link
|
||||||
|
if Proposal.successful.any?
|
||||||
|
link_to t("admin.questions.index.successful_proposals_tab"), successful_admin_proposals_path
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,3 +1,9 @@
|
|||||||
|
<% provide :main_class, "admin-proposals-successful" %>
|
||||||
|
|
||||||
|
<%= back_link_to admin_proposals_path %>
|
||||||
|
|
||||||
|
<%= header %>
|
||||||
|
|
||||||
<table>
|
<table>
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
@@ -6,7 +12,7 @@
|
|||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<% @proposals.each do |proposal| %>
|
<% proposals.each do |proposal| %>
|
||||||
<tr id="<%= dom_id(proposal) %>">
|
<tr id="<%= dom_id(proposal) %>">
|
||||||
<td>
|
<td>
|
||||||
<%= proposal.title %>
|
<%= proposal.title %>
|
||||||
12
app/components/admin/proposals/successful_component.rb
Normal file
12
app/components/admin/proposals/successful_component.rb
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
class Admin::Proposals::SuccessfulComponent < ApplicationComponent
|
||||||
|
include Header
|
||||||
|
attr_reader :proposals
|
||||||
|
|
||||||
|
def initialize(proposals)
|
||||||
|
@proposals = proposals
|
||||||
|
end
|
||||||
|
|
||||||
|
def title
|
||||||
|
t("admin.questions.index.successful_proposals_tab")
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -4,14 +4,7 @@ class Admin::Poll::QuestionsController < Admin::Poll::BaseController
|
|||||||
|
|
||||||
load_and_authorize_resource :poll
|
load_and_authorize_resource :poll
|
||||||
load_resource class: "Poll::Question"
|
load_resource class: "Poll::Question"
|
||||||
authorize_resource except: [:new, :index]
|
authorize_resource except: :new
|
||||||
|
|
||||||
def index
|
|
||||||
@polls = Poll.not_budget
|
|
||||||
@questions = @questions.search(search_params).page(params[:page]).order("created_at DESC")
|
|
||||||
|
|
||||||
@proposals = Proposal.successful.sort_by_confidence_score
|
|
||||||
end
|
|
||||||
|
|
||||||
def new
|
def new
|
||||||
proposal = Proposal.find(params[:proposal_id]) if params[:proposal_id].present?
|
proposal = Proposal.find(params[:proposal_id]) if params[:proposal_id].present?
|
||||||
@@ -61,8 +54,4 @@ class Admin::Poll::QuestionsController < Admin::Poll::BaseController
|
|||||||
attributes = [:poll_id, :question, :proposal_id, votation_type_attributes: [:vote_type, :max_votes]]
|
attributes = [:poll_id, :question, :proposal_id, votation_type_attributes: [:vote_type, :max_votes]]
|
||||||
[*attributes, translation_params(Poll::Question)]
|
[*attributes, translation_params(Poll::Question)]
|
||||||
end
|
end
|
||||||
|
|
||||||
def search_params
|
|
||||||
params.permit(:poll_id, :search)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -6,7 +6,11 @@ class Admin::ProposalsController < Admin::BaseController
|
|||||||
|
|
||||||
has_orders %w[created_at]
|
has_orders %w[created_at]
|
||||||
|
|
||||||
before_action :load_proposal, except: :index
|
before_action :load_proposal, except: [:index, :successful]
|
||||||
|
|
||||||
|
def successful
|
||||||
|
@proposals = Proposal.successful.sort_by_confidence_score
|
||||||
|
end
|
||||||
|
|
||||||
def show
|
def show
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
class Poll::Question < ApplicationRecord
|
class Poll::Question < ApplicationRecord
|
||||||
include Measurable
|
include Measurable
|
||||||
include Searchable
|
|
||||||
|
|
||||||
acts_as_paranoid column: :hidden_at
|
acts_as_paranoid column: :hidden_at
|
||||||
include ActsAsParanoidAliases
|
include ActsAsParanoidAliases
|
||||||
@@ -30,25 +29,9 @@ class Poll::Question < ApplicationRecord
|
|||||||
|
|
||||||
delegate :multiple?, :vote_type, to: :votation_type, allow_nil: true
|
delegate :multiple?, :vote_type, to: :votation_type, allow_nil: true
|
||||||
|
|
||||||
scope :by_poll_id, ->(poll_id) { where(poll_id: poll_id) }
|
|
||||||
|
|
||||||
scope :sort_for_list, -> { order(Arel.sql("poll_questions.proposal_id IS NULL"), :created_at) }
|
scope :sort_for_list, -> { order(Arel.sql("poll_questions.proposal_id IS NULL"), :created_at) }
|
||||||
scope :for_render, -> { includes(:author, :proposal) }
|
scope :for_render, -> { includes(:author, :proposal) }
|
||||||
|
|
||||||
def self.search(params)
|
|
||||||
results = all
|
|
||||||
results = results.by_poll_id(params[:poll_id]) if params[:poll_id].present?
|
|
||||||
results = results.pg_search(params[:search]) if params[:search].present?
|
|
||||||
results
|
|
||||||
end
|
|
||||||
|
|
||||||
def searchable_values
|
|
||||||
{ title => "A",
|
|
||||||
proposal&.title => "A",
|
|
||||||
author.username => "C",
|
|
||||||
author_visible_name => "C" }
|
|
||||||
end
|
|
||||||
|
|
||||||
def copy_attributes_from_proposal(proposal)
|
def copy_attributes_from_proposal(proposal)
|
||||||
if proposal.present?
|
if proposal.present?
|
||||||
self.author = proposal.author
|
self.author = proposal.author
|
||||||
|
|||||||
@@ -1,12 +0,0 @@
|
|||||||
<ul class="tabs" data-tabs id="questions-tabs">
|
|
||||||
<li class="tabs-title is-active">
|
|
||||||
<%= link_to "#tab-questions" do %>
|
|
||||||
<%= t("admin.questions.index.questions_tab") %>
|
|
||||||
<% end %>
|
|
||||||
</li>
|
|
||||||
<li class="tabs-title">
|
|
||||||
<%= link_to "#tab-successful-proposals" do %>
|
|
||||||
<%= t("admin.questions.index.successful_proposals_tab") %>
|
|
||||||
<% end %>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
<%= render Admin::Poll::Questions::FilterComponent.new(@polls) %>
|
|
||||||
|
|
||||||
<% if @questions.count == 0 %>
|
|
||||||
<div class="callout primary margin-top">
|
|
||||||
<%= t("admin.questions.index.no_questions") %>
|
|
||||||
</div>
|
|
||||||
<% else %>
|
|
||||||
<table>
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th><%= t("admin.questions.index.table_question") %></th>
|
|
||||||
<th><%= t("admin.questions.index.table_poll") %></th>
|
|
||||||
<th><%= t("admin.actions.actions") %></th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<% @questions.each do |question| %>
|
|
||||||
<tr id="<%= dom_id(question) %>">
|
|
||||||
<td><%= question.title %></td>
|
|
||||||
<td>
|
|
||||||
<% if question.poll.present? %>
|
|
||||||
<%= question.poll.name %>
|
|
||||||
<% else %>
|
|
||||||
<em><%= t("admin.questions.index.poll_not_assigned") %></em>
|
|
||||||
<% end %>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<%= render Admin::TableActionsComponent.new(question) do |actions| %>
|
|
||||||
<%= actions.action(:options, text: t("admin.polls.show.edit_answers")) %>
|
|
||||||
<% end %>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<% end %>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<%= paginate @questions %>
|
|
||||||
<% end %>
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
<h2 class="inline-block"><%= t("admin.questions.index.title") %></h2>
|
|
||||||
|
|
||||||
<%= link_to t("admin.questions.index.create"), new_admin_question_path,
|
|
||||||
class: "button float-right" %>
|
|
||||||
|
|
||||||
<%= render "search" %>
|
|
||||||
|
|
||||||
<div class="tabs-content" data-tabs-content="questions-tabs">
|
|
||||||
<%= render "filter_subnav" %>
|
|
||||||
|
|
||||||
<div class="tabs-panel is-active" id="tab-questions">
|
|
||||||
<%= render "questions" %>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="tabs-panel" id="tab-successful-proposals">
|
|
||||||
<%= render "successful_proposals" %>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
1
app/views/admin/proposals/successful.html.erb
Normal file
1
app/views/admin/proposals/successful.html.erb
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<%= render Admin::Proposals::SuccessfulComponent.new(@proposals) %>
|
||||||
@@ -1134,18 +1134,11 @@ en:
|
|||||||
multiple_description: "Allows to choose multiple answers. It's possible to set the maximum number of answers."
|
multiple_description: "Allows to choose multiple answers. It's possible to set the maximum number of answers."
|
||||||
questions:
|
questions:
|
||||||
index:
|
index:
|
||||||
title: "Questions"
|
|
||||||
create: "Create question"
|
create: "Create question"
|
||||||
no_questions: "There are no questions."
|
|
||||||
filter_poll: Filter by Poll
|
|
||||||
select_poll: Select Poll
|
select_poll: Select Poll
|
||||||
questions_tab: "Questions"
|
|
||||||
successful_proposals_tab: "Successful proposals"
|
successful_proposals_tab: "Successful proposals"
|
||||||
create_question: "Create question"
|
create_question: "Create question"
|
||||||
table_proposal: "Proposal"
|
table_proposal: "Proposal"
|
||||||
table_question: "Question"
|
|
||||||
table_poll: "Poll"
|
|
||||||
poll_not_assigned: "Poll not assigned"
|
|
||||||
edit:
|
edit:
|
||||||
title: "Edit Question"
|
title: "Edit Question"
|
||||||
form:
|
form:
|
||||||
|
|||||||
@@ -569,7 +569,6 @@ en:
|
|||||||
support: "You just have to click on the button that you will see below 'Support this proposal' and you can inform yourself about before promoting it. Only the proposals that achieve the maximum support will be carried out by the City Council, and I thought that you, I'm sure you help me achieve it!"
|
support: "You just have to click on the button that you will see below 'Support this proposal' and you can inform yourself about before promoting it. Only the proposals that achieve the maximum support will be carried out by the City Council, and I thought that you, I'm sure you help me achieve it!"
|
||||||
share: "And if you also do me the great favor of sharing my proposal with your friends, family and contacts, it would be perfect!"
|
share: "And if you also do me the great favor of sharing my proposal with your friends, family and contacts, it would be perfect!"
|
||||||
polls:
|
polls:
|
||||||
all: "All"
|
|
||||||
dates: "From %{open_at} to %{closed_at}"
|
dates: "From %{open_at} to %{closed_at}"
|
||||||
final_date: "Final recounts/Results"
|
final_date: "Final recounts/Results"
|
||||||
index:
|
index:
|
||||||
|
|||||||
@@ -1134,18 +1134,11 @@ es:
|
|||||||
multiple_description: "Permite elegir más de una respuesta. Se puede elegir el número máximo de respuestas."
|
multiple_description: "Permite elegir más de una respuesta. Se puede elegir el número máximo de respuestas."
|
||||||
questions:
|
questions:
|
||||||
index:
|
index:
|
||||||
title: "Preguntas de votaciones"
|
|
||||||
create: "Crear pregunta ciudadana"
|
create: "Crear pregunta ciudadana"
|
||||||
no_questions: "No hay ninguna pregunta ciudadana."
|
|
||||||
filter_poll: Filtrar por votación
|
|
||||||
select_poll: Seleccionar votación
|
select_poll: Seleccionar votación
|
||||||
questions_tab: "Preguntas"
|
|
||||||
successful_proposals_tab: "Propuestas que han superado el umbral"
|
successful_proposals_tab: "Propuestas que han superado el umbral"
|
||||||
create_question: "Crear pregunta para votación"
|
create_question: "Crear pregunta para votación"
|
||||||
table_proposal: "Propuesta"
|
table_proposal: "Propuesta"
|
||||||
table_question: "Pregunta"
|
|
||||||
table_poll: "Votación"
|
|
||||||
poll_not_assigned: "Votación no asignada"
|
|
||||||
edit:
|
edit:
|
||||||
title: "Editar pregunta ciudadana"
|
title: "Editar pregunta ciudadana"
|
||||||
form:
|
form:
|
||||||
|
|||||||
@@ -569,7 +569,6 @@ es:
|
|||||||
support: "Tan sólo tienes que hacer clic en el botón que verás a continuación 'Apoyar esta propuesta' y directamente podrás informarte acerca de ella antes de impulsarla. Sólo las propuestas que consigan el máximo apoyo se llevarán a cabo por parte del Ayuntamiento, y he pensado que tú ¡seguro que me ayudas a lograrlo!"
|
support: "Tan sólo tienes que hacer clic en el botón que verás a continuación 'Apoyar esta propuesta' y directamente podrás informarte acerca de ella antes de impulsarla. Sólo las propuestas que consigan el máximo apoyo se llevarán a cabo por parte del Ayuntamiento, y he pensado que tú ¡seguro que me ayudas a lograrlo!"
|
||||||
share: "Y si además, me haces el gran favor de compartir mi propuesta con tus amigos, familiares y contactos ¡sería perfecto!"
|
share: "Y si además, me haces el gran favor de compartir mi propuesta con tus amigos, familiares y contactos ¡sería perfecto!"
|
||||||
polls:
|
polls:
|
||||||
all: "Todas"
|
|
||||||
dates: "Desde el %{open_at} hasta el %{closed_at}"
|
dates: "Desde el %{open_at} hasta el %{closed_at}"
|
||||||
final_date: "Recuento final/Resultados"
|
final_date: "Recuento final/Resultados"
|
||||||
index:
|
index:
|
||||||
|
|||||||
@@ -45,6 +45,10 @@ 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
|
||||||
|
collection do
|
||||||
|
get :successful
|
||||||
|
end
|
||||||
|
|
||||||
member do
|
member do
|
||||||
patch :select
|
patch :select
|
||||||
patch :deselect
|
patch :deselect
|
||||||
@@ -192,7 +196,7 @@ namespace :admin do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
resources :questions, shallow: true do
|
resources :questions, except: :index, shallow: true do
|
||||||
resources :options, except: [:index, :show], controller: "questions/options", shallow: false
|
resources :options, except: [:index, :show], controller: "questions/options", shallow: false
|
||||||
resources :options, only: [], controller: "questions/options" do
|
resources :options, only: [], controller: "questions/options" do
|
||||||
resources :images, controller: "questions/options/images"
|
resources :images, controller: "questions/options/images"
|
||||||
|
|||||||
@@ -1,9 +0,0 @@
|
|||||||
require "rails_helper"
|
|
||||||
|
|
||||||
describe Admin::Poll::Questions::FilterComponent do
|
|
||||||
it "renders a button to submit the form" do
|
|
||||||
render_inline Admin::Poll::Questions::FilterComponent.new([])
|
|
||||||
|
|
||||||
expect(page).to have_button "Filter"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
35
spec/components/admin/proposals/index_component_spec.rb
Normal file
35
spec/components/admin/proposals/index_component_spec.rb
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
require "rails_helper"
|
||||||
|
|
||||||
|
describe Admin::Proposals::IndexComponent, controller: Admin::ProposalsController do
|
||||||
|
around do |example|
|
||||||
|
with_request_url(Rails.application.routes.url_helpers.admin_proposals_path) { example.run }
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "#successful_proposals_link" do
|
||||||
|
it "is shown when there are successful proposals" do
|
||||||
|
create(:proposal, :successful)
|
||||||
|
|
||||||
|
render_inline Admin::Proposals::IndexComponent.new(Proposal.page(1))
|
||||||
|
|
||||||
|
expect(page).to have_link "Successful proposals"
|
||||||
|
end
|
||||||
|
|
||||||
|
it "is not shown when there aren't any successful proposals" do
|
||||||
|
create(:proposal)
|
||||||
|
|
||||||
|
render_inline Admin::Proposals::IndexComponent.new(Proposal.page(1))
|
||||||
|
|
||||||
|
expect(page).not_to have_link "Successful proposals"
|
||||||
|
end
|
||||||
|
|
||||||
|
it "is shown when there are successful proposals on a previous page" do
|
||||||
|
allow(Proposal).to receive(:default_per_page).and_return(1)
|
||||||
|
create(:proposal, :successful)
|
||||||
|
create(:proposal)
|
||||||
|
|
||||||
|
render_inline Admin::Proposals::IndexComponent.new(Proposal.order(:id).page(2))
|
||||||
|
|
||||||
|
expect(page).to have_link "Successful proposals"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -118,10 +118,9 @@ describe "Admin poll questions", :admin do
|
|||||||
create(:poll, :future, name: "Proposals")
|
create(:poll, :future, name: "Proposals")
|
||||||
proposal = create(:proposal, :successful)
|
proposal = create(:proposal, :successful)
|
||||||
|
|
||||||
visit admin_proposal_path(proposal)
|
visit admin_proposals_path
|
||||||
|
click_link "Successful proposals"
|
||||||
expect(page).to have_content("This proposal has reached the required supports")
|
click_link "Create question"
|
||||||
click_link "Add this proposal to a poll to be voted"
|
|
||||||
|
|
||||||
expect(page).to have_current_path(new_admin_question_path, ignore_query: true)
|
expect(page).to have_current_path(new_admin_question_path, ignore_query: true)
|
||||||
expect(page).to have_field("Question", with: proposal.title)
|
expect(page).to have_field("Question", with: proposal.title)
|
||||||
@@ -130,11 +129,7 @@ describe "Admin poll questions", :admin do
|
|||||||
|
|
||||||
click_button "Save"
|
click_button "Save"
|
||||||
|
|
||||||
expect(page).to have_content(proposal.title)
|
expect(page).to have_content proposal.title
|
||||||
|
|
||||||
visit admin_questions_path
|
|
||||||
|
|
||||||
expect(page).to have_content(proposal.title)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
scenario "Update" do
|
scenario "Update" do
|
||||||
|
|||||||
@@ -1,13 +0,0 @@
|
|||||||
require "rails_helper"
|
|
||||||
|
|
||||||
describe "Poll Questions", :admin do
|
|
||||||
scenario "Do not display polls associated to a budget" do
|
|
||||||
create(:poll, name: "Citizen Proposal Poll")
|
|
||||||
create(:poll, :for_budget, name: "Participatory Budget Poll")
|
|
||||||
|
|
||||||
visit admin_questions_path
|
|
||||||
|
|
||||||
expect(page).to have_select("poll_id", text: "Citizen Proposal Poll")
|
|
||||||
expect(page).not_to have_select("poll_id", text: "Participatory Budget Poll")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
Reference in New Issue
Block a user