diff --git a/app/assets/stylesheets/admin/search.css b/app/assets/stylesheets/admin/search.css
index f4e818abd..0ece75fc5 100644
--- a/app/assets/stylesheets/admin/search.css
+++ b/app/assets/stylesheets/admin/search.css
@@ -1,6 +1,25 @@
.admin [role=search] {
display: flex;
+ &.complex {
+ @include breakpoint(small only) {
+ flex-direction: column;
+ }
+
+ @include breakpoint(medium) {
+ select {
+ height: $line-height * 2;
+ margin: 0 rem-calc(12);
+ }
+ }
+ }
+
+ &:not(.complex) {
+ @include breakpoint(medium) {
+ width: 50%;
+ }
+ }
+
[type="submit"] {
@include button($background: $link);
border-radius: 0;
@@ -10,8 +29,4 @@
@include button-disabled;
}
}
-
- @include breakpoint(medium) {
- width: 50%;
- }
}
diff --git a/app/components/admin/search_component.html.erb b/app/components/admin/search_component.html.erb
index 0caf05d0e..0286dcb48 100644
--- a/app/components/admin/search_component.html.erb
+++ b/app/components/admin/search_component.html.erb
@@ -1,4 +1,5 @@
<%= form_tag(url, options) do |f| %>
<%= text_field_tag :search, search_terms.to_s, placeholder: label, "aria-label": label %>
+ <%= content %>
<%= submit_tag t("admin.shared.search.search") %>
<% end %>
diff --git a/app/components/sdg_management/relations/index_component.html.erb b/app/components/sdg_management/relations/index_component.html.erb
index 43ba44b12..2cf9ca2be 100644
--- a/app/components/sdg_management/relations/index_component.html.erb
+++ b/app/components/sdg_management/relations/index_component.html.erb
@@ -1,6 +1,10 @@
<%= header %>
-<%= render Admin::SearchComponent.new(label: search_label) %>
+<%= render Admin::SearchComponent.new(label: search_label, class: "complex") do |component| %>
+ <%= component.select_tag :goal_code, goal_options,
+ include_blank: goal_blank_option,
+ "aria-label": goal_label %>
+<% end %>
diff --git a/app/components/sdg_management/relations/index_component.rb b/app/components/sdg_management/relations/index_component.rb
index 16a49194c..97d3cb49d 100644
--- a/app/components/sdg_management/relations/index_component.rb
+++ b/app/components/sdg_management/relations/index_component.rb
@@ -29,4 +29,16 @@ class SDGManagement::Relations::IndexComponent < ApplicationComponent
def search_label
t("admin.shared.search.label.#{model_class.table_name}")
end
+
+ def goal_label
+ t("admin.shared.search.advanced_filters.sdg_goals.label")
+ end
+
+ def goal_blank_option
+ t("admin.shared.search.advanced_filters.sdg_goals.all")
+ end
+
+ def goal_options
+ options_from_collection_for_select(SDG::Goal.all, :code, :code_and_title, params[:goal_code])
+ end
end
diff --git a/app/controllers/sdg_management/relations_controller.rb b/app/controllers/sdg_management/relations_controller.rb
index 870dc5fd2..aa03f5d26 100644
--- a/app/controllers/sdg_management/relations_controller.rb
+++ b/app/controllers/sdg_management/relations_controller.rb
@@ -3,7 +3,11 @@ class SDGManagement::RelationsController < SDGManagement::BaseController
before_action :load_record, only: [:edit, :update]
def index
- @records = relatable_class.accessible_by(current_ability).order(:id).page(params[:page])
+ @records = relatable_class
+ .accessible_by(current_ability)
+ .by_goal(params[:goal_code])
+ .order(:id)
+ .page(params[:page])
@records = @records.search(params[:search]) if params[:search].present?
end
diff --git a/app/models/concerns/sdg/relatable.rb b/app/models/concerns/sdg/relatable.rb
index 50f9b0183..e552fbd96 100644
--- a/app/models/concerns/sdg/relatable.rb
+++ b/app/models/concerns/sdg/relatable.rb
@@ -12,6 +12,14 @@ module SDG::Relatable
end
end
+ class_methods do
+ def by_goal(code)
+ return all if code.blank?
+
+ joins(:sdg_goals).merge(SDG::Goal.where(code: code))
+ end
+ end
+
def related_sdgs
sdg_relations.map(&:related_sdg)
end
diff --git a/config/locales/en/admin.yml b/config/locales/en/admin.yml
index 2acfdce7a..21041e674 100644
--- a/config/locales/en/admin.yml
+++ b/config/locales/en/admin.yml
@@ -1253,6 +1253,10 @@ en:
true_value: "Yes"
false_value: "No"
search:
+ advanced_filters:
+ sdg_goals:
+ all: "All goals"
+ label: "By goal"
label:
booths: "Search booth by name or location"
budget_investments: "Search investments by title, description or heading"
diff --git a/config/locales/es/admin.yml b/config/locales/es/admin.yml
index 62bca513c..6ea9c3505 100644
--- a/config/locales/es/admin.yml
+++ b/config/locales/es/admin.yml
@@ -1252,6 +1252,10 @@ es:
true_value: "Sí"
false_value: "No"
search:
+ advanced_filters:
+ sdg_goals:
+ all: "Todos los objetivos"
+ label: "Por objetivo"
label:
booths: "Buscar urna por nombre"
budget_investments: "Buscar proyectos por título, descripción o partida"
diff --git a/spec/models/sdg/relatable_spec.rb b/spec/models/sdg/relatable_spec.rb
index d161d4ddb..8f1e210d9 100644
--- a/spec/models/sdg/relatable_spec.rb
+++ b/spec/models/sdg/relatable_spec.rb
@@ -116,4 +116,25 @@ describe SDG::Relatable do
expect(relatable.reload.sdg_goals).to match_array [SDG::Goal[1], SDG::Goal[2]]
end
end
+
+ describe ".by_goal" do
+ it "returns everything if no code is provided" do
+ expect(relatable.class.by_goal("")).to eq [relatable]
+ expect(relatable.class.by_goal(nil)).to eq [relatable]
+ end
+
+ it "returns records associated with that goal" do
+ same_association = create(:proposal, sdg_goals: [goal])
+ both_associations = create(:proposal, sdg_goals: [goal, another_goal])
+
+ expect(relatable.class.by_goal(goal.code)).to match_array [same_association, both_associations]
+ end
+
+ it "does not return records not associated with that goal" do
+ create(:proposal)
+ create(:proposal, sdg_goals: [another_goal])
+
+ expect(relatable.class.by_goal(goal.code)).to be_empty
+ end
+ end
end
diff --git a/spec/system/sdg_management/relations_spec.rb b/spec/system/sdg_management/relations_spec.rb
index c3c2bbb3f..3518617cd 100644
--- a/spec/system/sdg_management/relations_spec.rb
+++ b/spec/system/sdg_management/relations_spec.rb
@@ -88,17 +88,31 @@ describe "SDG Relations", :js do
expect(page).to have_css "h2", exact_text: "Build a hospital"
end
- scenario "search" do
- create(:poll, name: "Internet speech freedom")
- create(:poll, name: "SDG interest")
+ describe "search" do
+ scenario "search by terms" do
+ create(:poll, name: "Internet speech freedom")
+ create(:poll, name: "SDG interest")
- visit sdg_management_polls_path
+ visit sdg_management_polls_path
- fill_in "search", with: "speech"
- click_button "Search"
+ fill_in "search", with: "speech"
+ click_button "Search"
- expect(page).to have_content "Internet speech freedom"
- expect(page).not_to have_content "SDG interest"
+ expect(page).to have_content "Internet speech freedom"
+ expect(page).not_to have_content "SDG interest"
+ end
+
+ scenario "goal filter" do
+ create(:budget_investment, title: "School", sdg_goals: [SDG::Goal[4]])
+ create(:budget_investment, title: "Hospital", sdg_goals: [SDG::Goal[3]])
+
+ visit sdg_management_budget_investments_path
+ select "4. Quality Education", from: "goal_code"
+ click_button "Search"
+
+ expect(page).to have_content "School"
+ expect(page).not_to have_content "Hospital"
+ end
end
end