Public view for suggested actions as well as resources has been
completelly redesigned.

Private side for this feature has been adapted as well in order to meet
the requirements.
This commit is contained in:
Juan Salvador Pérez García
2018-07-02 17:16:59 +02:00
parent 53baf983b5
commit 3c3f60dfcc
31 changed files with 290 additions and 158 deletions

View File

@@ -245,4 +245,8 @@
.body {
padding: 1rem 1.5rem 1rem 1.5rem;
}
.proposal-dashboard-action-links {
margin-bottom: 15pt;
}
}

View File

@@ -2,7 +2,7 @@ class Admin::ProposalDashboard::ActionsController < Admin::ProposalDashboard::Ba
helper_method :proposal_dashboard_action, :resource
def index
@proposal_dashboard_actions = ProposalDashboardAction.all
@proposal_dashboard_actions = ProposalDashboardAction.order(required_supports: :asc)
end
def new
@@ -53,7 +53,11 @@ class Admin::ProposalDashboard::ActionsController < Admin::ProposalDashboard::Ba
def proposal_dashboard_action_params
params
.require(:proposal_dashboard_action)
.permit(:title, :description, :link, :request_to_administrators, :day_offset, :required_supports, :order, :active, :action_type)
.permit(
:title, :description, :short_description, :request_to_administrators, :day_offset, :required_supports, :order, :active, :action_type,
documents_attributes: [:id, :title, :attachment, :cached_attachment, :user_id, :_destroy],
links_attributes: [:id, :label, :url, :open_in_new_tab, :_destroy]
)
end

View File

@@ -16,7 +16,7 @@ class ProposalsDashboardController < Dashboard::BaseController
authorize! :dashboard, proposal
ProposalExecutedDashboardAction.create(proposal: proposal, proposal_dashboard_action: proposal_dashboard_action, executed_at: Time.now)
redirect_to proposal_dashboard_index_path(proposal.to_param)
redirect_to progress_proposal_dashboard_index_path(proposal.to_param)
end
def new_request
@@ -27,11 +27,11 @@ class ProposalsDashboardController < Dashboard::BaseController
def create_request
authorize! :dashboard, proposal
source_params = proposal_executed_dashboard_action_params.merge(
source_params = {
proposal: proposal,
proposal_dashboard_action: proposal_dashboard_action,
executed_at: Time.now
)
}
@proposal_executed_dashboard_action = ProposalExecutedDashboardAction.new(source_params)
if @proposal_executed_dashboard_action.save
@@ -54,9 +54,6 @@ class ProposalsDashboardController < Dashboard::BaseController
private
def proposal_executed_dashboard_action_params
params.require(:proposal_executed_dashboard_action).permit(:comments)
end
def proposal_dashboard_action
@proposal_dashboard_action ||= ProposalDashboardAction.find(params[:id])

View File

@@ -58,7 +58,9 @@ module Abilities
can [:create, :destroy], Follow
can [:destroy], Document, documentable: { author_id: user.id }
can [:destroy], Document do |document|
document.documentable.try(:author_id) == user.id
end
can [:destroy], Image, imageable: { author_id: user.id }

View File

@@ -0,0 +1,9 @@
module Linkable
extend ActiveSupport::Concern
included do
has_many :links, as: :linkable, dependent: :destroy
accepts_nested_attributes_for :links, allow_destroy: true
end
end

7
app/models/link.rb Normal file
View File

@@ -0,0 +1,7 @@
class Link < ActiveRecord::Base
belongs_to :linkable, polymorphic: true
validates :label, presence: true
validates :url, presence: true
validates :linkable, presence: true
end

View File

@@ -1,4 +1,11 @@
class ProposalDashboardAction < ActiveRecord::Base
include Documentable
documentable max_documents_allowed: 3,
max_file_size: 3.megabytes,
accepted_content_types: [ 'application/pdf' ]
include Linkable
acts_as_paranoid column: :hidden_at
include ActsAsParanoidAliases
@@ -14,8 +21,7 @@ class ProposalDashboardAction < ActiveRecord::Base
validates :description,
presence: true,
allow_blank: false,
length: { in: 4..255 }
allow_blank: false
validates :action_type, presence: true
@@ -33,11 +39,6 @@ class ProposalDashboardAction < ActiveRecord::Base
greater_than_or_equal_to: 0
}
validates :link,
presence: true,
allow_blank: false,
unless: :request_to_administrators?
default_scope { order(order: :asc, title: :asc) }
scope :active, -> { where(active: true) }

View File

@@ -7,9 +7,4 @@ class ProposalExecutedDashboardAction < ActiveRecord::Base
validates :proposal, presence: true, uniqueness: { scope: :proposal_dashboard_action }
validates :proposal_dashboard_action, presence: true
validates :executed_at, presence: true
validates :comments, presence: true, allow_blank: false, if: :comments_required?
def comments_required?
proposal_dashboard_action&.request_to_administrators? || false
end
end

View File

@@ -1,5 +1,4 @@
<%= form_for [:admin, proposal_dashboard_action] do |f| %>
<%= render 'shared/errors' %>
<div class="row">
@@ -11,11 +10,19 @@
<div class="row">
<div class="small-12 column">
<%= f.label :description %>
<%= f.text_field :description, label: false %>
<%= f.label :short_description %>
<%= f.text_field :short_description, label: false %>
</div>
</div>
<div class="row">
<div class="small-12 column">
<%= f.cktext_area :description,
ckeditor: { language: I18n.locale } %>
</div>
</div>
<div class="row">
<div class="small-12 medium-3 column">
<%= f.label :action_type %>
<% ProposalDashboardAction.action_types.keys.each do |action_type_value| %>
@@ -24,18 +31,12 @@
<br>
<% end %>
</div>
</div>
<div class="small-12 column">
<%= f.check_box :request_to_administrators, label: ProposalDashboardAction.human_attribute_name(:request_to_administrators) %>
</div>
<div class="row">
<div class="small-12 column">
<%= f.label :link%>
<%= f.text_field :link, label: false %>
</div>
</div>
<div class="row">
<div class="small-12 medium-4 large-4 column">
<%= f.label :day_offset %>
@@ -57,6 +58,26 @@
<%= f.check_box :active, label: ProposalDashboardAction.human_attribute_name(:active) %>
</div>
<div class="small-12 column">
<hr>
</div>
<div class="documents small-12 column">
<%= render 'documents/nested_documents', documentable: proposal_dashboard_action, f: f %>
</div>
<div class="small-12 column">
<hr>
</div>
<div class="links small-12 column">
<%= render 'links/nested_links', linkable: proposal_dashboard_action, f: f %>
</div>
<div class="small-12 column">
<hr>
</div>
<div class="row">
<div class="actions small-12 large-3 medium-3 column">
<%= f.submit(class: 'button expanded', value: t('admin.proposal_dashboard_actions.form.submit_button')) %>

View File

@@ -10,7 +10,8 @@
<tr>
<th><%= ProposalDashboardAction.human_attribute_name(:title) %></th>
<th><%= ProposalDashboardAction.human_attribute_name(:action_type) %></th>
<th><%= ProposalDashboardAction.human_attribute_name(:active) %></th>
<th class="text-right"><%= ProposalDashboardAction.human_attribute_name(:required_supports) %></th>
<th class="text-center"><%= ProposalDashboardAction.human_attribute_name(:active) %></th>
<th></th>
</tr>
</thead>
@@ -26,8 +27,9 @@
<tr id="<%= dom_id(action) %>">
<td><%= action.title %></td>
<td><%= t("admin.proposal_dashboard_actions.action_type.#{action.action_type}") %></td>
<td><%= active_human_readable(action.active) %></td>
<td style="text-align: right">
<td class="text-right"><%= action.required_supports %></td>
<td class="text-center"><%= active_human_readable(action.active) %></td>
<td class="text-right">
<%= link_to t('admin.proposal_dashboard_actions.index.edit'),
edit_admin_proposal_dashboard_action_path(action),
class: 'edit-banner button hollow' %>

View File

@@ -3,7 +3,6 @@
<div class="callout">
<h5><%=t '.proposal', title: administrator_task.source.proposal.title %></h5>
<p><%=t '.request', title: administrator_task.source.proposal_dashboard_action.title %></p>
<%== administrator_task.source.comments unless administrator_task.source.comments.blank? %>
<%= link_to t('.check_details'), proposal_path(administrator_task.source.proposal), target: '_blank' %>
</div>

View File

@@ -0,0 +1,20 @@
<div id="<%= dom_id(f.object) %>" class="link link-fields nested-fields">
<div class="small-12 column">
<%= f.text_field :label, placeholder: t('.label_placeholder') %>
</div>
<div class="small-12 column">
<%= f.text_field :url, placeholder: t('.url_placeholder') %>
</div>
<div class="small-6 column">
<%= f.check_box :open_in_new_tab, label: Link.human_attribute_name(:open_in_new_tab) %>
</div>
<div class="small-6 column">
<%= f.check_box :_destroy, label: t('.destroy') if f.object.id.present? %>
</div>
<hr>
</div>

View File

@@ -0,0 +1,22 @@
<div class="links-list">
<%= f.hidden_field :id %>
<%= f.label :links, t('.title') %>
<p class="help-text"><%= t('.note') %></p>
<div id="nested-links">
<%= f.fields_for :links do |links_builder| %>
<%= render 'links/link_fields', f: links_builder %>
<% end %>
</div>
<%= link_to_add_association t('.add_new_link'), f, :links,
partial: 'links/link_fields',
id: 'new_link_button',
class: 'button hollow',
data: {
association_insertion_node: '#nested-links',
association_insertion_method: 'append'
} %>
</div>

View File

@@ -1,12 +1,8 @@
<%= form_for @proposal_executed_dashboard_action,
<% if proposal_dashboard_action.request_to_administrators %>
<%= form_for @proposal_executed_dashboard_action,
url: create_request_proposal_dashboard_url(proposal, proposal_dashboard_action) do |f| %>
<%= render 'shared/errors', resource: @proposal_executed_dashboard_action %>
<div class="ckeditor small-12 column">
<%= f.label :comments %>
<%= f.cktext_area :comments, ckeditor: { language: I18n.locale }, label: false %>
</div>
<div class="actions small-12 column">
<%= f.submit(class: 'button', value: t('.request')) %>
<%= f.submit(class: 'button hollow expanded', value: t('.request')) %>
</div>
<% end %>
<% end %>

View File

@@ -32,12 +32,10 @@
<% resources.each do |resource| %>
<li <%= 'class=is-active' if is_request_active(resource.id) %>>
<% if resource.request_to_administrators? %>
<%= link_to new_request_proposal_dashboard_path(proposal, resource) do %>
<span><%= resource.title %></span>
<% end %>
<% else %>
<%= link_to resource.title, resource.link, target: '_blank' %>
<span data-tooltip title="<%= resource.short_description %>">
<%= resource.title %>
</span>
<% end %>
</li>
<% end %>

View File

@@ -1,30 +1,18 @@
<tr>
<td>
<% if action.link.blank? %>
<span data-tooltip title="<%= action.description %>">
<%= link_to new_request_proposal_dashboard_path(proposal, action) do %>
<span data-tooltip title="<%= action.short_description || action.title %>">
<%= action.title %>
</span>
<% else %>
<%= link_to action.link, target: '_blank' do %>
<span data-tooltip title="<%= action.description %>">
<%= action.title %>
</span>
<% end %>
<% end %>
</td>
<td>
<% if action.proposals.where(id: proposal.id).any? %>
<%=l action.proposal_executed_dashboard_actions.find_by(proposal: proposal).executed_at, format: :short %>
<% else %>
<% if action.request_to_administrators? %>
<%= link_to t('.execute'),
new_request_proposal_dashboard_path(proposal, action) %>
<% else %>
<%= link_to t('.execute'),
execute_proposal_dashboard_path(proposal.to_param, action.to_param),
method: 'post',
data: { confirm: t('admin.actions.confirm') } %>
<% end %>
execute_proposal_dashboard_path(proposal, action),
method: 'post' %>
<% end %>
</td>
</tr>

View File

@@ -1,15 +1,25 @@
<% content_for :action_title, t('.title') %>
<div class="proposals-dashboard-new-request-form row">
<% content_for :action_title, proposal_dashboard_action.title %>
<div class="row">
<div class="small-12 medium-9 column">
<%= back_link_to %>
<h1><%= proposal_dashboard_action.title %></h1>
<div data-alert class="callout primary">
<%= proposal_dashboard_action.description %>
<%== proposal_dashboard_action.description %>
</div>
<div class="small-12 medium-3 column">
<% if proposal_dashboard_action.links.any? %>
<div class="proposal-dashboard-action-links">
<h3><%= t('.links') %></h3>
<% proposal_dashboard_action.links.each do |link| %>
<% if link.open_in_new_tab %>
<%= link_to link.label, link.url, target: '_blank' %>
<% else %>
<%= link_to link.label, link.url %>
<% end %>
<% end %>
</div>
<% end %>
<%= render 'documents/documents', documents: proposal_dashboard_action.documents %>
<%= render 'proposals_dashboard/form' %>
</div>
</div>

View File

@@ -112,6 +112,9 @@ en:
administrator_task:
one: Task
other: Tasks
link:
one: Link
other: Links
attributes:
budget:
name: "Name"
@@ -267,6 +270,7 @@ en:
limit: Number of items
proposal_dashboard_action:
title: Title
short_description: Short description
description: Description
link: External link
request_to_administrators: Admin request
@@ -275,12 +279,13 @@ en:
order: Order
active: Active
action_type: Type
proposal_executed_dashboard_action:
comments: Comments for the administrator
administrator_task:
source: Source
user: Executed by
executed_at: Executed at
link:
label: Title
url: Link
open_in_new_tab: Open in new tab
errors:
models:
user:

View File

@@ -531,7 +531,7 @@ en:
retire: Retire
send_notification: Send notification
new_request:
title: Administrator request
links: Links
dashboard:
polls:
form:
@@ -943,3 +943,12 @@ en:
text_sign_in: login
text_sign_up: sign up
title: How I can comment this document?
links:
nested_links:
title: Links
note: Add the links that are of interest
add_new_link: Add new link
link_fields:
label_placeholder: Link title
url_placeholder: Link address
destroy: Remove link

View File

@@ -112,6 +112,9 @@ es:
administrator_task:
one: Tarea
other: Tareas
link:
one: Enlace
other: Enlaces
attributes:
budget:
name: "Nombre"
@@ -268,6 +271,7 @@ es:
limit: Número de elementos
proposal_dashboard_action:
title: Título
short_description: Descripción corta
description: Descripción
link: Enlace externo
request_to_administrators: Petición para administrador
@@ -276,12 +280,14 @@ es:
order: Orden
active: Activa
action_type: Tipo
proposal_executed_dashboard_action:
comments: Comentarios para el administrador
administrator_task:
source: Fuente
user: Ejecutado por
executed_at: Ejecutado el
link:
label: Título
url: Enlace
open_in_new_tab: Abrir en ventana nueva
errors:
models:
user:

View File

@@ -531,7 +531,7 @@ es:
retire: Retirar
send_notification: Enviar notificación
new_request:
title: Petición al administrador
liks: Enlaces
dashboard:
polls:
form:
@@ -942,3 +942,12 @@ es:
text_sign_in: iniciar sesión
text_sign_up: registrarte
title: "¿Cómo puedo comentar este documento?"
links:
nested_links:
title: Enlaces
note: Añade los enlaces que sean de interés.
add_new_link: Añadir nuevo enlace
link_fields:
label_placeholder: Título del enlace
url_placeholder: Dirección del enlace
destroy: Borrar enlace

View File

@@ -0,0 +1,6 @@
class AddShortDescriptionToProposalDashboardActions < ActiveRecord::Migration
def change
add_column :proposal_dashboard_actions, :short_description, :string
change_column :proposal_dashboard_actions, :description, :text
end
end

View File

@@ -0,0 +1,12 @@
class CreateLinks < ActiveRecord::Migration
def change
create_table :links do |t|
t.string :label
t.string :url
t.boolean :open_in_new_tab
t.references :linkable, polymorphic: true, index: true
t.timestamps null: false
end
end
end

View File

@@ -0,0 +1,5 @@
class RemoveCommentsFromProposalExecutedDashboardAction < ActiveRecord::Migration
def change
remove_column :proposal_executed_dashboard_actions, :comments, :text
end
end

View File

@@ -11,7 +11,7 @@
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 20180625075520) do
ActiveRecord::Schema.define(version: 20180702085737) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
@@ -635,6 +635,18 @@ ActiveRecord::Schema.define(version: 20180625075520) do
add_index "legislation_questions", ["hidden_at"], name: "index_legislation_questions_on_hidden_at", using: :btree
add_index "legislation_questions", ["legislation_process_id"], name: "index_legislation_questions_on_legislation_process_id", using: :btree
create_table "links", force: :cascade do |t|
t.string "label"
t.string "url"
t.boolean "open_in_new_tab"
t.integer "linkable_id"
t.string "linkable_type"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
add_index "links", ["linkable_type", "linkable_id"], name: "index_links_on_linkable_type_and_linkable_id", using: :btree
create_table "local_census_records", force: :cascade do |t|
t.string "document_number", null: false
t.string "document_type", null: false
@@ -895,7 +907,7 @@ ActiveRecord::Schema.define(version: 20180625075520) do
create_table "proposal_dashboard_actions", force: :cascade do |t|
t.string "title", limit: 80
t.string "description"
t.text "description"
t.string "link"
t.boolean "request_to_administrators", default: false
t.integer "day_offset", default: 0
@@ -904,13 +916,13 @@ ActiveRecord::Schema.define(version: 20180625075520) do
t.boolean "active", default: true
t.datetime "hidden_at"
t.integer "action_type", default: 0, null: false
t.string "short_description"
end
create_table "proposal_executed_dashboard_actions", force: :cascade do |t|
t.integer "proposal_id"
t.integer "proposal_dashboard_action_id"
t.datetime "executed_at"
t.text "comments"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end

View File

@@ -0,0 +1,13 @@
namespace :proposal_actions do
desc 'Move link attribute to links collection'
task migrate_links: :environment do
ProposalDashboardAction.where.not(link: nil).each do |action|
Link.create!(
label: action.title,
url: action.link,
open_in_new_tab: true,
linkable: action
)
end
end
end

View File

@@ -1076,14 +1076,10 @@ LOREM_IPSUM
proposal
proposal_dashboard_action
executed_at { Time.current }
trait :with_comments do
comments { Faker::Lorem.sentence(10) }
end
end
factory :administrator_task do
source { |s| s.association(:proposal_executed_dashboard_action, :with_comments) }
source { |s| s.association(:proposal_executed_dashboard_action) }
user
executed_at { Time.current }
@@ -1097,4 +1093,15 @@ LOREM_IPSUM
executed_at { Time.current }
end
end
factory :link do
linkable { |s| s.association(:proposal_dashboard_action) }
label { Faker::Lorem.sentence }
url { Faker::Internet.url }
open_in_new_tab false
trait :open_in_new_tab do
open_in_new_tab true
end
end
end

View File

@@ -55,10 +55,6 @@ describe 'Administrator tasks' do
expect(page).to have_button('Mark as solved')
end
scenario 'shows the comments added by the user during the request' do
expect(page).to have_content(task.source.comments)
end
context 'and the Mark as solved button is pressed' do
before do
click_button 'Mark as solved'

29
spec/models/link_spec.rb Normal file
View File

@@ -0,0 +1,29 @@
require 'rails_helper'
describe Link do
subject do
build :link,
linkable: proposal_dashboard_action,
label: label,
url: url,
open_in_new_tab: true
end
let(:proposal_dashboard_action) { build :proposal_dashboard_action }
let(:label) { Faker::Lorem.sentence }
let(:url) { Faker::Internet.url }
it { should be_valid }
context 'when label is blank' do
let(:label) { '' }
it { should_not be_valid }
end
context 'when url is blank' do
let(:url) { '' }
it { should_not be_valid }
end
end

View File

@@ -7,7 +7,6 @@ describe ProposalDashboardAction do
description: description,
day_offset: day_offset,
required_supports: required_supports,
link: link,
request_to_administrators: request_to_administrators,
action_type: action_type
end
@@ -16,7 +15,6 @@ describe ProposalDashboardAction do
let(:description) { Faker::Lorem.sentence }
let(:day_offset) { 0 }
let(:required_supports) { 0 }
let(:link) { nil }
let(:request_to_administrators) { true }
let(:action_type) { 'resource' }
@@ -48,18 +46,6 @@ describe ProposalDashboardAction do
it { should_not be_valid }
end
context 'and description is very short' do
let(:description) { 'abc' }
it { should_not be_valid }
end
context 'and description is very long' do
let(:description) { 'a' * 256 }
it { should_not be_valid }
end
end
context 'when validating day_offset' do
@@ -102,32 +88,6 @@ describe ProposalDashboardAction do
end
end
context 'when url is blank' do
let(:link) { nil }
context 'and no request_to_administrators' do
let(:request_to_administrators) { false }
it { should_not be_valid }
end
context 'and request_to_administrators' do
let(:request_to_administrators) { true }
it { should be_valid }
end
end
context 'when url is not blank' do
let(:link) { Faker::Internet.url }
context 'and no request_to_administrators' do
let(:request_to_administrators) { false }
it { should be_valid }
end
end
context 'when action type is nil' do
let(:action_type) { nil }

View File

@@ -5,8 +5,7 @@ describe ProposalExecutedDashboardAction do
build :proposal_executed_dashboard_action,
proposal: proposal,
proposal_dashboard_action: proposal_dashboard_action,
executed_at: executed_at,
comments: comments
executed_at: executed_at
end
let(:proposal) { create :proposal }
@@ -15,7 +14,6 @@ describe ProposalExecutedDashboardAction do
end
let(:request_to_administrators) { false }
let(:executed_at) { Time.current }
let(:comments) { '' }
it { should be_valid }
@@ -40,18 +38,8 @@ describe ProposalExecutedDashboardAction do
context 'when the action sends a request to the administrators' do
let(:request_to_administrators) { true }
context 'and comments are blank' do
let(:comments) { '' }
it { should_not be_valid }
end
context 'and comments have value' do
let(:comments) { Faker::Lorem.sentence }
it { should be_valid }
end
end
context 'when it has been already executed' do
let!(:executed) { create(:proposal_executed_dashboard_action, proposal: proposal, proposal_dashboard_action: proposal_dashboard_action) }