From 2331cd048edcbc9c2f28eec343d194d817bd1fd4 Mon Sep 17 00:00:00 2001 From: Julian Herrero Date: Mon, 3 Dec 2018 16:11:37 +0100 Subject: [PATCH 01/30] Add pending specs for proposal notifications limits --- spec/features/proposal_notifications_spec.rb | 49 +++++++++++++++++++- 1 file changed, 47 insertions(+), 2 deletions(-) diff --git a/spec/features/proposal_notifications_spec.rb b/spec/features/proposal_notifications_spec.rb index f374a42c8..a4852b414 100644 --- a/spec/features/proposal_notifications_spec.rb +++ b/spec/features/proposal_notifications_spec.rb @@ -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 minium 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 minium of 3 days between notifications" + + travel_back + end end From ab1e9a931010c0dc3d261d8349bbf87bcbcaab6c Mon Sep 17 00:00:00 2001 From: Julian Herrero Date: Thu, 10 Jan 2019 13:48:42 +0100 Subject: [PATCH 02/30] Fix typo --- config/locales/en/activerecord.yml | 2 +- spec/features/proposal_notifications_spec.rb | 4 ++-- spec/models/proposal_notification_spec.rb | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/config/locales/en/activerecord.yml b/config/locales/en/activerecord.yml index f08b7c788..aab700334 100644 --- a/config/locales/en/activerecord.yml +++ b/config/locales/en/activerecord.yml @@ -355,7 +355,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: diff --git a/spec/features/proposal_notifications_spec.rb b/spec/features/proposal_notifications_spec.rb index a4852b414..b3a61eaff 100644 --- a/spec/features/proposal_notifications_spec.rb +++ b/spec/features/proposal_notifications_spec.rb @@ -440,7 +440,7 @@ feature 'Proposal Notifications' do 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 minium of 3 days between notifications" + 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 @@ -465,7 +465,7 @@ feature 'Proposal Notifications' do 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 minium of 3 days between notifications" + expect(page).not_to have_content "You have to wait a minimum of 3 days between notifications" travel_back end diff --git a/spec/models/proposal_notification_spec.rb b/spec/models/proposal_notification_spec.rb index d7ba529c4..0548c03d2 100644 --- a/spec/models/proposal_notification_spec.rb +++ b/spec/models/proposal_notification_spec.rb @@ -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) From f2210bc5b5a30a2c57b125365a6add81021b07a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javi=20Mart=C3=ADn?= Date: Wed, 16 Jan 2019 13:28:59 +0100 Subject: [PATCH 03/30] Update changelog for release 0.18.1 --- CHANGELOG.md | 25 ++++++++++++++++++++++ app/controllers/installation_controller.rb | 2 +- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 955ffc300..3121f2670 100644 --- a/CHANGELOG.md +++ b/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) diff --git a/app/controllers/installation_controller.rb b/app/controllers/installation_controller.rb index bc0e32943..8aef8b659 100644 --- a/app/controllers/installation_controller.rb +++ b/app/controllers/installation_controller.rb @@ -12,7 +12,7 @@ class InstallationController < ApplicationController def consul_installation_details { - release: 'v0.18' + release: "v0.18.1" }.merge(features: settings_feature_flags) end From c3c9b0222053523c33d7754425bc50365d71f26a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javi=20Mart=C3=ADn?= Date: Thu, 3 Jan 2019 17:12:52 +0100 Subject: [PATCH 04/30] Move milestone factories to their own file --- spec/factories/budgets.rb | 13 ------------- spec/factories/milestones.rb | 14 ++++++++++++++ 2 files changed, 14 insertions(+), 13 deletions(-) create mode 100644 spec/factories/milestones.rb diff --git a/spec/factories/budgets.rb b/spec/factories/budgets.rb index da7b0f1b9..e741eb683 100644 --- a/spec/factories/budgets.rb +++ b/spec/factories/budgets.rb @@ -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 diff --git a/spec/factories/milestones.rb b/spec/factories/milestones.rb new file mode 100644 index 000000000..ebd436b70 --- /dev/null +++ b/spec/factories/milestones.rb @@ -0,0 +1,14 @@ +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 +end From eaea95ccfbb3050f697aeed4e95d9c963dffa9a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javi=20Mart=C3=ADn?= Date: Fri, 4 Jan 2019 14:42:46 +0100 Subject: [PATCH 05/30] Add progress bar model --- app/models/concerns/milestoneable.rb | 2 + app/models/progress_bar.rb | 28 ++++++ app/models/progress_bar/translation.rb | 3 + config/locales/en/activerecord.yml | 10 ++ config/locales/es/activerecord.yml | 10 ++ .../20190103132925_create_progress_bars.rb | 23 +++++ db/schema.rb | 22 ++++- spec/factories/milestones.rb | 11 +++ spec/models/progress_bar_spec.rb | 97 +++++++++++++++++++ 9 files changed, 205 insertions(+), 1 deletion(-) create mode 100644 app/models/progress_bar.rb create mode 100644 app/models/progress_bar/translation.rb create mode 100644 db/migrate/20190103132925_create_progress_bars.rb create mode 100644 spec/models/progress_bar_spec.rb diff --git a/app/models/concerns/milestoneable.rb b/app/models/concerns/milestoneable.rb index 2e961c613..7f58a77bb 100644 --- a/app/models/concerns/milestoneable.rb +++ b/app/models/concerns/milestoneable.rb @@ -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 diff --git a/app/models/progress_bar.rb b/app/models/progress_bar.rb new file mode 100644 index 000000000..7a7973723 --- /dev/null +++ b/app/models/progress_bar.rb @@ -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 diff --git a/app/models/progress_bar/translation.rb b/app/models/progress_bar/translation.rb new file mode 100644 index 000000000..d61f1d47b --- /dev/null +++ b/app/models/progress_bar/translation.rb @@ -0,0 +1,3 @@ +class ProgressBar::Translation < Globalize::ActiveRecord::Translation + delegate :primary?, to: :globalized_model +end diff --git a/config/locales/en/activerecord.yml b/config/locales/en/activerecord.yml index aab700334..90e726039 100644 --- a/config/locales/en/activerecord.yml +++ b/config/locales/en/activerecord.yml @@ -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" diff --git a/config/locales/es/activerecord.yml b/config/locales/es/activerecord.yml index 2c0b210a0..45cfa15b0 100644 --- a/config/locales/es/activerecord.yml +++ b/config/locales/es/activerecord.yml @@ -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" diff --git a/db/migrate/20190103132925_create_progress_bars.rb b/db/migrate/20190103132925_create_progress_bars.rb new file mode 100644 index 000000000..899a4819f --- /dev/null +++ b/db/migrate/20190103132925_create_progress_bars.rb @@ -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 diff --git a/db/schema.rb b/db/schema.rb index e3241fd8d..0d5ed3d1a 100644 --- a/db/schema.rb +++ b/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: 20181206153510) 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: 20181206153510) 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" diff --git a/spec/factories/milestones.rb b/spec/factories/milestones.rb index ebd436b70..0e4071d15 100644 --- a/spec/factories/milestones.rb +++ b/spec/factories/milestones.rb @@ -11,4 +11,15 @@ FactoryBot.define do 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 diff --git a/spec/models/progress_bar_spec.rb b/spec/models/progress_bar_spec.rb new file mode 100644 index 000000000..46b0ce08b --- /dev/null +++ b/spec/models/progress_bar_spec.rb @@ -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 From 4f25581636975c1306034d284dcc7210f7f1d80f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javi=20Mart=C3=ADn?= Date: Fri, 4 Jan 2019 15:05:15 +0100 Subject: [PATCH 06/30] Add progress bar polymorphic views --- app/assets/javascripts/forms.js.coffee | 6 + .../admin/progress_bars_controller.rb | 69 +++++++++++ app/views/admin/progress_bars/_form.html.erb | 16 +++ .../progress_bars/_progress_bars.html.erb | 49 ++++++++ app/views/admin/progress_bars/edit.html.erb | 15 +++ app/views/admin/progress_bars/index.html.erb | 7 ++ app/views/admin/progress_bars/new.html.erb | 9 ++ .../initializers/foundation_rails_helper.rb | 8 ++ config/initializers/routes_hierarchy.rb | 2 + config/locales/en/admin.yml | 18 +++ config/locales/es/admin.yml | 19 +++ spec/shared/features/progressable.rb | 109 ++++++++++++++++++ 12 files changed, 327 insertions(+) create mode 100644 app/controllers/admin/progress_bars_controller.rb create mode 100644 app/views/admin/progress_bars/_form.html.erb create mode 100644 app/views/admin/progress_bars/_progress_bars.html.erb create mode 100644 app/views/admin/progress_bars/edit.html.erb create mode 100644 app/views/admin/progress_bars/index.html.erb create mode 100644 app/views/admin/progress_bars/new.html.erb create mode 100644 spec/shared/features/progressable.rb diff --git a/app/assets/javascripts/forms.js.coffee b/app/assets/javascripts/forms.js.coffee index edf4c525f..4e862dea8 100644 --- a/app/assets/javascripts/forms.js.coffee +++ b/app/assets/javascripts/forms.js.coffee @@ -23,8 +23,14 @@ App.Forms = false ) + synchronizeInputs: -> + $("[name='progress_bar[percentage]']").on + input: -> + $("[name='#{this.name}']").val($(this).val()) + initialize: -> App.Forms.disableEnter() App.Forms.submitOnChange() App.Forms.toggleLink() + App.Forms.synchronizeInputs() false diff --git a/app/controllers/admin/progress_bars_controller.rb b/app/controllers/admin/progress_bars_controller.rb new file mode 100644 index 000000000..a9611b364 --- /dev/null +++ b/app/controllers/admin/progress_bars_controller.rb @@ -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 diff --git a/app/views/admin/progress_bars/_form.html.erb b/app/views/admin/progress_bars/_form.html.erb new file mode 100644 index 000000000..2ec756a54 --- /dev/null +++ b/app/views/admin/progress_bars/_form.html.erb @@ -0,0 +1,16 @@ +<%= render "admin/shared/globalize_locales", resource: @progress_bar %> + +<%= translatable_form_for [:admin, *resource_hierarchy_for(@progress_bar)] do |f| %> + + <%= f.enum_select :kind %> + + <%= f.translatable_fields do |translations_form| %> + <%= translations_form.text_field :title %> + <% end %> + + <% progress_options = { min: ProgressBar::RANGE.min, max: ProgressBar::RANGE.max, step: 1 } %> + <%= f.text_field :percentage, { type: :range, id: "percentage_range" }.merge(progress_options) %> + <%= f.text_field :percentage, { type: :number, label: false }.merge(progress_options) %> + + <%= f.submit nil, class: "button success" %> +<% end %> diff --git a/app/views/admin/progress_bars/_progress_bars.html.erb b/app/views/admin/progress_bars/_progress_bars.html.erb new file mode 100644 index 000000000..39d48f8c9 --- /dev/null +++ b/app/views/admin/progress_bars/_progress_bars.html.erb @@ -0,0 +1,49 @@ +

<%= t("admin.progress_bars.index.title") %>

+ +<% if progressable.progress_bars.any? %> + + + + + + + + + + + + <% progressable.progress_bars.each do |progress_bar| %> + + + + + + + + <% end %> + +
<%= ProgressBar.human_attribute_name("id") %><%= ProgressBar.human_attribute_name("kind") %><%= ProgressBar.human_attribute_name("title") %><%= ProgressBar.human_attribute_name("percentage") %><%= t("admin.actions.actions") %>
+ <%= progress_bar.id %> + <%= ProgressBar.human_attribute_name("kind.#{progress_bar.kind}") %><%= progress_bar.title %> + <%= number_to_percentage(progress_bar.percentage, strip_insignificant_zeros: true) %> + + <%= link_to t("admin.actions.edit"), + polymorphic_path([:admin, *resource_hierarchy_for(progress_bar)], + action: :edit), + class: "button hollow expanded" %> + + <%= link_to t("admin.actions.delete"), + polymorphic_path([:admin, *resource_hierarchy_for(progress_bar)]), + method: :delete, + class: "button hollow alert expanded" %> +
+<% else %> +

<%= t("admin.progress_bars.index.no_progress_bars") %>

+<% end %> + +

+ <%= link_to t("admin.progress_bars.index.new_progress_bar"), + polymorphic_path([:admin, *resource_hierarchy_for(progressable.progress_bars.new)], + action: :new), + class: "button hollow" %> +

diff --git a/app/views/admin/progress_bars/edit.html.erb b/app/views/admin/progress_bars/edit.html.erb new file mode 100644 index 000000000..21dd27d9a --- /dev/null +++ b/app/views/admin/progress_bars/edit.html.erb @@ -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 %> + +

<%= bar_title %>

+ +<%= render "form" %> diff --git a/app/views/admin/progress_bars/index.html.erb b/app/views/admin/progress_bars/index.html.erb new file mode 100644 index 000000000..ff17e5188 --- /dev/null +++ b/app/views/admin/progress_bars/index.html.erb @@ -0,0 +1,7 @@ +<% provide :title do %> + <%= "#{t("admin.header.title")} - #{t("admin.progress_bars.index.title")}" %> +<% end %> + +<%= back_link_to polymorphic_path([:admin, *resource_hierarchy_for(@progressable)]) %> + +<%= render "admin/progress_bars/progress_bars", progressable: @progressable %> diff --git a/app/views/admin/progress_bars/new.html.erb b/app/views/admin/progress_bars/new.html.erb new file mode 100644 index 000000000..8c379ac3a --- /dev/null +++ b/app/views/admin/progress_bars/new.html.erb @@ -0,0 +1,9 @@ +<% provide :title do %> + <%= "#{t("admin.header.title")} - #{t("admin.progress_bars.new.creating")}" %> +<% end %> + +<%= back_link_to progress_bars_index %> + +

<%= t("admin.progress_bars.new.creating") %>

+ +<%= render "form" %> diff --git a/config/initializers/foundation_rails_helper.rb b/config/initializers/foundation_rails_helper.rb index ff5ae4618..3e121f0d9 100644 --- a/config/initializers/foundation_rails_helper.rb +++ b/config/initializers/foundation_rails_helper.rb @@ -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 diff --git a/config/initializers/routes_hierarchy.rb b/config/initializers/routes_hierarchy.rb index 0a712f923..06a7acc74 100644 --- a/config/initializers/routes_hierarchy.rb +++ b/config/initializers/routes_hierarchy.rb @@ -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" diff --git a/config/locales/en/admin.yml b/config/locales/en/admin.yml index 7033fefbf..76c3b7121 100644 --- a/config/locales/en/admin.yml +++ b/config/locales/en/admin.yml @@ -332,6 +332,24 @@ 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" + 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 diff --git a/config/locales/es/admin.yml b/config/locales/es/admin.yml index 0075225c7..a8b337ca6 100644 --- a/config/locales/es/admin.yml +++ b/config/locales/es/admin.yml @@ -332,6 +332,25 @@ 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" + 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 diff --git a/spec/shared/features/progressable.rb b/spec/shared/features/progressable.rb new file mode 100644 index 000000000..ec4cdca29 --- /dev/null +++ b/spec/shared/features/progressable.rb @@ -0,0 +1,109 @@ +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" + + 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" + 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" } + + 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 From c5d32c5ab9ac5831686de8a40f8d6deef13209d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javi=20Mart=C3=ADn?= Date: Fri, 4 Jan 2019 15:10:10 +0100 Subject: [PATCH 07/30] Manage progress bars in the admin area --- .../budget_investment_progress_bars_controller.rb | 8 ++++++++ .../admin/legislation/progress_bars_controller.rb | 14 ++++++++++++++ .../admin/proposal_progress_bars_controller.rb | 7 +++++++ .../admin/legislation/progress_bars/index.html.erb | 12 ++++++++++++ app/views/admin/milestones/_milestones.html.erb | 2 ++ config/routes/admin.rb | 3 +++ spec/shared/features/admin_milestoneable.rb | 1 + 7 files changed, 47 insertions(+) create mode 100644 app/controllers/admin/budget_investment_progress_bars_controller.rb create mode 100644 app/controllers/admin/legislation/progress_bars_controller.rb create mode 100644 app/controllers/admin/proposal_progress_bars_controller.rb create mode 100644 app/views/admin/legislation/progress_bars/index.html.erb diff --git a/app/controllers/admin/budget_investment_progress_bars_controller.rb b/app/controllers/admin/budget_investment_progress_bars_controller.rb new file mode 100644 index 000000000..bb4db0d79 --- /dev/null +++ b/app/controllers/admin/budget_investment_progress_bars_controller.rb @@ -0,0 +1,8 @@ +class Admin::BudgetInvestmentProgressBarsController < Admin::ProgressBarsController + + private + + def progressable + Budget::Investment.find(params[:budget_investment_id]) + end +end diff --git a/app/controllers/admin/legislation/progress_bars_controller.rb b/app/controllers/admin/legislation/progress_bars_controller.rb new file mode 100644 index 000000000..ba00d5e91 --- /dev/null +++ b/app/controllers/admin/legislation/progress_bars_controller.rb @@ -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 diff --git a/app/controllers/admin/proposal_progress_bars_controller.rb b/app/controllers/admin/proposal_progress_bars_controller.rb new file mode 100644 index 000000000..9259acc4b --- /dev/null +++ b/app/controllers/admin/proposal_progress_bars_controller.rb @@ -0,0 +1,7 @@ +class Admin::ProposalProgressBarsController < Admin::ProgressBarsController + + private + def progressable + Proposal.find(params[:proposal_id]) + end +end diff --git a/app/views/admin/legislation/progress_bars/index.html.erb b/app/views/admin/legislation/progress_bars/index.html.erb new file mode 100644 index 000000000..b84717689 --- /dev/null +++ b/app/views/admin/legislation/progress_bars/index.html.erb @@ -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") %> + +

<%= @process.title %>

+ +<%= render "admin/legislation/processes/subnav", process: @process, active: "milestones" %> +<%= render "admin/progress_bars/progress_bars", progressable: @process %> diff --git a/app/views/admin/milestones/_milestones.html.erb b/app/views/admin/milestones/_milestones.html.erb index f2ef31216..823e07717 100644 --- a/app/views/admin/milestones/_milestones.html.erb +++ b/app/views/admin/milestones/_milestones.html.erb @@ -1,5 +1,7 @@

<%= t("admin.milestones.index.milestone") %>

+<%= link_to t("admin.progress_bars.manage"), polymorphic_path([:admin, *resource_hierarchy_for(milestoneable.progress_bars.new)]) %> + <% if milestoneable.milestones.any? %> diff --git a/config/routes/admin.rb b/config/routes/admin.rb index 270a5061c..52740e9d6 100644 --- a/config/routes/admin.rb +++ b/config/routes/admin.rb @@ -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 diff --git a/spec/shared/features/admin_milestoneable.rb b/spec/shared/features/admin_milestoneable.rb index 17f43a012..c12fd7624 100644 --- a/spec/shared/features/admin_milestoneable.rb +++ b/spec/shared/features/admin_milestoneable.rb @@ -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) } From dfdf0b0636819a0db4a508df1054862957aecc20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javi=20Mart=C3=ADn?= Date: Fri, 4 Jan 2019 16:26:35 +0100 Subject: [PATCH 08/30] Hide title field for primary progress bars These bars don't have a title. --- app/assets/javascripts/forms.js.coffee | 13 +++++++++++++ spec/shared/features/progressable.rb | 5 +++++ 2 files changed, 18 insertions(+) diff --git a/app/assets/javascripts/forms.js.coffee b/app/assets/javascripts/forms.js.coffee index 4e862dea8..25fd2d5fd 100644 --- a/app/assets/javascripts/forms.js.coffee +++ b/app/assets/javascripts/forms.js.coffee @@ -28,9 +28,22 @@ App.Forms = input: -> $("[name='#{this.name}']").val($(this).val()) + hideOrShowFieldsAfterSelection: -> + $("[name='progress_bar[kind]']").on + change: -> + title_field = $("[name^='progress_bar'][name$='[title]']").parent() + + if this.value == "primary" + title_field.addClass("hide") + else + title_field.removeClass("hide") + + $("[name='progress_bar[kind]']").change() + initialize: -> App.Forms.disableEnter() App.Forms.submitOnChange() App.Forms.toggleLink() App.Forms.synchronizeInputs() + App.Forms.hideOrShowFieldsAfterSelection() false diff --git a/spec/shared/features/progressable.rb b/spec/shared/features/progressable.rb index ec4cdca29..870e61825 100644 --- a/spec/shared/features/progressable.rb +++ b/spec/shared/features/progressable.rb @@ -34,6 +34,8 @@ shared_examples "progressable" do |factory_name, path_name| select "Primary", from: "Type" + expect(page).not_to have_field "Title" + fill_in "Current progress", with: 43 click_button "Create Progress bar" @@ -65,6 +67,9 @@ shared_examples "progressable" do |factory_name, path_name| 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" From 7c0fb96b020533773ecec9c3e184409813def65d Mon Sep 17 00:00:00 2001 From: decabeza Date: Tue, 8 Jan 2019 18:21:16 +0100 Subject: [PATCH 09/30] Adds styles to admin progress bars views --- app/assets/stylesheets/admin.scss | 7 ++++ .../admin/milestones/_milestones.html.erb | 6 ++-- app/views/admin/progress_bars/_form.html.erb | 27 +++++++++++---- .../progress_bars/_progress_bars.html.erb | 34 ++++++++++++------- app/views/admin/progress_bars/index.html.erb | 2 ++ config/locales/en/admin.yml | 1 + config/locales/es/admin.yml | 1 + spec/shared/features/progressable.rb | 1 + 8 files changed, 58 insertions(+), 21 deletions(-) diff --git a/app/assets/stylesheets/admin.scss b/app/assets/stylesheets/admin.scss index f08d14fda..95f29e862 100644 --- a/app/assets/stylesheets/admin.scss +++ b/app/assets/stylesheets/admin.scss @@ -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; diff --git a/app/views/admin/milestones/_milestones.html.erb b/app/views/admin/milestones/_milestones.html.erb index 823e07717..1b5a4933b 100644 --- a/app/views/admin/milestones/_milestones.html.erb +++ b/app/views/admin/milestones/_milestones.html.erb @@ -1,6 +1,8 @@ -

<%= t("admin.milestones.index.milestone") %>

+

<%= t("admin.milestones.index.milestone") %>

-<%= link_to t("admin.progress_bars.manage"), polymorphic_path([:admin, *resource_hierarchy_for(milestoneable.progress_bars.new)]) %> +<%= 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? %>
diff --git a/app/views/admin/progress_bars/_form.html.erb b/app/views/admin/progress_bars/_form.html.erb index 2ec756a54..f4ed45493 100644 --- a/app/views/admin/progress_bars/_form.html.erb +++ b/app/views/admin/progress_bars/_form.html.erb @@ -2,15 +2,30 @@ <%= translatable_form_for [:admin, *resource_hierarchy_for(@progress_bar)] do |f| %> - <%= f.enum_select :kind %> +
+ <%= f.enum_select :kind %> +
- <%= f.translatable_fields do |translations_form| %> - <%= translations_form.text_field :title %> - <% end %> +
+ <%= f.translatable_fields do |translations_form| %> + <%= translations_form.text_field :title %> + <% end %> +
<% progress_options = { min: ProgressBar::RANGE.min, max: ProgressBar::RANGE.max, step: 1 } %> - <%= f.text_field :percentage, { type: :range, id: "percentage_range" }.merge(progress_options) %> - <%= f.text_field :percentage, { type: :number, label: false }.merge(progress_options) %> +
+ <%= f.text_field :percentage, { type: :range, + id: "percentage_range", + class: "column" }.merge(progress_options) %> +
+
+
+ <%= f.text_field :percentage, { type: :number, + label: false, + class: "input-group-field" }.merge(progress_options) %> + % +
+
<%= f.submit nil, class: "button success" %> <% end %> diff --git a/app/views/admin/progress_bars/_progress_bars.html.erb b/app/views/admin/progress_bars/_progress_bars.html.erb index 39d48f8c9..f56f3049b 100644 --- a/app/views/admin/progress_bars/_progress_bars.html.erb +++ b/app/views/admin/progress_bars/_progress_bars.html.erb @@ -1,4 +1,11 @@ -

<%= t("admin.progress_bars.index.title") %>

+

<%= t("admin.progress_bars.index.title") %>

+ +<%= 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? %>
@@ -7,7 +14,7 @@ - + @@ -18,32 +25,33 @@ <%= progress_bar.id %> - + <% end %>
<%= ProgressBar.human_attribute_name("id") %> <%= ProgressBar.human_attribute_name("kind") %> <%= ProgressBar.human_attribute_name("title") %><%= ProgressBar.human_attribute_name("percentage") %><%= ProgressBar.human_attribute_name("percentage") %> <%= t("admin.actions.actions") %>
<%= ProgressBar.human_attribute_name("kind.#{progress_bar.kind}") %><%= progress_bar.title %> + <% if progress_bar.title.present? %> + <%= progress_bar.title %> + <% else %> + <%= t("admin.progress_bars.index.primary") %> + <% end %> + <%= number_to_percentage(progress_bar.percentage, strip_insignificant_zeros: true) %> <%= link_to t("admin.actions.edit"), polymorphic_path([:admin, *resource_hierarchy_for(progress_bar)], action: :edit), - class: "button hollow expanded" %> + class: "button hollow" %> <%= link_to t("admin.actions.delete"), polymorphic_path([:admin, *resource_hierarchy_for(progress_bar)]), method: :delete, - class: "button hollow alert expanded" %> + class: "button hollow alert" %>
<% else %> -

<%= t("admin.progress_bars.index.no_progress_bars") %>

+
+ <%= t("admin.progress_bars.index.no_progress_bars") %> +
<% end %> - -

- <%= link_to t("admin.progress_bars.index.new_progress_bar"), - polymorphic_path([:admin, *resource_hierarchy_for(progressable.progress_bars.new)], - action: :new), - class: "button hollow" %> -

diff --git a/app/views/admin/progress_bars/index.html.erb b/app/views/admin/progress_bars/index.html.erb index ff17e5188..bcac8d7a4 100644 --- a/app/views/admin/progress_bars/index.html.erb +++ b/app/views/admin/progress_bars/index.html.erb @@ -4,4 +4,6 @@ <%= back_link_to polymorphic_path([:admin, *resource_hierarchy_for(@progressable)]) %> +
+ <%= render "admin/progress_bars/progress_bars", progressable: @progressable %> diff --git a/config/locales/en/admin.yml b/config/locales/en/admin.yml index 76c3b7121..6f7d9d4d5 100644 --- a/config/locales/en/admin.yml +++ b/config/locales/en/admin.yml @@ -338,6 +338,7 @@ en: title: "Progress bars" no_progress_bars: "There are no progress bars" new_progress_bar: "Create new progress bar" + primary: "Primary progress bar" new: creating: "Create progress bar" edit: diff --git a/config/locales/es/admin.yml b/config/locales/es/admin.yml index a8b337ca6..60a02402f 100644 --- a/config/locales/es/admin.yml +++ b/config/locales/es/admin.yml @@ -338,6 +338,7 @@ es: 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" new: creating: "Crear barra de progreso" edit: diff --git a/spec/shared/features/progressable.rb b/spec/shared/features/progressable.rb index 870e61825..b28c383c6 100644 --- a/spec/shared/features/progressable.rb +++ b/spec/shared/features/progressable.rb @@ -42,6 +42,7 @@ shared_examples "progressable" do |factory_name, path_name| 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 From 96454a41f0ad09bcb54139dce06560ccaa01d292 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javi=20Mart=C3=ADn?= Date: Tue, 8 Jan 2019 20:44:00 +0100 Subject: [PATCH 10/30] Use I18n keys instead of `human_attribute_name` Even if it means duplicating the translations in many cases, it's consistent with the rest of the application. --- app/views/admin/progress_bars/_progress_bars.html.erb | 8 ++++---- config/locales/en/admin.yml | 4 ++++ config/locales/es/admin.yml | 4 ++++ 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/app/views/admin/progress_bars/_progress_bars.html.erb b/app/views/admin/progress_bars/_progress_bars.html.erb index f56f3049b..3715c2f35 100644 --- a/app/views/admin/progress_bars/_progress_bars.html.erb +++ b/app/views/admin/progress_bars/_progress_bars.html.erb @@ -11,10 +11,10 @@ - - - - + + + + diff --git a/config/locales/en/admin.yml b/config/locales/en/admin.yml index 6f7d9d4d5..a86f8a315 100644 --- a/config/locales/en/admin.yml +++ b/config/locales/en/admin.yml @@ -339,6 +339,10 @@ en: 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: diff --git a/config/locales/es/admin.yml b/config/locales/es/admin.yml index 60a02402f..d33d91211 100644 --- a/config/locales/es/admin.yml +++ b/config/locales/es/admin.yml @@ -339,6 +339,10 @@ es: 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: From fff5673ec0e825731c6864bb8a4819027170b195 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javi=20Mart=C3=ADn?= Date: Tue, 8 Jan 2019 20:28:09 +0100 Subject: [PATCH 11/30] Simplify hiding/showing progress bar type field With a parent element for just input and label, there aren't conflicts with the globalize tabs code anymore. --- app/assets/javascripts/forms.js.coffee | 4 ++-- app/views/admin/progress_bars/_form.html.erb | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/app/assets/javascripts/forms.js.coffee b/app/assets/javascripts/forms.js.coffee index 25fd2d5fd..aa7c4818f 100644 --- a/app/assets/javascripts/forms.js.coffee +++ b/app/assets/javascripts/forms.js.coffee @@ -34,9 +34,9 @@ App.Forms = title_field = $("[name^='progress_bar'][name$='[title]']").parent() if this.value == "primary" - title_field.addClass("hide") + title_field.hide() else - title_field.removeClass("hide") + title_field.show() $("[name='progress_bar[kind]']").change() diff --git a/app/views/admin/progress_bars/_form.html.erb b/app/views/admin/progress_bars/_form.html.erb index f4ed45493..cdc6af59e 100644 --- a/app/views/admin/progress_bars/_form.html.erb +++ b/app/views/admin/progress_bars/_form.html.erb @@ -6,11 +6,11 @@ <%= f.enum_select :kind %> -
- <%= f.translatable_fields do |translations_form| %> + <%= f.translatable_fields do |translations_form| %> +
<%= translations_form.text_field :title %> - <% end %> -
+
+ <% end %> <% progress_options = { min: ProgressBar::RANGE.min, max: ProgressBar::RANGE.max, step: 1 } %>
From 789476e6ab5dca24099e16b65610fe87abed4b2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javi=20Mart=C3=ADn?= Date: Tue, 8 Jan 2019 20:34:55 +0100 Subject: [PATCH 12/30] Synchronize percentage for new progress bars According to the HTML specification: > The default value is the minimum plus half the difference between the > minimum and the maximum, unless the maximum is less than the minimum, > in which case the default value is the minimum. So for new progress bars, we had a numeric value of `nil` and a range value of `50`, meaning the input fields weren't in sync. Manually triggering the event on the progress, while not an ideal solution (ideally we would be able to define `0` as default), sets the value of the numeric field. --- app/assets/javascripts/forms.js.coffee | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/assets/javascripts/forms.js.coffee b/app/assets/javascripts/forms.js.coffee index aa7c4818f..3562335a4 100644 --- a/app/assets/javascripts/forms.js.coffee +++ b/app/assets/javascripts/forms.js.coffee @@ -28,6 +28,8 @@ App.Forms = input: -> $("[name='#{this.name}']").val($(this).val()) + $("[name='progress_bar[percentage]'][type='range']").trigger("input") + hideOrShowFieldsAfterSelection: -> $("[name='progress_bar[kind]']").on change: -> From 51a4ca98ad1104c3c54bab762d16099322b15203 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javi=20Mart=C3=ADn?= Date: Thu, 10 Jan 2019 10:32:15 +0100 Subject: [PATCH 13/30] Move milestone styles to their own sheet --- app/assets/stylesheets/application.scss | 1 + app/assets/stylesheets/milestones.scss | 111 +++++++++++++++++++++ app/assets/stylesheets/participation.scss | 112 ---------------------- 3 files changed, 112 insertions(+), 112 deletions(-) create mode 100644 app/assets/stylesheets/milestones.scss diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss index 3f93ffa6b..5e993d5d6 100644 --- a/app/assets/stylesheets/application.scss +++ b/app/assets/stylesheets/application.scss @@ -6,6 +6,7 @@ @import 'admin'; @import 'layout'; @import 'participation'; +@import 'milestones'; @import 'pages'; @import 'legislation'; @import 'legislation_process'; diff --git a/app/assets/stylesheets/milestones.scss b/app/assets/stylesheets/milestones.scss new file mode 100644 index 000000000..41cf2a175 --- /dev/null +++ b/app/assets/stylesheets/milestones.scss @@ -0,0 +1,111 @@ +.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; +} diff --git a/app/assets/stylesheets/participation.scss b/app/assets/stylesheets/participation.scss index 023686b6e..ba02e18ad 100644 --- a/app/assets/stylesheets/participation.scss +++ b/app/assets/stylesheets/participation.scss @@ -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-"] { From cb92d29ddccb71ce39f98315b8668a3ad5bf9661 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javi=20Mart=C3=ADn?= Date: Thu, 10 Jan 2019 10:35:16 +0100 Subject: [PATCH 14/30] Simplify nth-child selectors Using `nth-child(odd), nth-child(even)` is the same as selecting all the elements. --- app/assets/stylesheets/milestones.scss | 29 +++++++++++++------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/app/assets/stylesheets/milestones.scss b/app/assets/stylesheets/milestones.scss index 41cf2a175..b740163af 100644 --- a/app/assets/stylesheets/milestones.scss +++ b/app/assets/stylesheets/milestones.scss @@ -46,8 +46,7 @@ } } -.tab-milestones .timeline ul li:nth-child(odd), -.tab-milestones .timeline ul li:nth-child(even) { +.tab-milestones .timeline ul li { .milestone-content { @@ -59,27 +58,27 @@ width: rem-calc(450); } } -} -.tab-milestones .timeline ul li:nth-child(odd) { + &:nth-child(odd) { - .milestone-content { - text-align: right; + .milestone-content { + text-align: right; - @include breakpoint(medium) { - margin-left: rem-calc(-315); - } + @include breakpoint(medium) { + margin-left: rem-calc(-315); + } - @include breakpoint(large) { - margin-left: rem-calc(-465); + @include breakpoint(large) { + margin-left: rem-calc(-465); + } } } -} -.tab-milestones .timeline ul li:nth-child(even) { + &:nth-child(even) { - .milestone-content { - left: 15px; + .milestone-content { + left: 15px; + } } } From 39c8d431f87b24bdf4c4ef3c2f13bfe89730f534 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javi=20Mart=C3=ADn?= Date: Thu, 10 Jan 2019 10:38:18 +0100 Subject: [PATCH 15/30] Group milestones timeline `li` CSS rules together --- app/assets/stylesheets/milestones.scss | 55 ++++++++++++-------------- 1 file changed, 26 insertions(+), 29 deletions(-) diff --git a/app/assets/stylesheets/milestones.scss b/app/assets/stylesheets/milestones.scss index b740163af..c9a9cda9b 100644 --- a/app/assets/stylesheets/milestones.scss +++ b/app/assets/stylesheets/milestones.scss @@ -1,35 +1,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 { @@ -47,6 +18,32 @@ } .tab-milestones .timeline ul li { + margin: 0 auto; + position: relative; + width: 0; + + &::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 { From 46296b702eec2a9bd4c0cab40ee0722bdb2143b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javi=20Mart=C3=ADn?= Date: Thu, 10 Jan 2019 10:39:52 +0100 Subject: [PATCH 16/30] Group milestone content CSS rules together --- app/assets/stylesheets/milestones.scss | 27 ++++++++++++-------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/app/assets/stylesheets/milestones.scss b/app/assets/stylesheets/milestones.scss index c9a9cda9b..0df9cf465 100644 --- a/app/assets/stylesheets/milestones.scss +++ b/app/assets/stylesheets/milestones.scss @@ -3,21 +3,7 @@ position: relative; } -.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 { +.tab-milestones .timeline li { margin: 0 auto; position: relative; width: 0; @@ -46,6 +32,8 @@ } .milestone-content { + padding: $line-height / 6 $line-height / 2; + position: relative; @include breakpoint(medium) { width: rem-calc(300); @@ -54,6 +42,15 @@ @include breakpoint(large) { width: rem-calc(450); } + + h3 { + margin-bottom: 0; + } + + .milestone-date { + color: $text-medium; + font-size: $small-font-size; + } } &:nth-child(odd) { From fb72fc48fdc1d728bccf8f9e76dcda421b66a4c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javi=20Mart=C3=ADn?= Date: Thu, 10 Jan 2019 10:45:51 +0100 Subject: [PATCH 17/30] Simplify milestones styles for small devices The selector `nth-child(even)` didn't need specific rules, and it's easier to understand the code for the selector `nth-child(odd)` if all breakpoints are grouped together. --- app/assets/stylesheets/milestones.scss | 27 +++++++++----------------- 1 file changed, 9 insertions(+), 18 deletions(-) diff --git a/app/assets/stylesheets/milestones.scss b/app/assets/stylesheets/milestones.scss index 0df9cf465..bc4515665 100644 --- a/app/assets/stylesheets/milestones.scss +++ b/app/assets/stylesheets/milestones.scss @@ -8,6 +8,10 @@ position: relative; width: 0; + @include breakpoint(small only) { + width: 100%; + } + &::before { background: $budget; border-radius: rem-calc(20); @@ -65,6 +69,11 @@ @include breakpoint(large) { margin-left: rem-calc(-465); } + + @include breakpoint(small only) { + left: 15px; + text-align: left; + } } } @@ -76,24 +85,6 @@ } } -.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); From 908afb5f326ae83b22326bfe8ffffebf569ce2dc Mon Sep 17 00:00:00 2001 From: decabeza Date: Thu, 17 Jan 2019 14:08:47 +0100 Subject: [PATCH 18/30] Update budgets confirm group es translation --- config/locales/es/budgets.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config/locales/es/budgets.yml b/config/locales/es/budgets.yml index 5b4406b3e..81b8b4ca9 100644 --- a/config/locales/es/budgets.yml +++ b/config/locales/es/budgets.yml @@ -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 From f5c7065d9075bce50d77bc434b0765fee5245d4e Mon Sep 17 00:00:00 2001 From: decabeza Date: Tue, 22 Jan 2019 11:52:25 +0100 Subject: [PATCH 19/30] Remove help and recommendations on legislation proposal new form --- app/views/legislation/proposals/new.html.erb | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/app/views/legislation/proposals/new.html.erb b/app/views/legislation/proposals/new.html.erb index e6da71dba..0ce9e2da7 100644 --- a/app/views/legislation/proposals/new.html.erb +++ b/app/views/legislation/proposals/new.html.erb @@ -1,24 +1,10 @@
-
+
<%= back_link_to %>

<%= t("proposals.new.start_new") %>

-
- <%= link_to help_path(anchor: "proposals"), title: t('shared.target_blank_html'), target: "_blank" do %> - <%= t("proposals.new.more_info")%> - <% end %> -
+ <%= render "legislation/proposals/form", form_url: legislation_process_proposals_url, id: @proposal.id %>
- -
- -

<%= t("proposals.new.recommendations_title") %>

-
    -
  • <%= t("proposals.new.recommendation_one") %>
  • -
  • <%= t("proposals.new.recommendation_two") %>
  • -
  • <%= t("proposals.new.recommendation_three") %>
  • -
-
From 75531c6c80246a887bc7c0fc782b7999f9755e17 Mon Sep 17 00:00:00 2001 From: decabeza Date: Tue, 22 Jan 2019 18:09:56 +0100 Subject: [PATCH 20/30] Show current phase as selected on phase select on admin budgets form --- app/views/admin/budgets/_form.html.erb | 2 +- spec/features/admin/budgets_spec.rb | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/app/views/admin/budgets/_form.html.erb b/app/views/admin/budgets/_form.html.erb index 9a31c6cd2..7c8175613 100644 --- a/app/views/admin/budgets/_form.html.erb +++ b/app/views/admin/budgets/_form.html.erb @@ -6,7 +6,7 @@
- <%= f.select :phase, budget_phases_select_options, selected: "drafting" %> + <%= f.select :phase, budget_phases_select_options %>
<%= f.select :currency_symbol, budget_currency_symbol_select_options %> diff --git a/spec/features/admin/budgets_spec.rb b/spec/features/admin/budgets_spec.rb index ffd67f457..d3efb5de3 100644 --- a/spec/features/admin/budgets_spec.rb +++ b/spec/features/admin/budgets_spec.rb @@ -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| From 210ab69197f83e5c1f83d2e9e2bdf31925b6ac85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javi=20Mart=C3=ADn?= Date: Tue, 15 Jan 2019 14:26:26 +0100 Subject: [PATCH 21/30] Add milestone seeds to legislation processs --- db/dev_seeds/milestones.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/db/dev_seeds/milestones.rb b/db/dev_seeds/milestones.rb index 41b3f40ab..0943a32b4 100644 --- a/db/dev_seeds/milestones.rb +++ b/db/dev_seeds/milestones.rb @@ -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( From 731723838213f0d85d66d5b7b75dec27e859ff42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javi=20Mart=C3=ADn?= Date: Tue, 15 Jan 2019 14:34:59 +0100 Subject: [PATCH 22/30] Reduce the number of locales for milestones seeds Creating records for every locale was taking too long now that CONSUL is available in 15 languages. --- db/dev_seeds.rb | 4 ++++ db/dev_seeds/milestones.rb | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/db/dev_seeds.rb b/db/dev_seeds.rb index cc568b119..8b2671b44 100644 --- a/db/dev_seeds.rb +++ b/db/dev_seeds.rb @@ -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' diff --git a/db/dev_seeds/milestones.rb b/db/dev_seeds/milestones.rb index 0943a32b4..0440c0f01 100644 --- a/db/dev_seeds/milestones.rb +++ b/db/dev_seeds/milestones.rb @@ -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) From 0a710a77f26312806899e332b036dc3e291c2812 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javi=20Mart=C3=ADn?= Date: Tue, 15 Jan 2019 14:36:40 +0100 Subject: [PATCH 23/30] Add progress bars dev seeds --- db/dev_seeds/milestones.rb | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/db/dev_seeds/milestones.rb b/db/dev_seeds/milestones.rb index 0440c0f01..54ed1e997 100644 --- a/db/dev_seeds/milestones.rb +++ b/db/dev_seeds/milestones.rb @@ -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 - From 62088bc635b9000fde04f8e1e0b02587ee9f540f Mon Sep 17 00:00:00 2001 From: decabeza Date: Wed, 23 Jan 2019 17:43:05 +0100 Subject: [PATCH 24/30] Hide poll results and stats to admins --- app/views/polls/_poll_subnav.html.erb | 6 ++---- spec/features/polls/polls_spec.rb | 25 ++++++++++++++++--------- 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/app/views/polls/_poll_subnav.html.erb b/app/views/polls/_poll_subnav.html.erb index 94d522dab..ff1e7434e 100644 --- a/app/views/polls/_poll_subnav.html.erb +++ b/app/views/polls/_poll_subnav.html.erb @@ -1,10 +1,8 @@ -<% if current_user && current_user.administrator? || - (@poll.expired? && (@poll.results_enabled? || @poll.stats_enabled?)) %>
<% @images.each do |image| %> - + diff --git a/app/views/proposals/_geozones.html.erb b/app/views/proposals/_geozones.html.erb index 7e4dbcaa4..9840f8fdc 100644 --- a/app/views/proposals/_geozones.html.erb +++ b/app/views/proposals/_geozones.html.erb @@ -2,5 +2,5 @@
<%= 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 %> diff --git a/spec/features/admin/site_customization/images_spec.rb b/spec/features/admin/site_customization/images_spec.rb index f4419e97e..d2f23d34e 100644 --- a/spec/features/admin/site_customization/images_spec.rb +++ b/spec/features/admin/site_customization/images_spec.rb @@ -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 diff --git a/spec/fixtures/files/custom_map.jpg b/spec/fixtures/files/custom_map.jpg new file mode 100644 index 0000000000000000000000000000000000000000..d5fbd5bb51201fe30d33037cf7d9135faf877662 GIT binary patch literal 87504 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 X2{dW Date: Thu, 24 Jan 2019 10:58:24 +0100 Subject: [PATCH 28/30] Allow admins delete poll answer documents --- app/models/abilities/administrator.rb | 1 + .../poll/questions/answers/documents.html.erb | 26 +++++------ .../answers/documents/documents_spec.rb | 44 +++++++++++++++++++ 3 files changed, 58 insertions(+), 13 deletions(-) create mode 100644 spec/features/admin/poll/questions/answers/documents/documents_spec.rb diff --git a/app/models/abilities/administrator.rb b/app/models/abilities/administrator.rb index bdc457bc0..847f1effc 100644 --- a/app/models/abilities/administrator.rb +++ b/app/models/abilities/administrator.rb @@ -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 diff --git a/app/views/admin/poll/questions/answers/documents.html.erb b/app/views/admin/poll/questions/answers/documents.html.erb index 54dd25a18..933be2b94 100644 --- a/app/views/admin/poll/questions/answers/documents.html.erb +++ b/app/views/admin/poll/questions/answers/documents.html.erb @@ -14,18 +14,12 @@ <%= render 'shared/errors', resource: @answer %> -

-
-
- <%= render 'documents/nested_documents', documentable: @answer, f: f %> -
+
+ <%= render 'documents/nested_documents', documentable: @answer, f: f %> +
-
-
- <%= f.submit(class: "button expanded", value: t("shared.save")) %> -
-
-
+
+ <%= f.submit(class: "button expanded", value: t("shared.save")) %>
<% end %> @@ -42,11 +36,17 @@ <%= link_to document.title, document.attachment.url %>
<% end %> diff --git a/spec/features/admin/poll/questions/answers/documents/documents_spec.rb b/spec/features/admin/poll/questions/answers/documents/documents_spec.rb new file mode 100644 index 000000000..34d43a454 --- /dev/null +++ b/spec/features/admin/poll/questions/answers/documents/documents_spec.rb @@ -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 From b588cd3a0b81c1ea0a380d7b0ed51796e80438cf Mon Sep 17 00:00:00 2001 From: decabeza Date: Thu, 24 Jan 2019 21:39:08 +0100 Subject: [PATCH 29/30] Add missing i18n --- config/locales/en/admin.yml | 1 + config/locales/es/admin.yml | 1 + 2 files changed, 2 insertions(+) diff --git a/config/locales/en/admin.yml b/config/locales/en/admin.yml index a86f8a315..0b51d9556 100644 --- a/config/locales/en/admin.yml +++ b/config/locales/en/admin.yml @@ -1187,6 +1187,7 @@ en: author: Author content: Content created_at: Created at + delete: Delete spending_proposals: index: geozone_filter_all: All zones diff --git a/config/locales/es/admin.yml b/config/locales/es/admin.yml index d33d91211..dc8e66fb0 100644 --- a/config/locales/es/admin.yml +++ b/config/locales/es/admin.yml @@ -1187,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 From dacc2d529dd96ffa0b55644eb4ad3b9cb01bda11 Mon Sep 17 00:00:00 2001 From: rgarcia Date: Wed, 9 May 2018 18:59:35 +0200 Subject: [PATCH 30/30] Fix destroy document specs We were linking to the document url itself, which does not have a route associated and so the specs fails With this commit we are using the correct path to the destroy action of the DocumentsController. We are also using the referrer instead of a params[:from] attribute, as it avoids having to pass an extra parameter, making the code prettier and it works the same way --- app/controllers/documents_controller.rb | 2 +- app/views/documents/_document.html.erb | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/app/controllers/documents_controller.rb b/app/controllers/documents_controller.rb index 001d23446..1d6df8d14 100644 --- a/app/controllers/documents_controller.rb +++ b/app/controllers/documents_controller.rb @@ -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 diff --git a/app/views/documents/_document.html.erb b/app/views/documents/_document.html.erb index bf549e92b..9075bdd7c 100644 --- a/app/views/documents/_document.html.erb +++ b/app/views/documents/_document.html.erb @@ -13,7 +13,8 @@ <% if can?(:destroy, document) %>
<%= 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 %>
<%= ProgressBar.human_attribute_name("id") %><%= ProgressBar.human_attribute_name("kind") %><%= ProgressBar.human_attribute_name("title") %><%= ProgressBar.human_attribute_name("percentage") %><%= t("admin.progress_bars.index.table_id") %><%= t("admin.progress_bars.index.table_kind") %><%= t("admin.progress_bars.index.table_title") %><%= t("admin.progress_bars.index.table_percentage") %> <%= t("admin.actions.actions") %>
<%= image.name %> (<%= image.required_width %>x<%= image.required_height %>) - <%= 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") } %>