From 07c25cb9afec8491f5ac9364a9547dba726c6506 Mon Sep 17 00:00:00 2001 From: Riku Rauhala Date: Tue, 29 Oct 2024 15:26:38 +0200 Subject: [PATCH 01/12] [Backend] Rename a bunch of things for consistency --- .../src/config/organizationConstants.ts | 2 +- services/backend/src/events.ts | 10 ++++----- services/backend/src/routes/studyProgramme.ts | 22 +++++++++---------- .../backend/src/services/analyticsService.ts | 20 ++++++++--------- .../faculty/facultyGraduationTimes.ts | 12 +++++----- .../faculty/facultyStudentProgress.ts | 6 ++--- .../src/services/faculty/facultyStudents.ts | 6 ++--- .../services/faculty/facultyThesisWriters.ts | 6 ++--- .../backend/src/services/programmeModules.ts | 6 ++--- .../studyProgrammeGraduations.ts | 2 +- .../studyProgramme/studyProgrammeHelpers.ts | 2 +- .../studyProgramme/studyProgrammeUpdates.ts | 10 ++++----- .../studyProgramme/studyTrackStats.ts | 8 +++++-- 13 files changed, 58 insertions(+), 54 deletions(-) diff --git a/services/backend/src/config/organizationConstants.ts b/services/backend/src/config/organizationConstants.ts index 72eccc89c2..1c7c2ce3c4 100644 --- a/services/backend/src/config/organizationConstants.ts +++ b/services/backend/src/config/organizationConstants.ts @@ -1,4 +1,4 @@ -// Linter was not having any of this so neeeded to add resolveJsonModule:true to tsconfig +// Linter was not having any of this so needed to add resolveJsonModule:true to tsconfig // export const { facultyCodes, ignoredFacultyCodes, magicFacultyCode } = require('../environment/organizationConfig.json') export { facultyCodes, ignoredFacultyCodes, magicFacultyCode } from '../environment/organizationConfig.json' diff --git a/services/backend/src/events.ts b/services/backend/src/events.ts index 15172246e5..2d43271e4e 100644 --- a/services/backend/src/events.ts +++ b/services/backend/src/events.ts @@ -8,8 +8,8 @@ import { computeLanguageCenterData, LANGUAGE_CENTER_REDIS_KEY } from './services import { findStudentsCloseToGraduation, CLOSE_TO_GRADUATION_REDIS_KEY } from './services/populations/closeToGraduation' import { redisClient } from './services/redis' import { getCurrentSemester } from './services/semesters' -import { combinedStudyprogrammes, isRelevantProgramme } from './services/studyProgramme/studyProgrammeHelpers' -import { updateBasicView, updateStudytrackView } from './services/studyProgramme/studyProgrammeUpdates' +import { combinedStudyProgrammes, isRelevantProgramme } from './services/studyProgramme/studyProgrammeHelpers' +import { updateBasicView, updateStudyTrackView } from './services/studyProgramme/studyProgrammeUpdates' import { findAndSaveTeachers } from './services/teachers/top' import { deleteOutdatedUsers } from './services/userService' import logger from './util/logger' @@ -61,10 +61,10 @@ const refreshProgrammesAndFaculties = async () => { export const refreshProgramme = async (code: string) => { await updateBasicView(code, '') - await updateStudytrackView(code, '') - const combinedProgramme = combinedStudyprogrammes[code] || '' + await updateStudyTrackView(code, '') + const combinedProgramme = combinedStudyProgrammes[code] || '' await updateBasicView(code, combinedProgramme) - await updateStudytrackView(code, combinedProgramme) + await updateStudyTrackView(code, combinedProgramme) } export const refreshProgrammes = async () => { diff --git a/services/backend/src/routes/studyProgramme.ts b/services/backend/src/routes/studyProgramme.ts index 5966c3a6e9..c9144003c6 100644 --- a/services/backend/src/routes/studyProgramme.ts +++ b/services/backend/src/routes/studyProgramme.ts @@ -5,8 +5,8 @@ import { setBasicStats, getGraduationStats, setGraduationStats, - getStudytrackStats, - setStudytrackStats, + getStudyTrackStats, + setStudyTrackStats, } from '../services/analyticsService' import { getCreditsProduced } from '../services/providerCredits' import { getProgrammeName } from '../services/studyProgramme' @@ -15,8 +15,8 @@ import { getStudyProgrammeCoursesForStudyTrack, getStudyProgrammeStatsForColorizedCoursesTable, } from '../services/studyProgramme/studyProgrammeCourses' -import { getGraduationStatsForStudytrack } from '../services/studyProgramme/studyProgrammeGraduations' -import { updateBasicView, updateStudytrackView } from '../services/studyProgramme/studyProgrammeUpdates' +import { getGraduationStatsForStudyTrack } from '../services/studyProgramme/studyProgrammeGraduations' +import { updateBasicView, updateStudyTrackView } from '../services/studyProgramme/studyProgrammeUpdates' import { getStudyRightsInProgramme } from '../services/studyProgramme/studyRightFinders' import { getStudyTrackStatsForStudyProgramme } from '../services/studyProgramme/studyTrackStats' import { Graduated, SpecialGroups, YearType } from '../types' @@ -89,7 +89,7 @@ router.get('/:id/graduationstats', async (req: GetStatsRequest, res: Response) = return res.json(data) } - const updatedStats = await getGraduationStatsForStudytrack({ + const updatedStats = await getGraduationStatsForStudyTrack({ studyProgramme: code, combinedProgramme, settings: { @@ -142,7 +142,7 @@ router.get('/:id/studytrackstats', async (req: GetStudyTrackStatsRequest, res: R } logInfoForGrafana(code, combinedProgramme) - const data = await getStudytrackStats(code, combinedProgramme, graduated, specialGroups) + const data = await getStudyTrackStats(code, combinedProgramme, graduated, specialGroups) if (data) { return res.json(data) } @@ -158,7 +158,7 @@ router.get('/:id/studytrackstats', async (req: GetStudyTrackStatsRequest, res: R studyRightsOfProgramme, }) if (updated) { - await setStudytrackStats(updated, graduated, specialGroups) + await setStudyTrackStats(updated, graduated, specialGroups) } return res.json(updated) }) @@ -202,7 +202,7 @@ router.get('/:id/update_studytrackview', async (req: GetUpdateViewRequest, res: return res.status(400).json({ error: 'Missing code' }) } try { - const result = await updateStudytrackView(code, combinedProgramme) + const result = await updateStudyTrackView(code, combinedProgramme) return res.json(result) } catch (error) { const message = `Failed to update study track stats for programme ${code}${combinedProgramme ? `+${combinedProgramme}` : ''}` @@ -229,7 +229,7 @@ router.get('/:id/evaluationstats', async (req: GetEvaluationStatsRequest, res: R const combinedProgramme = '' let gradData = await getGraduationStats(code, combinedProgramme, yearType, specialGroups) if (!gradData) { - const updatedStats = await getGraduationStatsForStudytrack({ + const updatedStats = await getGraduationStatsForStudyTrack({ studyProgramme: code, combinedProgramme, settings: { @@ -243,7 +243,7 @@ router.get('/:id/evaluationstats', async (req: GetEvaluationStatsRequest, res: R } } - let progressData = await getStudytrackStats(code, combinedProgramme, graduated, specialGroups) + let progressData = await getStudyTrackStats(code, combinedProgramme, graduated, specialGroups) if (!progressData) { const studyRightsOfProgramme = await getStudyRightsInProgramme(code, false, true) const updated = await getStudyTrackStatsForStudyProgramme({ @@ -256,7 +256,7 @@ router.get('/:id/evaluationstats', async (req: GetEvaluationStatsRequest, res: R studyRightsOfProgramme, }) if (updated) { - await setStudytrackStats(updated, graduated, specialGroups) + await setStudyTrackStats(updated, graduated, specialGroups) progressData = updated } } diff --git a/services/backend/src/services/analyticsService.ts b/services/backend/src/services/analyticsService.ts index 4939c0ea2a..d5d92be55b 100644 --- a/services/backend/src/services/analyticsService.ts +++ b/services/backend/src/services/analyticsService.ts @@ -17,7 +17,7 @@ const createRedisKeyForCreditStats = (id: string, yearType: YearType, specialGro const createRedisKeyForGraduationStats = (id: string, yearType: YearType, specialGroups: SpecialGroups) => { return `GRADUATION_STATS_${id}_${yearType}_${specialGroups}` } -const createRedisKeyForStudytrackStats = (id: string, graduated: Graduated, specialGroups: SpecialGroups) => { +const createRedisKeyForStudyTrackStats = (id: string, graduated: Graduated, specialGroups: SpecialGroups) => { return `STUDYTRACK_STATS_${id}_${graduated}_${specialGroups}` } @@ -34,8 +34,8 @@ export const getBasicStats = async ( yearType: YearType, specialGroups: SpecialGroups ) => { - const searchkey = combinedProgramme ? `${id}-${combinedProgramme}` : id - const redisKey = createRedisKeyForBasicStats(searchkey, yearType, specialGroups) + const searchKey = combinedProgramme ? `${id}-${combinedProgramme}` : id + const redisKey = createRedisKeyForBasicStats(searchKey, yearType, specialGroups) const dataFromRedis = await redisClient.get(redisKey) if (!dataFromRedis) { return null @@ -102,8 +102,8 @@ export const getGraduationStats = async ( yearType: YearType, specialGroups: SpecialGroups ) => { - const searchkey = combinedProgramme ? `${id}-${combinedProgramme}` : id - const redisKey = createRedisKeyForGraduationStats(searchkey, yearType, specialGroups) + const searchKey = combinedProgramme ? `${id}-${combinedProgramme}` : id + const redisKey = createRedisKeyForGraduationStats(searchKey, yearType, specialGroups) const dataFromRedis = await redisClient.get(redisKey) if (!dataFromRedis) { return null @@ -129,14 +129,14 @@ export const setGraduationStats = async (data, yearType: YearType, specialGroups return dataToRedis } -export const getStudytrackStats = async ( +export const getStudyTrackStats = async ( id: string, combinedProgramme: string | null, graduated: Graduated, specialGroups: SpecialGroups ) => { - const searchkey = combinedProgramme ? `${id}-${combinedProgramme}` : id - const redisKey = createRedisKeyForStudytrackStats(searchkey, graduated, specialGroups) + const searchKey = combinedProgramme ? `${id}-${combinedProgramme}` : id + const redisKey = createRedisKeyForStudyTrackStats(searchKey, graduated, specialGroups) const dataFromRedis = await redisClient.get(redisKey) if (!dataFromRedis) { return null @@ -144,9 +144,9 @@ export const getStudytrackStats = async ( return JSON.parse(dataFromRedis) } -export const setStudytrackStats = async (data, graduated: Graduated, specialGroups: SpecialGroups) => { +export const setStudyTrackStats = async (data, graduated: Graduated, specialGroups: SpecialGroups) => { const { id } = data - const redisKey = createRedisKeyForStudytrackStats(id, graduated, specialGroups) + const redisKey = createRedisKeyForStudyTrackStats(id, graduated, specialGroups) const dataToRedis = { ...data, status: 'DONE', diff --git a/services/backend/src/services/faculty/facultyGraduationTimes.ts b/services/backend/src/services/faculty/facultyGraduationTimes.ts index 0c41453787..9b4ab9209f 100644 --- a/services/backend/src/services/faculty/facultyGraduationTimes.ts +++ b/services/backend/src/services/faculty/facultyGraduationTimes.ts @@ -1,8 +1,8 @@ import { cloneDeep, omit } from 'lodash' import { DegreeProgrammeType, Name } from '../../types' -import { getGraduationStats, getStudytrackStats, setGraduationStats, setStudytrackStats } from '../analyticsService' -import { getGraduationStatsForStudytrack, GraduationTimes } from '../studyProgramme/studyProgrammeGraduations' +import { getGraduationStats, getStudyTrackStats, setGraduationStats, setStudyTrackStats } from '../analyticsService' +import { getGraduationStatsForStudyTrack, GraduationTimes } from '../studyProgramme/studyProgrammeGraduations' import { getMedian } from '../studyProgramme/studyProgrammeHelpers' import { getStudyRightsInProgramme } from '../studyProgramme/studyRightFinders' import { @@ -25,7 +25,7 @@ export const programmeTypes = { } as const const getStatsByGraduationYear = async (facultyProgrammes: ProgrammesOfOrganization) => { - const newStats: Array>> = [] + const newStats: Array>> = [] const medians: Record = {} const programmes: { medians: Record> } = { medians: {} } @@ -38,7 +38,7 @@ const getStatsByGraduationYear = async (facultyProgrammes: ProgrammesOfOrganizat newStats.push(statsFromRedis) continue } - const updatedStats = await getGraduationStatsForStudytrack({ + const updatedStats = await getGraduationStatsForStudyTrack({ studyProgramme: programme.code, combinedProgramme: '', settings: { @@ -136,7 +136,7 @@ const getStatsByStartYear = async (facultyProgrammes: ProgrammesOfOrganization) if (programme.degreeProgrammeType == null || !(programme.degreeProgrammeType in programmeTypes)) { continue } - const statsFromRedis = await getStudytrackStats(programme.code, '', 'GRADUATED_INCLUDED', 'SPECIAL_EXCLUDED') + const statsFromRedis = await getStudyTrackStats(programme.code, '', 'GRADUATED_INCLUDED', 'SPECIAL_EXCLUDED') if (statsFromRedis) { newStats.push(statsFromRedis) continue @@ -152,7 +152,7 @@ const getStatsByStartYear = async (facultyProgrammes: ProgrammesOfOrganization) }, studyRightsOfProgramme, }) - await setStudytrackStats(updatedStats, 'GRADUATED_INCLUDED', 'SPECIAL_EXCLUDED') + await setStudyTrackStats(updatedStats, 'GRADUATED_INCLUDED', 'SPECIAL_EXCLUDED') newStats.push(updatedStats) } diff --git a/services/backend/src/services/faculty/facultyStudentProgress.ts b/services/backend/src/services/faculty/facultyStudentProgress.ts index 8ce9e1f28e..c94e65b694 100644 --- a/services/backend/src/services/faculty/facultyStudentProgress.ts +++ b/services/backend/src/services/faculty/facultyStudentProgress.ts @@ -3,7 +3,7 @@ import moment from 'moment' import { rootOrgId } from '../../config' import { Graduated, SpecialGroups, Unarray } from '../../types' -import { getStudytrackStats, setStudytrackStats } from '../analyticsService' +import { getStudyTrackStats, setStudyTrackStats } from '../analyticsService' import { getYearsArray } from '../studyProgramme/studyProgrammeHelpers' import { getStudyRightsInProgramme } from '../studyProgramme/studyRightFinders' import { getStudyTrackStatsForStudyProgramme } from '../studyProgramme/studyTrackStats' @@ -114,7 +114,7 @@ export const combineFacultyStudentProgress = async ( ) { continue } - const statsFromRedis = await getStudytrackStats(studyProgramme, null, graduated, specialGroups) + const statsFromRedis = await getStudyTrackStats(studyProgramme, null, graduated, specialGroups) if (statsFromRedis) { statsOfProgrammes.push(statsFromRedis) } else { @@ -128,7 +128,7 @@ export const combineFacultyStudentProgress = async ( studyRightsOfProgramme, }) statsOfProgrammes.push(updatedStats) - setStudytrackStats(updatedStats, graduated, specialGroups) + setStudyTrackStats(updatedStats, graduated, specialGroups) } } diff --git a/services/backend/src/services/faculty/facultyStudents.ts b/services/backend/src/services/faculty/facultyStudents.ts index f64e65cac3..f69a505113 100644 --- a/services/backend/src/services/faculty/facultyStudents.ts +++ b/services/backend/src/services/faculty/facultyStudents.ts @@ -1,5 +1,5 @@ import { Unarray } from '../../types' -import { getStudytrackStats, setStudytrackStats } from '../analyticsService' +import { getStudyTrackStats, setStudyTrackStats } from '../analyticsService' import { getPercentage, tableTitles } from '../studyProgramme/studyProgrammeHelpers' import { getStudyRightsInProgramme } from '../studyProgramme/studyRightFinders' import { getStudyTrackStatsForStudyProgramme } from '../studyProgramme/studyTrackStats' @@ -65,7 +65,7 @@ export const combineFacultyStudents = async ( const newStats: StudyTrackStats[] = [] for (const studyProgramme of programmeCodes) { - const statsFromRedis = await getStudytrackStats(studyProgramme, null, graduated, specialGroups) + const statsFromRedis = await getStudyTrackStats(studyProgramme, null, graduated, specialGroups) if (statsFromRedis) { newStats.push(statsFromRedis) if (!years.length) { @@ -82,7 +82,7 @@ export const combineFacultyStudents = async ( }, studyRightsOfProgramme, }) - setStudytrackStats(updatedStats, graduated, specialGroups) + setStudyTrackStats(updatedStats, graduated, specialGroups) if (!years.length) { years = updatedStats.years } diff --git a/services/backend/src/services/faculty/facultyThesisWriters.ts b/services/backend/src/services/faculty/facultyThesisWriters.ts index 6ad4b912a7..a9bb6f7296 100644 --- a/services/backend/src/services/faculty/facultyThesisWriters.ts +++ b/services/backend/src/services/faculty/facultyThesisWriters.ts @@ -2,7 +2,7 @@ import { cloneDeep } from 'lodash' import { DegreeProgrammeType } from '../../types' import { getGraduationStats, setGraduationStats } from '../analyticsService' -import { getGraduationStatsForStudytrack } from '../studyProgramme/studyProgrammeGraduations' +import { getGraduationStatsForStudyTrack } from '../studyProgramme/studyProgrammeGraduations' import { getDegreeProgrammesOfFaculty, ProgrammesOfOrganization } from './faculty' type ProgrammeName = { @@ -25,7 +25,7 @@ const calculateCombinedStats = async ( ] const programmeTableStats: Record>> = {} - const newStats: Array>> = [] + const newStats: Array>> = [] const combinedTableStats: Array> = [] let years: Array = [] const programmeNames: Record = {} @@ -47,7 +47,7 @@ const calculateCombinedStats = async ( newStats.push(statsFromRedis) continue } - const updatedStats = await getGraduationStatsForStudytrack({ + const updatedStats = await getGraduationStatsForStudyTrack({ studyProgramme: programme.code, combinedProgramme: '', settings: { diff --git a/services/backend/src/services/programmeModules.ts b/services/backend/src/services/programmeModules.ts index 74f4aeb9db..bcc338e4c6 100644 --- a/services/backend/src/services/programmeModules.ts +++ b/services/backend/src/services/programmeModules.ts @@ -5,7 +5,7 @@ import { ProgrammeModule } from '../models' import { ExcludedCourse } from '../models/kone' import { Name } from '../types' import logger from '../util/logger' -import { combinedStudyprogrammes } from './studyProgramme/studyProgrammeHelpers' +import { combinedStudyProgrammes } from './studyProgramme/studyProgrammeHelpers' export const getCurriculumVersions = async (code: string) => { try { @@ -134,8 +134,8 @@ const getCoursesAndModulesForProgramme = async (code: string, periodIds: string) export const getCoursesAndModules = async (code: string, periodIds: string) => { const defaultProgrammeCourses = await getCoursesAndModulesForProgramme(code, periodIds) - if (code in combinedStudyprogrammes) { - const secondProgramme = combinedStudyprogrammes[code as keyof typeof combinedStudyprogrammes] + if (code in combinedStudyProgrammes) { + const secondProgramme = combinedStudyProgrammes[code as keyof typeof combinedStudyProgrammes] const secondProgrammeCourses = await getCoursesAndModulesForProgramme(secondProgramme, periodIds) return { defaultProgrammeCourses, secondProgrammeCourses } } diff --git a/services/backend/src/services/studyProgramme/studyProgrammeGraduations.ts b/services/backend/src/services/studyProgramme/studyProgrammeGraduations.ts index 16d50a69fd..e5e575fe8b 100644 --- a/services/backend/src/services/studyProgramme/studyProgrammeGraduations.ts +++ b/services/backend/src/services/studyProgramme/studyProgrammeGraduations.ts @@ -292,7 +292,7 @@ const getProgrammesBeforeOrAfter = async (studyprogramme: string, queryParameter return null } -export const getGraduationStatsForStudytrack = async ({ +export const getGraduationStatsForStudyTrack = async ({ studyProgramme, combinedProgramme, settings, diff --git a/services/backend/src/services/studyProgramme/studyProgrammeHelpers.ts b/services/backend/src/services/studyProgramme/studyProgrammeHelpers.ts index 7cbcdd93c2..dfc263e159 100644 --- a/services/backend/src/services/studyProgramme/studyProgrammeHelpers.ts +++ b/services/backend/src/services/studyProgramme/studyProgrammeHelpers.ts @@ -78,7 +78,7 @@ export const getStartDate = (isAcademicYear: boolean) => { } // In the object programmes should be {bachelorCode: masterCode} -export const combinedStudyprogrammes = { KH90_001: 'MH90_001' } as const +export const combinedStudyProgrammes = { KH90_001: 'MH90_001' } as const // There are 9 course_unit_types // 1. urn:code:course-unit-type:regular diff --git a/services/backend/src/services/studyProgramme/studyProgrammeUpdates.ts b/services/backend/src/services/studyProgramme/studyProgrammeUpdates.ts index f07483d3b1..a3e435edb9 100644 --- a/services/backend/src/services/studyProgramme/studyProgrammeUpdates.ts +++ b/services/backend/src/services/studyProgramme/studyProgrammeUpdates.ts @@ -1,7 +1,7 @@ -import { setBasicStats, setCreditStats, setGraduationStats, setStudytrackStats } from '../analyticsService' +import { setBasicStats, setCreditStats, setGraduationStats, setStudyTrackStats } from '../analyticsService' import { computeCreditsProduced } from '../providerCredits' import { getBasicStatsForStudytrack } from './studyProgrammeBasics' -import { getGraduationStatsForStudytrack } from './studyProgrammeGraduations' +import { getGraduationStatsForStudyTrack } from './studyProgrammeGraduations' import { getStudyRightsInProgramme } from './studyRightFinders' import { getStudyTrackStatsForStudyProgramme } from './studyTrackStats' @@ -29,7 +29,7 @@ export const updateBasicView = async (code: string, combinedProgramme: string) = await setCreditStats(creditStats, isAcademicYear, includeAllSpecials) } - const graduationStats = await getGraduationStatsForStudytrack({ + const graduationStats = await getGraduationStatsForStudyTrack({ studyProgramme: code, combinedProgramme, settings: { isAcademicYear, includeAllSpecials }, @@ -41,7 +41,7 @@ export const updateBasicView = async (code: string, combinedProgramme: string) = return 'OK' } -export const updateStudytrackView = async (code: string, combinedProgramme: string) => { +export const updateStudyTrackView = async (code: string, combinedProgramme: string) => { const graduatedOptions = ['GRADUATED_INCLUDED', 'GRADUATED_EXCLUDED'] as const const specialGroupOptions = ['SPECIAL_INCLUDED', 'SPECIAL_EXCLUDED'] as const const studyRightsOfProgramme = await getStudyRightsInProgramme(code, false, true) @@ -57,7 +57,7 @@ export const updateStudytrackView = async (code: string, combinedProgramme: stri }, studyRightsOfProgramme, }) - await setStudytrackStats(stats, graduated, specialGroup) + await setStudyTrackStats(stats, graduated, specialGroup) } } diff --git a/services/backend/src/services/studyProgramme/studyTrackStats.ts b/services/backend/src/services/studyProgramme/studyTrackStats.ts index cc707f25f6..5b85b83bf9 100644 --- a/services/backend/src/services/studyProgramme/studyTrackStats.ts +++ b/services/backend/src/services/studyProgramme/studyTrackStats.ts @@ -344,9 +344,13 @@ const getMainStatsByTrackAndYear = async ( : {} for (const studyRight of studyRightsOfProgramme) { - if (!studyRight.semesterEnrollments || !studyRight.student) continue + if (!studyRight.semesterEnrollments || !studyRight.student) { + continue + } const studyRightElement = studyRight.studyRightElements.find(element => element.code === studyProgramme) - if (!studyRightElement) continue + if (!studyRightElement) { + continue + } if (!includeGraduated && studyRightElement.graduated) { continue } From 37fcd15f060301ca796821132df3ab095af0817e Mon Sep 17 00:00:00 2001 From: Riku Rauhala Date: Tue, 29 Oct 2024 20:08:44 +0200 Subject: [PATCH 02/12] [Study programme] Rename a bunch of stuff --- .../studyProgramme/studyRightFinders.ts | 5 ++-- .../studyProgramme/studyTrackStats.ts | 4 +-- .../StudyTrackOverview/index.jsx | 25 +++++++++++-------- 3 files changed, 19 insertions(+), 15 deletions(-) diff --git a/services/backend/src/services/studyProgramme/studyRightFinders.ts b/services/backend/src/services/studyProgramme/studyRightFinders.ts index ec12d9beab..e82402ea27 100644 --- a/services/backend/src/services/studyProgramme/studyRightFinders.ts +++ b/services/backend/src/services/studyProgramme/studyRightFinders.ts @@ -85,8 +85,8 @@ export const getStudyTracksForProgramme = async (studyProgramme: string) => { ) } -export const getSISStudyRightsOfStudents = async (studentNumbers: string[]) => - ( +export const getSISStudyRightsOfStudents = async (studentNumbers: string[]) => { + return ( await SISStudyRight.findAll({ where: { studentNumber: { @@ -96,3 +96,4 @@ export const getSISStudyRightsOfStudents = async (studentNumbers: string[]) => attributes: ['id', 'studentNumber', 'extentCode', 'semesterEnrollments', 'startDate', 'endDate'], }) ).map(studyRight => studyRight.toJSON()) +} diff --git a/services/backend/src/services/studyProgramme/studyTrackStats.ts b/services/backend/src/services/studyProgramme/studyTrackStats.ts index 5b85b83bf9..be8b494635 100644 --- a/services/backend/src/services/studyProgramme/studyTrackStats.ts +++ b/services/backend/src/services/studyProgramme/studyTrackStats.ts @@ -479,7 +479,7 @@ export const getStudyTrackStatsForStudyProgramme = async ({ const since = getStartDate(isAcademicYear) const years = getYearsArray(since.getFullYear(), isAcademicYear, includeYearsCombined) - const studytrackOptions = await getStudyTracksForProgramme(studyProgramme) + const studyTracks = await getStudyTracksForProgramme(studyProgramme) const doCombo = studyProgramme.startsWith('MH') && !['MH30_001', 'MH30_003'].includes(studyProgramme) const stats = await getMainStatsByTrackAndYear( @@ -501,7 +501,7 @@ export const getStudyTrackStatsForStudyProgramme = async ({ years, ...stats, doCombo, - studytrackOptions, + studyTracks, includeGraduated: settings.graduated, populationTitles: [...tableTitles.studytracksStart, ...graduatedTitles, ...tableTitles.studytracksEnd], } diff --git a/services/frontend/src/components/StudyProgramme/StudyTrackOverview/index.jsx b/services/frontend/src/components/StudyProgramme/StudyTrackOverview/index.jsx index 2fcb758091..12ddfa0fe6 100644 --- a/services/frontend/src/components/StudyProgramme/StudyTrackOverview/index.jsx +++ b/services/frontend/src/components/StudyProgramme/StudyTrackOverview/index.jsx @@ -53,11 +53,15 @@ export const StudyTrackOverview = ({ ) const isError = (stats.isSuccess && !stats.data) || stats.isError - - if (isError) return

Something went wrong, please try refreshing the page.

+ if (isError) { + return

Something went wrong, please try refreshing the page.

+ } const noData = stats.isSuccess && stats.mainStatsByYear && !stats.mainStatsByYear.Total.length - if (noData) return

There is no data available for the selected programme between 2017-2022

+ if (noData) { + return

There is no data available for the selected programme between 2017-2022

+ } + const infoTextGraduationTimes = studyProgramme.includes('MH') ? 'AverageGraduationTimesStudyTracksMaster' : 'AverageGraduationTimesStudyTracks' @@ -88,8 +92,7 @@ export const StudyTrackOverview = ({ const studyTrackStatsGraduationStats = { basic: {}, combo: {} } // One of the study track options is always the study programme itself - const studyProgrammeHasStudyTracks = - Object.keys(stats?.data?.studytrackOptions || {}).length > 1 && track === studyProgramme + const programmeHasStudyTracks = Object.keys(stats?.data?.studyTracks || {}).length > 1 && track === studyProgramme const calculateStudyTrackStats = combo => { const studyTrackStatsGraduationStats = Object.entries(stats.data.graduationTimes) @@ -127,7 +130,7 @@ export const StudyTrackOverview = ({ return { studyTrackStatsGraduationStats, studyTrackStatsClassSizes } } - if (studyProgrammeHasStudyTracks && Object.keys(stats?.data?.graduationTimes || {}).length > 1) { + if (programmeHasStudyTracks && Object.keys(stats?.data?.graduationTimes || {}).length > 1) { studyTrackStatsGraduationStats.basic = calculateStudyTrackStats() if (stats?.data?.doCombo) { studyTrackStatsGraduationStats.combo = calculateStudyTrackStats(true) @@ -140,7 +143,7 @@ export const StudyTrackOverview = ({ ) : ( <> - +
@@ -211,7 +214,7 @@ export const StudyTrackOverview = ({ setValue={setShowMedian} value={showMedian} /> - {studyProgrammeHasStudyTracks ? ( + {programmeHasStudyTracks ? (
{stats?.data.doCombo && ( Date: Tue, 29 Oct 2024 21:05:15 +0200 Subject: [PATCH 03/12] [Frontend] Rename useGetStudyTrackStatsQuery --- .../components/StudyProgramme/StudyTrackOverview/index.jsx | 4 ++-- services/frontend/src/redux/studyProgramme.js | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/services/frontend/src/components/StudyProgramme/StudyTrackOverview/index.jsx b/services/frontend/src/components/StudyProgramme/StudyTrackOverview/index.jsx index 12ddfa0fe6..5240255d58 100644 --- a/services/frontend/src/components/StudyProgramme/StudyTrackOverview/index.jsx +++ b/services/frontend/src/components/StudyProgramme/StudyTrackOverview/index.jsx @@ -10,7 +10,7 @@ import { BreakdownBarChart } from '@/components/StudyProgramme/BreakdownBarChart import { MedianTimeBarChart } from '@/components/StudyProgramme/MedianTimeBarChart' import { Toggle } from '@/components/StudyProgramme/Toggle' import '@/components/StudyProgramme/studyprogramme.css' -import { useGetStudytrackStatsQuery } from '@/redux/studyProgramme' +import { useGetStudyTrackStatsQuery } from '@/redux/studyProgramme' import { ProgressOfStudents } from './ProgressOfStudents' import { StudyTrackDataTable } from './StudyTrackDataTable' import { StudyTrackSelector } from './StudyTrackSelector' @@ -27,7 +27,7 @@ export const StudyTrackOverview = ({ const [track, setTrack] = useState(studyProgramme) const special = specialGroupsExcluded ? 'SPECIAL_EXCLUDED' : 'SPECIAL_INCLUDED' const grad = graduated ? 'GRADUATED_EXCLUDED' : 'GRADUATED_INCLUDED' - const stats = useGetStudytrackStatsQuery({ + const stats = useGetStudyTrackStatsQuery({ id: studyProgramme, combinedProgramme, specialGroups: special, diff --git a/services/frontend/src/redux/studyProgramme.js b/services/frontend/src/redux/studyProgramme.js index 8f75db9439..23662afafb 100644 --- a/services/frontend/src/redux/studyProgramme.js +++ b/services/frontend/src/redux/studyProgramme.js @@ -19,7 +19,7 @@ const studyProgrammeApi = RTKApi.injectEndpoints({ query: ({ id, yearType, specialGroups, combinedProgramme }) => `/v2/studyprogrammes/${id}/graduationstats?year_type=${yearType}&special_groups=${specialGroups}&combined_programme=${combinedProgramme}`, }), - getStudytrackStats: builder.query({ + getStudyTrackStats: builder.query({ query: ({ id, graduated, specialGroups, combinedProgramme }) => `/v2/studyprogrammes/${id}/studytrackstats?graduated=${graduated}&special_groups=${specialGroups}&combined_programme=${combinedProgramme}`, }), @@ -50,7 +50,7 @@ export const { useGetBasicStatsQuery, useGetCreditStatsQuery, useGetGraduationStatsQuery, - useGetStudytrackStatsQuery, + useGetStudyTrackStatsQuery, useUpdateBasicViewQuery, useUpdateStudyTrackViewQuery, useGetProgrammeCoursesStatsQuery, From f2a8672c2212ddac41b7233d9632a3ea58c308c6 Mon Sep 17 00:00:00 2001 From: Riku Rauhala Date: Wed, 30 Oct 2024 14:23:56 +0200 Subject: [PATCH 04/12] [Study programme] Add route for study tracks of a programmec --- services/backend/src/routes/studyProgramme.ts | 15 ++++++++- services/frontend/src/redux/studyProgramme.js | 32 +++++++++++-------- 2 files changed, 32 insertions(+), 15 deletions(-) diff --git a/services/backend/src/routes/studyProgramme.ts b/services/backend/src/routes/studyProgramme.ts index c9144003c6..93af236529 100644 --- a/services/backend/src/routes/studyProgramme.ts +++ b/services/backend/src/routes/studyProgramme.ts @@ -17,7 +17,7 @@ import { } from '../services/studyProgramme/studyProgrammeCourses' import { getGraduationStatsForStudyTrack } from '../services/studyProgramme/studyProgrammeGraduations' import { updateBasicView, updateStudyTrackView } from '../services/studyProgramme/studyProgrammeUpdates' -import { getStudyRightsInProgramme } from '../services/studyProgramme/studyRightFinders' +import { getStudyRightsInProgramme, getStudyTracksForProgramme } from '../services/studyProgramme/studyRightFinders' import { getStudyTrackStatsForStudyProgramme } from '../services/studyProgramme/studyTrackStats' import { Graduated, SpecialGroups, YearType } from '../types' import logger from '../util/logger' @@ -173,6 +173,19 @@ router.get('/:id/colorizedtablecoursestats', async (req: Request, res: Response) } }) +router.get('/:id/studytracks', async (req: Request, res: Response) => { + const code = req.params.id + if (!code) { + return res.status(422).end() + } + try { + const data = await getStudyTracksForProgramme(code) + return res.json(data) + } catch (error) { + logger.error({ message: `Failed to get study tracks for study programme ${code}`, meta: `${error}` }) + } +}) + interface GetUpdateViewRequest extends Request { query: { combined_programme: string diff --git a/services/frontend/src/redux/studyProgramme.js b/services/frontend/src/redux/studyProgramme.js index 23662afafb..0768af1272 100644 --- a/services/frontend/src/redux/studyProgramme.js +++ b/services/frontend/src/redux/studyProgramme.js @@ -9,12 +9,19 @@ const studyProgrammeApi = RTKApi.injectEndpoints({ query: ({ id, yearType, specialGroups, combinedProgramme }) => `/v2/studyprogrammes/${id}/basicstats?year_type=${yearType}&special_groups=${specialGroups}&combined_programme=${combinedProgramme}`, }), + getColorizedTableCourseStats: builder.query({ + query: ({ id }) => `/v2/studyprogrammes/${id}/colorizedtablecoursestats`, + }), getCreditStats: builder.query({ query: ({ codes, isAcademicYear, specialGroups }) => `/v2/studyprogrammes/creditstats?codes=${JSON.stringify( codes )}&isAcademicYear=${isAcademicYear}&includeSpecials=${specialGroups}`, }), + getEvaluationStats: builder.query({ + query: ({ id, yearType, specialGroups, graduated }) => + `/v2/studyprogrammes/${id}/evaluationstats?year_type=${yearType}&special_groups=${specialGroups}&graduated=${graduated}`, + }), getGraduationStats: builder.query({ query: ({ id, yearType, specialGroups, combinedProgramme }) => `/v2/studyprogrammes/${id}/graduationstats?year_type=${yearType}&special_groups=${specialGroups}&combined_programme=${combinedProgramme}`, @@ -23,6 +30,13 @@ const studyProgrammeApi = RTKApi.injectEndpoints({ query: ({ id, graduated, specialGroups, combinedProgramme }) => `/v2/studyprogrammes/${id}/studytrackstats?graduated=${graduated}&special_groups=${specialGroups}&combined_programme=${combinedProgramme}`, }), + getProgrammeCoursesStats: builder.query({ + query: ({ id, academicyear, combinedProgramme }) => + `/v2/studyprogrammes/${id}/coursestats?academicyear=${academicyear}&combined_programme=${combinedProgramme}`, + }), + getStudyTracks: builder.query({ + query: ({ id }) => `/v2/studyprogrammes/${id}/studytracks`, + }), updateBasicView: builder.query({ query: ({ id, combinedProgramme }) => `/v2/studyprogrammes/${id}/update_basicview?combined_programme=${combinedProgramme}`, @@ -31,31 +45,21 @@ const studyProgrammeApi = RTKApi.injectEndpoints({ query: ({ id, combinedProgramme }) => `/v2/studyprogrammes/${id}/update_studytrackview?combined_programme=${combinedProgramme}`, }), - getProgrammeCoursesStats: builder.query({ - query: ({ id, academicyear, combinedProgramme }) => - `/v2/studyprogrammes/${id}/coursestats?academicyear=${academicyear}&combined_programme=${combinedProgramme}`, - }), - getEvaluationStats: builder.query({ - query: ({ id, yearType, specialGroups, graduated }) => - `/v2/studyprogrammes/${id}/evaluationstats?year_type=${yearType}&special_groups=${specialGroups}&graduated=${graduated}`, - }), - getColorizedTableCourseStats: builder.query({ - query: ({ id }) => `/v2/studyprogrammes/${id}/colorizedtablecoursestats`, - }), }), overrideExisting: false, }) export const { useGetBasicStatsQuery, + useGetColorizedTableCourseStatsQuery, useGetCreditStatsQuery, + useGetEvaluationStatsQuery, useGetGraduationStatsQuery, useGetStudyTrackStatsQuery, + useGetProgrammeCoursesStatsQuery, + useGetStudyTracksQuery, useUpdateBasicViewQuery, useUpdateStudyTrackViewQuery, - useGetProgrammeCoursesStatsQuery, - useGetEvaluationStatsQuery, - useGetColorizedTableCourseStatsQuery, } = studyProgrammeApi const getFilteredAndFormattedStudyProgrammes = (getTextIn, studyProgrammes) => { From 84504ab0d29b75da22c3d9dd5231379b01f1bf1c Mon Sep 17 00:00:00 2001 From: Riku Rauhala Date: Wed, 30 Oct 2024 15:22:17 +0200 Subject: [PATCH 05/12] [Class statistics] Add initial form for selecting study tracks --- .../PopulationSearch/PopulationSearchForm.jsx | 63 +++++++++++++++++-- 1 file changed, 57 insertions(+), 6 deletions(-) diff --git a/services/frontend/src/components/PopulationSearch/PopulationSearchForm.jsx b/services/frontend/src/components/PopulationSearch/PopulationSearchForm.jsx index ba53c333e2..9aa778c61b 100644 --- a/services/frontend/src/components/PopulationSearch/PopulationSearchForm.jsx +++ b/services/frontend/src/components/PopulationSearch/PopulationSearchForm.jsx @@ -16,6 +16,7 @@ import { YEAR_DATE_FORMAT } from '@/constants/date' import { useGetAuthorizedUserQuery } from '@/redux/auth' import { getPopulationStatistics, clearPopulations, useGetProgrammesQuery } from '@/redux/populations' import { clearSelected } from '@/redux/populationSelectedStudentCourses' +import { useGetStudyTracksQuery } from '@/redux/studyProgramme' import { useGetStudyProgrammePinsQuery } from '@/redux/studyProgrammePins' import { formatQueryParamsToArrays } from '@/shared/util' import { momentFromFormat, reformatDate } from '@/util/timeAndDate' @@ -57,6 +58,9 @@ export const PopulationSearchForm = ({ onProgress }) => { }, } : programmes + const { data: studyTracks = {}, isLoading: studyTracksAreLoading } = useGetStudyTracksQuery({ + id: query.studyRights.programme, + }) const { data: studyProgrammePins } = useGetStudyProgrammePinsQuery() const pinnedProgrammes = studyProgrammePins?.studyProgrammes || [] @@ -78,10 +82,9 @@ export const PopulationSearchForm = ({ onProgress }) => { const sameSemesters = isEqual(previousQuery.semesters, query.semesters) const sameStudentStatuses = isEqual(previousQuery.studentStatuses, query.studentStatuses) const sameYears = isEqual(previousQuery.years, query.years) - const sameStudyrights = isEqual(previousQuery.studyRights, query.studyRights) - const sameTag = previousQuery.tag === query.tag - - return sameStudyrights && sameMonths && sameYear && sameSemesters && sameStudentStatuses && sameYears && sameTag + const sameStudyRights = isEqual(previousQuery.studyRights, query.studyRights) + const sameTag = query.tag === previousQuery.tag + return sameStudyRights && sameMonths && sameYear && sameSemesters && sameStudentStatuses && sameYears && sameTag } const fetchPopulation = async query => { @@ -119,7 +122,14 @@ export const PopulationSearchForm = ({ onProgress }) => { const handleProgrammeChange = (_event, { value: programme }) => { setQuery({ ...query, - studyRights: programme === '' ? {} : { programme }, + studyRights: programme === '' ? {} : { ...query.studyRights, programme }, + }) + } + + const handleStudyTrackChange = (_event, { value: studyTrack }) => { + setQuery({ + ...query, + studyRights: studyTrack === '' ? {} : { ...query.studyRights, studyTrack }, }) } @@ -151,7 +161,7 @@ export const PopulationSearchForm = ({ onProgress }) => { const getSearchHistoryTextFromQuery = () => { const { studyRights, semesters, months, year, studentStatuses } = query const studyRightsText = `${getTextIn(studyProgrammes[studyRights.programme].name)} ${Object.values(studyRights) - .filter(studyright => studyright) + .filter(studyRight => studyRight) .join(', ')}` const timeText = `${semesters.join(', ')}/${year}-${parseInt(year, 10) + 1}, ${months} months` const studentStatusesText = @@ -314,6 +324,46 @@ export const PopulationSearchForm = ({ onProgress }) => { ) } + const renderStudyTrackSelector = () => { + if (studyTracksAreLoading) { + return + } + + let studyTracksToRender + if (Object.values(studyTracks).length > 1) { + studyTracksToRender = Object.keys(studyTracks) + .filter(studyTrack => studyTrack !== query.studyRights.programme) + .map(studyTrack => ({ + code: studyTrack, + description: studyTrack, + icon: null, + text: getTextIn(studyTracks[studyTrack]), + value: studyTrack, + })) + } + + return ( + + + + + ) + } + if (location.search !== '') { return null } @@ -330,6 +380,7 @@ export const PopulationSearchForm = ({ onProgress }) => {
{renderEnrollmentDateSelector()} {renderStudyProgrammeSelector()} + {renderStudyTrackSelector()} See class From fc70a24b413d84063e0429dc64615aa5613420cb Mon Sep 17 00:00:00 2001 From: Riku Rauhala Date: Wed, 30 Oct 2024 15:28:08 +0200 Subject: [PATCH 06/12] [Class statistics] Remove error message from the search from --- .../components/PopulationSearch/PopulationSearchForm.jsx | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/services/frontend/src/components/PopulationSearch/PopulationSearchForm.jsx b/services/frontend/src/components/PopulationSearch/PopulationSearchForm.jsx index 9aa778c61b..200c5dd252 100644 --- a/services/frontend/src/components/PopulationSearch/PopulationSearchForm.jsx +++ b/services/frontend/src/components/PopulationSearch/PopulationSearchForm.jsx @@ -368,20 +368,13 @@ export const PopulationSearchForm = ({ onProgress }) => { return null } - let invalidQuery = false - let errorMessage - - if (!query.studyRights.programme) { - invalidQuery = true - errorMessage = 'Select study programme' - } + const invalidQuery = !query.studyRights.programme return ( {renderEnrollmentDateSelector()} {renderStudyProgrammeSelector()} {renderStudyTrackSelector()} - See class From 576051dae399462fea299998229d1beaa403ba7e Mon Sep 17 00:00:00 2001 From: Riku Rauhala Date: Wed, 30 Oct 2024 15:44:12 +0200 Subject: [PATCH 07/12] [Class statistics] Remove redundant date from search history --- .../components/PopulationSearch/PopulationSearchForm.jsx | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/services/frontend/src/components/PopulationSearch/PopulationSearchForm.jsx b/services/frontend/src/components/PopulationSearch/PopulationSearchForm.jsx index 200c5dd252..738108aaf3 100644 --- a/services/frontend/src/components/PopulationSearch/PopulationSearchForm.jsx +++ b/services/frontend/src/components/PopulationSearch/PopulationSearchForm.jsx @@ -378,14 +378,7 @@ export const PopulationSearchForm = ({ onProgress }) => { See class - { - item.date = new Date(item.date) - return item - })} - updateItem={updateItemInSearchHistory} - /> + ) } From 2a5f47da36fe04f5fc1826412e522dd05d2d181d Mon Sep 17 00:00:00 2001 From: Riku Rauhala Date: Wed, 30 Oct 2024 18:11:37 +0200 Subject: [PATCH 08/12] [Search history] Update styling --- services/frontend/src/components/SearchHistory/index.jsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/services/frontend/src/components/SearchHistory/index.jsx b/services/frontend/src/components/SearchHistory/index.jsx index ddfb1cff7f..68b89e6d63 100644 --- a/services/frontend/src/components/SearchHistory/index.jsx +++ b/services/frontend/src/components/SearchHistory/index.jsx @@ -1,7 +1,7 @@ import { sortBy } from 'lodash' import moment from 'moment' import { useState } from 'react' -import { Form, Header, Icon, Segment } from 'semantic-ui-react' +import { Form, Header, HeaderContent, Icon, Segment } from 'semantic-ui-react' import { DISPLAY_DATE_FORMAT_DEV } from '@/constants/date' @@ -27,9 +27,9 @@ export const SearchHistory = ({ disabled, handleSearch, header = 'Previous searc return ( -
+
- {header} + {header}
Date: Wed, 30 Oct 2024 18:27:36 +0200 Subject: [PATCH 09/12] [Population search] Extract LoadingIcon --- .../PopulationSearch/PopulationSearchForm.jsx | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/services/frontend/src/components/PopulationSearch/PopulationSearchForm.jsx b/services/frontend/src/components/PopulationSearch/PopulationSearchForm.jsx index 738108aaf3..c8ce99270d 100644 --- a/services/frontend/src/components/PopulationSearch/PopulationSearchForm.jsx +++ b/services/frontend/src/components/PopulationSearch/PopulationSearchForm.jsx @@ -31,6 +31,12 @@ const initialQuery = () => ({ months: getMonths('2017', 'FALL'), }) +const LoadingIcon = () => ( +
+ +
+) + export const PopulationSearchForm = ({ onProgress }) => { const history = useHistory() const location = useLocation() @@ -273,7 +279,7 @@ export const PopulationSearchForm = ({ onProgress }) => { const renderStudyProgrammeSelector = () => { const { studyRights } = query if (programmesAreLoading) { - return + return } if (Object.values(studyProgrammes).length === 0 && !programmesAreLoading) { return ( @@ -326,7 +332,7 @@ export const PopulationSearchForm = ({ onProgress }) => { const renderStudyTrackSelector = () => { if (studyTracksAreLoading) { - return + return } let studyTracksToRender From 48f5c58a3fb8cebc7a5e2c5eb09fcbd56d74246a Mon Sep 17 00:00:00 2001 From: Riku Rauhala Date: Wed, 30 Oct 2024 19:15:39 +0200 Subject: [PATCH 10/12] [Population search] Replace LoadingIcons with disabling inputs Prevents layout shift and disallows selecting a study track if there are no available study tracks --- .../PopulationSearch/PopulationSearchForm.jsx | 74 ++++++++----------- 1 file changed, 30 insertions(+), 44 deletions(-) diff --git a/services/frontend/src/components/PopulationSearch/PopulationSearchForm.jsx b/services/frontend/src/components/PopulationSearch/PopulationSearchForm.jsx index c8ce99270d..e454572a5d 100644 --- a/services/frontend/src/components/PopulationSearch/PopulationSearchForm.jsx +++ b/services/frontend/src/components/PopulationSearch/PopulationSearchForm.jsx @@ -5,7 +5,7 @@ import { useEffect, useState } from 'react' import Datetime from 'react-datetime' import { useDispatch, useSelector } from 'react-redux' import { useHistory, useLocation } from 'react-router-dom' -import { Button, Form, Icon, Message } from 'semantic-ui-react' +import { Button, Form, Message } from 'semantic-ui-react' import { createPinnedFirstComparator, isNewStudyProgramme, textAndDescriptionSearch } from '@/common' import { useSearchHistory } from '@/common/hooks' @@ -31,12 +31,6 @@ const initialQuery = () => ({ months: getMonths('2017', 'FALL'), }) -const LoadingIcon = () => ( -
- -
-) - export const PopulationSearchForm = ({ onProgress }) => { const history = useHistory() const location = useLocation() @@ -277,10 +271,6 @@ export const PopulationSearchForm = ({ onProgress }) => { } const renderStudyProgrammeSelector = () => { - const { studyRights } = query - if (programmesAreLoading) { - return - } if (Object.values(studyProgrammes).length === 0 && !programmesAreLoading) { return ( { ) } - let programmesToRender - if (Object.values(studyProgrammes).length !== 0) { - let sortedStudyProgrammes = sortBy(studyProgrammes, programme => getTextIn(programme.name)) - if (filterProgrammes) { - sortedStudyProgrammes = sortedStudyProgrammes.filter(programme => isNewStudyProgramme(programme.code)) - } - programmesToRender = sortedStudyProgrammes.map(({ code, name }) => ({ - code, - description: code, - icon: pinnedProgrammes.includes(code) ? 'pin' : '', - name, - text: getTextIn(name), - value: code, - })) - } + const studyProgrammesAvailable = Object.values(studyProgrammes).length > 0 && !programmesAreLoading + const programmesToRender = studyProgrammesAvailable + ? sortBy(studyProgrammes, programme => getTextIn(programme.name)) + .filter(programme => !filterProgrammes || isNewStudyProgramme(programme.code)) + .map(({ code, name }) => ({ + code, + description: code, + icon: pinnedProgrammes.includes(code) ? 'pin' : '', + name, + text: getTextIn(name), + value: code, + })) + : [] const pinnedFirstComparator = createPinnedFirstComparator(pinnedProgrammes) return ( @@ -315,6 +303,7 @@ export const PopulationSearchForm = ({ onProgress }) => { clearable closeOnChange data-cy="select-study-programme" + disabled={!studyProgrammesAvailable} fluid noResultsMessage="No selectable study programmes" onChange={handleProgrammeChange} @@ -324,29 +313,25 @@ export const PopulationSearchForm = ({ onProgress }) => { selectOnBlur={false} selectOnNavigation={false} selection - value={studyRights.programme} + value={query.studyRights.programme} /> ) } const renderStudyTrackSelector = () => { - if (studyTracksAreLoading) { - return - } - - let studyTracksToRender - if (Object.values(studyTracks).length > 1) { - studyTracksToRender = Object.keys(studyTracks) - .filter(studyTrack => studyTrack !== query.studyRights.programme) - .map(studyTrack => ({ - code: studyTrack, - description: studyTrack, - icon: null, - text: getTextIn(studyTracks[studyTrack]), - value: studyTrack, - })) - } + const studyTracksAvailable = Object.values(studyTracks).length > 1 && !studyTracksAreLoading + const studyTracksToRender = studyTracksAvailable + ? Object.keys(studyTracks) + .filter(studyTrack => studyTrack !== query.studyRights.programme) + .map(studyTrack => ({ + code: studyTrack, + description: studyTrack, + icon: null, + text: getTextIn(studyTracks[studyTrack]), + value: studyTrack, + })) + : [] return ( @@ -355,11 +340,12 @@ export const PopulationSearchForm = ({ onProgress }) => { clearable closeOnChange data-cy="select-study-track" + disabled={!studyTracksAvailable} fluid noResultsMessage="No selectable study tracks" onChange={handleStudyTrackChange} options={studyTracksToRender} - placeholder="Select study track" + placeholder={studyTracksAvailable ? 'Select study track' : 'No study tracks available for this programme'} search={textAndDescriptionSearch} selectOnBlur={false} selectOnNavigation={false} From 062b81d537c149466a584aec570f95e549841ecc Mon Sep 17 00:00:00 2001 From: Riku Rauhala Date: Wed, 30 Oct 2024 19:31:22 +0200 Subject: [PATCH 11/12] [Population search] Update info box text Add mention of the new study track selector --- .../frontend/src/common/InfoToolTips/populationStatistics.js | 1 + 1 file changed, 1 insertion(+) diff --git a/services/frontend/src/common/InfoToolTips/populationStatistics.js b/services/frontend/src/common/InfoToolTips/populationStatistics.js index 4de475ed99..84970a5226 100644 --- a/services/frontend/src/common/InfoToolTips/populationStatistics.js +++ b/services/frontend/src/common/InfoToolTips/populationStatistics.js @@ -95,6 +95,7 @@ export const populationStatisticsToolTips = { - **Class of**: lukuvuosi, jolloin opiskelija on ilmoittautunut ensimmäisen kerran (läsnä- tai poissaolevaksi) ohjelmaan. Ilmoittautumisen opinto-oikeus voi olla ensi- tai toissijainen. - **Study programme**: haluttu koulutusohjelma. Kiinnitetyt (suosikeiksi valitut) ohjelmat näkyvät ensimmäisinä valikossa. Kiinnitys on mahdollista koulutusohjelmalistauksessa. + - **Study track**: (valinnainen) koulutusohjelman opintosuunta. Valittavissa vain, jos ohjelmalla on opintosuuntia. `, StudentsGuidanceGroups: `**Students** From 6808bfddc7dbdf8748731fb4a321dda78a4a99bb Mon Sep 17 00:00:00 2001 From: Riku Rauhala Date: Wed, 30 Oct 2024 19:56:22 +0200 Subject: [PATCH 12/12] [Population search] Fix logic for clearing the selections --- .../components/PopulationSearch/PopulationSearchForm.jsx | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/services/frontend/src/components/PopulationSearch/PopulationSearchForm.jsx b/services/frontend/src/components/PopulationSearch/PopulationSearchForm.jsx index e454572a5d..4995ecde23 100644 --- a/services/frontend/src/components/PopulationSearch/PopulationSearchForm.jsx +++ b/services/frontend/src/components/PopulationSearch/PopulationSearchForm.jsx @@ -122,14 +122,18 @@ export const PopulationSearchForm = ({ onProgress }) => { const handleProgrammeChange = (_event, { value: programme }) => { setQuery({ ...query, - studyRights: programme === '' ? {} : { ...query.studyRights, programme }, + studyRights: + programme === '' + ? { ...query.studyRights, studyTrack: undefined, programme: undefined } + : { ...query.studyRights, studyTrack: undefined, programme }, }) } const handleStudyTrackChange = (_event, { value: studyTrack }) => { setQuery({ ...query, - studyRights: studyTrack === '' ? {} : { ...query.studyRights, studyTrack }, + studyRights: + studyTrack === '' ? { ...query.studyRights, studyTrack: undefined } : { ...query.studyRights, studyTrack }, }) }