Skip to content

Commit 0031caf

Browse files
authored
Merge pull request #2897 from objectcomputing/feature-2894/custom-skill-query
Feature 2894/custom skill query
2 parents 9b2147c + d558dfc commit 0031caf

File tree

7 files changed

+69
-113
lines changed

7 files changed

+69
-113
lines changed

server/src/main/java/com/objectcomputing/checkins/services/member_skill/MemberSkillRepository.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.objectcomputing.checkins.services.member_skill;
22

3+
import io.micronaut.data.annotation.Query;
34
import io.micronaut.data.jdbc.annotation.JdbcRepository;
45
import io.micronaut.data.model.query.builder.sql.Dialect;
56
import io.micronaut.data.repository.CrudRepository;
@@ -19,6 +20,13 @@ public interface MemberSkillRepository extends CrudRepository<MemberSkill, UUID>
1920

2021
List<MemberSkill> findBySkillid(UUID skillid);
2122

22-
Optional<MemberSkill> findByMemberidAndSkillid(UUID memberId,UUID skillid );
23+
Optional<MemberSkill> findByMemberidAndSkillid(UUID memberId, UUID skillid);
2324

25+
@Query(value = "SELECT member_skills.* FROM member_skills " +
26+
"INNER JOIN member_profile " +
27+
"ON member_skills.memberid = member_profile.id " +
28+
"WHERE :targetSkillId = member_skills.skillid " +
29+
"AND member_profile.terminationdate IS NULL",
30+
nativeQuery = true)
31+
List<MemberSkill> activeMemberSkills(String targetSkillId);
2432
}

server/src/main/java/com/objectcomputing/checkins/services/member_skill/skillsreport/SkillsReportServicesImpl.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,8 @@ private List<TeamMemberSkillDTO> getPotentialQualifyingMembers(List<SkillLevelDT
9292
throw new BadArgException("Invalid requested skill ID");
9393
}
9494

95-
final List<MemberSkill> temp = memberSkillRepo.findBySkillid(skill.getId());
95+
final List<MemberSkill> temp =
96+
memberSkillRepo.activeMemberSkills(skill.getId().toString());
9697
if (skill.getLevel() != null && !temp.isEmpty()) {
9798
for (MemberSkill memSkill : temp) {
9899
if (memSkill.getSkilllevel() != null && isSkillLevelSatisfied(memSkill.getSkilllevel(), skill.getLevel())) {

server/src/test/java/com/objectcomputing/checkins/services/member_skill/skillsreport/SkillsReportServicesImplTest.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ void testReport() {
108108
MemberProfile member2 = createASecondDefaultMemberProfile();
109109
MemberProfile member3 = createAThirdDefaultMemberProfile();
110110
MemberProfile member4 = createADefaultMemberProfileForPdl(member1);
111+
MemberProfile member5 = createAPastTerminatedMemberProfile();
111112

112113
final UUID skillId1 = skill1.getId();
113114
final UUID skillId2 = skill2.getId();
@@ -128,6 +129,12 @@ void testReport() {
128129
final MemberSkill ms8 = createMemberSkill(member4, skill2, SkillLevel.INTERMEDIATE_LEVEL, LocalDate.now());
129130
final MemberSkill ms9 = createMemberSkill(member4, skill4, SkillLevel.EXPERT_LEVEL, LocalDate.now());
130131

132+
// Skills for the terminated member
133+
createMemberSkill(member5, skill1, SkillLevel.ADVANCED_LEVEL, LocalDate.now());
134+
createMemberSkill(member5, skill2, SkillLevel.ADVANCED_LEVEL, LocalDate.now());
135+
createMemberSkill(member5, skill3, SkillLevel.ADVANCED_LEVEL, LocalDate.now());
136+
createMemberSkill(member5, skill4, SkillLevel.ADVANCED_LEVEL, LocalDate.now());
137+
131138
// List of skills required in first request
132139
final SkillLevelDTO dto1 = new SkillLevelDTO();
133140
final SkillLevelDTO dto2 = new SkillLevelDTO();

web-ui/src/pages/SkillReportPage.jsx

Lines changed: 23 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React, { useContext, useRef, useState } from 'react';
1+
import React, { useContext, useRef, useState, useEffect } from 'react';
22

33
import { Button, TextField } from '@mui/material';
44
import Autocomplete from '@mui/material/Autocomplete';
@@ -54,26 +54,28 @@ const SkillReportPage = props => {
5454
processedQPs
5555
);
5656

57-
const handleSearch = async searchRequestDTO => {
58-
let res = await reportSkills(searchRequestDTO, csrf);
59-
let memberSkillsFound;
60-
if (res && res.payload) {
61-
memberSkillsFound =
62-
!res.error && res.payload.data.teamMembers
63-
? res.payload.data.teamMembers
64-
: undefined;
65-
}
66-
// Filter out skills of terminated members
67-
memberSkillsFound = memberSkillsFound?.filter(memberSkill =>
68-
memberIds.includes(memberSkill.id)
69-
);
70-
if (memberSkillsFound && memberIds) {
71-
let newSort = sortMembersBySkill(memberSkillsFound);
72-
setSearchResults(newSort);
73-
} else {
74-
setSearchResults([]);
75-
}
76-
};
57+
useEffect(() => {
58+
const handleSearch = async () => {
59+
let memberSkillsFound = [];
60+
61+
if (searchSkills.length > 0) {
62+
const searchRequestDTO = createRequestDTO(editedSearchRequest);
63+
const res = await reportSkills(searchRequestDTO, csrf);
64+
if (res && res.payload) {
65+
memberSkillsFound =
66+
!res.error && res.payload.data?.teamMembers
67+
? res.payload.data.teamMembers
68+
: [];
69+
}
70+
memberSkillsFound = sortMembersBySkill(memberSkillsFound);
71+
}
72+
73+
setSearchResults(memberSkillsFound);
74+
};
75+
76+
handleSearch();
77+
}, [searchSkills]);
78+
7779

7880
function skillsToSkillLevelDTO(skills) {
7981
return skills.map((skill, index) => {
@@ -124,26 +126,6 @@ const SkillReportPage = props => {
124126
/>
125127
)}
126128
/>
127-
<div className="SkillsSearch-actions fullWidth">
128-
<Button
129-
onClick={() => {
130-
if (!searchSkills.length) {
131-
window.snackDispatch({
132-
type: UPDATE_TOAST,
133-
payload: {
134-
severity: 'error',
135-
toast: 'Must select a skill'
136-
}
137-
});
138-
} else {
139-
handleSearch(createRequestDTO(editedSearchRequest));
140-
}
141-
}}
142-
color="primary"
143-
>
144-
Run Search
145-
</Button>
146-
</div>
147129
</div>
148130
<SearchResults searchResults={searchResults} />
149131
</div>

web-ui/src/pages/TeamSkillReportPage.jsx

Lines changed: 28 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React, { useContext, useRef, useState } from 'react';
1+
import React, { useContext, useRef, useState, useEffect } from 'react';
22

33
import { Autocomplete, Button, TextField, Typography } from '@mui/material';
44

@@ -72,33 +72,33 @@ const TeamSkillReportPage = () => {
7272
processedQPs
7373
);
7474

75-
const handleSearch = async searchRequestDTO => {
76-
let res = await reportSkills(searchRequestDTO, csrf);
77-
let memberSkillsFound;
78-
if (res && res.payload) {
79-
memberSkillsFound =
80-
!res.error && res.payload.data.teamMembers
81-
? res.payload.data.teamMembers
82-
: undefined;
83-
}
84-
if (memberSkillsFound && memberProfiles) {
85-
// Filter the member skill down to only members that are not terminated.
86-
memberSkillsFound = memberSkillsFound.filter(
87-
mSkill => memberProfiles.find(member => member.id == mSkill.id)
88-
);
89-
90-
setAllSearchResults(memberSkillsFound);
91-
let membersSelected = memberSkillsFound.filter(mSkill =>
92-
selectedMembers.some(member => member.id === mSkill.id)
93-
);
94-
let newSort = sortMembersBySkill(membersSelected);
95-
setSearchResults(newSort);
96-
} else {
97-
setSearchResults([]);
98-
setAllSearchResults([]);
99-
}
100-
setShowRadar(true);
101-
};
75+
useEffect(() => {
76+
const handleSearch = async () => {
77+
if (searchSkills.length > 0) {
78+
const searchRequestDTO = createRequest(editedSearchRequest);
79+
const res = await reportSkills(searchRequestDTO, csrf);
80+
let memberSkillsFound;
81+
if (res && res.payload) {
82+
memberSkillsFound =
83+
!res.error && res.payload.data.teamMembers
84+
? res.payload.data.teamMembers
85+
: [];
86+
}
87+
88+
setAllSearchResults(memberSkillsFound);
89+
const membersSelected = memberSkillsFound.filter(mSkill =>
90+
selectedMembers.some(member => member.id === mSkill.id)
91+
);
92+
setSearchResults(sortMembersBySkill(membersSelected));
93+
setShowRadar(true);
94+
} else {
95+
setSearchResults([]);
96+
setAllSearchResults([]);
97+
setShowRadar(false);
98+
}
99+
};
100+
handleSearch();
101+
}, [selectedMembers, searchSkills]);
102102

103103
function skillsToSkillLevel(skills) {
104104
return skills.map(skill => {
@@ -194,24 +194,6 @@ const TeamSkillReportPage = () => {
194194
/>
195195
)}
196196
/>
197-
<Button
198-
onClick={() => {
199-
if (!searchSkills.length) {
200-
window.snackDispatch({
201-
type: UPDATE_TOAST,
202-
payload: {
203-
severity: 'error',
204-
toast: 'Must select a skill'
205-
}
206-
});
207-
return;
208-
}
209-
handleSearch(createRequest(editedSearchRequest));
210-
}}
211-
color="primary"
212-
>
213-
Run Search
214-
</Button>
215197
</div>
216198
{showRadar && (
217199
<div>

web-ui/src/pages/__snapshots__/SkillReportPage.test.jsx.snap

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -91,20 +91,6 @@ exports[`renders correctly 1`] = `
9191
</div>
9292
</div>
9393
</div>
94-
<div
95-
class="SkillsSearch-actions fullWidth"
96-
>
97-
<button
98-
class="MuiButtonBase-root MuiButton-root MuiButton-text MuiButton-textPrimary MuiButton-sizeMedium MuiButton-textSizeMedium MuiButton-colorPrimary MuiButton-root MuiButton-text MuiButton-textPrimary MuiButton-sizeMedium MuiButton-textSizeMedium MuiButton-colorPrimary css-1e6y48t-MuiButtonBase-root-MuiButton-root"
99-
tabindex="0"
100-
type="button"
101-
>
102-
Run Search
103-
<span
104-
class="MuiTouchRipple-root css-8je8zh-MuiTouchRipple-root"
105-
/>
106-
</button>
107-
</div>
10894
</div>
10995
<div
11096
class="results-section"

web-ui/src/pages/__snapshots__/TeamSkillReportPage.test.jsx.snap

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -155,16 +155,6 @@ exports[`renders correctly 1`] = `
155155
</div>
156156
</div>
157157
</div>
158-
<button
159-
class="MuiButtonBase-root MuiButton-root MuiButton-text MuiButton-textPrimary MuiButton-sizeMedium MuiButton-textSizeMedium MuiButton-colorPrimary MuiButton-root MuiButton-text MuiButton-textPrimary MuiButton-sizeMedium MuiButton-textSizeMedium MuiButton-colorPrimary css-1e6y48t-MuiButtonBase-root-MuiButton-root"
160-
tabindex="0"
161-
type="button"
162-
>
163-
Run Search
164-
<span
165-
class="MuiTouchRipple-root css-8je8zh-MuiTouchRipple-root"
166-
/>
167-
</button>
168158
</div>
169159
</div>
170160
</div>

0 commit comments

Comments
 (0)