Skip to content

Commit

Permalink
Re-Add Skill - People Search (#651)
Browse files Browse the repository at this point in the history
* beginn with people_skill implementation

* implement template to search for people with skills

* disable rubocop for fetch entries method

* implement method to get query params

* beginn with implementation of view of people and their filtered skills

* finish implementation of view of search results and add auto submit on other search fields

* make rubocop happy

* use partial to display person_skill

* use helper methods to retrieve level and interest instead of instance variables

* make rubocop happy

* begin with rebuild

* change view structure to match data which we retrieve from filter

* modify people_skills_filter method to return valid data format

* give parameter to partial

* overwrite entries method to have direct acces to data

* make rubocop happy

* ignore unnecessary api controller tests

* begin with implementation of the first test

* write controller tests

* implement feature tests

* delete unnecessary include

* add filtered count

* resolve requested feedback

* make rubocop happy

* remove unnecessary method

* use to_i method instead of Integer cast
  • Loading branch information
Vakmeth authored Apr 15, 2024
1 parent 3e53287 commit 800f456
Show file tree
Hide file tree
Showing 11 changed files with 174 additions and 70 deletions.
26 changes: 26 additions & 0 deletions app/controllers/people_skills_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# frozen_string_literal: true

class PeopleSkillsController < CrudController
include ParamConverters
helper_method :search_level, :search_interest

def entries
return [] if params[:skill_id].blank?

base = PeopleSkill.includes(:person, skill: [
:category,
:people, { people_skills: :person }
])
PeopleSkillsFilter.new(
base, true, params[:level], params[:interest], params[:skill_id]
).scope
end

def search_level
params[:level] ? params[:level].to_i : 1
end

def search_interest
params[:interest] ? params[:interest].to_i : 1
end
end
28 changes: 4 additions & 24 deletions app/domain/people_skills_filter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -50,41 +50,21 @@ def filter_by_level_and_interest(entries)
person_ids = persons_with_required_skill(skills_per_person)

# include skill and person to access name and title in query
data = find_person_skills(entries, person_ids)

# Serialize Data and convert to json before returning
JSON.generate(PeopleSearchSkillSerializer.serialize(data))
find_person_skills(entries, person_ids)
end

def find_person_skills(entries, person_ids)
skills_by_person(entries, person_ids).map do |person_id, skills|
{ person_id: person_id, name: skills.first.person.name, skills: map_skills(skills) }
skills_by_person(entries, person_ids).map do |person, skills|
{ person: person, skills: skills }
end
end

def skills_by_person(entries, person_ids)
entries.includes(:skill, :person)
.where(person_id: person_ids, skill_id: skill_ids)
.group_by(&:person_id)
.group_by(&:person)
end

# rubocop:disable Metrics/MethodLength
def map_skills(skills)
skills.map do |skill|
{
people_skill_id: skill.id,
skill_id: skill.skill_id,
title: skill.skill.title,
level: skill.level,
interest: skill.interest,
certificate: skill.certificate,
core_competence: skill.core_competence
}
end
end
# rubocop:enable Metrics/MethodLength


def filter_for_skills_and_levels_and_interests(entries)
result = PeopleSkill.none
levels_and_interests_for_skills.each do |search_param|
Expand Down
2 changes: 1 addition & 1 deletion app/views/layouts/application.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
%li.bg-skills-blue.h-100.d-flex.align-items-center
%a.nav-link.cursor-pointer.ps-2.pe-2{href: people_path} Profil
%li.bg-skills-blue.h-100.d-flex.align-items-center
%a.nav-link.cursor-pointer.ps-2.pe-2= "Skill Suche"
%a.nav-link.cursor-pointer.ps-2.pe-2{href: people_skills_path} Skill Suche
%li.bg-skills-blue.h-100.d-flex.align-items-center
%a.nav-link.cursor-pointer.ps-2.pe-2= "CV Suche"
%li.bg-skills-blue.h-100.d-flex.align-items-center
Expand Down
6 changes: 3 additions & 3 deletions app/views/people/people_skills/edit.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,12 @@
%div.col-2
= ff.object.skill.title
%div.col-2
%div.d-flex.flex-column{data: {controller: "skills-level"}}
%div.d-flex.flex-column.align-items-center{data: {controller: "skills-level"}}
%label.form-label.text-gray{"data-skills-level-target": "label"}= t ExpertiseTopicSkillValue.skill_levels.key(ff.object.level - 1)
= ff.range_field :level, min: 1, max: 5, class: "form-range w-75",
"data-action": "change->skills-level#toggleLevel", "data-skills-level-target": "switch"
%div.col-2
%div.d-flex.flex-column
%div.col-3
%div.d-flex.flex-column.align-items-center
%label.form-label.text-gray= t "people-skills.interest"
.rate
= ff.radio_button :interest, 5, checked: ff.object.interest == 5, id: "star5#{ff.object.id}"
Expand Down
40 changes: 4 additions & 36 deletions app/views/people/people_skills/index.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -15,39 +15,7 @@
%div.white-header.mw-100.border-bottom.text-gray
=category_child.title + " (#{people_skills_of_category(category_child).count})"
- people_skills_of_category(category_child).each do |person_skill|
= form_with(model: @person) do
%div.mw-100.border-bottom.text-black.ps-5.border
%div.d-flex.flex-row.align-items-center.mt-3.mb-3
%div.col-2
= person_skill.skill.title
%div.col-2
%div.d-flex.flex-column
%label.form-label.text-gray= t ExpertiseTopicSkillValue.skill_levels.key(person_skill.level - 1)
%input{value: person_skill.level, class: "form-range w-75", type: "range", min: 1, max: 5, disabled: true}
%div.col-2
%div.d-flex.flex-column
%label.form-label.text-gray= t "people-skills.interest"
.rate.rate-show
%input{name: "people_skill[interest]", type: "radio", value: 5, id: "star5#{person_skill.id}",
checked: person_skill.interest == 5, disabled: true}/
%label{for: "star5#{person_skill.id}", title: "text", id: "star-label5#{person_skill.id}"} 5 stars
%input{name: "people_skill[interest]", type: "radio", value: 4, id: "star4#{person_skill.id}",
checked: person_skill.interest == 4, disabled: true}/
%label{for: "star4#{person_skill.id}", title: "text", id: "star-label4#{person_skill.id}"} 4 stars
%input{name: "people_skill[interest]", type: "radio", value: 3, id: "star3#{person_skill.id}",
checked: person_skill.interest == 3, disabled: true}/
%label{for: "star3#{person_skill.id}", title: "text", id: "star-label3#{person_skill.id}"} 3 stars
%input{name: "people_skill[interest]", type: "radio", value: 2, id: "star2#{person_skill.id}",
checked: person_skill.interest == 2, disabled: true}/
%label{for: "star2#{person_skill.id}", title: "text", id: "star-label2#{person_skill.id}"} 2 stars
%input{name: "people_skill[interest]", type: "radio", value: 1, id: "star1#{person_skill.id}",
checked: person_skill.interest == 1, disabled: true}/
%label{for: "star1#{person_skill.id}", title: "text", id: "star-label1#{person_skill.id}"} 1 star
%div.col-2
%div.d-flex.flex-row.form-check
%input.check_box{type: "checkbox", class: "form-check-input me-2", checked: person_skill.certificate, disabled: true}
%label.form-label.text-gray= t "people-skills.certificate"
%div.col-2
%div.d-flex.flex-row.form-check
%input.check_box{type: "checkbox", class: "form-check-input me-2", checked: person_skill.core_competence, disabled: true}
%label.form-label.text-gray= t "people-skills.core-competence"
- @person_skill = person_skill
%div.mw-100.border-bottom.text-black.ps-5.border
%div.d-flex.flex-row.align-items-center.mt-3.mb-3
= render("people_skills/person_skill", {person_skill: @person_skill})
31 changes: 31 additions & 0 deletions app/views/people_skills/_person_skill.html.haml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
%div.d-flex.align-items-center.col-2
= person_skill.skill.title
%div.d-flex.flex-column.align-items-center.col-2
%label.form-label.text-gray= t ExpertiseTopicSkillValue.skill_levels.key(person_skill.level - 1)
%input{value: person_skill.level, class: "form-range w-75", type: "range", min: 1, max: 5, disabled: true}
%div.d-flex.flex-column.align-items-center.col-3
%label.form-label.text-gray= t "people-skills.interest"
.rate.rate-show
%input{type: "radio", value: 5, id: "star5#{person_skill.id}",
checked: person_skill.interest == 5, disabled: true}/
%label{for: "star5#{person_skill.id}", title: "text", id: "star-label5#{person_skill.id}"} 5 stars
%input{type: "radio", value: 4, id: "star4#{person_skill.id}",
checked: person_skill.interest == 4, disabled: true}/
%label{for: "star4#{person_skill.id}", title: "text", id: "star-label4#{person_skill.id}"} 4 stars
%input{type: "radio", value: 3, id: "star3#{person_skill.id}",
checked: person_skill.interest == 3, disabled: true}/
%label{for: "star3#{person_skill.id}", title: "text", id: "star-label3#{person_skill.id}"} 3 stars
%input{type: "radio", value: 2, id: "star2#{person_skill.id}",
checked: person_skill.interest == 2, disabled: true}/
%label{for: "star2#{person_skill.id}", title: "text", id: "star-label2#{person_skill.id}"} 2 stars
%input{type: "radio", value: 1, id: "star1#{person_skill.id}",
checked: person_skill.interest == 1, disabled: true}/
%label{for: "star1#{person_skill.id}", title: "text", id: "star-label1#{person_skill.id}"} 1 star
%div.d-flex.align-items-center.col-2
%div.d-flex.flex-row.form-check
%input.check_box{type: "checkbox", class: "form-check-input me-2", checked: person_skill.certificate, disabled: true}
%label.form-label.text-gray= t "people-skills.certificate"
%div.d-flex.align-items-center
%div.d-flex.flex-row.form-check.col-2
%input.check_box{type: "checkbox", class: "form-check-input me-2", checked: person_skill.core_competence, disabled: true}
%label.form-label.text-gray= t "people-skills.core-competence"
38 changes: 38 additions & 0 deletions app/views/people_skills/index.html.haml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
%div.mt-3
= form_with(url: people_skills_path, method: :get) do |form|
%div.w-100.d-flex.flex-row.justify-content-start{data: {controller: "skills-level"}}
%div.w-50.mt-3
= form.collection_select :skill_id, Skill.all.sort_by(&:title), :id, :title, {include_blank: "Select option", selected: params[:skill_id]},
class: "form-select w-100", onchange: "this.form.requestSubmit()"
%div.w-25.d-flex.flex-column.align-items-center
%label.form-label.text-gray.fs-6{"data-skills-level-target": "label"}= t ExpertiseTopicSkillValue.skill_levels.key(search_level - 1)
= form.range_field :level, min: 1, max: 5, value: search_level, class: "form-range w-75",
"data-action": "change->skills-level#toggleLevel", "data-skills-level-target": "switch",
onchange: "this.form.requestSubmit()"
%div.w-25.d-flex.flex-column.align-items-center
%label.form-label.text-gray.fs-6.mb-0.mt-0 Interesse
.rate
= form.radio_button :interest, 5, id: "star5", checked: search_interest == 5, onClick: "this.form.requestSubmit()"
%label{for: "star5", title: "text", id: "star-label5", class: "star5"} 5 stars
= form.radio_button :interest, 4, id: "star4", checked: search_interest == 4, onClick: "this.form.requestSubmit()"
%label{for: "star4", title: "text", id: "star-label4", class: "star4"} 4 stars
= form.radio_button :interest, 3, id: "star3", checked: search_interest == 3, onClick: "this.form.requestSubmit()"
%label{for: "star3", title: "text", id: "star-label3", class: "star3"} 3 stars
= form.radio_button :interest, 2, id: "star2", checked: search_interest == 2, onClick: "this.form.requestSubmit()"
%label{for: "star2", title: "text", id: "star-label2", class: "star2"} 2 stars
= form.radio_button :interest, 1, id: "star1", checked: search_interest == 1, onClick: "this.form.requestSubmit()"
%label{for: "star1", title: "text", id: "star-label1", class: "star1"} 1 star
%div.profile-header.mw-100.border-bottom.mt-4.fw-normal
Suchresultate
%turbo-frame{id: "search-results"}
%div.border.p-3.rounded-bottom
- if entries.size == 0
Keine Resultate
- else
- entries.each do | filtered_entry|
%div.d-flex.flex-row.w-100.border-bottom
%div.d-flex.flex-column.mt-2.mb-2.w-25.justify-content-start
= link_to filtered_entry[:person].name, person_path(filtered_entry[:person]), {"data-turbo"=>false}
%div.d-flex.flex-row.mt-2.mb-2.w-75
- filtered_entry[:skills].each do |person_skill|
= render('person_skill', {person_skill: person_skill})
1 change: 1 addition & 0 deletions config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
end

resources :skills
resources :people_skills


# Status
Expand Down
14 changes: 8 additions & 6 deletions spec/controllers/api/people_skills_controller_spec.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
require 'rails_helper'

describe Api::PeopleSkillsController do
# Ignore some tests because PeopleSkillsFilter returns data no longer as a
# json since the new skills is server side rendered now
describe 'PeopleSkillsController' do
before { load_pictures }

Expand Down Expand Up @@ -35,7 +37,7 @@
json_object_includes_keys(rails_attrs, keys)
end

it 'returns Rails skills' do
xit 'returns Rails skills' do
keys = %w[person skills]

process :index, method: :get, params: { type: 'Skill', skill_id: rails.id, level: '1', interest: '1'}
Expand Down Expand Up @@ -64,7 +66,7 @@
json_object_includes_keys(skill_relationships_hope, keys)
end

it 'only returns above a level' do
xit 'only returns above a level' do
keys = %w[person skills]

process :index, method: :get, params: { type: 'Skill', skill_id: rails.id, level: '2', interest: '1'}
Expand All @@ -83,7 +85,7 @@
json_object_includes_keys(skill_relationships_wally, keys)
end

it 'only returns above an interest' do
xit 'only returns above an interest' do
keys = %w[person skills]

process :index, method: :get, params: { type: 'Skill', skill_id: rails.id, level: '1', interest: '4'}
Expand Down Expand Up @@ -114,7 +116,7 @@
expect(skills.count).to eq(0)
end

it 'returns AND search' do
xit 'returns AND search' do
keys = %w[person skills]

process :index, method: :get, params: { type: 'Skill', skill_id: rails.id.to_s + "," + cunit.id.to_s, level: '1,4', interest: '1,1'}
Expand All @@ -135,7 +137,7 @@
json_object_includes_keys(skill_relationships_wally, keys)
end

it 'returns AND search for 4' do
xit 'returns AND search for 4' do
keys = %w[person skills]

process :index, method: :get, params: { type: 'Skill', skill_id: rails.id.to_s + "," + junit.id.to_s + "," + ember.id.to_s + "," + cunit.id.to_s, level: '1,4,1,1', interest: '1,1,1,1'}
Expand Down Expand Up @@ -166,7 +168,7 @@
expect(skills.count).to eq(0)
end

it 'returns AND search for 5' do
xit 'returns AND search for 5' do
keys = %w[person skills]

process :index, method: :get, params: { type: 'Skill', skill_id: rails.id.to_s + "," + junit.id.to_s + "," + bash.id.to_s + "," + ember.id.to_s + "," + cunit.id.to_s, level: '1,1,1,1,1', interest: '1,1,1,1,1'}
Expand Down
23 changes: 23 additions & 0 deletions spec/controllers/people_skills_controller_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
require 'rails_helper'

describe PeopleSkillsController do
before(:each) do
sign_in auth_users(:user), scope: :auth_user
end

describe 'Search people with skills' do
render_views

it 'should return matching entries' do
get :index, params: {skill_id: skills(:rails).id, level: 1, interest: 1}
expect(response.code).to eq("200")
expect(response.body).to include("Bob Anderson")
end

it 'should return no results if skill id is not given' do
get :index, params: {skill_id: nil, level: 1, interest: 1}
expect(response.code).to eq("200")
expect(response.body).to include("Keine Resultate")
end
end
end
35 changes: 35 additions & 0 deletions spec/features/people_skill_search_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
require 'rails_helper'

describe :people_skills do
describe 'People Search', type: :feature, js: true do
let(:skill) { skills(:rails).attributes }

before(:each) do
sign_in auth_users(:user), scope: :auth_user
end

it 'Should return matching entries to page' do
visit people_skills_path
select skill["title"].to_s, from: 'skill_id'
page.find(".star5").click(x: 10, y: 10)
page.find("#level").set(3)
expect(page).to have_text('Bob Anderson')
expect(page).to have_text('Wally Allround')
end

it 'Should set values of query parameters' do
visit(people_skills_path + "?skill_id=#{skill["id"]}&level=3&interest=5")
expect(page).to have_select("skill_id", selected: "Rails")
expect(page).to have_field("level", with: 3)
expect(page).to have_field("interest", with: 5, visible: false)
end

it 'Should return no results if skill id is not set' do
visit(people_skills_path + "?level=3&interest=5")
expect(page).to have_field("level", with: 3)
expect(page).to have_field("interest", with: 5, visible: false)
expect(page).to have_text("Keine Resultate")
end

end
end

0 comments on commit 800f456

Please sign in to comment.