Skip to content

Commit

Permalink
Merge pull request #2454 from NationalSecurityAgency/t#2426/expiratio…
Browse files Browse the repository at this point in the history
…n-history-fixes

T#2426/expiration history fixes
  • Loading branch information
sudo-may authored Oct 23, 2023
2 parents 42a0310 + 81be52a commit eed125b
Show file tree
Hide file tree
Showing 6 changed files with 87 additions and 21 deletions.
27 changes: 14 additions & 13 deletions dashboard/src/components/expiration/ExpirationHistory.vue
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ limitations under the License.
</b-form-group>
</div>
<div class="col-md-6">
<b-form-group label="User Id Filter" label-class="text-muted">
<b-input v-model="filters.userId" v-on:keydown.enter="applyFilters" data-cy="userIdFilter" aria-label="user id filter"/>
<b-form-group label="User Filter" label-class="text-muted">
<b-input v-model="filters.userIdForDisplay" v-on:keydown.enter="applyFilters" data-cy="userIdFilter" aria-label="user id filter"/>
</b-form-group>
</div>
</div>
Expand All @@ -42,7 +42,7 @@ limitations under the License.
@sort-changed="sortTable"
tableStoredStateId="expirationHistoryTable"
data-cy="expirationHistoryTable">
<template #head(userId)="data">
<template #head(userIdForDisplay)="data">
<span class="text-primary">
<i class="fas fa-user-cog skills-color-skills" aria-hidden="true"/> {{ data.label }}
</span>
Expand All @@ -54,7 +54,7 @@ limitations under the License.
<span class="text-primary"><i class="fas fa-clock text-warning" aria-hidden="true"></i> {{ data.label }}</span>
</template>
<template v-slot:cell(skillName)="data">
<link-to-skill-page :project-id="projectId" :skill-id="data.item.skillId" :link-label="data.label" data-cy="linkToSkill"/>
<a :href="getUrl(data.item)">{{ data.value }}</a>
</template>
<template v-slot:cell(expiredOn)="data">
<date-cell :value="data.value" />
Expand All @@ -68,7 +68,6 @@ limitations under the License.
<script>
import SubPageHeader from '@/components/utils/pages/SubPageHeader';
import SkillsBTable from '@/components/utils/table/SkillsBTable';
import LinkToSkillPage from '@/components/utils/LinkToSkillPage';
import ExpirationService from '@/components/expiration/ExpirationService';
import DateCell from '../utils/table/DateCell';
Expand All @@ -78,22 +77,21 @@ limitations under the License.
SubPageHeader,
SkillsBTable,
DateCell,
LinkToSkillPage,
},
data() {
return {
projectId: this.$route.params.projectId,
filters: {
skillName: '',
userId: '',
userIdForDisplay: '',
},
table: {
options: {
busy: false,
bordered: true,
outlined: true,
stacked: 'md',
sortBy: 'userId',
sortBy: 'userIdForDisplay',
sortDesc: true,
tableDescription: 'ExpirationHistory',
fields: [
Expand All @@ -103,7 +101,7 @@ limitations under the License.
sortable: true,
},
{
key: 'userId',
key: 'userIdForDisplay',
label: 'User',
sortable: true,
},
Expand Down Expand Up @@ -136,7 +134,7 @@ limitations under the License.
orderBy: this.table.options.sortBy,
ascending: !this.table.options.sortDesc,
skillName: this.filters.skillName,
userId: this.filters.userId,
userIdForDisplay: this.filters.userIdForDisplay,
};
return ExpirationService.getExpiredSkills(this.$route.params.projectId, params).then((res) => {
this.table.items = res.data;
Expand Down Expand Up @@ -166,19 +164,22 @@ limitations under the License.
if (this.filters.skillName) {
filterMessage += ` ${this.filters.skillName}`;
}
if (this.filters.userId) {
filterMessage += ` ${this.filters.userId}`;
if (this.filters.userIdForDisplay) {
filterMessage += ` ${this.filters.userIdForDisplay}`;
}
this.$nextTick(() => this.$announcer.polite(filterMessage));
});
},
reset() {
this.filters.userId = '';
this.filters.userIdForDisplay = '';
this.filters.skillName = '';
this.loadData().then(() => {
this.$nextTick(() => this.$announcer.polite('Skill expiration history table filters have been removed'));
});
},
getUrl(item) {
return `/administrator/projects/${encodeURIComponent(this.projectId)}/subjects/${encodeURIComponent(item.subjectId)}/skills/${encodeURIComponent(item.skillId)}/`;
},
},
};
</script>
60 changes: 60 additions & 0 deletions e2e-tests/cypress/e2e/skill-expiration-table_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -375,4 +375,64 @@ describe('Expired Skill Table Tests', () => {
}],
], 5);
});

it('Sort by skill name', () => {
cy.createProject(1)
cy.createSubject(1, 1);
cy.createSkill(1, 1, 1)
cy.createSkill(1, 1, 2)
cy.createSkill(1, 1, 3)

cy.configureExpiration(1, 0, 1, 'DAILY');
cy.configureExpiration(2, 0, 1, 'DAILY');
cy.configureExpiration(3, 0, 1, 'DAILY');
let yesterday = moment.utc().subtract(1, 'day')
let twoDaysAgo = moment.utc().subtract(2, 'day')
cy.doReportSkill({ project: 1, skill: 1, subjNum: 1, userId: Cypress.env('proxyUser'), date: yesterday.format('YYYY-MM-DD HH:mm') });
cy.doReportSkill({ project: 1, skill: 1, subjNum: 1, userId: Cypress.env('proxyUser'), date: twoDaysAgo.format('YYYY-MM-DD HH:mm') });
cy.doReportSkill({ project: 1, skill: 2, subjNum: 1, userId: Cypress.env('proxyUser'), date: yesterday.format('YYYY-MM-DD HH:mm') });
cy.doReportSkill({ project: 1, skill: 2, subjNum: 1, userId: Cypress.env('proxyUser'), date: twoDaysAgo.format('YYYY-MM-DD HH:mm') });
cy.doReportSkill({ project: 1, skill: 3, subjNum: 1, userId: Cypress.env('proxyUser'), date: yesterday.format('YYYY-MM-DD HH:mm') });
cy.doReportSkill({ project: 1, skill: 3, subjNum: 1, userId: Cypress.env('proxyUser'), date: twoDaysAgo.format('YYYY-MM-DD HH:mm') });

cy.expireSkills();

cy.visit('/administrator/projects/proj1/expirationHistory');

const tableSelector = '[data-cy=expirationHistoryTable]';
const headerSelector = `${tableSelector} thead tr th`;
cy.get(headerSelector).contains('Skill Name').click();

cy.validateTable(tableSelector, [
[{
colIndex: 0,
value: 'Very Great Skill 1'
}],
[{
colIndex: 0,
value: 'Very Great Skill 2'
}],
[{
colIndex: 0,
value: 'Very Great Skill 3'
}],
], 3);

cy.get(headerSelector).contains('Skill Name').click();

cy.validateTable(tableSelector, [
[{
colIndex: 0,
value: 'Very Great Skill 3'
}],
[{
colIndex: 0,
value: 'Very Great Skill 2'
}],
[{
colIndex: 0,
value: 'Very Great Skill 1'
}],
], 3);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -1706,13 +1706,12 @@ class AdminController {
@RequestMapping(value = "/projects/{projectId}/expirations", method = RequestMethod.GET, produces = "application/json")
@ResponseBody
TableResult getExpiredSkills(@PathVariable(name = "projectId") String projectId,
@RequestParam(name = "userId", required = false) String userIdParam,
@RequestParam(name = "userIdForDisplay", required = false) String userIdParam,
@RequestParam(name = "skillName", required = false) String skillName,
@RequestParam int page,
@RequestParam int limit,
@RequestParam String orderBy,
@RequestParam Boolean ascending) {
String userId = userInfoService.getUserName(userIdParam);
PageRequest pageRequest = PageRequest.of(page - 1, limit, ascending ? ASC : DESC, orderBy)
return userAchievementExpirationService.findAllExpiredAchievements(projectId, userIdParam, skillName, pageRequest);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@ package skills.controller.result.model

interface ExpiredSkillRes {
String getUserId()
String getUserIdForDisplay()
String getSkillId()
Date getExpiredOn()
String getSkillName()
String getSubjectId()
}
Original file line number Diff line number Diff line change
Expand Up @@ -68,14 +68,18 @@ interface ExpiredUserAchievementRepo extends CrudRepository<ExpiredUserAchieveme
@Param("olderThanDate") Date olderThanDate)

@Query(value = '''
SELECT eua.userId as userId, eua.skillId as skillId, eua.expiredOn as expiredOn, skill.name as skillName
FROM ExpiredUserAchievement eua, SkillDef skill
WHERE eua.projectId = :projectId AND eua.skillId = skill.skillId AND eua.projectId = skill.projectId
AND(:userId is null OR lower(eua.userId) like lower(concat('%', :userId, '%')))
SELECT eua.userId as userId, eua.skillId as skillId, eua.expiredOn as expiredOn, skill.name as skillName, userAttrs.userIdForDisplay as userIdForDisplay, subjectDef.skillId as subjectId
FROM ExpiredUserAchievement eua, SkillDef skill, UserAttrs userAttrs, SkillDef subjectDef, SkillRelDef srd
WHERE eua.projectId = :projectId AND eua.skillId = skill.skillId AND eua.projectId = skill.projectId AND userAttrs.userId = eua.userId
AND subjectDef = srd.parent AND
skill = srd.child AND
(srd.type = 'RuleSetDefinition' or srd.type = 'GroupSkillToSubject') AND
subjectDef.type = 'Subject'
AND(:userFilter is null OR lower(userAttrs.userIdForDisplay) like lower(concat('%', :userFilter, '%')))
AND(:skillNameFilter is null OR lower(skill.name) like lower(concat('%', :skillNameFilter, '%')))
''')
Page<ExpiredSkillRes> findAllExpiredAchievements(@Param("projectId") String projectId,
@Param("userId") String userId,
@Param("userFilter") String userFilter,
@Param("skillNameFilter") String skillNameFilter, PageRequest pageRequest)

}
Original file line number Diff line number Diff line change
Expand Up @@ -1034,7 +1034,7 @@ class SkillsService {
}

def getExpiredSkills(String projectId, String userId, String skillName, int limit = 10, int page = 1, String orderBy = 'userId', boolean ascending = true) {
return wsHelper.adminGet("/projects/${projectId}/expirations?limit=${limit}&ascending=${ascending ? 1 : 0}&page=${page}&orderBy=${orderBy}&userId=${userId}&skillName=${skillName}".toString())
return wsHelper.adminGet("/projects/${projectId}/expirations?limit=${limit}&ascending=${ascending ? 1 : 0}&page=${page}&orderBy=${orderBy}&userIdForDisplay=${userId}&skillName=${skillName}".toString())
}

def getLastSkillEventForProject(String projectId) {
Expand Down

0 comments on commit eed125b

Please sign in to comment.