Merge pull request #3195 from consul/milestone_progress_bar
[Backport] Manage milestone progress bars
This commit is contained in:
@@ -23,8 +23,29 @@ App.Forms =
|
|||||||
false
|
false
|
||||||
)
|
)
|
||||||
|
|
||||||
|
synchronizeInputs: ->
|
||||||
|
$("[name='progress_bar[percentage]']").on
|
||||||
|
input: ->
|
||||||
|
$("[name='#{this.name}']").val($(this).val())
|
||||||
|
|
||||||
|
$("[name='progress_bar[percentage]'][type='range']").trigger("input")
|
||||||
|
|
||||||
|
hideOrShowFieldsAfterSelection: ->
|
||||||
|
$("[name='progress_bar[kind]']").on
|
||||||
|
change: ->
|
||||||
|
title_field = $("[name^='progress_bar'][name$='[title]']").parent()
|
||||||
|
|
||||||
|
if this.value == "primary"
|
||||||
|
title_field.hide()
|
||||||
|
else
|
||||||
|
title_field.show()
|
||||||
|
|
||||||
|
$("[name='progress_bar[kind]']").change()
|
||||||
|
|
||||||
initialize: ->
|
initialize: ->
|
||||||
App.Forms.disableEnter()
|
App.Forms.disableEnter()
|
||||||
App.Forms.submitOnChange()
|
App.Forms.submitOnChange()
|
||||||
App.Forms.toggleLink()
|
App.Forms.toggleLink()
|
||||||
|
App.Forms.synchronizeInputs()
|
||||||
|
App.Forms.hideOrShowFieldsAfterSelection()
|
||||||
false
|
false
|
||||||
|
|||||||
@@ -251,6 +251,13 @@ $sidebar-active: #f4fcd0;
|
|||||||
max-width: none;
|
max-width: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
form {
|
||||||
|
|
||||||
|
.input-group-label {
|
||||||
|
height: $line-height * 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.menu.simple {
|
.menu.simple {
|
||||||
margin-bottom: $line-height / 2;
|
margin-bottom: $line-height / 2;
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
class Admin::BudgetInvestmentProgressBarsController < Admin::ProgressBarsController
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def progressable
|
||||||
|
Budget::Investment.find(params[:budget_investment_id])
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
class Admin::Legislation::ProgressBarsController < Admin::ProgressBarsController
|
||||||
|
include FeatureFlags
|
||||||
|
feature_flag :legislation
|
||||||
|
|
||||||
|
def index
|
||||||
|
@process = progressable
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def progressable
|
||||||
|
::Legislation::Process.find(params[:process_id])
|
||||||
|
end
|
||||||
|
end
|
||||||
69
app/controllers/admin/progress_bars_controller.rb
Normal file
69
app/controllers/admin/progress_bars_controller.rb
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
class Admin::ProgressBarsController < Admin::BaseController
|
||||||
|
include Translatable
|
||||||
|
|
||||||
|
before_action :load_progressable
|
||||||
|
before_action :load_progress_bar, only: [:edit, :update, :destroy]
|
||||||
|
helper_method :progress_bars_index
|
||||||
|
|
||||||
|
def index
|
||||||
|
end
|
||||||
|
|
||||||
|
def new
|
||||||
|
@progress_bar = @progressable.progress_bars.new
|
||||||
|
end
|
||||||
|
|
||||||
|
def create
|
||||||
|
@progress_bar = @progressable.progress_bars.new(progress_bar_params)
|
||||||
|
if @progress_bar.save
|
||||||
|
redirect_to progress_bars_index, notice: t("admin.progress_bars.create.notice")
|
||||||
|
else
|
||||||
|
render :new
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def edit
|
||||||
|
end
|
||||||
|
|
||||||
|
def update
|
||||||
|
if @progress_bar.update(progress_bar_params)
|
||||||
|
redirect_to progress_bars_index, notice: t('admin.progress_bars.update.notice')
|
||||||
|
else
|
||||||
|
render :edit
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def destroy
|
||||||
|
@progress_bar.destroy
|
||||||
|
redirect_to progress_bars_index, notice: t('admin.progress_bars.delete.notice')
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def progress_bar_params
|
||||||
|
params.require(:progress_bar).permit(allowed_params)
|
||||||
|
end
|
||||||
|
|
||||||
|
def allowed_params
|
||||||
|
[
|
||||||
|
:kind,
|
||||||
|
:percentage,
|
||||||
|
translation_params(ProgressBar)
|
||||||
|
]
|
||||||
|
end
|
||||||
|
|
||||||
|
def load_progressable
|
||||||
|
@progressable = progressable
|
||||||
|
end
|
||||||
|
|
||||||
|
def progressable
|
||||||
|
raise "This method must be implemented in subclass #{self.class.name}"
|
||||||
|
end
|
||||||
|
|
||||||
|
def load_progress_bar
|
||||||
|
@progress_bar = progressable.progress_bars.find(params[:id])
|
||||||
|
end
|
||||||
|
|
||||||
|
def progress_bars_index
|
||||||
|
polymorphic_path([:admin, *resource_hierarchy_for(@progressable), ProgressBar.new])
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
class Admin::ProposalProgressBarsController < Admin::ProgressBarsController
|
||||||
|
|
||||||
|
private
|
||||||
|
def progressable
|
||||||
|
Proposal.find(params[:proposal_id])
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -5,5 +5,7 @@ module Milestoneable
|
|||||||
has_many :milestones, as: :milestoneable, dependent: :destroy
|
has_many :milestones, as: :milestoneable, dependent: :destroy
|
||||||
|
|
||||||
scope :with_milestones, -> { joins(:milestones).distinct }
|
scope :with_milestones, -> { joins(:milestones).distinct }
|
||||||
|
|
||||||
|
has_many :progress_bars, as: :progressable
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
28
app/models/progress_bar.rb
Normal file
28
app/models/progress_bar.rb
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
class ProgressBar < ActiveRecord::Base
|
||||||
|
self.inheritance_column = nil
|
||||||
|
RANGE = 0..100
|
||||||
|
|
||||||
|
enum kind: %i[primary secondary]
|
||||||
|
|
||||||
|
belongs_to :progressable, polymorphic: true
|
||||||
|
|
||||||
|
translates :title, touch: true
|
||||||
|
include Globalizable
|
||||||
|
|
||||||
|
validates :progressable, presence: true
|
||||||
|
validates :kind, presence: true,
|
||||||
|
uniqueness: {
|
||||||
|
scope: [:progressable_type, :progressable_id],
|
||||||
|
conditions: -> { primary }
|
||||||
|
}
|
||||||
|
validates :percentage, presence: true, inclusion: RANGE, numericality: { only_integer: true }
|
||||||
|
|
||||||
|
before_validation :assign_progress_bar_to_translations
|
||||||
|
validates_translation :title, presence: true, unless: :primary?
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def assign_progress_bar_to_translations
|
||||||
|
translations.each { |translation| translation.globalized_model = self }
|
||||||
|
end
|
||||||
|
end
|
||||||
3
app/models/progress_bar/translation.rb
Normal file
3
app/models/progress_bar/translation.rb
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
class ProgressBar::Translation < Globalize::ActiveRecord::Translation
|
||||||
|
delegate :primary?, to: :globalized_model
|
||||||
|
end
|
||||||
12
app/views/admin/legislation/progress_bars/index.html.erb
Normal file
12
app/views/admin/legislation/progress_bars/index.html.erb
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<% provide :title do %>
|
||||||
|
<%= "#{t("admin.header.title")} - #{t("admin.menu.legislation")}" %> -
|
||||||
|
<%= "#{@process.title} - #{t("admin.progress_bars.index.title")}" %>
|
||||||
|
<% end %>
|
||||||
|
|
||||||
|
<%= back_link_to admin_legislation_process_milestones_path(@progressable),
|
||||||
|
t("admin.legislation.processes.edit.back") %>
|
||||||
|
|
||||||
|
<h2><%= @process.title %></h2>
|
||||||
|
|
||||||
|
<%= render "admin/legislation/processes/subnav", process: @process, active: "milestones" %>
|
||||||
|
<%= render "admin/progress_bars/progress_bars", progressable: @process %>
|
||||||
@@ -1,4 +1,8 @@
|
|||||||
<h2><%= t("admin.milestones.index.milestone") %></h2>
|
<h2 class="inline-block"><%= t("admin.milestones.index.milestone") %></h2>
|
||||||
|
|
||||||
|
<%= link_to t("admin.progress_bars.manage"),
|
||||||
|
polymorphic_path([:admin, *resource_hierarchy_for(milestoneable.progress_bars.new)]),
|
||||||
|
class: "button hollow float-right" %>
|
||||||
|
|
||||||
<% if milestoneable.milestones.any? %>
|
<% if milestoneable.milestones.any? %>
|
||||||
<table>
|
<table>
|
||||||
|
|||||||
31
app/views/admin/progress_bars/_form.html.erb
Normal file
31
app/views/admin/progress_bars/_form.html.erb
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
<%= render "admin/shared/globalize_locales", resource: @progress_bar %>
|
||||||
|
|
||||||
|
<%= translatable_form_for [:admin, *resource_hierarchy_for(@progress_bar)] do |f| %>
|
||||||
|
|
||||||
|
<div class="small-12 medium-6">
|
||||||
|
<%= f.enum_select :kind %>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<%= f.translatable_fields do |translations_form| %>
|
||||||
|
<div class="small-12 medium-6">
|
||||||
|
<%= translations_form.text_field :title %>
|
||||||
|
</div>
|
||||||
|
<% end %>
|
||||||
|
|
||||||
|
<% progress_options = { min: ProgressBar::RANGE.min, max: ProgressBar::RANGE.max, step: 1 } %>
|
||||||
|
<div class="small-12 medium-6 large-2">
|
||||||
|
<%= f.text_field :percentage, { type: :range,
|
||||||
|
id: "percentage_range",
|
||||||
|
class: "column" }.merge(progress_options) %>
|
||||||
|
</div>
|
||||||
|
<div class="small-12 medium-6 large-2">
|
||||||
|
<div class="input-group">
|
||||||
|
<%= f.text_field :percentage, { type: :number,
|
||||||
|
label: false,
|
||||||
|
class: "input-group-field" }.merge(progress_options) %>
|
||||||
|
<span class="input-group-label">%</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<%= f.submit nil, class: "button success" %>
|
||||||
|
<% end %>
|
||||||
57
app/views/admin/progress_bars/_progress_bars.html.erb
Normal file
57
app/views/admin/progress_bars/_progress_bars.html.erb
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
<h2 class="inline-block"><%= t("admin.progress_bars.index.title") %></h2>
|
||||||
|
|
||||||
|
<%= link_to t("admin.progress_bars.index.new_progress_bar"),
|
||||||
|
polymorphic_path(
|
||||||
|
[:admin, *resource_hierarchy_for(ProgressBar.new(progressable: progressable))],
|
||||||
|
action: :new
|
||||||
|
),
|
||||||
|
class: "button float-right" %>
|
||||||
|
|
||||||
|
<% if progressable.progress_bars.any? %>
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th><%= t("admin.progress_bars.index.table_id") %></th>
|
||||||
|
<th><%= t("admin.progress_bars.index.table_kind") %></th>
|
||||||
|
<th><%= t("admin.progress_bars.index.table_title") %></th>
|
||||||
|
<th class="text-center"><%= t("admin.progress_bars.index.table_percentage") %></th>
|
||||||
|
<th><%= t("admin.actions.actions") %></th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<% progressable.progress_bars.each do |progress_bar| %>
|
||||||
|
<tr id="<%= dom_id(progress_bar) %>" class="progress-bar">
|
||||||
|
<td>
|
||||||
|
<%= progress_bar.id %>
|
||||||
|
</td>
|
||||||
|
<td><%= ProgressBar.human_attribute_name("kind.#{progress_bar.kind}") %></td>
|
||||||
|
<td>
|
||||||
|
<% if progress_bar.title.present? %>
|
||||||
|
<%= progress_bar.title %>
|
||||||
|
<% else %>
|
||||||
|
<strong><%= t("admin.progress_bars.index.primary") %></strong>
|
||||||
|
<% end %>
|
||||||
|
</td>
|
||||||
|
<td class="text-center">
|
||||||
|
<%= number_to_percentage(progress_bar.percentage, strip_insignificant_zeros: true) %>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<%= link_to t("admin.actions.edit"),
|
||||||
|
polymorphic_path([:admin, *resource_hierarchy_for(progress_bar)],
|
||||||
|
action: :edit),
|
||||||
|
class: "button hollow" %>
|
||||||
|
|
||||||
|
<%= link_to t("admin.actions.delete"),
|
||||||
|
polymorphic_path([:admin, *resource_hierarchy_for(progress_bar)]),
|
||||||
|
method: :delete,
|
||||||
|
class: "button hollow alert" %>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<% end %>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<% else %>
|
||||||
|
<div class="callout primary">
|
||||||
|
<%= t("admin.progress_bars.index.no_progress_bars") %>
|
||||||
|
</div>
|
||||||
|
<% end %>
|
||||||
15
app/views/admin/progress_bars/edit.html.erb
Normal file
15
app/views/admin/progress_bars/edit.html.erb
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
<% if @progress_bar.primary? %>
|
||||||
|
<% bar_title = t("admin.progress_bars.edit.title.primary") %>
|
||||||
|
<% else %>
|
||||||
|
<% bar_title = t("admin.progress_bars.edit.title.secondary", title: @progress_bar.title) %>
|
||||||
|
<% end %>
|
||||||
|
|
||||||
|
<% provide :title do %>
|
||||||
|
<%= "#{t("admin.header.title")} - #{bar_title}" %>
|
||||||
|
<% end %>
|
||||||
|
|
||||||
|
<%= back_link_to progress_bars_index %>
|
||||||
|
|
||||||
|
<h2><%= bar_title %></h2>
|
||||||
|
|
||||||
|
<%= render "form" %>
|
||||||
9
app/views/admin/progress_bars/index.html.erb
Normal file
9
app/views/admin/progress_bars/index.html.erb
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
<% provide :title do %>
|
||||||
|
<%= "#{t("admin.header.title")} - #{t("admin.progress_bars.index.title")}" %>
|
||||||
|
<% end %>
|
||||||
|
|
||||||
|
<%= back_link_to polymorphic_path([:admin, *resource_hierarchy_for(@progressable)]) %>
|
||||||
|
|
||||||
|
<div class="clear"></div>
|
||||||
|
|
||||||
|
<%= render "admin/progress_bars/progress_bars", progressable: @progressable %>
|
||||||
9
app/views/admin/progress_bars/new.html.erb
Normal file
9
app/views/admin/progress_bars/new.html.erb
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
<% provide :title do %>
|
||||||
|
<%= "#{t("admin.header.title")} - #{t("admin.progress_bars.new.creating")}" %>
|
||||||
|
<% end %>
|
||||||
|
|
||||||
|
<%= back_link_to progress_bars_index %>
|
||||||
|
|
||||||
|
<h2><%= t("admin.progress_bars.new.creating") %></h2>
|
||||||
|
|
||||||
|
<%= render "form" %>
|
||||||
@@ -5,5 +5,13 @@ module FoundationRailsHelper
|
|||||||
super(attribute, opts)
|
super(attribute, opts)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def enum_select(attribute, options = {}, html_options = {})
|
||||||
|
choices = object.class.send(attribute.to_s.pluralize).keys.map do |name|
|
||||||
|
[object.class.human_attribute_name("#{attribute}.#{name}"), name]
|
||||||
|
end
|
||||||
|
|
||||||
|
select attribute, choices, options, html_options
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -9,6 +9,8 @@ module ActionDispatch::Routing::UrlFor
|
|||||||
[resource.budget, resource]
|
[resource.budget, resource]
|
||||||
when "Milestone"
|
when "Milestone"
|
||||||
[*resource_hierarchy_for(resource.milestoneable), resource]
|
[*resource_hierarchy_for(resource.milestoneable), resource]
|
||||||
|
when "ProgressBar"
|
||||||
|
[*resource_hierarchy_for(resource.progressable), resource]
|
||||||
when "Legislation::Annotation"
|
when "Legislation::Annotation"
|
||||||
[resource.draft_version.process, resource.draft_version, resource]
|
[resource.draft_version.process, resource.draft_version, resource]
|
||||||
when "Legislation::Proposal", "Legislation::Question", "Legislation::DraftVersion"
|
when "Legislation::Proposal", "Legislation::Question", "Legislation::DraftVersion"
|
||||||
|
|||||||
@@ -16,6 +16,9 @@ en:
|
|||||||
milestone/status:
|
milestone/status:
|
||||||
one: "Milestone Status"
|
one: "Milestone Status"
|
||||||
other: "Milestone Statuses"
|
other: "Milestone Statuses"
|
||||||
|
progress_bar:
|
||||||
|
one: "Progress bar"
|
||||||
|
other: "Progress bars"
|
||||||
comment:
|
comment:
|
||||||
one: "Comment"
|
one: "Comment"
|
||||||
other: "Comments"
|
other: "Comments"
|
||||||
@@ -136,6 +139,13 @@ en:
|
|||||||
milestone/status:
|
milestone/status:
|
||||||
name: "Name"
|
name: "Name"
|
||||||
description: "Description (optional)"
|
description: "Description (optional)"
|
||||||
|
progress_bar:
|
||||||
|
kind: "Type"
|
||||||
|
title: "Title"
|
||||||
|
percentage: "Current progress"
|
||||||
|
progress_bar/kind:
|
||||||
|
primary: "Primary"
|
||||||
|
secondary: "Secondary"
|
||||||
budget/heading:
|
budget/heading:
|
||||||
name: "Heading name"
|
name: "Heading name"
|
||||||
price: "Price"
|
price: "Price"
|
||||||
|
|||||||
@@ -332,6 +332,29 @@ en:
|
|||||||
notice: Milestone status created successfully
|
notice: Milestone status created successfully
|
||||||
delete:
|
delete:
|
||||||
notice: Milestone status deleted successfully
|
notice: Milestone status deleted successfully
|
||||||
|
progress_bars:
|
||||||
|
manage: "Manage progress bars"
|
||||||
|
index:
|
||||||
|
title: "Progress bars"
|
||||||
|
no_progress_bars: "There are no progress bars"
|
||||||
|
new_progress_bar: "Create new progress bar"
|
||||||
|
primary: "Primary progress bar"
|
||||||
|
table_id: "ID"
|
||||||
|
table_kind: "Type"
|
||||||
|
table_title: "Title"
|
||||||
|
table_percentage: "Current progress"
|
||||||
|
new:
|
||||||
|
creating: "Create progress bar"
|
||||||
|
edit:
|
||||||
|
title:
|
||||||
|
primary: "Edit primary progress bar"
|
||||||
|
secondary: "Edit progress bar %{title}"
|
||||||
|
create:
|
||||||
|
notice: "Progress bar created successfully!"
|
||||||
|
update:
|
||||||
|
notice: "Progress bar updated successfully"
|
||||||
|
delete:
|
||||||
|
notice: "Progress bar deleted successfully"
|
||||||
comments:
|
comments:
|
||||||
index:
|
index:
|
||||||
filter: Filter
|
filter: Filter
|
||||||
|
|||||||
@@ -16,6 +16,9 @@ es:
|
|||||||
milestone/status:
|
milestone/status:
|
||||||
one: "Estado de seguimiento"
|
one: "Estado de seguimiento"
|
||||||
other: "Estados de seguimiento"
|
other: "Estados de seguimiento"
|
||||||
|
progress_bar:
|
||||||
|
one: "Barra de progreso"
|
||||||
|
other: "Barras de progreso"
|
||||||
comment:
|
comment:
|
||||||
one: "Comentario"
|
one: "Comentario"
|
||||||
other: "Comentarios"
|
other: "Comentarios"
|
||||||
@@ -136,6 +139,13 @@ es:
|
|||||||
milestone/status:
|
milestone/status:
|
||||||
name: "Nombre"
|
name: "Nombre"
|
||||||
description: "Descripción (opcional)"
|
description: "Descripción (opcional)"
|
||||||
|
progress_bar:
|
||||||
|
kind: "Tipo"
|
||||||
|
title: "Título"
|
||||||
|
percentage: "Progreso"
|
||||||
|
progress_bar/kind:
|
||||||
|
primary: "Principal"
|
||||||
|
secondary: "Secundaria"
|
||||||
budget/heading:
|
budget/heading:
|
||||||
name: "Nombre de la partida"
|
name: "Nombre de la partida"
|
||||||
price: "Cantidad"
|
price: "Cantidad"
|
||||||
|
|||||||
@@ -332,6 +332,30 @@ es:
|
|||||||
notice: Estado de seguimiento creado correctamente
|
notice: Estado de seguimiento creado correctamente
|
||||||
delete:
|
delete:
|
||||||
notice: Estado de seguimiento eliminado correctamente
|
notice: Estado de seguimiento eliminado correctamente
|
||||||
|
progress_bars:
|
||||||
|
manage: "Gestionar barras de progreso"
|
||||||
|
index:
|
||||||
|
title: "Barras de progreso"
|
||||||
|
no_progress_bars: "No hay barras de progreso"
|
||||||
|
new_progress_bar: "Crear nueva barra de progreso"
|
||||||
|
primary: "Barra de progreso principal"
|
||||||
|
table_id: "ID"
|
||||||
|
table_kind: "Tipo"
|
||||||
|
table_title: "Título"
|
||||||
|
table_percentage: "Progreso"
|
||||||
|
new:
|
||||||
|
creating: "Crear barra de progreso"
|
||||||
|
edit:
|
||||||
|
title:
|
||||||
|
primary: "Editar barra de progreso principal"
|
||||||
|
secondary: "Editar barra de progreso %{title}"
|
||||||
|
create:
|
||||||
|
notice: "¡Barra de progreso creada con éxito!"
|
||||||
|
update:
|
||||||
|
notice: "Barra de progreso actualizada"
|
||||||
|
delete:
|
||||||
|
notice: "Barra de progreso eliminada correctamente"
|
||||||
|
|
||||||
comments:
|
comments:
|
||||||
index:
|
index:
|
||||||
filter: Filtro
|
filter: Filtro
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ namespace :admin do
|
|||||||
|
|
||||||
resources :proposals, only: [:index, :show] do
|
resources :proposals, only: [:index, :show] do
|
||||||
resources :milestones, controller: "proposal_milestones"
|
resources :milestones, controller: "proposal_milestones"
|
||||||
|
resources :progress_bars, except: :show, controller: "proposal_progress_bars"
|
||||||
end
|
end
|
||||||
|
|
||||||
resources :hidden_proposals, only: :index do
|
resources :hidden_proposals, only: :index do
|
||||||
@@ -67,6 +68,7 @@ namespace :admin do
|
|||||||
|
|
||||||
resources :budget_investments, only: [:index, :show, :edit, :update] do
|
resources :budget_investments, only: [:index, :show, :edit, :update] do
|
||||||
resources :milestones, controller: 'budget_investment_milestones'
|
resources :milestones, controller: 'budget_investment_milestones'
|
||||||
|
resources :progress_bars, except: :show, controller: "budget_investment_progress_bars"
|
||||||
member { patch :toggle_selection }
|
member { patch :toggle_selection }
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -203,6 +205,7 @@ namespace :admin do
|
|||||||
end
|
end
|
||||||
resources :draft_versions
|
resources :draft_versions
|
||||||
resources :milestones
|
resources :milestones
|
||||||
|
resources :progress_bars, except: :show
|
||||||
resource :homepage, only: [:edit, :update]
|
resource :homepage, only: [:edit, :update]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
23
db/migrate/20190103132925_create_progress_bars.rb
Normal file
23
db/migrate/20190103132925_create_progress_bars.rb
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
class CreateProgressBars < ActiveRecord::Migration
|
||||||
|
def change
|
||||||
|
create_table :progress_bars do |t|
|
||||||
|
t.integer :kind
|
||||||
|
t.integer :percentage
|
||||||
|
t.references :progressable, polymorphic: true
|
||||||
|
|
||||||
|
t.timestamps null: false
|
||||||
|
end
|
||||||
|
|
||||||
|
reversible do |change|
|
||||||
|
change.up do
|
||||||
|
ProgressBar.create_translation_table!({
|
||||||
|
title: :string
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
change.down do
|
||||||
|
ProgressBar.drop_translation_table!
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
22
db/schema.rb
22
db/schema.rb
@@ -11,7 +11,7 @@
|
|||||||
#
|
#
|
||||||
# It's strongly recommended that you check this file into your version control system.
|
# It's strongly recommended that you check this file into your version control system.
|
||||||
|
|
||||||
ActiveRecord::Schema.define(version: 20181206153510) do
|
ActiveRecord::Schema.define(version: 20190103132925) do
|
||||||
|
|
||||||
# These are extensions that must be enabled in order to support this database
|
# These are extensions that must be enabled in order to support this database
|
||||||
enable_extension "plpgsql"
|
enable_extension "plpgsql"
|
||||||
@@ -1088,6 +1088,26 @@ ActiveRecord::Schema.define(version: 20181206153510) do
|
|||||||
|
|
||||||
add_index "polls", ["starts_at", "ends_at"], name: "index_polls_on_starts_at_and_ends_at", using: :btree
|
add_index "polls", ["starts_at", "ends_at"], name: "index_polls_on_starts_at_and_ends_at", using: :btree
|
||||||
|
|
||||||
|
create_table "progress_bar_translations", force: :cascade do |t|
|
||||||
|
t.integer "progress_bar_id", null: false
|
||||||
|
t.string "locale", null: false
|
||||||
|
t.datetime "created_at", null: false
|
||||||
|
t.datetime "updated_at", null: false
|
||||||
|
t.string "title"
|
||||||
|
end
|
||||||
|
|
||||||
|
add_index "progress_bar_translations", ["locale"], name: "index_progress_bar_translations_on_locale", using: :btree
|
||||||
|
add_index "progress_bar_translations", ["progress_bar_id"], name: "index_progress_bar_translations_on_progress_bar_id", using: :btree
|
||||||
|
|
||||||
|
create_table "progress_bars", force: :cascade do |t|
|
||||||
|
t.integer "kind"
|
||||||
|
t.integer "percentage"
|
||||||
|
t.integer "progressable_id"
|
||||||
|
t.string "progressable_type"
|
||||||
|
t.datetime "created_at", null: false
|
||||||
|
t.datetime "updated_at", null: false
|
||||||
|
end
|
||||||
|
|
||||||
create_table "proposal_notifications", force: :cascade do |t|
|
create_table "proposal_notifications", force: :cascade do |t|
|
||||||
t.string "title"
|
t.string "title"
|
||||||
t.text "body"
|
t.text "body"
|
||||||
|
|||||||
@@ -195,19 +195,6 @@ FactoryBot.define do
|
|||||||
reason "unfeasible"
|
reason "unfeasible"
|
||||||
end
|
end
|
||||||
|
|
||||||
factory :milestone_status, class: 'Milestone::Status' do
|
|
||||||
sequence(:name) { |n| "Milestone status #{n} name" }
|
|
||||||
sequence(:description) { |n| "Milestone status #{n} description" }
|
|
||||||
end
|
|
||||||
|
|
||||||
factory :milestone, class: 'Milestone' do
|
|
||||||
association :milestoneable, factory: :budget_investment
|
|
||||||
association :status, factory: :milestone_status
|
|
||||||
sequence(:title) { |n| "Budget investment milestone #{n} title" }
|
|
||||||
description 'Milestone description'
|
|
||||||
publication_date { Date.current }
|
|
||||||
end
|
|
||||||
|
|
||||||
factory :valuator_group, class: ValuatorGroup do
|
factory :valuator_group, class: ValuatorGroup do
|
||||||
sequence(:name) { |n| "Valuator Group #{n}" }
|
sequence(:name) { |n| "Valuator Group #{n}" }
|
||||||
end
|
end
|
||||||
|
|||||||
25
spec/factories/milestones.rb
Normal file
25
spec/factories/milestones.rb
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
FactoryBot.define do
|
||||||
|
factory :milestone_status, class: "Milestone::Status" do
|
||||||
|
sequence(:name) { |n| "Milestone status #{n} name" }
|
||||||
|
sequence(:description) { |n| "Milestone status #{n} description" }
|
||||||
|
end
|
||||||
|
|
||||||
|
factory :milestone do
|
||||||
|
association :milestoneable, factory: :budget_investment
|
||||||
|
association :status, factory: :milestone_status
|
||||||
|
sequence(:title) { |n| "Milestone #{n} title" }
|
||||||
|
description "Milestone description"
|
||||||
|
publication_date { Date.current }
|
||||||
|
end
|
||||||
|
|
||||||
|
factory :progress_bar do
|
||||||
|
association :progressable, factory: :budget_investment
|
||||||
|
percentage { rand(0..100) }
|
||||||
|
kind :primary
|
||||||
|
|
||||||
|
trait(:secondary) do
|
||||||
|
kind :secondary
|
||||||
|
sequence(:title) { |n| "Progress bar #{n} title" }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
97
spec/models/progress_bar_spec.rb
Normal file
97
spec/models/progress_bar_spec.rb
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
require "rails_helper"
|
||||||
|
|
||||||
|
describe ProgressBar do
|
||||||
|
let(:progress_bar) { build(:progress_bar) }
|
||||||
|
|
||||||
|
it "is valid" do
|
||||||
|
expect(progress_bar).to be_valid
|
||||||
|
end
|
||||||
|
|
||||||
|
it "is valid without a title" do
|
||||||
|
progress_bar.title = nil
|
||||||
|
|
||||||
|
expect(progress_bar).to be_valid
|
||||||
|
end
|
||||||
|
|
||||||
|
it "is not valid with a custom type" do
|
||||||
|
expect { progress_bar.kind = "terciary" }.to raise_exception(ArgumentError)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "is not valid without a percentage" do
|
||||||
|
progress_bar.percentage = nil
|
||||||
|
|
||||||
|
expect(progress_bar).not_to be_valid
|
||||||
|
end
|
||||||
|
|
||||||
|
it "is not valid with a non-numeric percentage" do
|
||||||
|
progress_bar.percentage = "High"
|
||||||
|
|
||||||
|
expect(progress_bar).not_to be_valid
|
||||||
|
end
|
||||||
|
|
||||||
|
it "is not valid with a non-integer percentage" do
|
||||||
|
progress_bar.percentage = 22.83
|
||||||
|
|
||||||
|
expect(progress_bar).not_to be_valid
|
||||||
|
end
|
||||||
|
|
||||||
|
it "is not valid with a negative percentage" do
|
||||||
|
progress_bar.percentage = -1
|
||||||
|
|
||||||
|
expect(progress_bar).not_to be_valid
|
||||||
|
end
|
||||||
|
|
||||||
|
it "is not valid with a percentage bigger than 100" do
|
||||||
|
progress_bar.percentage = 101
|
||||||
|
|
||||||
|
expect(progress_bar).not_to be_valid
|
||||||
|
end
|
||||||
|
|
||||||
|
it "is valid with an integer percentage within the limits" do
|
||||||
|
progress_bar.percentage = 0
|
||||||
|
|
||||||
|
expect(progress_bar).to be_valid
|
||||||
|
|
||||||
|
progress_bar.percentage = 100
|
||||||
|
|
||||||
|
expect(progress_bar).to be_valid
|
||||||
|
|
||||||
|
progress_bar.percentage = 83
|
||||||
|
|
||||||
|
expect(progress_bar).to be_valid
|
||||||
|
end
|
||||||
|
|
||||||
|
it "is not valid without a progressable" do
|
||||||
|
progress_bar.progressable = nil
|
||||||
|
|
||||||
|
expect(progress_bar).not_to be_valid
|
||||||
|
end
|
||||||
|
|
||||||
|
it "cannot have another primary progress bar for the same progressable" do
|
||||||
|
progress_bar.save
|
||||||
|
duplicate = build(:progress_bar, progressable: progress_bar.progressable)
|
||||||
|
|
||||||
|
expect(duplicate).not_to be_valid
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "secondary progress bar" do
|
||||||
|
let(:progress_bar) { build(:progress_bar, :secondary) }
|
||||||
|
|
||||||
|
it "is valid" do
|
||||||
|
expect(progress_bar).to be_valid
|
||||||
|
end
|
||||||
|
|
||||||
|
it "is invalid without a title" do
|
||||||
|
progress_bar.title = nil
|
||||||
|
|
||||||
|
expect(progress_bar).not_to be_valid
|
||||||
|
end
|
||||||
|
|
||||||
|
it "can have another secondary progress bar for the same progressable" do
|
||||||
|
progress_bar.save
|
||||||
|
duplicate = build(:progress_bar, progressable: progress_bar.progressable)
|
||||||
|
|
||||||
|
expect(duplicate).to be_valid
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
shared_examples "admin_milestoneable" do |factory_name, path_name|
|
shared_examples "admin_milestoneable" do |factory_name, path_name|
|
||||||
|
it_behaves_like "progressable", factory_name, path_name
|
||||||
|
|
||||||
feature "Admin milestones" do
|
feature "Admin milestones" do
|
||||||
let!(:milestoneable) { create(factory_name) }
|
let!(:milestoneable) { create(factory_name) }
|
||||||
|
|||||||
115
spec/shared/features/progressable.rb
Normal file
115
spec/shared/features/progressable.rb
Normal file
@@ -0,0 +1,115 @@
|
|||||||
|
shared_examples "progressable" do |factory_name, path_name|
|
||||||
|
let!(:progressable) { create(factory_name) }
|
||||||
|
|
||||||
|
feature "Manage progress bars" do
|
||||||
|
let(:progressable_path) { send(path_name, *resource_hierarchy_for(progressable)) }
|
||||||
|
|
||||||
|
let(:path) do
|
||||||
|
polymorphic_path([:admin, *resource_hierarchy_for(progressable.progress_bars.new)])
|
||||||
|
end
|
||||||
|
|
||||||
|
context "Index" do
|
||||||
|
scenario "Link to index path" do
|
||||||
|
create(:progress_bar, :secondary, progressable: progressable,
|
||||||
|
title: "Reading documents",
|
||||||
|
percentage: 20)
|
||||||
|
|
||||||
|
visit progressable_path
|
||||||
|
click_link "Manage progress bars"
|
||||||
|
|
||||||
|
expect(page).to have_content "Reading documents"
|
||||||
|
end
|
||||||
|
|
||||||
|
scenario "No progress bars" do
|
||||||
|
visit path
|
||||||
|
|
||||||
|
expect(page).to have_content("There are no progress bars")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "New" do
|
||||||
|
scenario "Primary progress bar", :js do
|
||||||
|
visit path
|
||||||
|
click_link "Create new progress bar"
|
||||||
|
|
||||||
|
select "Primary", from: "Type"
|
||||||
|
|
||||||
|
expect(page).not_to have_field "Title"
|
||||||
|
|
||||||
|
fill_in "Current progress", with: 43
|
||||||
|
click_button "Create Progress bar"
|
||||||
|
|
||||||
|
expect(page).to have_content "Progress bar created successfully"
|
||||||
|
expect(page).to have_content "43%"
|
||||||
|
expect(page).to have_content "Primary"
|
||||||
|
expect(page).to have_content "Primary progress bar"
|
||||||
|
end
|
||||||
|
|
||||||
|
scenario "Secondary progress bar", :js do
|
||||||
|
visit path
|
||||||
|
click_link "Create new progress bar"
|
||||||
|
|
||||||
|
select "Secondary", from: "Type"
|
||||||
|
fill_in "Current progress", with: 36
|
||||||
|
fill_in "Title", with: "Plant trees"
|
||||||
|
click_button "Create Progress bar"
|
||||||
|
|
||||||
|
expect(page).to have_content "Progress bar created successfully"
|
||||||
|
expect(page).to have_content "36%"
|
||||||
|
expect(page).to have_content "Secondary"
|
||||||
|
expect(page).to have_content "Plant trees"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "Edit" do
|
||||||
|
scenario "Primary progress bar", :js do
|
||||||
|
bar = create(:progress_bar, progressable: progressable)
|
||||||
|
|
||||||
|
visit path
|
||||||
|
within("#progress_bar_#{bar.id}") { click_link "Edit" }
|
||||||
|
|
||||||
|
expect(page).to have_field "Current progress"
|
||||||
|
expect(page).not_to have_field "Title"
|
||||||
|
|
||||||
|
fill_in "Current progress", with: 44
|
||||||
|
click_button "Update Progress bar"
|
||||||
|
|
||||||
|
expect(page).to have_content "Progress bar updated successfully"
|
||||||
|
|
||||||
|
within("#progress_bar_#{bar.id}") do
|
||||||
|
expect(page).to have_content "44%"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
scenario "Secondary progress bar", :js do
|
||||||
|
bar = create(:progress_bar, :secondary, progressable: progressable)
|
||||||
|
|
||||||
|
visit path
|
||||||
|
within("#progress_bar_#{bar.id}") { click_link "Edit" }
|
||||||
|
|
||||||
|
fill_in "Current progress", with: 76
|
||||||
|
fill_in "Title", with: "Updated title"
|
||||||
|
click_button "Update Progress bar"
|
||||||
|
|
||||||
|
expect(page).to have_content "Progress bar updated successfully"
|
||||||
|
|
||||||
|
within("#progress_bar_#{bar.id}") do
|
||||||
|
expect(page).to have_content "76%"
|
||||||
|
expect(page).to have_content "Updated title"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "Delete" do
|
||||||
|
scenario "Remove progress bar" do
|
||||||
|
bar = create(:progress_bar, progressable: progressable, percentage: 34)
|
||||||
|
|
||||||
|
visit path
|
||||||
|
within("#progress_bar_#{bar.id}") { click_link "Delete" }
|
||||||
|
|
||||||
|
expect(page).to have_content "Progress bar deleted successfully"
|
||||||
|
expect(page).not_to have_content "34%"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
Reference in New Issue
Block a user