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 1/9] 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 2/9] 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 3/9] 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 4/9] 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 5/9] 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 6/9] 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 7/9] 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 8/9] 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 9/9] 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: ->
<%= 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") %>