Merge branch 'master' into add_cards_to_custom_pages
This commit is contained in:
25
CHANGELOG.md
25
CHANGELOG.md
@@ -3,6 +3,30 @@
|
||||
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
|
||||
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html)
|
||||
|
||||
## [0.18.1](https://github.com/consul/consul/tree/v0.18.1) (2019-01-17)
|
||||
|
||||
### Added
|
||||
|
||||
- **Legislation:** Legislation process homepage phase [\#3188](https://github.com/consul/consul/pull/3188)
|
||||
- **Legislation:** Show documents on processes proposals phase [\#3136](https://github.com/consul/consul/pull/3136)
|
||||
- **Maintenance-Refactorings:** Remove semicolons from controllers [\#3160](https://github.com/consul/consul/pull/3160)
|
||||
- **Maintenance-Refactorings:** Remove before action not used [\#3167](https://github.com/consul/consul/pull/3167)
|
||||
- **Maintenance-Rubocop:** Enable double quotes rubocop rule [\#3175](https://github.com/consul/consul/pull/3175)
|
||||
- **Maintenance-Rubocop:** Enable line length rubocop rule [\#3165](https://github.com/consul/consul/pull/3165)
|
||||
- **Maintenance-Rubocop:** Add rubocop rule to indent private methods [\#3134](https://github.com/consul/consul/pull/3134)
|
||||
|
||||
### Changed
|
||||
|
||||
- **Admin:** Improve CRUD budgets and content blocks [\#3173](https://github.com/consul/consul/pull/3173)
|
||||
- **Design/UX:** new CRUD budgets, content blocks and heading map [\#3150](https://github.com/consul/consul/pull/3150)
|
||||
- **Design/UX:** Processes key dates [\#3137](https://github.com/consul/consul/pull/3137)
|
||||
|
||||
### Fixed
|
||||
|
||||
- **Admin:** checks for deleted proposals [\#3154](https://github.com/consul/consul/pull/3154)
|
||||
- **Admin:** Add default order for admin budget investments list [\#3151](https://github.com/consul/consul/pull/3151)
|
||||
- **Budgets:** Bug Management Cannot create Budget Investment without a map location [\#3133](https://github.com/consul/consul/pull/3133)
|
||||
|
||||
## [0.18.0](https://github.com/consul/consul/compare/v0.17...v0.18) (2018-12-27)
|
||||
|
||||
### Added
|
||||
@@ -47,6 +71,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
|
||||
- **Admin:** Improve visualization for small resolution [\#3025](https://github.com/consul/consul/pull/3025)
|
||||
- **Admin:** Budgets admin [\#3012](https://github.com/consul/consul/pull/3012)
|
||||
- **Budgets:** Budget investments social share [\#3053](https://github.com/consul/consul/pull/3053)
|
||||
- **Design/UX:** Documents title [\#3131](https://github.com/consul/consul/pull/3131)
|
||||
- **Design/UX:** Proposal create question [\#3122](https://github.com/consul/consul/pull/3122)
|
||||
- **Design/UX:** Budget investments price explanation [\#3121](https://github.com/consul/consul/pull/3121)
|
||||
- **Design/UX:** Change CRUD for budget groups and headings [\#3106](https://github.com/consul/consul/pull/3106)
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 47 KiB After Width: | Height: | Size: 85 KiB |
@@ -23,8 +23,29 @@ App.Forms =
|
||||
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: ->
|
||||
App.Forms.disableEnter()
|
||||
App.Forms.submitOnChange()
|
||||
App.Forms.toggleLink()
|
||||
App.Forms.synchronizeInputs()
|
||||
App.Forms.hideOrShowFieldsAfterSelection()
|
||||
false
|
||||
|
||||
@@ -251,6 +251,13 @@ $sidebar-active: #f4fcd0;
|
||||
max-width: none;
|
||||
}
|
||||
|
||||
form {
|
||||
|
||||
.input-group-label {
|
||||
height: $line-height * 2;
|
||||
}
|
||||
}
|
||||
|
||||
.menu.simple {
|
||||
margin-bottom: $line-height / 2;
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
@import 'admin';
|
||||
@import 'layout';
|
||||
@import 'participation';
|
||||
@import 'milestones';
|
||||
@import 'pages';
|
||||
@import 'legislation';
|
||||
@import 'legislation_process';
|
||||
|
||||
95
app/assets/stylesheets/milestones.scss
Normal file
95
app/assets/stylesheets/milestones.scss
Normal file
@@ -0,0 +1,95 @@
|
||||
.tab-milestones ul {
|
||||
margin-top: rem-calc(40);
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.tab-milestones .timeline li {
|
||||
margin: 0 auto;
|
||||
position: relative;
|
||||
width: 0;
|
||||
|
||||
@include breakpoint(small only) {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
&::before {
|
||||
background: $budget;
|
||||
border-radius: rem-calc(20);
|
||||
content: '';
|
||||
height: rem-calc(20);
|
||||
position: absolute;
|
||||
top: 5px;
|
||||
transform: translateX(-50%);
|
||||
width: rem-calc(20);
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
&::after {
|
||||
background: $light-gray;
|
||||
bottom: 100%;
|
||||
content: '';
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
top: 25px;
|
||||
width: 1px;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.milestone-content {
|
||||
padding: $line-height / 6 $line-height / 2;
|
||||
position: relative;
|
||||
|
||||
@include breakpoint(medium) {
|
||||
width: rem-calc(300);
|
||||
}
|
||||
|
||||
@include breakpoint(large) {
|
||||
width: rem-calc(450);
|
||||
}
|
||||
|
||||
h3 {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.milestone-date {
|
||||
color: $text-medium;
|
||||
font-size: $small-font-size;
|
||||
}
|
||||
}
|
||||
|
||||
&:nth-child(odd) {
|
||||
|
||||
.milestone-content {
|
||||
text-align: right;
|
||||
|
||||
@include breakpoint(medium) {
|
||||
margin-left: rem-calc(-315);
|
||||
}
|
||||
|
||||
@include breakpoint(large) {
|
||||
margin-left: rem-calc(-465);
|
||||
}
|
||||
|
||||
@include breakpoint(small only) {
|
||||
left: 15px;
|
||||
text-align: left;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&:nth-child(even) {
|
||||
|
||||
.milestone-content {
|
||||
left: 15px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.milestone-status {
|
||||
background: $budget;
|
||||
border-radius: rem-calc(4);
|
||||
color: #fff;
|
||||
display: inline-block;
|
||||
margin-top: $line-height / 6;
|
||||
padding: $line-height / 4 $line-height / 2;
|
||||
}
|
||||
@@ -523,118 +523,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
.tab-milestones ul {
|
||||
margin-top: rem-calc(40);
|
||||
position: relative;
|
||||
|
||||
li {
|
||||
margin: 0 auto;
|
||||
position: relative;
|
||||
width: 0;
|
||||
}
|
||||
|
||||
li::before {
|
||||
background: $budget;
|
||||
border-radius: rem-calc(20);
|
||||
content: '';
|
||||
height: rem-calc(20);
|
||||
position: absolute;
|
||||
top: 5px;
|
||||
transform: translateX(-50%);
|
||||
width: rem-calc(20);
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
li::after {
|
||||
background: $light-gray;
|
||||
bottom: 100%;
|
||||
content: '';
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
top: 25px;
|
||||
width: 1px;
|
||||
z-index: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.tab-milestones ul .milestone-content {
|
||||
padding: $line-height / 6 $line-height / 2;
|
||||
position: relative;
|
||||
|
||||
h3 {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.milestone-date {
|
||||
color: $text-medium;
|
||||
font-size: $small-font-size;
|
||||
}
|
||||
}
|
||||
|
||||
.tab-milestones .timeline ul li:nth-child(odd),
|
||||
.tab-milestones .timeline ul li:nth-child(even) {
|
||||
|
||||
.milestone-content {
|
||||
|
||||
@include breakpoint(medium) {
|
||||
width: rem-calc(300);
|
||||
}
|
||||
|
||||
@include breakpoint(large) {
|
||||
width: rem-calc(450);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.tab-milestones .timeline ul li:nth-child(odd) {
|
||||
|
||||
.milestone-content {
|
||||
text-align: right;
|
||||
|
||||
@include breakpoint(medium) {
|
||||
margin-left: rem-calc(-315);
|
||||
}
|
||||
|
||||
@include breakpoint(large) {
|
||||
margin-left: rem-calc(-465);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.tab-milestones .timeline ul li:nth-child(even) {
|
||||
|
||||
.milestone-content {
|
||||
left: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
.tab-milestones {
|
||||
@include breakpoint(small only) {
|
||||
|
||||
.timeline ul li {
|
||||
width: 100%;
|
||||
|
||||
&:nth-child(odd),
|
||||
&:nth-child(even) {
|
||||
|
||||
.milestone-content {
|
||||
left: 15px;
|
||||
text-align: left;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.milestone-status {
|
||||
background: $budget;
|
||||
border-radius: rem-calc(4);
|
||||
color: #fff;
|
||||
display: inline-block;
|
||||
margin-top: $line-height / 6;
|
||||
padding: $line-height / 4 $line-height / 2;
|
||||
}
|
||||
|
||||
.show-actions-menu {
|
||||
|
||||
[class^="icon-"] {
|
||||
|
||||
@@ -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
|
||||
@@ -11,7 +11,7 @@ class DocumentsController < ApplicationController
|
||||
else
|
||||
flash[:alert] = t "documents.actions.destroy.alert"
|
||||
end
|
||||
redirect_to params[:from]
|
||||
redirect_to request.referer
|
||||
end
|
||||
format.js do
|
||||
if @document.destroy
|
||||
|
||||
@@ -12,7 +12,7 @@ class InstallationController < ApplicationController
|
||||
|
||||
def consul_installation_details
|
||||
{
|
||||
release: 'v0.18'
|
||||
release: "v0.18.1"
|
||||
}.merge(features: settings_feature_flags)
|
||||
end
|
||||
|
||||
|
||||
@@ -49,4 +49,19 @@ module PollsHelper
|
||||
question.answers.where(author: current_user).any? { |vote| current_user.current_sign_in_at > vote.updated_at }
|
||||
end
|
||||
|
||||
def show_stats_or_results?
|
||||
@poll.expired? && (@poll.results_enabled? || @poll.stats_enabled?)
|
||||
end
|
||||
|
||||
def results_menu?
|
||||
controller_name == "polls" && action_name == "results"
|
||||
end
|
||||
|
||||
def stats_menu?
|
||||
controller_name == "polls" && action_name == "stats"
|
||||
end
|
||||
|
||||
def info_menu?
|
||||
controller_name == "polls" && action_name == "show"
|
||||
end
|
||||
end
|
||||
|
||||
@@ -93,6 +93,7 @@ module Abilities
|
||||
cannot :comment_as_moderator, [::Legislation::Question, Legislation::Annotation, ::Legislation::Proposal]
|
||||
|
||||
can [:create], Document
|
||||
can [:destroy], Document, documentable_type: "Poll::Question::Answer"
|
||||
can [:create, :destroy], DirectUpload
|
||||
|
||||
can [:deliver], Newsletter, hidden_at: nil
|
||||
|
||||
@@ -5,5 +5,7 @@ module Milestoneable
|
||||
has_many :milestones, as: :milestoneable, dependent: :destroy
|
||||
|
||||
scope :with_milestones, -> { joins(:milestones).distinct }
|
||||
|
||||
has_many :progress_bars, as: :progressable
|
||||
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
|
||||
@@ -4,13 +4,14 @@ class SiteCustomization::Image < ActiveRecord::Base
|
||||
"social_media_icon" => [470, 246],
|
||||
"social_media_icon_twitter" => [246, 246],
|
||||
"apple-touch-icon-200" => [200, 200],
|
||||
"budget_execution_no_image" => [800, 600]
|
||||
"budget_execution_no_image" => [800, 600],
|
||||
"map" => [420, 500]
|
||||
}
|
||||
|
||||
has_attached_file :image
|
||||
|
||||
validates :name, presence: true, uniqueness: true, inclusion: { in: VALID_IMAGES.keys }
|
||||
validates_attachment_content_type :image, content_type: ["image/png"]
|
||||
validates_attachment_content_type :image, content_type: ["image/png", "image/jpeg"]
|
||||
validate :check_image
|
||||
|
||||
def self.all_images
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
<div class="margin-top">
|
||||
<div class="small-12 medium-6 column">
|
||||
<%= f.select :phase, budget_phases_select_options, selected: "drafting" %>
|
||||
<%= f.select :phase, budget_phases_select_options %>
|
||||
</div>
|
||||
<div class="small-12 medium-3 column end">
|
||||
<%= f.select :currency_symbol, budget_currency_symbol_select_options %>
|
||||
|
||||
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? %>
|
||||
<table>
|
||||
|
||||
@@ -14,19 +14,13 @@
|
||||
|
||||
<%= render 'shared/errors', resource: @answer %>
|
||||
|
||||
<div class="row">
|
||||
<div class="small-12 column">
|
||||
<div class="documents small-12">
|
||||
<div class="documents">
|
||||
<%= render 'documents/nested_documents', documentable: @answer, f: f %>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="actions small-12 medium-4 margin-top">
|
||||
<div class="small-12 medium-6 large-2">
|
||||
<%= f.submit(class: "button expanded", value: t("shared.save")) %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<% if @answer.documents.present? %>
|
||||
@@ -42,11 +36,17 @@
|
||||
<%= link_to document.title, document.attachment.url %>
|
||||
</td>
|
||||
<td class="text-right">
|
||||
<%= link_to t('documents.buttons.download_document'),
|
||||
<%= link_to t("documents.buttons.download_document"),
|
||||
document.attachment.url,
|
||||
target: "_blank",
|
||||
rel: "nofollow",
|
||||
class: 'button hollow' %>
|
||||
class: "button hollow" %>
|
||||
|
||||
<%= link_to t("admin.shared.delete"),
|
||||
document_path(document),
|
||||
method: :delete,
|
||||
class: "button hollow alert",
|
||||
data: { confirm: t("admin.actions.confirm") } %>
|
||||
</td>
|
||||
</tr>
|
||||
<% end %>
|
||||
|
||||
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" %>
|
||||
@@ -9,7 +9,7 @@
|
||||
</thead>
|
||||
<tbody>
|
||||
<% @images.each do |image| %>
|
||||
<tr class="<%= image.name %>">
|
||||
<tr id="image_<%= image.name %>">
|
||||
<td class="small-12 medium-4">
|
||||
<strong><%= image.name %></strong> (<%= image.required_width %>x<%= image.required_height %>)
|
||||
</td>
|
||||
|
||||
@@ -13,7 +13,8 @@
|
||||
<% if can?(:destroy, document) %>
|
||||
<br>
|
||||
<%= link_to t("documents.buttons.destroy_document"),
|
||||
document_path(document, from: request.url), method: :delete,
|
||||
document,
|
||||
method: :delete,
|
||||
data: { confirm: t("documents.actions.destroy.confirm") },
|
||||
class: "delete" %>
|
||||
<% end %>
|
||||
|
||||
@@ -1,24 +1,10 @@
|
||||
<div class="proposal-form row">
|
||||
|
||||
<div class="small-12 medium-9 column">
|
||||
<div class="small-12 column">
|
||||
<%= back_link_to %>
|
||||
|
||||
<h1><%= t("proposals.new.start_new") %></h1>
|
||||
<div data-alert class="callout primary">
|
||||
<%= link_to help_path(anchor: "proposals"), title: t('shared.target_blank_html'), target: "_blank" do %>
|
||||
<%= t("proposals.new.more_info")%>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<%= render "legislation/proposals/form", form_url: legislation_process_proposals_url, id: @proposal.id %>
|
||||
</div>
|
||||
|
||||
<div class="small-12 medium-3 column">
|
||||
<span class="icon-proposals float-right"></span>
|
||||
<h2><%= t("proposals.new.recommendations_title") %></h2>
|
||||
<ul class="recommendations">
|
||||
<li><%= t("proposals.new.recommendation_one") %></li>
|
||||
<li><%= t("proposals.new.recommendation_two") %></li>
|
||||
<li><%= t("proposals.new.recommendation_three") %></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
<% if current_user && current_user.administrator? ||
|
||||
(@poll.expired? && (@poll.results_enabled? || @poll.stats_enabled?)) %>
|
||||
<% if show_stats_or_results? %>
|
||||
<div class="row margin-top">
|
||||
<div class="small-12 column">
|
||||
<ul class="menu simple clear">
|
||||
<% if current_user && current_user.administrator? || @poll.results_enabled? %>
|
||||
<% if controller_name == "polls" && action_name == "results" %>
|
||||
<% if @poll.results_enabled? %>
|
||||
<% if results_menu? %>
|
||||
<li class="is-active">
|
||||
<h2><%= t("polls.show.results_menu") %></h2>
|
||||
</li>
|
||||
@@ -13,8 +12,8 @@
|
||||
<% end %>
|
||||
<% end %>
|
||||
|
||||
<% if current_user && current_user.administrator? || @poll.stats_enabled? %>
|
||||
<% if controller_name == "polls" && action_name == "stats" %>
|
||||
<% if @poll.stats_enabled? %>
|
||||
<% if stats_menu? %>
|
||||
<li class="is-active">
|
||||
<h2><%= t("polls.show.stats_menu") %></h2>
|
||||
</li>
|
||||
@@ -23,7 +22,7 @@
|
||||
<% end %>
|
||||
<% end %>
|
||||
|
||||
<% if controller_name == "polls" && action_name == "show" %>
|
||||
<% if info_menu? %>
|
||||
<li class="is-active">
|
||||
<h2><%= t("polls.show.info_menu") %></h2>
|
||||
</li>
|
||||
|
||||
@@ -2,5 +2,5 @@
|
||||
<h2 class="sidebar-title"><%= t("shared.tags_cloud.districts") %></h2>
|
||||
<br>
|
||||
<%= link_to map_proposals_path, id: 'map', title: t("shared.tags_cloud.districts_list") do %>
|
||||
<%= image_tag("map.jpg", alt: t("shared.tags_cloud.districts_list")) %>
|
||||
<%= image_tag(image_path_for("map.jpg"), alt: t("shared.tags_cloud.districts_list")) %>
|
||||
<% end %>
|
||||
|
||||
@@ -5,5 +5,13 @@ module FoundationRailsHelper
|
||||
super(attribute, opts)
|
||||
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
|
||||
|
||||
@@ -9,6 +9,8 @@ module ActionDispatch::Routing::UrlFor
|
||||
[resource.budget, resource]
|
||||
when "Milestone"
|
||||
[*resource_hierarchy_for(resource.milestoneable), resource]
|
||||
when "ProgressBar"
|
||||
[*resource_hierarchy_for(resource.progressable), resource]
|
||||
when "Legislation::Annotation"
|
||||
[resource.draft_version.process, resource.draft_version, resource]
|
||||
when "Legislation::Proposal", "Legislation::Question", "Legislation::DraftVersion"
|
||||
|
||||
@@ -16,6 +16,9 @@ en:
|
||||
milestone/status:
|
||||
one: "Milestone Status"
|
||||
other: "Milestone Statuses"
|
||||
progress_bar:
|
||||
one: "Progress bar"
|
||||
other: "Progress bars"
|
||||
comment:
|
||||
one: "Comment"
|
||||
other: "Comments"
|
||||
@@ -136,6 +139,13 @@ en:
|
||||
milestone/status:
|
||||
name: "Name"
|
||||
description: "Description (optional)"
|
||||
progress_bar:
|
||||
kind: "Type"
|
||||
title: "Title"
|
||||
percentage: "Current progress"
|
||||
progress_bar/kind:
|
||||
primary: "Primary"
|
||||
secondary: "Secondary"
|
||||
budget/heading:
|
||||
name: "Heading name"
|
||||
price: "Price"
|
||||
@@ -355,7 +365,7 @@ en:
|
||||
proposal_notification:
|
||||
attributes:
|
||||
minimum_interval:
|
||||
invalid: "You have to wait a minium of %{interval} days between notifications"
|
||||
invalid: "You have to wait a minimum of %{interval} days between notifications"
|
||||
signature:
|
||||
attributes:
|
||||
document_number:
|
||||
|
||||
@@ -332,6 +332,29 @@ en:
|
||||
notice: Milestone status created successfully
|
||||
delete:
|
||||
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:
|
||||
index:
|
||||
filter: Filter
|
||||
@@ -1164,6 +1187,7 @@ en:
|
||||
author: Author
|
||||
content: Content
|
||||
created_at: Created at
|
||||
delete: Delete
|
||||
spending_proposals:
|
||||
index:
|
||||
geozone_filter_all: All zones
|
||||
|
||||
@@ -16,6 +16,9 @@ es:
|
||||
milestone/status:
|
||||
one: "Estado de seguimiento"
|
||||
other: "Estados de seguimiento"
|
||||
progress_bar:
|
||||
one: "Barra de progreso"
|
||||
other: "Barras de progreso"
|
||||
comment:
|
||||
one: "Comentario"
|
||||
other: "Comentarios"
|
||||
@@ -136,6 +139,13 @@ es:
|
||||
milestone/status:
|
||||
name: "Nombre"
|
||||
description: "Descripción (opcional)"
|
||||
progress_bar:
|
||||
kind: "Tipo"
|
||||
title: "Título"
|
||||
percentage: "Progreso"
|
||||
progress_bar/kind:
|
||||
primary: "Principal"
|
||||
secondary: "Secundaria"
|
||||
budget/heading:
|
||||
name: "Nombre de la partida"
|
||||
price: "Cantidad"
|
||||
|
||||
@@ -332,6 +332,30 @@ es:
|
||||
notice: Estado de seguimiento creado correctamente
|
||||
delete:
|
||||
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:
|
||||
index:
|
||||
filter: Filtro
|
||||
@@ -1163,6 +1187,7 @@ es:
|
||||
author: Autor
|
||||
content: Contenido
|
||||
created_at: Fecha de creación
|
||||
delete: Eliminar
|
||||
spending_proposals:
|
||||
index:
|
||||
geozone_filter_all: Todos los ámbitos de actuación
|
||||
|
||||
@@ -135,8 +135,8 @@ es:
|
||||
already_supported: Ya has apoyado este proyecto de inversión. ¡Compártelo!
|
||||
support_title: Apoyar este proyecto
|
||||
confirm_group:
|
||||
one: "Sólo puedes apoyar proyectos en %{count} distrito. Si sigues adelante no podrás cambiar la elección de este distrito. ¿Estás seguro?"
|
||||
other: "Sólo puedes apoyar proyectos en %{count} distritos. Si sigues adelante no podrás cambiar la elección de este distrito. ¿Estás seguro?"
|
||||
one: "Sólo puedes apoyar proyectos en %{count} distrito. Si sigues adelante no podrás cambiar la elección de este distrito. ¿Estás seguro/a?"
|
||||
other: "Sólo puedes apoyar proyectos en %{count} distritos. Si sigues adelante no podrás cambiar la elección de este distrito. ¿Estás seguro/a?"
|
||||
supports:
|
||||
zero: Sin apoyos
|
||||
one: 1 apoyo
|
||||
|
||||
@@ -31,6 +31,7 @@ namespace :admin do
|
||||
|
||||
resources :proposals, only: [:index, :show] do
|
||||
resources :milestones, controller: "proposal_milestones"
|
||||
resources :progress_bars, except: :show, controller: "proposal_progress_bars"
|
||||
end
|
||||
|
||||
resources :hidden_proposals, only: :index do
|
||||
@@ -67,6 +68,7 @@ namespace :admin do
|
||||
|
||||
resources :budget_investments, only: [:index, :show, :edit, :update] do
|
||||
resources :milestones, controller: 'budget_investment_milestones'
|
||||
resources :progress_bars, except: :show, controller: "budget_investment_progress_bars"
|
||||
member { patch :toggle_selection }
|
||||
end
|
||||
|
||||
@@ -203,6 +205,7 @@ namespace :admin do
|
||||
end
|
||||
resources :draft_versions
|
||||
resources :milestones
|
||||
resources :progress_bars, except: :show
|
||||
resource :homepage, only: [:edit, :update]
|
||||
end
|
||||
end
|
||||
|
||||
@@ -15,6 +15,10 @@ def log(msg)
|
||||
@logger.info "#{msg}\n"
|
||||
end
|
||||
|
||||
def random_locales
|
||||
[I18n.default_locale, *I18n.available_locales.sample(4)].uniq
|
||||
end
|
||||
|
||||
require_relative 'dev_seeds/settings'
|
||||
require_relative 'dev_seeds/geozones'
|
||||
require_relative 'dev_seeds/users'
|
||||
|
||||
@@ -6,7 +6,7 @@ section "Creating default Milestone Statuses" do
|
||||
end
|
||||
|
||||
section "Creating investment milestones" do
|
||||
[Budget::Investment, Proposal].each do |model|
|
||||
[Budget::Investment, Proposal, Legislation::Process].each do |model|
|
||||
model.find_each do |record|
|
||||
rand(1..5).times do
|
||||
milestone = record.milestones.build(
|
||||
@@ -14,7 +14,7 @@ section "Creating investment milestones" do
|
||||
status_id: Milestone::Status.all.sample
|
||||
)
|
||||
|
||||
I18n.available_locales.map do |locale|
|
||||
random_locales.map do |locale|
|
||||
Globalize.with_locale(locale) do
|
||||
milestone.description = "Description for locale #{locale}"
|
||||
milestone.title = I18n.l(Time.current, format: :datetime)
|
||||
@@ -22,7 +22,24 @@ section "Creating investment milestones" do
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if rand < 0.8
|
||||
record.progress_bars.create!(kind: :primary, percentage: rand(ProgressBar::RANGE))
|
||||
end
|
||||
|
||||
rand(0..3).times do
|
||||
progress_bar = record.progress_bars.build(
|
||||
kind: :secondary,
|
||||
percentage: rand(ProgressBar::RANGE)
|
||||
)
|
||||
|
||||
random_locales.map do |locale|
|
||||
Globalize.with_locale(locale) do
|
||||
progress_bar.title = "Description for locale #{locale}"
|
||||
progress_bar.save!
|
||||
end
|
||||
end
|
||||
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.
|
||||
|
||||
ActiveRecord::Schema.define(version: 20181218164126) do
|
||||
ActiveRecord::Schema.define(version: 20190103132925) do
|
||||
|
||||
# These are extensions that must be enabled in order to support this database
|
||||
enable_extension "plpgsql"
|
||||
@@ -1088,6 +1088,26 @@ ActiveRecord::Schema.define(version: 20181218164126) do
|
||||
|
||||
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|
|
||||
t.string "title"
|
||||
t.text "body"
|
||||
|
||||
@@ -195,19 +195,6 @@ FactoryBot.define do
|
||||
reason "unfeasible"
|
||||
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
|
||||
sequence(:name) { |n| "Valuator Group #{n}" }
|
||||
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
|
||||
@@ -144,9 +144,13 @@ feature 'Admin budgets' do
|
||||
let!(:budget) { create(:budget) }
|
||||
|
||||
scenario 'Show phases table' do
|
||||
budget.update(phase: "selecting")
|
||||
|
||||
visit admin_budgets_path
|
||||
click_link 'Edit budget'
|
||||
|
||||
expect(page).to have_select("budget_phase", selected: "Selecting projects")
|
||||
|
||||
within '#budget-phases-table' do
|
||||
|
||||
Budget::Phase::PHASE_KINDS.each do |phase_kind|
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
require "rails_helper"
|
||||
|
||||
feature "Documents" do
|
||||
|
||||
background do
|
||||
admin = create(:administrator)
|
||||
login_as(admin.user)
|
||||
end
|
||||
|
||||
context "Index" do
|
||||
scenario "Answer with no documents" do
|
||||
answer = create(:poll_question_answer, question: create(:poll_question))
|
||||
document = create(:document)
|
||||
|
||||
visit admin_answer_documents_path(answer)
|
||||
|
||||
expect(page).not_to have_content(document.title)
|
||||
end
|
||||
|
||||
scenario "Answer with documents" do
|
||||
answer = create(:poll_question_answer, question: create(:poll_question))
|
||||
document = create(:document, documentable: answer)
|
||||
|
||||
visit admin_answer_documents_path(answer)
|
||||
|
||||
expect(page).to have_content(document.title)
|
||||
end
|
||||
end
|
||||
|
||||
scenario "Remove document from answer", :js do
|
||||
answer = create(:poll_question_answer, question: create(:poll_question))
|
||||
document = create(:document, documentable: answer)
|
||||
|
||||
visit admin_answer_documents_path(answer)
|
||||
expect(page).to have_content(document.title)
|
||||
|
||||
accept_confirm "Are you sure?" do
|
||||
click_link "Delete"
|
||||
end
|
||||
|
||||
expect(page).not_to have_content(document.title)
|
||||
end
|
||||
|
||||
end
|
||||
@@ -7,22 +7,57 @@ feature "Admin custom images" do
|
||||
login_as(admin.user)
|
||||
end
|
||||
|
||||
scenario "Upload valid image" do
|
||||
scenario "Upload valid png image" do
|
||||
visit admin_root_path
|
||||
|
||||
within("#side_menu") do
|
||||
click_link "Custom images"
|
||||
end
|
||||
|
||||
within("tr.logo_header") do
|
||||
within("tr#image_logo_header") do
|
||||
attach_file "site_customization_image_image", "spec/fixtures/files/logo_header.png"
|
||||
click_button "Update"
|
||||
end
|
||||
|
||||
expect(page).to have_css("tr.logo_header img[src*='logo_header.png']")
|
||||
expect(page).to have_css("tr#image_logo_header img[src*='logo_header.png']")
|
||||
expect(page).to have_css("img[src*='logo_header.png']", count: 1)
|
||||
end
|
||||
|
||||
scenario "Upload valid jpg image" do
|
||||
visit admin_root_path
|
||||
|
||||
within("#side_menu") do
|
||||
click_link "Custom images"
|
||||
end
|
||||
|
||||
within("tr#image_map") do
|
||||
attach_file "site_customization_image_image", "spec/fixtures/files/custom_map.jpg"
|
||||
click_button "Update"
|
||||
end
|
||||
|
||||
expect(page).to have_css("tr#image_map img[src*='custom_map.jpg']")
|
||||
expect(page).to have_css("img[src*='custom_map.jpg']", count: 1)
|
||||
end
|
||||
|
||||
scenario "Image is replaced on front view" do
|
||||
visit admin_root_path
|
||||
|
||||
within("#side_menu") do
|
||||
click_link "Custom images"
|
||||
end
|
||||
|
||||
within("tr#image_map") do
|
||||
attach_file "site_customization_image_image", "spec/fixtures/files/custom_map.jpg"
|
||||
click_button "Update"
|
||||
end
|
||||
|
||||
visit proposals_path
|
||||
|
||||
within("#map") do
|
||||
expect(page).to have_css("img[src*='custom_map.jpg']")
|
||||
end
|
||||
end
|
||||
|
||||
scenario "Upload invalid image" do
|
||||
visit admin_root_path
|
||||
|
||||
@@ -30,7 +65,7 @@ feature "Admin custom images" do
|
||||
click_link "Custom images"
|
||||
end
|
||||
|
||||
within("tr.social_media_icon") do
|
||||
within("tr#image_social_media_icon") do
|
||||
attach_file "site_customization_image_image", "spec/fixtures/files/logo_header.png"
|
||||
click_button "Update"
|
||||
end
|
||||
@@ -46,14 +81,14 @@ feature "Admin custom images" do
|
||||
click_link "Custom images"
|
||||
end
|
||||
|
||||
within("tr.social_media_icon") do
|
||||
within("tr#image_social_media_icon") do
|
||||
attach_file "site_customization_image_image", "spec/fixtures/files/social_media_icon.png"
|
||||
click_button "Update"
|
||||
end
|
||||
|
||||
expect(page).to have_css("img[src*='social_media_icon.png']")
|
||||
|
||||
within("tr.social_media_icon") do
|
||||
within("tr#image_social_media_icon") do
|
||||
click_link "Delete"
|
||||
end
|
||||
|
||||
|
||||
@@ -474,21 +474,28 @@ feature 'Polls' do
|
||||
expect(page).to have_content("You do not have permission to carry out the action 'stats' on poll.")
|
||||
end
|
||||
|
||||
scenario "Show poll results and stats if user is administrator" do
|
||||
poll = create(:poll, :current, results_enabled: false, stats_enabled: false)
|
||||
user = create(:administrator).user
|
||||
scenario "Do not show poll results or stats if are disabled" do
|
||||
poll = create(:poll, :expired, results_enabled: false, stats_enabled: false)
|
||||
question1 = create(:poll_question, poll: poll)
|
||||
create(:poll_question_answer, question: question1, title: "Han Solo")
|
||||
create(:poll_question_answer, question: question1, title: "Chewbacca")
|
||||
question2 = create(:poll_question, poll: poll)
|
||||
create(:poll_question_answer, question: question2, title: "Leia")
|
||||
create(:poll_question_answer, question: question2, title: "Luke")
|
||||
user = create(:user)
|
||||
admin = create(:administrator).user
|
||||
|
||||
login_as user
|
||||
visit poll_path(poll)
|
||||
|
||||
expect(page).to have_content("Poll results")
|
||||
expect(page).to have_content("Participation statistics")
|
||||
expect(page).not_to have_content("Poll results")
|
||||
expect(page).not_to have_content("Participation statistics")
|
||||
|
||||
visit results_poll_path(poll)
|
||||
expect(page).to have_content("Questions")
|
||||
login_as admin
|
||||
visit poll_path(poll)
|
||||
|
||||
visit stats_poll_path(poll)
|
||||
expect(page).to have_content("Participation data")
|
||||
expect(page).not_to have_content("Poll results")
|
||||
expect(page).not_to have_content("Participation statistics")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -422,8 +422,53 @@ feature 'Proposal Notifications' do
|
||||
|
||||
context "Limits" do
|
||||
|
||||
pending "Cannot send more than one notification within established interval"
|
||||
pending "use timecop to make sure notifications can be sent after time interval"
|
||||
scenario "Cannot send more than one notification within established interval" do
|
||||
author = create(:user)
|
||||
proposal = create(:proposal, author: author)
|
||||
|
||||
login_as author.reload
|
||||
|
||||
visit new_proposal_notification_path(proposal_id: proposal.id)
|
||||
fill_in "Title", with: "Thank you for supporting my proposal"
|
||||
fill_in "Message", with: "Please share it with others so we can make it happen!"
|
||||
click_button "Send message"
|
||||
|
||||
expect(page).to have_content "Your message has been sent correctly."
|
||||
|
||||
visit new_proposal_notification_path(proposal_id: proposal.id)
|
||||
fill_in "Title", with: "Thank you again for supporting my proposal"
|
||||
fill_in "Message", with: "Please share it again with others so we can make it happen!"
|
||||
click_button "Send message"
|
||||
|
||||
expect(page).to have_content "You have to wait a minimum of 3 days between notifications"
|
||||
expect(page).not_to have_content "Your message has been sent correctly."
|
||||
end
|
||||
|
||||
scenario "Use time traveling to make sure notifications can be sent after time interval" do
|
||||
author = create(:user)
|
||||
proposal = create(:proposal, author: author)
|
||||
|
||||
login_as author.reload
|
||||
|
||||
visit new_proposal_notification_path(proposal_id: proposal.id)
|
||||
fill_in "Title", with: "Thank you for supporting my proposal"
|
||||
fill_in "Message", with: "Please share it with others so we can make it happen!"
|
||||
click_button "Send message"
|
||||
|
||||
expect(page).to have_content "Your message has been sent correctly."
|
||||
|
||||
travel 3.days + 1.second
|
||||
|
||||
visit new_proposal_notification_path(proposal_id: proposal.id)
|
||||
fill_in "Title", with: "Thank you again for supporting my proposal"
|
||||
fill_in "Message", with: "Please share it again with others so we can make it happen!"
|
||||
click_button "Send message"
|
||||
|
||||
expect(page).to have_content "Your message has been sent correctly."
|
||||
expect(page).not_to have_content "You have to wait a minimum of 3 days between notifications"
|
||||
|
||||
travel_back
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
BIN
spec/fixtures/files/custom_map.jpg
vendored
Normal file
BIN
spec/fixtures/files/custom_map.jpg
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 86 KiB |
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
|
||||
@@ -50,7 +50,7 @@ describe ProposalNotification do
|
||||
Setting[:proposal_notification_minimum_interval_in_days] = 3
|
||||
end
|
||||
|
||||
it "is not valid if below minium interval" do
|
||||
it "is not valid if below minimum interval" do
|
||||
proposal = create(:proposal)
|
||||
|
||||
notification1 = create(:proposal_notification, proposal: proposal)
|
||||
@@ -60,7 +60,7 @@ describe ProposalNotification do
|
||||
expect(notification2).not_to be_valid
|
||||
end
|
||||
|
||||
it "is valid if notifications above minium interval" do
|
||||
it "is valid if notifications above minimum interval" do
|
||||
proposal = create(:proposal)
|
||||
|
||||
notification1 = create(:proposal_notification, proposal: proposal, created_at: 4.days.ago)
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
shared_examples "admin_milestoneable" do |factory_name, path_name|
|
||||
it_behaves_like "progressable", factory_name, path_name
|
||||
|
||||
feature "Admin milestones" do
|
||||
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