From 2ad66409e214421bb8f7f22337b816f1fba7789d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sen=C3=A9n=20Rodero=20Rodr=C3=ADguez?= Date: Mon, 23 Nov 2020 17:00:17 +0100 Subject: [PATCH 01/10] Add SDG LocalTarget model --- app/models/concerns/sdg/relatable.rb | 2 +- app/models/sdg/local_target.rb | 37 +++++++++ app/models/sdg/target.rb | 1 + config/locales/en/activerecord.yml | 4 + config/locales/es/activerecord.yml | 4 + ...20201123124006_create_sdg_local_targets.rb | 22 ++++++ db/schema.rb | 22 +++++- spec/factories/sdg.rb | 8 ++ spec/models/sdg/local_target_spec.rb | 77 +++++++++++++++++++ spec/models/sdg/relatable_spec.rb | 24 +++++- 10 files changed, 198 insertions(+), 3 deletions(-) create mode 100644 app/models/sdg/local_target.rb create mode 100644 db/migrate/20201123124006_create_sdg_local_targets.rb create mode 100644 spec/models/sdg/local_target_spec.rb diff --git a/app/models/concerns/sdg/relatable.rb b/app/models/concerns/sdg/relatable.rb index e85e1407c..9da20b0d5 100644 --- a/app/models/concerns/sdg/relatable.rb +++ b/app/models/concerns/sdg/relatable.rb @@ -4,7 +4,7 @@ module SDG::Relatable included do has_many :sdg_relations, as: :relatable, dependent: :destroy, class_name: "SDG::Relation" - %w[SDG::Goal SDG::Target].each do |sdg_type| + %w[SDG::Goal SDG::Target SDG::LocalTarget].each do |sdg_type| has_many sdg_type.constantize.table_name.to_sym, through: :sdg_relations, source: :related_sdg, diff --git a/app/models/sdg/local_target.rb b/app/models/sdg/local_target.rb new file mode 100644 index 000000000..8443e2a40 --- /dev/null +++ b/app/models/sdg/local_target.rb @@ -0,0 +1,37 @@ +class SDG::LocalTarget < ApplicationRecord + include Comparable + include SDG::Related + + delegate :goal, to: :target + + translates :title, touch: true + translates :description, touch: true + include Globalizable + + validates_translation :title, presence: true + validates_translation :description, presence: true + + validates :code, presence: true, uniqueness: true, + format: ->(local_target) { /\A#{local_target.target&.code}\.\d+/ } + validates :target, presence: true + + belongs_to :target + + def <=>(local_target) + return unless local_target.class == self.class + + [target, numeric_subcode] <=> [local_target.target, local_target.numeric_subcode] + end + + protected + + def numeric_subcode + subcode.to_i + end + + private + + def subcode + code.split(".").last + end +end diff --git a/app/models/sdg/target.rb b/app/models/sdg/target.rb index ad165e280..6ff87d155 100644 --- a/app/models/sdg/target.rb +++ b/app/models/sdg/target.rb @@ -6,6 +6,7 @@ class SDG::Target < ApplicationRecord validates :goal, presence: true belongs_to :goal + has_many :local_targets, dependent: :destroy def title I18n.t("sdg.goals.goal_#{goal.code}.targets.target_#{code_key}.title") diff --git a/config/locales/en/activerecord.yml b/config/locales/en/activerecord.yml index 5721fc5e5..ca6200560 100644 --- a/config/locales/en/activerecord.yml +++ b/config/locales/en/activerecord.yml @@ -571,6 +571,10 @@ en: attributes: locale: already_translated: Already translated resource + sdg/local_target: + attributes: + code: + invalid: "must start with the same code as its target followed by a dot and end with a number" messages: translations_too_short: Is mandatory to provide one translation at least record_invalid: "Validation failed: %{errors}" diff --git a/config/locales/es/activerecord.yml b/config/locales/es/activerecord.yml index 4abe798c7..0b82e9120 100644 --- a/config/locales/es/activerecord.yml +++ b/config/locales/es/activerecord.yml @@ -573,6 +573,10 @@ es: attributes: locale: already_translated: Recurso ya traducido + sdg/local_target: + attributes: + code: + invalid: "debe empezar con el código de su meta seguido de un punto y terminar con un número" messages: translations_too_short: El obligatorio proporcionar una traducción como mínimo record_invalid: "Error de validación: %{errors}" diff --git a/db/migrate/20201123124006_create_sdg_local_targets.rb b/db/migrate/20201123124006_create_sdg_local_targets.rb new file mode 100644 index 000000000..264a9cee9 --- /dev/null +++ b/db/migrate/20201123124006_create_sdg_local_targets.rb @@ -0,0 +1,22 @@ +class CreateSDGLocalTargets < ActiveRecord::Migration[5.2] + def change + create_table :sdg_local_targets do |t| + t.references :target + t.string :code + t.timestamps + + t.index :code, unique: true + end + + create_table :sdg_local_target_translations do |t| + t.bigint :sdg_local_target_id, null: false + t.string :locale, null: false + t.string :title + t.text :description + t.timestamps null: false + + t.index :locale + t.index :sdg_local_target_id + end + end +end diff --git a/db/schema.rb b/db/schema.rb index 5b1944278..601a3cdd3 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 2020_11_17_200945) do +ActiveRecord::Schema.define(version: 2020_11_23_124006) do # These are extensions that must be enabled in order to support this database enable_extension "pg_trgm" @@ -1304,6 +1304,26 @@ ActiveRecord::Schema.define(version: 2020_11_17_200945) do t.index ["code"], name: "index_sdg_goals_on_code", unique: true end + create_table "sdg_local_target_translations", force: :cascade do |t| + t.bigint "sdg_local_target_id", null: false + t.string "locale", null: false + t.string "title" + t.text "description" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index ["locale"], name: "index_sdg_local_target_translations_on_locale" + t.index ["sdg_local_target_id"], name: "index_sdg_local_target_translations_on_sdg_local_target_id" + end + + create_table "sdg_local_targets", force: :cascade do |t| + t.bigint "target_id" + t.string "code" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index ["code"], name: "index_sdg_local_targets_on_code", unique: true + t.index ["target_id"], name: "index_sdg_local_targets_on_target_id" + end + create_table "sdg_relations", force: :cascade do |t| t.string "related_sdg_type" t.bigint "related_sdg_id" diff --git a/spec/factories/sdg.rb b/spec/factories/sdg.rb index 5e46622e8..9495a4114 100644 --- a/spec/factories/sdg.rb +++ b/spec/factories/sdg.rb @@ -6,4 +6,12 @@ FactoryBot.define do factory :sdg_target, class: "SDG::Target" do sequence(:code, 1) { |n| "#{n}.#{n}" } end + + factory :sdg_local_target, class: "SDG::LocalTarget" do + code { "1.1.1" } + sequence(:title) { |n| "Local Target #{n} title" } + sequence(:description) { |n| "Help for Local Target #{n}" } + + target { SDG::Target[code.rpartition(".").first] } + end end diff --git a/spec/models/sdg/local_target_spec.rb b/spec/models/sdg/local_target_spec.rb new file mode 100644 index 000000000..24c51c683 --- /dev/null +++ b/spec/models/sdg/local_target_spec.rb @@ -0,0 +1,77 @@ +require "rails_helper" + +describe SDG::LocalTarget do + describe "Concerns" do + it_behaves_like "globalizable", :sdg_local_target + end + + it "is valid" do + expect(build(:sdg_local_target)).to be_valid + end + + it "is not valid without a title" do + expect(build(:sdg_local_target, title: nil)).not_to be_valid + end + + it "is not valid without a description" do + expect(build(:sdg_local_target, description: nil)).not_to be_valid + end + + it "is not valid without a code" do + expect(build(:sdg_local_target, code: nil, target: SDG::Target[1.1])).not_to be_valid + end + + it "is not valid when code does not include associated target code" do + local_target = build(:sdg_local_target, code: "1.6.1", target: SDG::Target[1.1]) + + expect(local_target).not_to be_valid + expect(local_target.errors.full_messages).to include "Code must start with the same code as its target followed by a dot and end with a number" + end + + it "is not valid when local target code part is not a number" do + local_target = build(:sdg_local_target, code: "1.1.A", target: SDG::Target[1.1]) + + expect(local_target).not_to be_valid + expect(local_target.errors.full_messages).to include "Code must start with the same code as its target followed by a dot and end with a number" + end + + it "is not valid if code is not unique" do + create(:sdg_local_target, code: "1.1.1") + local_target = build(:sdg_local_target, code: "1.1.1") + + expect(local_target).not_to be_valid + expect(local_target.errors.full_messages).to include "Code has already been taken" + end + + it "is not valid without a target" do + expect(build(:sdg_local_target, target: nil)).not_to be_valid + end + + describe "#goal" do + it "returns the target goal" do + local_target = create(:sdg_local_target, code: "1.1.1") + + expect(local_target.goal).to eq(SDG::Goal[1]) + end + end + + describe "#<=>" do + let(:local_target,) { create(:sdg_local_target, code: "10.B.10") } + + it "compares using the target first" do + lesser_local_target = create(:sdg_local_target, code: "10.A.1") + greater_local_target = create(:sdg_local_target, code: "11.1.1") + + expect(local_target).to be > lesser_local_target + expect(local_target).to be < greater_local_target + end + + it "compares using the local target code when the target is the same" do + lesser_local_target = create(:sdg_local_target, code: "10.B.9") + greater_local_target = create(:sdg_local_target, code: "10.B.11") + + expect(local_target).to be > lesser_local_target + expect(local_target).to be < greater_local_target + end + end +end diff --git a/spec/models/sdg/relatable_spec.rb b/spec/models/sdg/relatable_spec.rb index 4b87971be..e6fd1b8d0 100644 --- a/spec/models/sdg/relatable_spec.rb +++ b/spec/models/sdg/relatable_spec.rb @@ -3,8 +3,10 @@ require "rails_helper" describe SDG::Relatable do let(:goal) { SDG::Goal[1] } let(:target) { SDG::Target["1.2"] } + let(:local_target) { create(:sdg_local_target, code: "1.2.1") } let(:another_goal) { SDG::Goal[2] } let(:another_target) { SDG::Target["2.3"] } + let(:another_local_target) { create(:sdg_local_target, code: "2.3.1") } let(:relatable) { create(:proposal) } @@ -44,12 +46,32 @@ describe SDG::Relatable do end end + describe "#sdg_local_targets" do + it "can assign local targets to a model" do + relatable.sdg_local_targets = [local_target, another_local_target] + + expect(SDG::Relation.count).to be 2 + expect(SDG::Relation.first.relatable).to eq relatable + expect(SDG::Relation.last.relatable).to eq relatable + expect(SDG::Relation.first.related_sdg).to eq local_target + expect(SDG::Relation.last.related_sdg).to eq another_local_target + end + + it "can obtain the list of local targets" do + relatable.sdg_local_targets = [local_target, another_local_target] + + expect(relatable.reload.sdg_local_targets).to match_array [local_target, another_local_target] + end + end + describe "#related_sdgs" do it "returns all related goals and targets" do relatable.sdg_goals = [goal, another_goal] relatable.sdg_targets = [target, another_target] + relatable.sdg_local_targets = [local_target, another_local_target] - expect(relatable.reload.related_sdgs).to match_array [goal, another_goal, target, another_target] + related_sdgs = [goal, another_goal, target, another_target, local_target, another_local_target] + expect(relatable.reload.related_sdgs).to match_array related_sdgs end end end From 88bcf527d8808265196e79443cb8bffb5128c38e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sen=C3=A9n=20Rodero=20Rodr=C3=ADguez?= Date: Mon, 23 Nov 2020 17:29:40 +0100 Subject: [PATCH 02/10] Add local_targets index to the administration --- .../local_targets/index_component.html.erb | 33 +++++++++++++++++++ .../local_targets/index_component.rb | 23 +++++++++++++ .../sdg_management/subnavigation_component.rb | 2 +- .../local_targets_controller.rb | 7 ++++ .../local_targets/index.html.erb | 1 + config/locales/en/activerecord.yml | 7 ++++ config/locales/es/activerecord.yml | 7 ++++ config/routes/sdg_management.rb | 1 + .../sdg_management/local_targets_spec.rb | 33 +++++++++++++++++++ 9 files changed, 113 insertions(+), 1 deletion(-) create mode 100644 app/components/sdg_management/local_targets/index_component.html.erb create mode 100644 app/components/sdg_management/local_targets/index_component.rb create mode 100644 app/controllers/sdg_management/local_targets_controller.rb create mode 100644 app/views/sdg_management/local_targets/index.html.erb create mode 100644 spec/system/sdg_management/local_targets_spec.rb diff --git a/app/components/sdg_management/local_targets/index_component.html.erb b/app/components/sdg_management/local_targets/index_component.html.erb new file mode 100644 index 000000000..c8b14d546 --- /dev/null +++ b/app/components/sdg_management/local_targets/index_component.html.erb @@ -0,0 +1,33 @@ +<%= header %> + +<%= render SDGManagement::SubnavigationComponent.new(current: :local_targets) do %> + + + + + + + + + + <% local_targets.group_by(&:target).map do |target, local_targets| %> + + + + + <% local_targets.each do |local_target| %> + + + + + <% end %> + <% end %> + +
<%= attribute_name(:title) %>
+ <%= target.code %> <%= target.title %> +
+ <%= local_target.code %> + + <%= local_target.title %> +
+<% end %> diff --git a/app/components/sdg_management/local_targets/index_component.rb b/app/components/sdg_management/local_targets/index_component.rb new file mode 100644 index 000000000..38d767b8d --- /dev/null +++ b/app/components/sdg_management/local_targets/index_component.rb @@ -0,0 +1,23 @@ +class SDGManagement::LocalTargets::IndexComponent < ApplicationComponent + include SDGManagement::Header + + attr_reader :local_targets + + def initialize(local_targets) + @local_targets = local_targets + end + + private + + def title + SDG::LocalTarget.model_name.human(count: 2).titleize + end + + def attribute_name(attribute) + SDG::LocalTarget.human_attribute_name(attribute) + end + + def header_id(object) + "#{dom_id(object)}_header" + end +end diff --git a/app/components/sdg_management/subnavigation_component.rb b/app/components/sdg_management/subnavigation_component.rb index 35d1a0fda..41096a618 100644 --- a/app/components/sdg_management/subnavigation_component.rb +++ b/app/components/sdg_management/subnavigation_component.rb @@ -8,7 +8,7 @@ class SDGManagement::SubnavigationComponent < ApplicationComponent private def sections - %i[goals targets] + %i[goals targets local_targets] end def link_to_section(section) diff --git a/app/controllers/sdg_management/local_targets_controller.rb b/app/controllers/sdg_management/local_targets_controller.rb new file mode 100644 index 000000000..2db2b5d68 --- /dev/null +++ b/app/controllers/sdg_management/local_targets_controller.rb @@ -0,0 +1,7 @@ +class SDGManagement::LocalTargetsController < SDGManagement::BaseController + LocalTarget = ::SDG::LocalTarget + + def index + @local_targets = LocalTarget.all.sort + end +end diff --git a/app/views/sdg_management/local_targets/index.html.erb b/app/views/sdg_management/local_targets/index.html.erb new file mode 100644 index 000000000..de6e04103 --- /dev/null +++ b/app/views/sdg_management/local_targets/index.html.erb @@ -0,0 +1 @@ +<%= render SDGManagement::LocalTargets::IndexComponent.new(@local_targets) %> diff --git a/config/locales/en/activerecord.yml b/config/locales/en/activerecord.yml index ca6200560..0ec2fc59f 100644 --- a/config/locales/en/activerecord.yml +++ b/config/locales/en/activerecord.yml @@ -75,6 +75,9 @@ en: sdg/goal: one: "goal" other: "goals" + sdg/local_target: + one: "local target" + other: "local targets" sdg/target: one: "target" other: "targets" @@ -318,6 +321,10 @@ en: code: "Code" title: "Title" description: "Description" + sdg/local_target: + title: "Title" + sdg/local_target/translation: + title: "Title" sdg/target: code: "Code" title: "Title" diff --git a/config/locales/es/activerecord.yml b/config/locales/es/activerecord.yml index 0b82e9120..32319ae1f 100644 --- a/config/locales/es/activerecord.yml +++ b/config/locales/es/activerecord.yml @@ -75,6 +75,9 @@ es: sdg/goal: one: "objetivo" other: "objetivos" + sdg/local_target: + one: "meta localizada" + other: "metas localizadas" sdg/target: one: "meta" other: "metas" @@ -315,6 +318,10 @@ es: code: "Código" title: "Título" description: "Descripción" + sdg/local_target: + title: "Título" + sdg/local_target/translation: + title: "Título" sdg/target: code: "Código" title: "Título" diff --git a/config/routes/sdg_management.rb b/config/routes/sdg_management.rb index 50b0f45d5..ae1a232e4 100644 --- a/config/routes/sdg_management.rb +++ b/config/routes/sdg_management.rb @@ -3,4 +3,5 @@ namespace :sdg_management do resources :goals, only: [:index] resources :targets, only: [:index] + resources :local_targets, only: [:index] end diff --git a/spec/system/sdg_management/local_targets_spec.rb b/spec/system/sdg_management/local_targets_spec.rb new file mode 100644 index 000000000..89f550b0e --- /dev/null +++ b/spec/system/sdg_management/local_targets_spec.rb @@ -0,0 +1,33 @@ +require "rails_helper" + +describe "Local Targets", :js do + before do + login_as(create(:administrator).user) + Setting["feature.sdg"] = true + end + + describe "Index" do + scenario "Visit the index" do + create(:sdg_local_target, code: "1.1.1", title: "Affordable food") + + visit sdg_management_goals_path + click_link "Local Targets" + + expect(page).to have_title "SDG content - Local Targets" + within("table") { expect(page).to have_content "Affordable food for everyone" } + end + + scenario "Show local targets grouped by target" do + target_1 = SDG::Target["1.1"] + target_1_local_target = create(:sdg_local_target, code: "1.1.1", target: target_1) + target_2 = SDG::Target["2.1"] + target_2_local_target = create(:sdg_local_target, code: "2.1.1", target: target_2) + + visit sdg_management_local_targets_path + + expect(target_1.title).to appear_before(target_1_local_target.title) + expect(target_1_local_target.title).to appear_before(target_2.title) + expect(target_2.title).to appear_before(target_2_local_target.title) + end + end +end From 3364423698851f6466bae7fe9bc6a2ae1007daae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sen=C3=A9n=20Rodero=20Rodr=C3=ADguez?= Date: Tue, 24 Nov 2020 18:05:44 +0100 Subject: [PATCH 03/10] Update SDG header component MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add a header element as component markup wrapper * Allow component to receive an optional block * Add reusable styles for header links Co-autored-by: Javi Martín --- app/assets/stylesheets/admin.scss | 10 ++++++++++ app/assets/stylesheets/mixins.scss | 11 +++++++++++ app/components/sdg_management/header.rb | 10 ++++++++-- 3 files changed, 29 insertions(+), 2 deletions(-) diff --git a/app/assets/stylesheets/admin.scss b/app/assets/stylesheets/admin.scss index e6bab74a3..cd79a951b 100644 --- a/app/assets/stylesheets/admin.scss +++ b/app/assets/stylesheets/admin.scss @@ -614,6 +614,16 @@ code { } } +.admin-content > header { + align-items: flex-start; + display: flex; + + a { + @include hollow-button; + margin-left: auto; + } +} + .admin-content .select-geozone, .admin-content .select-heading { diff --git a/app/assets/stylesheets/mixins.scss b/app/assets/stylesheets/mixins.scss index 060e31d83..875a1b913 100644 --- a/app/assets/stylesheets/mixins.scss +++ b/app/assets/stylesheets/mixins.scss @@ -198,3 +198,14 @@ transform: translateX(-50%); } } + +@mixin hollow-button($color: $link) { + @include button($style: hollow, $background: $color); + font-size: $base-font-size; + margin-bottom: 0; + + &:focus, + &:hover { + text-decoration: none; + } +} diff --git a/app/components/sdg_management/header.rb b/app/components/sdg_management/header.rb index 0a9370031..c9cb60d6e 100644 --- a/app/components/sdg_management/header.rb +++ b/app/components/sdg_management/header.rb @@ -1,11 +1,17 @@ module SDGManagement::Header extend ActiveSupport::Concern - def header + def header(&block) provide(:title) do "#{t("sdg_management.header.title")} - #{title}" end - tag.h2 title + tag.header do + if block_given? + tag.h2(title) + capture(&block) + else + tag.h2(title) + end + end end end From 5611f589097710285ad7361e7aa6c17d9681d277 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sen=C3=A9n=20Rodero=20Rodr=C3=ADguez?= Date: Tue, 24 Nov 2020 17:06:54 +0100 Subject: [PATCH 04/10] Add SDG page to create local targets --- .../local_targets/form_component.html.erb | 41 +++++++++++++++++++ .../local_targets/form_component.rb | 40 ++++++++++++++++++ .../local_targets/index_component.html.erb | 6 ++- .../local_targets_controller.rb | 23 +++++++++++ .../sdg_management/local_targets/new.html.erb | 1 + config/locales/en/activerecord.yml | 3 ++ config/locales/en/general.yml | 1 + config/locales/en/sdg_management.yml | 10 +++++ config/locales/es/activerecord.yml | 3 ++ config/locales/es/general.yml | 1 + config/locales/es/sdg_management.yml | 10 +++++ config/routes/sdg_management.rb | 2 +- .../sdg_management/local_targets_spec.rb | 29 +++++++++++++ 13 files changed, 168 insertions(+), 2 deletions(-) create mode 100644 app/components/sdg_management/local_targets/form_component.html.erb create mode 100644 app/components/sdg_management/local_targets/form_component.rb create mode 100644 app/views/sdg_management/local_targets/new.html.erb diff --git a/app/components/sdg_management/local_targets/form_component.html.erb b/app/components/sdg_management/local_targets/form_component.html.erb new file mode 100644 index 000000000..df7c8a9ae --- /dev/null +++ b/app/components/sdg_management/local_targets/form_component.html.erb @@ -0,0 +1,41 @@ +<%= back_link_to sdg_management_local_targets_path %> + +<%= header %> + +<%= render "shared/globalize_locales", resource: local_target %> + +<%= translatable_form_for [:sdg_managment, local_target], url: form_url do |f| %> + <%= render "shared/errors", resource: local_target %> + +
+
+ <%= f.select :target_id, target_options %> +
+
+ +
+
+ <%= f.text_field :code, hint: t("sdg_management.local_targets.form.code") %> +
+
+ +
+ <%= f.translatable_fields do |translations_form| %> +
+ <%= translations_form.text_field :title %> +
+ +
+ <%= translations_form.text_area :description, + rows: 4, + hint: t("sdg_management.local_targets.form.description") %> +
+ <% end %> +
+ +
+
+ <%= f.submit class: "button" %> +
+
+<% end %> diff --git a/app/components/sdg_management/local_targets/form_component.rb b/app/components/sdg_management/local_targets/form_component.rb new file mode 100644 index 000000000..2d54e1ecd --- /dev/null +++ b/app/components/sdg_management/local_targets/form_component.rb @@ -0,0 +1,40 @@ +class SDGManagement::LocalTargets::FormComponent < ApplicationComponent + delegate :back_link_to, to: :helpers + include SDGManagement::Header + include TranslatableFormHelper + include GlobalizeHelper + + attr_reader :local_target + + def initialize(local_target) + @local_target = local_target + end + + private + + def title + t("sdg_management.local_targets.new.title") + end + + def form_url + if local_target.persisted? + sdg_management_local_target_path(local_target) + else + sdg_management_local_targets_path + end + end + + def target_options + grouped_targets = SDG::Goal.order(:code).map do |goal| + [ + code_and_title(goal), + goal.targets.sort.map { |target| [code_and_title(target), target.id] } + ] + end + grouped_options_for_select(grouped_targets, local_target.target_id) + end + + def code_and_title(resource) + "#{resource.code} #{resource.title}" + end +end diff --git a/app/components/sdg_management/local_targets/index_component.html.erb b/app/components/sdg_management/local_targets/index_component.html.erb index c8b14d546..383dbfbfa 100644 --- a/app/components/sdg_management/local_targets/index_component.html.erb +++ b/app/components/sdg_management/local_targets/index_component.html.erb @@ -1,4 +1,8 @@ -<%= header %> +<%= header do %> + <%= link_to t("sdg_management.local_targets.index.new"), + new_sdg_management_local_target_path, + class: "new-link" %> +<% end %> <%= render SDGManagement::SubnavigationComponent.new(current: :local_targets) do %> diff --git a/app/controllers/sdg_management/local_targets_controller.rb b/app/controllers/sdg_management/local_targets_controller.rb index 2db2b5d68..ba9e4cfe6 100644 --- a/app/controllers/sdg_management/local_targets_controller.rb +++ b/app/controllers/sdg_management/local_targets_controller.rb @@ -1,7 +1,30 @@ class SDGManagement::LocalTargetsController < SDGManagement::BaseController + include Translatable + LocalTarget = ::SDG::LocalTarget def index @local_targets = LocalTarget.all.sort end + + def new + @local_target = LocalTarget.new + end + + def create + @local_target = LocalTarget.new(local_target_params) + + if @local_target.save + redirect_to sdg_management_local_targets_path, notice: t("sdg_management.local_targets.create.notice") + else + render :new + end + end + + private + + def local_target_params + translations_attributes = translation_params(LocalTarget) + params.require(:sdg_local_target).permit(:code, :target_id, translations_attributes) + end end diff --git a/app/views/sdg_management/local_targets/new.html.erb b/app/views/sdg_management/local_targets/new.html.erb new file mode 100644 index 000000000..07818dd63 --- /dev/null +++ b/app/views/sdg_management/local_targets/new.html.erb @@ -0,0 +1 @@ +<%= render SDGManagement::LocalTargets::FormComponent.new(@local_target) %> diff --git a/config/locales/en/activerecord.yml b/config/locales/en/activerecord.yml index 0ec2fc59f..73edfc440 100644 --- a/config/locales/en/activerecord.yml +++ b/config/locales/en/activerecord.yml @@ -322,9 +322,12 @@ en: title: "Title" description: "Description" sdg/local_target: + code: "Code" + target_id: "Target" title: "Title" sdg/local_target/translation: title: "Title" + description: "Description" sdg/target: code: "Code" title: "Title" diff --git a/config/locales/en/general.yml b/config/locales/en/general.yml index 293e3b4e7..5a47cdb64 100644 --- a/config/locales/en/general.yml +++ b/config/locales/en/general.yml @@ -190,6 +190,7 @@ en: local_census_records/import: Local Census Records Import site_customization/content_block: content block site_customization/page: page + sdg/local_target: local target geozones: none: All city layouts: diff --git a/config/locales/en/sdg_management.yml b/config/locales/en/sdg_management.yml index d71b2e7be..8652a0b07 100644 --- a/config/locales/en/sdg_management.yml +++ b/config/locales/en/sdg_management.yml @@ -4,3 +4,13 @@ en: title: "SDG content" menu: sdg_content: "Goals and Targets" + local_targets: + create: + notice: "Local target created successfully" + form: + code: "Code must start with the selected target code followed by a dot" + description: "This description will be shown as help to users." + index: + new: "Create local target" + new: + title: "New local target" diff --git a/config/locales/es/activerecord.yml b/config/locales/es/activerecord.yml index 32319ae1f..070ec9aa4 100644 --- a/config/locales/es/activerecord.yml +++ b/config/locales/es/activerecord.yml @@ -319,9 +319,12 @@ es: title: "Título" description: "Descripción" sdg/local_target: + code: "Código" + target_id: "Meta" title: "Título" sdg/local_target/translation: title: "Título" + description: "Descripción" sdg/target: code: "Código" title: "Título" diff --git a/config/locales/es/general.yml b/config/locales/es/general.yml index 660cc7835..7f7b2b713 100644 --- a/config/locales/es/general.yml +++ b/config/locales/es/general.yml @@ -190,6 +190,7 @@ es: local_census_records/import: la importación de registros del censo local site_customization/content_block: el bloque site_customization/page: la página + sdg/local_target: la meta localizada geozones: none: Toda la ciudad layouts: diff --git a/config/locales/es/sdg_management.yml b/config/locales/es/sdg_management.yml index 58a378678..a26748835 100644 --- a/config/locales/es/sdg_management.yml +++ b/config/locales/es/sdg_management.yml @@ -4,3 +4,13 @@ es: title: "Contenido ODS" menu: sdg_content: "Objetivos y Metas" + local_targets: + create: + notice: "Meta localizada creada correctamente" + form: + code: "El código debe comenzar por el código de la meta seleccionada seguida de un '.'" + description: "Este texto ser mostrará como ayuda para los usuarios." + index: + new: "Crear meta localizada" + new: + title: "Nueva meta localizada" diff --git a/config/routes/sdg_management.rb b/config/routes/sdg_management.rb index ae1a232e4..5ca450cf3 100644 --- a/config/routes/sdg_management.rb +++ b/config/routes/sdg_management.rb @@ -3,5 +3,5 @@ namespace :sdg_management do resources :goals, only: [:index] resources :targets, only: [:index] - resources :local_targets, only: [:index] + resources :local_targets, only: [:index, :new, :create] end diff --git a/spec/system/sdg_management/local_targets_spec.rb b/spec/system/sdg_management/local_targets_spec.rb index 89f550b0e..61f042552 100644 --- a/spec/system/sdg_management/local_targets_spec.rb +++ b/spec/system/sdg_management/local_targets_spec.rb @@ -15,6 +15,7 @@ describe "Local Targets", :js do expect(page).to have_title "SDG content - Local Targets" within("table") { expect(page).to have_content "Affordable food for everyone" } + expect(page).to have_link "Create local target", href: new_sdg_management_local_target_path end scenario "Show local targets grouped by target" do @@ -30,4 +31,32 @@ describe "Local Targets", :js do expect(target_2.title).to appear_before(target_2_local_target.title) end end + + describe "Create" do + scenario "Shows succesful notice when form is fullfilled correctly" do + visit new_sdg_management_local_target_path + + target = SDG::Target["1.1"] + select "#{target.code} #{target.title}", from: "Target" + fill_in "Code", with: "1.1.1" + fill_in "Title", with: "Local target title" + fill_in "Description", with: "Local target description" + click_button "Create local target" + + expect(page).to have_content("Local target created successfully") + expect(page).to have_content("1.1.1") + end + + scenario "Shows form errors when not valid" do + visit new_sdg_management_local_target_path + + target = SDG::Target["2.3"] + code_and_title = "#{target.code} #{target.title}" + select code_and_title, from: "Target" + click_button "Create local target" + + expect(page).to have_content("errors prevented this local target from being saved.") + expect(page).to have_select("Target", selected: code_and_title) + end + end end From eb0f13018c398dfe6d8273d5b9c1f1d4f6feff90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sen=C3=A9n=20Rodero=20Rodr=C3=ADguez?= Date: Tue, 24 Nov 2020 18:52:41 +0100 Subject: [PATCH 05/10] Add actions column to SDG local targets index --- .../sdg_management/local_targets/index_component.html.erb | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/components/sdg_management/local_targets/index_component.html.erb b/app/components/sdg_management/local_targets/index_component.html.erb index 383dbfbfa..cb6804b87 100644 --- a/app/components/sdg_management/local_targets/index_component.html.erb +++ b/app/components/sdg_management/local_targets/index_component.html.erb @@ -10,13 +10,14 @@ + <% local_targets.group_by(&:target).map do |target, local_targets| %> - @@ -29,6 +30,8 @@ + <% end %> <% end %> From a21193774401f60178c3b76b680360d800069aa9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sen=C3=A9n=20Rodero=20Rodr=C3=ADguez?= Date: Wed, 25 Nov 2020 10:59:55 +0100 Subject: [PATCH 06/10] Add SDG page to update local targets --- .../local_targets/form_component.rb | 6 +++- .../local_targets/index_component.html.erb | 1 + .../local_targets/index_component.rb | 7 +++++ .../local_targets_controller.rb | 14 +++++++++ .../local_targets/edit.html.erb | 1 + config/locales/en/sdg_management.yml | 4 +++ config/locales/es/sdg_management.yml | 4 +++ config/routes/sdg_management.rb | 2 +- .../sdg_management/local_targets_spec.rb | 29 +++++++++++++++++-- 9 files changed, 64 insertions(+), 4 deletions(-) create mode 100644 app/views/sdg_management/local_targets/edit.html.erb diff --git a/app/components/sdg_management/local_targets/form_component.rb b/app/components/sdg_management/local_targets/form_component.rb index 2d54e1ecd..933e70bd1 100644 --- a/app/components/sdg_management/local_targets/form_component.rb +++ b/app/components/sdg_management/local_targets/form_component.rb @@ -13,7 +13,11 @@ class SDGManagement::LocalTargets::FormComponent < ApplicationComponent private def title - t("sdg_management.local_targets.new.title") + if local_target.persisted? + t("sdg_management.local_targets.edit.title") + else + t("sdg_management.local_targets.new.title") + end end def form_url diff --git a/app/components/sdg_management/local_targets/index_component.html.erb b/app/components/sdg_management/local_targets/index_component.html.erb index cb6804b87..0512c531b 100644 --- a/app/components/sdg_management/local_targets/index_component.html.erb +++ b/app/components/sdg_management/local_targets/index_component.html.erb @@ -31,6 +31,7 @@ <%= local_target.title %> <% end %> diff --git a/app/components/sdg_management/local_targets/index_component.rb b/app/components/sdg_management/local_targets/index_component.rb index 38d767b8d..44a2ea46b 100644 --- a/app/components/sdg_management/local_targets/index_component.rb +++ b/app/components/sdg_management/local_targets/index_component.rb @@ -20,4 +20,11 @@ class SDGManagement::LocalTargets::IndexComponent < ApplicationComponent def header_id(object) "#{dom_id(object)}_header" end + + def actions(local_target) + render Admin::TableActionsComponent.new( + local_target, + actions: [:edit], + edit_path: edit_sdg_management_local_target_path(local_target)) + end end diff --git a/app/controllers/sdg_management/local_targets_controller.rb b/app/controllers/sdg_management/local_targets_controller.rb index ba9e4cfe6..3d03fd812 100644 --- a/app/controllers/sdg_management/local_targets_controller.rb +++ b/app/controllers/sdg_management/local_targets_controller.rb @@ -21,6 +21,20 @@ class SDGManagement::LocalTargetsController < SDGManagement::BaseController end end + def edit + @local_target = LocalTarget.find(params[:id]) + end + + def update + @local_target = LocalTarget.find(params[:id]) + + if @local_target.update(local_target_params) + redirect_to sdg_management_local_targets_path, notice: t("sdg_management.local_targets.update.notice") + else + render :edit + end + end + private def local_target_params diff --git a/app/views/sdg_management/local_targets/edit.html.erb b/app/views/sdg_management/local_targets/edit.html.erb new file mode 100644 index 000000000..07818dd63 --- /dev/null +++ b/app/views/sdg_management/local_targets/edit.html.erb @@ -0,0 +1 @@ +<%= render SDGManagement::LocalTargets::FormComponent.new(@local_target) %> diff --git a/config/locales/en/sdg_management.yml b/config/locales/en/sdg_management.yml index 8652a0b07..f5b4ae58a 100644 --- a/config/locales/en/sdg_management.yml +++ b/config/locales/en/sdg_management.yml @@ -7,6 +7,8 @@ en: local_targets: create: notice: "Local target created successfully" + edit: + title: "Edit local target" form: code: "Code must start with the selected target code followed by a dot" description: "This description will be shown as help to users." @@ -14,3 +16,5 @@ en: new: "Create local target" new: title: "New local target" + update: + notice: "Local target updated successfully" diff --git a/config/locales/es/sdg_management.yml b/config/locales/es/sdg_management.yml index a26748835..7fa86f5bf 100644 --- a/config/locales/es/sdg_management.yml +++ b/config/locales/es/sdg_management.yml @@ -7,6 +7,8 @@ es: local_targets: create: notice: "Meta localizada creada correctamente" + edit: + title: "Editar meta localizada" form: code: "El código debe comenzar por el código de la meta seleccionada seguida de un '.'" description: "Este texto ser mostrará como ayuda para los usuarios." @@ -14,3 +16,5 @@ es: new: "Crear meta localizada" new: title: "Nueva meta localizada" + update: + notice: "Meta localizada asctualizada correctamente" diff --git a/config/routes/sdg_management.rb b/config/routes/sdg_management.rb index 5ca450cf3..0aa11ab32 100644 --- a/config/routes/sdg_management.rb +++ b/config/routes/sdg_management.rb @@ -3,5 +3,5 @@ namespace :sdg_management do resources :goals, only: [:index] resources :targets, only: [:index] - resources :local_targets, only: [:index, :new, :create] + resources :local_targets, only: [:index, :new, :create, :edit, :update] end diff --git a/spec/system/sdg_management/local_targets_spec.rb b/spec/system/sdg_management/local_targets_spec.rb index 61f042552..5430ed721 100644 --- a/spec/system/sdg_management/local_targets_spec.rb +++ b/spec/system/sdg_management/local_targets_spec.rb @@ -14,8 +14,10 @@ describe "Local Targets", :js do click_link "Local Targets" expect(page).to have_title "SDG content - Local Targets" - within("table") { expect(page).to have_content "Affordable food for everyone" } - expect(page).to have_link "Create local target", href: new_sdg_management_local_target_path + within("table tr", text: "Affordable food") do + expect(page).to have_link "Edit" + end + expect(page).to have_link "Create local target" end scenario "Show local targets grouped by target" do @@ -59,4 +61,27 @@ describe "Local Targets", :js do expect(page).to have_select("Target", selected: code_and_title) end end + + describe "Update" do + let!(:local_target) { create(:sdg_local_target, code: "1.1.1") } + + scenario "Shows succesful notice when form is fullfilled correctly" do + visit edit_sdg_management_local_target_path(local_target) + + fill_in "Title", with: "Local target title update" + click_button "Update local target" + + expect(page).to have_content("Local target updated successfully") + expect(page).to have_content("Local target title update") + end + + scenario "Shows form errors when changes are not valid" do + visit edit_sdg_management_local_target_path(local_target) + + fill_in "Title", with: "" + click_button "Update local target" + + expect(page).to have_content("1 error prevented this local target from being saved.") + end + end end From 8f7809ddb483038feab980ed5b7ca70a1cd5b657 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sen=C3=A9n=20Rodero=20Rodr=C3=ADguez?= Date: Wed, 25 Nov 2020 15:25:51 +0100 Subject: [PATCH 07/10] Allow to destroy SDG local targets --- .../sdg_management/local_targets/index_component.rb | 4 ++-- .../sdg_management/local_targets_controller.rb | 6 ++++++ config/locales/en/sdg_management.yml | 2 ++ config/locales/es/sdg_management.yml | 2 ++ config/routes/sdg_management.rb | 2 +- spec/system/sdg_management/local_targets_spec.rb | 13 +++++++++++++ 6 files changed, 26 insertions(+), 3 deletions(-) diff --git a/app/components/sdg_management/local_targets/index_component.rb b/app/components/sdg_management/local_targets/index_component.rb index 44a2ea46b..882836409 100644 --- a/app/components/sdg_management/local_targets/index_component.rb +++ b/app/components/sdg_management/local_targets/index_component.rb @@ -24,7 +24,7 @@ class SDGManagement::LocalTargets::IndexComponent < ApplicationComponent def actions(local_target) render Admin::TableActionsComponent.new( local_target, - actions: [:edit], - edit_path: edit_sdg_management_local_target_path(local_target)) + edit_path: edit_sdg_management_local_target_path(local_target), + destroy_path: sdg_management_local_target_path(local_target)) end end diff --git a/app/controllers/sdg_management/local_targets_controller.rb b/app/controllers/sdg_management/local_targets_controller.rb index 3d03fd812..d23fe06a7 100644 --- a/app/controllers/sdg_management/local_targets_controller.rb +++ b/app/controllers/sdg_management/local_targets_controller.rb @@ -35,6 +35,12 @@ class SDGManagement::LocalTargetsController < SDGManagement::BaseController end end + def destroy + @local_target = LocalTarget.find(params[:id]) + @local_target.destroy! + redirect_to sdg_management_local_targets_path, notice: t("sdg_management.local_targets.destroy.notice") + end + private def local_target_params diff --git a/config/locales/en/sdg_management.yml b/config/locales/en/sdg_management.yml index f5b4ae58a..1e075fd76 100644 --- a/config/locales/en/sdg_management.yml +++ b/config/locales/en/sdg_management.yml @@ -7,6 +7,8 @@ en: local_targets: create: notice: "Local target created successfully" + destroy: + notice: "Local target deleted successfully" edit: title: "Edit local target" form: diff --git a/config/locales/es/sdg_management.yml b/config/locales/es/sdg_management.yml index 7fa86f5bf..4ee4d8893 100644 --- a/config/locales/es/sdg_management.yml +++ b/config/locales/es/sdg_management.yml @@ -7,6 +7,8 @@ es: local_targets: create: notice: "Meta localizada creada correctamente" + destroy: + notice: "Meta localizada eliminada correctamente" edit: title: "Editar meta localizada" form: diff --git a/config/routes/sdg_management.rb b/config/routes/sdg_management.rb index 0aa11ab32..cad7cbe66 100644 --- a/config/routes/sdg_management.rb +++ b/config/routes/sdg_management.rb @@ -3,5 +3,5 @@ namespace :sdg_management do resources :goals, only: [:index] resources :targets, only: [:index] - resources :local_targets, only: [:index, :new, :create, :edit, :update] + resources :local_targets, except: [:show] end diff --git a/spec/system/sdg_management/local_targets_spec.rb b/spec/system/sdg_management/local_targets_spec.rb index 5430ed721..437ec6c22 100644 --- a/spec/system/sdg_management/local_targets_spec.rb +++ b/spec/system/sdg_management/local_targets_spec.rb @@ -16,6 +16,7 @@ describe "Local Targets", :js do expect(page).to have_title "SDG content - Local Targets" within("table tr", text: "Affordable food") do expect(page).to have_link "Edit" + expect(page).to have_link "Delete" end expect(page).to have_link "Create local target" end @@ -84,4 +85,16 @@ describe "Local Targets", :js do expect(page).to have_content("1 error prevented this local target from being saved.") end end + + describe "Destroy" do + scenario "Shows succesful notice when local target is destroyed successfully" do + create(:sdg_local_target, code: "1.1.1") + visit sdg_management_local_targets_path + + accept_confirm { click_link "Delete" } + + expect(page).to have_content("Local target deleted successfully") + expect(page).not_to have_content("1.1.1") + end + end end From 5fa7503374fcc5d0926001a3986bf6a8061d3d60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sen=C3=A9n=20Rodero=20Rodr=C3=ADguez?= Date: Wed, 2 Dec 2020 18:10:37 +0100 Subject: [PATCH 08/10] Include `local_targets` controller --- app/components/sdg_management/menu_component.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/components/sdg_management/menu_component.rb b/app/components/sdg_management/menu_component.rb index 7c22e27c2..b879fe716 100644 --- a/app/components/sdg_management/menu_component.rb +++ b/app/components/sdg_management/menu_component.rb @@ -2,6 +2,6 @@ class SDGManagement::MenuComponent < ApplicationComponent private def sdg? - controller_name == "goals" || controller_name == "targets" + %w[goals targets local_targets].include?(controller_name) end end From 4a8db5e91abe85cab9e420607cf671d88a64a04c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sen=C3=A9n=20Rodero=20Rodr=C3=ADguez?= Date: Tue, 8 Dec 2020 12:36:55 +0100 Subject: [PATCH 09/10] Add SDG local targets to development seeds --- db/dev_seeds/sdg.rb | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/db/dev_seeds/sdg.rb b/db/dev_seeds/sdg.rb index 01336730e..414332602 100644 --- a/db/dev_seeds/sdg.rb +++ b/db/dev_seeds/sdg.rb @@ -1,3 +1,21 @@ section "Creating Sustainable Development Goals" do load Rails.root.join("db", "sdg.rb") + + SDG::Target.sample(30).each do |target| + title = "Title for default locale" + description = "Description for default locale" + rand(2..3).times do |n| + local_target = SDG::LocalTarget.create!(code: "#{target.code}.#{n + 1}", + title: title, + description: description, + target: target) + random_locales.map do |locale| + Globalize.with_locale(locale) do + local_target.title = "Title for locale #{locale}" + local_target.description = "Description for locale #{locale}" + local_target.save! + end + end + end + end end From 80cac0a7d23e80403475f229b8471119fbad5610 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sen=C3=A9n=20Rodero=20Rodr=C3=ADguez?= Date: Tue, 8 Dec 2020 19:14:39 +0100 Subject: [PATCH 10/10] Add SDG relations to development seeds --- db/dev_seeds/sdg.rb | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/db/dev_seeds/sdg.rb b/db/dev_seeds/sdg.rb index 414332602..055f64e41 100644 --- a/db/dev_seeds/sdg.rb +++ b/db/dev_seeds/sdg.rb @@ -18,4 +18,15 @@ section "Creating Sustainable Development Goals" do end end end + + relatables = [Debate, Proposal, Poll, Legislation::Process, Budget::Investment] + relatables.map { |relatable| relatable.sample(5) }.flatten.each do |relatable| + Array(SDG::Goal.sample(rand(1..3))).each do |goal| + target = goal.targets.sample + local_target = target.local_targets.sample + relatable.sdg_goals << goal + relatable.sdg_targets << target + relatable.sdg_local_targets << local_target if local_target.present? + end + end end
<%= attribute_name(:title) %><%= t("admin.actions.actions") %>
+ <%= target.code %> <%= target.title %>
<%= local_target.title %> +
+ <%= actions(local_target) %>