mirror of
https://github.com/UniversityOfHelsinkiCS/oodikone.git
synced 2026-10-12 19:03:39 +03:00
[Evaluation overview] Remove everything
This commit is contained in:
@@ -55,8 +55,6 @@ jobs:
|
||||
spec: cypress/e2e/Language_center.js
|
||||
- name: 'Test study guidance groups'
|
||||
spec: cypress/e2e/Study_guidance_groups.js
|
||||
- name: 'Test evaluation overview'
|
||||
spec: cypress/e2e/Evaluation_overview.js
|
||||
- name: 'Test university'
|
||||
spec: cypress/e2e/University.js
|
||||
name: ${{ matrix.name }}
|
||||
|
||||
@@ -213,8 +213,6 @@ jobs:
|
||||
spec: cypress/e2e/Language_center.js
|
||||
- name: 'Test study guidance groups'
|
||||
spec: cypress/e2e/Study_guidance_groups.js
|
||||
- name: 'Test evaluation overview'
|
||||
spec: cypress/e2e/Evaluation_overview.js
|
||||
- name: 'Test university'
|
||||
spec: cypress/e2e/University.js
|
||||
name: ${{ matrix.name }}
|
||||
|
||||
@@ -1,514 +0,0 @@
|
||||
/// <reference types="cypress" />
|
||||
|
||||
const { getEmptyYears } = require('../support/commands')
|
||||
|
||||
describe('Evaluation overview', () => {
|
||||
describe('Programme view', () => {
|
||||
beforeEach(() => {
|
||||
cy.init('/evaluationoverview/programme/KH50_001', 'admin')
|
||||
})
|
||||
|
||||
it('Page opens correctly', () => {
|
||||
cy.contains('Matemaattisten tieteiden kandiohjelma')
|
||||
cy.contains('KH50_001')
|
||||
cy.contains("This view is an abridged version of Oodikone's Studyprogramme Overview")
|
||||
})
|
||||
|
||||
it('Progress data is shown correctly with graduated included', () => {
|
||||
cy.get('[data-cy="Graph-StudyTrackProgress"]').within(() => {
|
||||
const totalStats = ['12.9%', '6.9%', '9.7%', '9.2%', '3.7%', '6.0%', '51.6%']
|
||||
for (const stat of totalStats) {
|
||||
cy.contains(stat)
|
||||
}
|
||||
})
|
||||
|
||||
const years = getEmptyYears(true)
|
||||
|
||||
const tableContents = [
|
||||
...years.map(year => [year, 0, 0, 0, 0, 0, 0, 0, 0]),
|
||||
['2023 - 2024', 8, 8, 0, 0, 0, 0, 0, 0],
|
||||
['2022 - 2023', 26, 9, 9, 4, 3, 0, 1, 0],
|
||||
['2021 - 2022', 32, 8, 3, 8, 8, 5, 0, 0],
|
||||
['2020 - 2021', 27, 2, 1, 3, 6, 2, 4, 9],
|
||||
['2019 - 2020', 33, 1, 0, 2, 1, 0, 3, 26],
|
||||
['2018 - 2019', 44, 0, 1, 1, 2, 0, 3, 37],
|
||||
['2017 - 2018', 47, 0, 1, 3, 0, 1, 2, 40],
|
||||
['Total', 217, 28, 15, 21, 20, 8, 13, 112],
|
||||
]
|
||||
|
||||
cy.checkTableStats(tableContents, 'StudyTrackProgress')
|
||||
})
|
||||
|
||||
it('Progress data is shown correctly with graduated excluded', () => {
|
||||
cy.get('[data-cy=GraduatedToggle]').click()
|
||||
cy.get('[data-cy="Graph-StudyTrackProgress"]').within(() => {
|
||||
const totalStats = ['30.8%', '15.4%', '22.0%', '20.9%', '4.4%', '5.5%']
|
||||
for (const stat of totalStats) {
|
||||
cy.contains(stat)
|
||||
}
|
||||
})
|
||||
|
||||
const years = getEmptyYears(true)
|
||||
|
||||
const tableContents = [
|
||||
...years.map(year => [year, 0, 0, 0, 0, 0, 0, 0, 0]),
|
||||
['2023 - 2024', 8, 8, 0, 0, 0, 0, 0, 0],
|
||||
['2022 - 2023', 24, 9, 8, 4, 3, 0, 0, 0],
|
||||
['2021 - 2022', 31, 8, 3, 8, 8, 4, 0, 0],
|
||||
['2020 - 2021', 11, 2, 1, 2, 5, 0, 0, 1],
|
||||
['2019 - 2020', 7, 1, 0, 2, 1, 0, 0, 3],
|
||||
['2018 - 2019', 5, 0, 1, 1, 2, 0, 0, 1],
|
||||
['2017 - 2018', 5, 0, 1, 3, 0, 0, 1, 0],
|
||||
['Total', 91, 28, 14, 20, 19, 4, 1, 5],
|
||||
]
|
||||
|
||||
cy.checkTableStats(tableContents, 'StudyTrackProgress')
|
||||
})
|
||||
|
||||
it('Graduation times breakdown data is shown correctly', () => {
|
||||
cy.get('[data-cy=graduation-times-graph-breakdown]').within(() => {
|
||||
cy.contains('Graduation year')
|
||||
cy.contains('2021')
|
||||
cy.get('[aria-label="2021, 8. Overtime."]')
|
||||
cy.get('[aria-label="2021, 24. Max. year overtime."]')
|
||||
cy.get('[aria-label="2021, 14. On time."]').trigger('mouseover')
|
||||
cy.contains('Graduated On time: 14 students')
|
||||
})
|
||||
|
||||
cy.get('[data-cy=YearToggle]').click()
|
||||
|
||||
cy.get('[data-cy=graduation-times-graph-breakdown]').within(() => {
|
||||
cy.contains('Graduation year')
|
||||
cy.contains('2021 - 2022')
|
||||
cy.get('[aria-label="2021 - 2022, 13. Overtime."]')
|
||||
cy.get('[aria-label="2021 - 2022, 21. Max. year overtime."]')
|
||||
cy.get('[aria-label="2021 - 2022, 21. On time."]').trigger('mouseover')
|
||||
cy.contains('Graduated On time: 21 students')
|
||||
})
|
||||
})
|
||||
|
||||
it('Graduation times median time data is shown correctly', () => {
|
||||
cy.get('[data-cy=GraduationTimeToggle]').click()
|
||||
|
||||
cy.get('[data-cy=graduation-times-graph]').within(() => {
|
||||
cy.contains('Graduation year')
|
||||
cy.contains('2021')
|
||||
cy.contains('46 graduated').trigger('mouseover')
|
||||
cy.contains('46 students graduated in year 2021')
|
||||
cy.contains('median study time: 41 months')
|
||||
cy.contains('14 graduated on time')
|
||||
cy.contains('24 graduated max year overtime')
|
||||
cy.contains('8 graduated over year late')
|
||||
})
|
||||
|
||||
cy.get('[data-cy=YearToggle]').click()
|
||||
|
||||
cy.get('[data-cy=graduation-times-graph]').within(() => {
|
||||
cy.contains('Graduation year')
|
||||
cy.contains('2021 - 2022')
|
||||
cy.contains('55 graduated').trigger('mouseover')
|
||||
cy.contains('55 students graduated in year 2021 - 2022')
|
||||
cy.contains('median study time: 40 months')
|
||||
cy.contains('21 graduated on time')
|
||||
cy.contains('21 graduated max year overtime')
|
||||
cy.contains('13 graduated over year late')
|
||||
})
|
||||
})
|
||||
|
||||
it("'Programmes before or after' data is shown correctly", () => {
|
||||
cy.get('[data-cy=Graph-ProgrammesBeforeOrAfter]').within(() => {
|
||||
cy.contains('Matematiikan ja tilastotieteen maisteriohjelma')
|
||||
cy.contains('Tietojenkäsittelytieteen maisteriohjelma')
|
||||
cy.contains('Datatieteen maisteriohjelma')
|
||||
cy.contains('2021')
|
||||
cy.contains('32')
|
||||
cy.contains('19')
|
||||
})
|
||||
|
||||
let emptyYears = new Array(getEmptyYears(false).length).fill(0)
|
||||
|
||||
let tableContents = [
|
||||
['MH50_001', 'MAST', 'Matematiikan ja tilastotieteen maisteriohjelma', 0, 0, 1, 9, 32, 19, 15, ...emptyYears],
|
||||
['MH50_002', 'LSI', 'Life Science Informatics -maisteriohjelma', 0, 0, 0, 1, 2, 1, 1, ...emptyYears],
|
||||
[
|
||||
'MH50_003',
|
||||
'TCM',
|
||||
'Teoreettisten ja laskennallisten menetelmien maisteriohjelma',
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
1,
|
||||
...emptyYears,
|
||||
],
|
||||
['MH50_009', 'CSM', 'Tietojenkäsittelytieteen maisteriohjelma', 0, 0, 0, 0, 2, 3, 2, ...emptyYears],
|
||||
['MH50_010', 'DATA', 'Datatieteen maisteriohjelma', 0, 0, 0, 1, 5, 10, 1, ...emptyYears],
|
||||
['MH70_009', 'ECON', 'Taloustieteen maisteriohjelma', 0, 0, 0, 0, 4, 7, 4, ...emptyYears],
|
||||
]
|
||||
|
||||
cy.checkTableStats(tableContents, 'undefined')
|
||||
|
||||
cy.get('[data-cy=YearToggle]').click()
|
||||
|
||||
cy.get('[data-cy=Graph-ProgrammesBeforeOrAfter]').within(() => {
|
||||
cy.contains('Matematiikan ja tilastotieteen maisteriohjelma')
|
||||
cy.contains('Tietojenkäsittelytieteen maisteriohjelma')
|
||||
cy.contains('Datatieteen maisteriohjelma')
|
||||
cy.contains('2021 - 2022')
|
||||
cy.contains('28')
|
||||
cy.contains('16')
|
||||
})
|
||||
|
||||
emptyYears = new Array(getEmptyYears(true).length).fill(0)
|
||||
|
||||
tableContents = [
|
||||
['MH50_001', 'MAST', 'Matematiikan ja tilastotieteen maisteriohjelma', 0, 0, 4, 24, 28, 16, 4, ...emptyYears],
|
||||
['MH50_002', 'LSI', 'Life Science Informatics -maisteriohjelma', 0, 0, 1, 0, 3, 1, 0, ...emptyYears],
|
||||
[
|
||||
'MH50_003',
|
||||
'TCM',
|
||||
'Teoreettisten ja laskennallisten menetelmien maisteriohjelma',
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
1,
|
||||
2,
|
||||
0,
|
||||
...emptyYears,
|
||||
],
|
||||
['MH50_009', 'CSM', 'Tietojenkäsittelytieteen maisteriohjelma', 0, 0, 0, 0, 4, 3, 0, ...emptyYears],
|
||||
['MH50_010', 'DATA', 'Datatieteen maisteriohjelma', 0, 0, 1, 0, 12, 4, 0, ...emptyYears],
|
||||
['MH70_009', 'ECON', 'Taloustieteen maisteriohjelma', 0, 0, 0, 4, 6, 5, 0, ...emptyYears],
|
||||
]
|
||||
|
||||
cy.checkTableStats(tableContents, 'undefined')
|
||||
})
|
||||
})
|
||||
|
||||
describe('Faculty view', () => {
|
||||
beforeEach(() => {
|
||||
cy.init('/evaluationoverview/faculty/H50', 'admin')
|
||||
})
|
||||
|
||||
it('Page opens correctly', () => {
|
||||
cy.contains('Matemaattis-luonnontieteellinen tiedekunta')
|
||||
cy.contains('H50')
|
||||
cy.contains("This view is an abridged version of Oodikone's Faculty Overview")
|
||||
})
|
||||
|
||||
describe('Progress stats', () => {
|
||||
describe('Bachelor stats', () => {
|
||||
it('graph with graduated included is shown correctly', () => {
|
||||
cy.get('[data-cy="Graph-FacultyBachelorsProgress"]').within(() => {
|
||||
const totalStats = ['12.2%', '5.3%', '7.5%', '8.2%', '5.3%', '6.3%', '55.2%']
|
||||
for (const stat of totalStats) {
|
||||
cy.contains(stat)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
it('graph with graduated excluded is shown correctly', () => {
|
||||
cy.get('[data-cy="GraduatedToggle"]').click()
|
||||
cy.get('[data-cy="Graph-FacultyBachelorsProgress"]').within(() => {
|
||||
const totalStats = ['30.5%', '12.5%', '18.0%', '19.5%', '7.0%', '3.1%', '9.4%']
|
||||
for (const stat of totalStats) {
|
||||
cy.contains(stat)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
it('table with graduated included is shown correctly', () => {
|
||||
cy.get('[data-cy="Table-FacultyBachelorsProgress"]')
|
||||
const years = getEmptyYears(true)
|
||||
const tableContents = [
|
||||
...years.map(year => [year, 0, 0, 0, 0, 0, 0, 0, 0]),
|
||||
['2023 - 2024', 14, 13, 0, 0, 0, 0, 0, 1],
|
||||
['2022 - 2023', 32, 11, 10, 6, 4, 0, 1, 0],
|
||||
['2021 - 2022', 44, 10, 4, 9, 11, 7, 1, 2],
|
||||
['2020 - 2021', 38, 3, 1, 3, 7, 3, 8, 13],
|
||||
['2019 - 2020', 50, 2, 0, 2, 1, 4, 5, 36],
|
||||
['2018 - 2019', 75, 0, 1, 1, 2, 2, 3, 66],
|
||||
['2017 - 2018', 66, 0, 1, 3, 1, 1, 2, 58],
|
||||
['Total', 319, 39, 17, 24, 26, 17, 20, 176],
|
||||
]
|
||||
cy.checkTableStats(tableContents, 'FacultyBachelorsProgress')
|
||||
})
|
||||
|
||||
it('table with graduated excluded is shown correctly', () => {
|
||||
cy.get('[data-cy="GraduatedToggle"]').click()
|
||||
cy.get('[data-cy="Table-FacultyBachelorsProgress"]')
|
||||
const years = getEmptyYears(true)
|
||||
const tableContents = [
|
||||
...years.map(year => [year, 0, 0, 0, 0, 0, 0, 0, 0]),
|
||||
['2023 - 2024', 14, 13, 0, 0, 0, 0, 0, 1],
|
||||
['2022 - 2023', 30, 11, 9, 6, 4, 0, 0, 0],
|
||||
['2021 - 2022', 41, 10, 4, 9, 11, 6, 0, 1],
|
||||
['2020 - 2021', 14, 3, 1, 2, 6, 0, 1, 1],
|
||||
['2019 - 2020', 14, 2, 0, 2, 1, 3, 2, 4],
|
||||
['2018 - 2019', 6, 0, 1, 1, 2, 0, 0, 2],
|
||||
['2017 - 2018', 9, 0, 1, 3, 1, 0, 1, 3],
|
||||
['Total', 128, 39, 16, 23, 25, 9, 4, 12],
|
||||
]
|
||||
cy.checkTableStats(tableContents, 'FacultyBachelorsProgress')
|
||||
})
|
||||
})
|
||||
|
||||
describe('Bachelor + master stats', () => {
|
||||
it('graph with graduated included is shown correctly', () => {
|
||||
cy.get('[data-cy=Graph-FacultyBachelorMastersProgress]').within(() => {
|
||||
const totalStats = ['21.3%', '8.4%', '10.1%', '14.0%', '12.4%', '6.7%', '27.0%']
|
||||
for (const stat of totalStats) {
|
||||
cy.contains(stat)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
it('graph with graduated excluded is shown correctly', () => {
|
||||
cy.get('[data-cy="GraduatedToggle"]').click()
|
||||
cy.get('[data-cy=Graph-FacultyBachelorMastersProgress]').within(() => {
|
||||
const totalStats = ['28.7%', '11.6%', '14.0%', '18.6%', '15.5%', '3.1%', '8.5%']
|
||||
for (const stat of totalStats) {
|
||||
cy.contains(stat)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
it('table with graduated included is shown correctly', () => {
|
||||
cy.get('[data-cy="Table-FacultyBachelorMastersProgress"]')
|
||||
const years = getEmptyYears(true)
|
||||
const tableContents = [
|
||||
...years.map(year => [year, 0, 0, 0, 0, 0, 0, 0, 0]),
|
||||
['2023 - 2024', 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
['2022 - 2023', 2, 2, 0, 0, 0, 0, 0, 0],
|
||||
['2021 - 2022', 4, 2, 0, 0, 0, 1, 0, 1],
|
||||
['2020 - 2021', 23, 13, 2, 4, 0, 4, 0, 0],
|
||||
['2019 - 2020', 32, 7, 7, 4, 7, 3, 3, 1],
|
||||
['2018 - 2019', 63, 10, 2, 5, 13, 7, 4, 22],
|
||||
['2017 - 2018', 54, 4, 4, 5, 5, 7, 5, 24],
|
||||
['Total', 178, 38, 15, 18, 25, 22, 12, 48],
|
||||
]
|
||||
cy.checkTableStats(tableContents, 'FacultyBachelorMastersProgress')
|
||||
})
|
||||
|
||||
it('table with graduated excluded is shown correctly', () => {
|
||||
cy.get('[data-cy="GraduatedToggle"]').click()
|
||||
cy.get('[data-cy="Table-FacultyBachelorMastersProgress"]')
|
||||
const years = getEmptyYears(true)
|
||||
const tableContents = [
|
||||
...years.map(year => [year, 0, 0, 0, 0, 0, 0, 0, 0]),
|
||||
['2023 - 2024', 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
['2022 - 2023', 2, 2, 0, 0, 0, 0, 0, 0],
|
||||
['2021 - 2022', 4, 2, 0, 0, 0, 1, 0, 1],
|
||||
['2020 - 2021', 21, 13, 2, 4, 0, 2, 0, 0],
|
||||
['2019 - 2020', 31, 7, 7, 4, 7, 3, 2, 1],
|
||||
['2018 - 2019', 41, 9, 2, 5, 12, 7, 1, 5],
|
||||
['2017 - 2018', 30, 4, 4, 5, 5, 7, 1, 4],
|
||||
['Total', 129, 37, 15, 18, 24, 20, 4, 11],
|
||||
]
|
||||
cy.checkTableStats(tableContents, 'FacultyBachelorMastersProgress')
|
||||
})
|
||||
})
|
||||
|
||||
describe('Master stats', () => {
|
||||
it('graph with graduated included is shown correctly', () => {
|
||||
cy.get('[data-cy=Graph-FacultyMastersProgress]').within(() => {
|
||||
const totalStats = ['16.1%', '12.9%', '6.5%', '12.9%', '9.7%', '16.1%', '25.8%']
|
||||
for (const stat of totalStats) {
|
||||
cy.contains(stat)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
it('graph with graduated excluded is shown correctly', () => {
|
||||
cy.get('[data-cy="GraduatedToggle"]').click()
|
||||
cy.get('[data-cy=Graph-FacultyMastersProgress]').within(() => {
|
||||
const totalStats = ['23.8%', '19.0%', '9.5%', '9.5%', '9.5%', '14.3%', '14.3%']
|
||||
for (const stat of totalStats) {
|
||||
cy.contains(stat)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
it('table with graduated included is shown correctly', () => {
|
||||
cy.get('[data-cy="Table-FacultyMastersProgress"]')
|
||||
const years = getEmptyYears(true)
|
||||
const tableContents = [
|
||||
...years.map(year => [year, 0, 0, 0, 0, 0, 0, 0, 0]),
|
||||
['2023 - 2024', 4, 4, 0, 0, 0, 0, 0, 0],
|
||||
['2022 - 2023', 5, 0, 1, 1, 2, 0, 0, 1],
|
||||
['2021 - 2022', 8, 1, 2, 0, 2, 1, 1, 1],
|
||||
['2020 - 2021', 3, 0, 0, 0, 0, 0, 2, 1],
|
||||
['2019 - 2020', 7, 0, 0, 1, 0, 1, 1, 4],
|
||||
['2018 - 2019', 2, 0, 0, 0, 0, 1, 0, 1],
|
||||
['2017 - 2018', 2, 0, 1, 0, 0, 0, 1, 0],
|
||||
['Total', 31, 5, 4, 2, 4, 3, 5, 8],
|
||||
]
|
||||
cy.checkTableStats(tableContents, 'FacultyMastersProgress')
|
||||
})
|
||||
|
||||
it('table with graduated excluded is shown correctly', () => {
|
||||
cy.get('[data-cy="GraduatedToggle"]').click()
|
||||
cy.get('[data-cy="Table-FacultyMastersProgress"]')
|
||||
const years = getEmptyYears(true)
|
||||
const tableContents = [
|
||||
...years.map(year => [year, 0, 0, 0, 0, 0, 0, 0, 0]),
|
||||
['2023 - 2024', 4, 4, 0, 0, 0, 0, 0, 0],
|
||||
['2022 - 2023', 5, 0, 1, 1, 2, 0, 0, 1],
|
||||
['2021 - 2022', 5, 1, 2, 0, 0, 0, 1, 1],
|
||||
['2020 - 2021', 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
['2019 - 2020', 3, 0, 0, 1, 0, 1, 1, 0],
|
||||
['2018 - 2019', 2, 0, 0, 0, 0, 1, 0, 1],
|
||||
['2017 - 2018', 2, 0, 1, 0, 0, 0, 1, 0],
|
||||
['Total', 21, 5, 4, 2, 2, 2, 3, 3],
|
||||
]
|
||||
cy.checkTableStats(tableContents, 'FacultyMastersProgress')
|
||||
})
|
||||
})
|
||||
|
||||
describe('Doctor stats', () => {
|
||||
it('graph with graduated included is shown correctly', () => {
|
||||
cy.get('[data-cy=Graph-FacultyDoctoralProgress]').within(() => {
|
||||
const totalStats = ['6.0%', '18.0%', '16.0%', '14.0%', '46.0%']
|
||||
for (const stat of totalStats) {
|
||||
cy.contains(stat)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
it('graph with graduated excluded is shown correctly', () => {
|
||||
cy.get('[data-cy="GraduatedToggle"]').click()
|
||||
cy.get('[data-cy=Graph-FacultyDoctoralProgress]').within(() => {
|
||||
const totalStats = ['9.1%', '24.2%', '12.1%', '15.2%', '39.4%']
|
||||
for (const stat of totalStats) {
|
||||
cy.contains(stat)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
it('table with graduated included is shown correctly', () => {
|
||||
cy.get('[data-cy="Table-FacultyDoctoralProgress"]')
|
||||
const years = getEmptyYears(true)
|
||||
const tableContents = [
|
||||
...years.map(year => [year, 0, 0, 0, 0, 0, 0]),
|
||||
['2023 - 2024', 1, 1, 0, 0, 0, 0],
|
||||
['2022 - 2023', 9, 1, 7, 1, 0, 0],
|
||||
['2021 - 2022', 3, 1, 1, 0, 0, 1],
|
||||
['2020 - 2021', 5, 0, 0, 2, 1, 2],
|
||||
['2019 - 2020', 11, 0, 0, 1, 4, 6],
|
||||
['2018 - 2019', 14, 0, 1, 4, 2, 7],
|
||||
['2017 - 2018', 7, 0, 0, 0, 0, 7],
|
||||
['Total', 50, 3, 9, 8, 7, 23],
|
||||
]
|
||||
cy.checkTableStats(tableContents, 'FacultyDoctoralProgress')
|
||||
})
|
||||
|
||||
it('table with graduated excluded is shown correctly', () => {
|
||||
cy.get('[data-cy="GraduatedToggle"]').click()
|
||||
cy.get('[data-cy="Table-FacultyDoctoralProgress"]')
|
||||
const years = getEmptyYears(true)
|
||||
const tableContents = [
|
||||
...years.map(year => [year, 0, 0, 0, 0, 0, 0]),
|
||||
['2023 - 2024', 1, 1, 0, 0, 0, 0],
|
||||
['2022 - 2023', 9, 1, 7, 1, 0, 0],
|
||||
['2021 - 2022', 3, 1, 1, 0, 0, 1],
|
||||
['2020 - 2021', 4, 0, 0, 2, 0, 2],
|
||||
['2019 - 2020', 9, 0, 0, 1, 4, 4],
|
||||
['2018 - 2019', 5, 0, 0, 0, 1, 4],
|
||||
['2017 - 2018', 2, 0, 0, 0, 0, 2],
|
||||
['Total', 33, 3, 8, 4, 5, 13],
|
||||
]
|
||||
cy.checkTableStats(tableContents, 'FacultyDoctoralProgress')
|
||||
})
|
||||
})
|
||||
|
||||
it('Years in the tables can be clicked to show programme level breakdown', () => {
|
||||
cy.get('[data-cy="Table-FacultyBachelorsProgress"]').within(() => {
|
||||
cy.contains('2021 - 2022').click()
|
||||
cy.contains('31.3%').trigger('mouseover', { force: true })
|
||||
cy.contains('Matemaattisten tieteiden kandiohjelma')
|
||||
cy.contains('MAT - KH50_001')
|
||||
cy.contains('0 Credits: 0')
|
||||
cy.contains('1 ≤ Credits < 45: 10')
|
||||
cy.contains('45 ≤ Credits < 90: 9')
|
||||
cy.contains('90 ≤ Credits < 135: 11')
|
||||
cy.contains('135 ≤ Credits < 180: 2')
|
||||
cy.contains('180 ≤ Credits: 0')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('Graduation times stats', () => {
|
||||
it('All the correct sections are displayed', () => {
|
||||
const checkSections = breakdown => {
|
||||
const sections = ['bachelor', 'bcMsCombo', 'master', 'doctor']
|
||||
for (const section of sections) {
|
||||
cy.get(`[data-cy=Section-${section}]`).within(() => {
|
||||
cy.get('div.graduations-chart-container').within(() => {
|
||||
cy.get(`div.faculty-${breakdown ? 'breakdown-' : ''}graph`)
|
||||
cy.get('div.graduations-message').contains("Click a bar to view that year's programme level breakdown")
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
checkSections(true)
|
||||
cy.get('[data-cy=GraduationTimeToggle]').click()
|
||||
checkSections(false)
|
||||
})
|
||||
|
||||
it('Graduation times breakdown data is shown correctly', () => {
|
||||
cy.get('[data-cy=Section-bachelor]').within(() => {
|
||||
cy.contains('Graduation year')
|
||||
cy.contains('2022')
|
||||
|
||||
cy.get('[aria-label="2022, 29. On time."]').trigger('mouseover')
|
||||
cy.contains('On time: 29')
|
||||
|
||||
cy.get('[aria-label="2022, 29. On time."]').trigger('click')
|
||||
cy.contains('Year 2022 by graduation year')
|
||||
|
||||
cy.get('[aria-label="MAT, 22. On time."]').trigger('mouseover')
|
||||
cy.contains('Matemaattisten tieteiden kandiohjelma')
|
||||
cy.contains('KH50_001')
|
||||
cy.contains('On time: 22')
|
||||
|
||||
cy.get('[aria-label="MFKK, 7. On time."]').trigger('mouseover')
|
||||
cy.contains('Matematiikan, fysiikan ja kemian opettajan kandiohjelma')
|
||||
cy.contains('KH50_004')
|
||||
cy.contains('On time: 7')
|
||||
})
|
||||
})
|
||||
|
||||
it('Graduation times median time data is shown correctly', () => {
|
||||
cy.get('[data-cy=GraduationTimeToggle]').click()
|
||||
|
||||
cy.get('[data-cy=Section-bachelor]').within(() => {
|
||||
cy.contains('Graduation year')
|
||||
cy.contains('2021')
|
||||
|
||||
cy.contains('70 graduated').trigger('mouseover')
|
||||
cy.contains('70 students graduated in year 2021')
|
||||
cy.contains('median study time: 39.5 months')
|
||||
cy.contains('28 graduated on time')
|
||||
cy.contains('32 graduated max year overtime')
|
||||
cy.contains('10 graduated over year late')
|
||||
|
||||
cy.contains('70 graduated').trigger('click')
|
||||
cy.contains('Year 2021 by graduation year')
|
||||
|
||||
cy.get('[aria-label="MAT, 41."]').trigger('mouseover')
|
||||
cy.contains('Matemaattisten tieteiden kandiohjelma')
|
||||
cy.contains('KH50_001')
|
||||
cy.contains('47 students graduated in year 2021')
|
||||
cy.contains('median study time: 41 months')
|
||||
cy.contains('14 graduated on time')
|
||||
cy.contains('25 graduated max year overtime')
|
||||
cy.contains('8 graduated over year late')
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -23,9 +23,9 @@ The roles `openUniSearch` and `studyGuidanceGroups` simply enable certain views
|
||||
|
||||
- Can see statistics of every course and year
|
||||
|
||||
### katselemusViewer
|
||||
### katselmusViewer
|
||||
|
||||
- Enables the _Evaluation overview_ view
|
||||
- Enables the _Evaluation overview_ view (deprecated)
|
||||
|
||||
### teachers
|
||||
|
||||
|
||||
@@ -9,7 +9,6 @@ import {
|
||||
setStudyTrackStats,
|
||||
} from '../services/analyticsService'
|
||||
import { getCreditsProduced } from '../services/providerCredits'
|
||||
import { getProgrammeName } from '../services/studyProgramme'
|
||||
import { getBasicStatsForStudytrack } from '../services/studyProgramme/studyProgrammeBasics'
|
||||
import {
|
||||
getStudyProgrammeCoursesForStudyTrack,
|
||||
@@ -224,73 +223,4 @@ router.get('/:id/update_studytrackview', async (req: GetUpdateViewRequest, res:
|
||||
}
|
||||
})
|
||||
|
||||
interface GetEvaluationStatsRequest extends Request {
|
||||
query: {
|
||||
graduated: Graduated
|
||||
year_type: YearType
|
||||
special_groups: SpecialGroups
|
||||
}
|
||||
}
|
||||
|
||||
router.get('/:id/evaluationstats', async (req: GetEvaluationStatsRequest, res: Response) => {
|
||||
const code = req.params.id
|
||||
const { graduated, year_type: yearType, special_groups: specialGroups } = req.query
|
||||
if (!code) {
|
||||
return res.status(422).end()
|
||||
}
|
||||
// Statistics for Tilannekuvalomake view
|
||||
const combinedProgramme = ''
|
||||
let gradData = await getGraduationStats(code, combinedProgramme, yearType, specialGroups)
|
||||
if (!gradData) {
|
||||
const updatedStats = await getGraduationStatsForStudyTrack({
|
||||
studyProgramme: code,
|
||||
combinedProgramme,
|
||||
settings: {
|
||||
isAcademicYear: yearType === 'ACADEMIC_YEAR',
|
||||
includeAllSpecials: specialGroups === 'SPECIAL_INCLUDED',
|
||||
},
|
||||
})
|
||||
if (updatedStats) {
|
||||
await setGraduationStats(updatedStats, yearType, specialGroups)
|
||||
gradData = updatedStats
|
||||
}
|
||||
}
|
||||
|
||||
let progressData = await getStudyTrackStats(code, combinedProgramme, graduated, specialGroups)
|
||||
if (!progressData) {
|
||||
const studyRightsOfProgramme = await getStudyRightsInProgramme(code, false, true)
|
||||
const updated = await getStudyTrackStatsForStudyProgramme({
|
||||
studyProgramme: code,
|
||||
combinedProgramme,
|
||||
settings: {
|
||||
graduated: graduated === 'GRADUATED_INCLUDED',
|
||||
specialGroups: specialGroups === 'SPECIAL_INCLUDED',
|
||||
},
|
||||
studyRightsOfProgramme,
|
||||
})
|
||||
if (updated) {
|
||||
await setStudyTrackStats(updated, graduated, specialGroups)
|
||||
progressData = updated
|
||||
}
|
||||
}
|
||||
|
||||
const programmeName = await getProgrammeName(code)
|
||||
|
||||
delete gradData.tableStats
|
||||
delete gradData.graphStats
|
||||
delete gradData.titles
|
||||
const data = {
|
||||
id: code,
|
||||
programmeName,
|
||||
status: gradData?.status,
|
||||
lastUpdated: gradData.lastUpdated,
|
||||
graduations: gradData,
|
||||
creditCounts: progressData?.creditCounts,
|
||||
creditCountsCombo: progressData?.creditCountsCombo,
|
||||
years: progressData?.years,
|
||||
}
|
||||
|
||||
return res.json(data)
|
||||
})
|
||||
|
||||
export default router
|
||||
|
||||
@@ -155,11 +155,6 @@ studyProgrammeToolTips.studyTrackOverviewCombinedProgramme = studyProgrammeToolT
|
||||
'kentän **All** arvon (lukuun ottamatta *Current status* -kategorian **Graduated bachelor** -saraketta).'
|
||||
)
|
||||
|
||||
studyProgrammeToolTips.studyTrackProgressEvaluationOverview = studyProgrammeToolTips.studyTrackProgress.replace(
|
||||
'Jos sivun yläosassa on valittuna ”All study rights” (oletus), mukana ovat myös ohjelmaan siirtyneet ja ohjelmasta pois siirtyneet opiskelijat.',
|
||||
''
|
||||
)
|
||||
|
||||
studyProgrammeToolTips.averageGraduationTimesStudyTracksMaster =
|
||||
studyProgrammeToolTips.averageGraduationTimesStudyTracks.replace(
|
||||
'on valmistunut.',
|
||||
|
||||
@@ -1,58 +0,0 @@
|
||||
import { GraduationTimes } from '@/components/FacultyStatistics/TimesAndPaths/GraduationTimes'
|
||||
|
||||
export const FacultyGraduations = ({ faculty, graduationStats, groupByStartYear, showMedian, universityMode }) => {
|
||||
const groupBy = groupByStartYear ? 'byStartYear' : 'byGradYear'
|
||||
const yearLabel = groupByStartYear ? 'Start year' : 'Graduation year'
|
||||
const data = graduationStats?.data?.[groupBy].medians
|
||||
const goals = graduationStats?.data?.goals
|
||||
const goalExceptions = { ...goals?.exceptions, needed: faculty === 'H30' }
|
||||
const programmeData = graduationStats?.data?.[groupBy].programmes.medians
|
||||
const programmeNames = graduationStats?.data?.programmeNames
|
||||
const classSizes = graduationStats?.data?.classSizes
|
||||
const commonProps = {
|
||||
yearLabel,
|
||||
programmeNames,
|
||||
showMedian,
|
||||
classSizes,
|
||||
goalExceptions,
|
||||
groupBy,
|
||||
mode: universityMode ? 'faculty' : 'programme',
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<GraduationTimes
|
||||
data={data?.bachelor}
|
||||
goal={goals?.bachelor}
|
||||
level="bachelor"
|
||||
levelProgrammeData={programmeData?.bachelor}
|
||||
title="Bachelor"
|
||||
{...commonProps}
|
||||
/>
|
||||
<GraduationTimes
|
||||
data={data?.bcMsCombo}
|
||||
goal={goals?.bcMsCombo}
|
||||
level="bcMsCombo"
|
||||
levelProgrammeData={programmeData?.bcMsCombo}
|
||||
title="Bachelor + Master"
|
||||
{...commonProps}
|
||||
/>
|
||||
<GraduationTimes
|
||||
data={data?.master}
|
||||
goal={goals?.master}
|
||||
level="master"
|
||||
levelProgrammeData={programmeData?.master}
|
||||
title="Master"
|
||||
{...commonProps}
|
||||
/>
|
||||
<GraduationTimes
|
||||
data={data?.doctor}
|
||||
goal={goals?.doctor}
|
||||
level="doctor"
|
||||
levelProgrammeData={programmeData?.doctor}
|
||||
title="Doctor"
|
||||
{...commonProps}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -1,138 +0,0 @@
|
||||
import { Message } from 'semantic-ui-react'
|
||||
|
||||
import { calculateStats, sortProgrammeKeys } from '@/components/FacultyStatistics/facultyHelpers'
|
||||
import { FacultyBarChart } from '@/components/FacultyStatistics/FacultyProgrammeOverview/FacultyBarChart'
|
||||
import { FacultyProgressTable } from '@/components/FacultyStatistics/FacultyProgrammeOverview/FacultyProgressTable'
|
||||
|
||||
export const FacultyProgress = ({ faculty, progressStats, getDivider }) => {
|
||||
const bachelorStats = calculateStats(progressStats?.data?.creditCounts?.bachelor, 180)
|
||||
const bachelorMasterStats = calculateStats(
|
||||
progressStats?.data?.creditCounts?.bachelorMaster,
|
||||
faculty === 'H90' ? 360 : 300,
|
||||
180,
|
||||
7
|
||||
)
|
||||
const masterStats = calculateStats(progressStats?.data?.creditCounts?.master, 120)
|
||||
const doctorStats = calculateStats(progressStats?.data?.creditCounts?.doctor, 40, 0, 5)
|
||||
|
||||
return (
|
||||
<>
|
||||
{bachelorStats != null && (
|
||||
<>
|
||||
{getDivider('Bachelor', 'BachelorStudentsOfTheFacultyByStartingYear', 'no-infobox')}
|
||||
<FacultyBarChart
|
||||
cypress="FacultyBachelorsProgress"
|
||||
data={{
|
||||
id: faculty,
|
||||
stats: bachelorStats.chartStats,
|
||||
years: progressStats?.data.years,
|
||||
}}
|
||||
/>
|
||||
<FacultyProgressTable
|
||||
cypress="Table-FacultyBachelorsProgress"
|
||||
data={bachelorStats.tableStats}
|
||||
programmeNames={progressStats?.data.programmeNames}
|
||||
programmeStats={progressStats?.data.bachelorsProgStats}
|
||||
progressTitles={progressStats?.data.yearlyBachelorTitles}
|
||||
sortedKeys={sortProgrammeKeys(
|
||||
Object.keys(progressStats?.data.bachelorsProgStats).map(obj => [
|
||||
obj,
|
||||
progressStats?.data?.programmeNames[obj].code,
|
||||
]),
|
||||
faculty
|
||||
).map(listObj => listObj[0])}
|
||||
titles={bachelorStats.tableTitles}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
{bachelorMasterStats != null && (
|
||||
<>
|
||||
{getDivider('Bachelor + Master', 'ProgressOfBachelorMaster', 'no-infobox')}
|
||||
<Message data-cy="FacultyProgrammesShownInfo">
|
||||
The starting year is the studyright start in the bachelor programme. The credits are computed by the start
|
||||
date of the bachelor programme and at the moment, they do not include any transferred credits. Thus, in
|
||||
these statistics some students have fewer credits than in reality.
|
||||
</Message>
|
||||
<FacultyBarChart
|
||||
cypress="FacultyBachelorMastersProgress"
|
||||
data={{
|
||||
id: faculty,
|
||||
stats: bachelorMasterStats.chartStats,
|
||||
years: progressStats?.data.years,
|
||||
}}
|
||||
/>
|
||||
<FacultyProgressTable
|
||||
cypress="Table-FacultyBachelorMastersProgress"
|
||||
data={bachelorMasterStats.tableStats}
|
||||
programmeNames={progressStats?.data.programmeNames}
|
||||
programmeStats={progressStats?.data.bcMsProgStats}
|
||||
progressTitles={progressStats?.data.yearlyBcMsTitles}
|
||||
sortedKeys={sortProgrammeKeys(
|
||||
Object.keys(progressStats?.data.bcMsProgStats).map(obj => [
|
||||
obj,
|
||||
progressStats?.data?.programmeNames[obj].code,
|
||||
]),
|
||||
faculty
|
||||
).map(listObj => listObj[0])}
|
||||
titles={bachelorMasterStats.tableTitles}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
{masterStats != null && faculty !== 'H90' && (
|
||||
<>
|
||||
{getDivider('Master', 'MasterStudentsOfTheFacultyByStartingYear', 'no-infobox')}
|
||||
<FacultyBarChart
|
||||
cypress="FacultyMastersProgress"
|
||||
data={{
|
||||
id: faculty,
|
||||
stats: masterStats.chartStats,
|
||||
years: progressStats?.data.years,
|
||||
}}
|
||||
/>
|
||||
<FacultyProgressTable
|
||||
cypress="Table-FacultyMastersProgress"
|
||||
data={masterStats.tableStats}
|
||||
programmeNames={progressStats?.data.programmeNames}
|
||||
programmeStats={progressStats?.data.mastersProgStats}
|
||||
progressTitles={progressStats?.data.yearlyMasterTitles}
|
||||
sortedKeys={sortProgrammeKeys(
|
||||
Object.keys(progressStats?.data.mastersProgStats).map(obj => [
|
||||
obj,
|
||||
progressStats?.data?.programmeNames[obj].code,
|
||||
]),
|
||||
faculty
|
||||
).map(listObj => listObj[0])}
|
||||
titles={masterStats.tableTitles}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
{doctorStats != null && (
|
||||
<>
|
||||
{getDivider('Doctor', 'DoctoralStudentsOfTheFacultyByStartingYear', 'no-infobox')}
|
||||
<FacultyBarChart
|
||||
cypress="FacultyDoctoralProgress"
|
||||
data={{
|
||||
id: faculty,
|
||||
stats: doctorStats.chartStats,
|
||||
years: progressStats?.data.years,
|
||||
}}
|
||||
/>
|
||||
<FacultyProgressTable
|
||||
cypress="Table-FacultyDoctoralProgress"
|
||||
data={doctorStats.tableStats}
|
||||
programmeNames={progressStats?.data.programmeNames}
|
||||
programmeStats={progressStats?.data.doctoralProgStats}
|
||||
sortedKeys={sortProgrammeKeys(
|
||||
Object.keys(progressStats?.data.doctoralProgStats).map(obj => [
|
||||
obj,
|
||||
progressStats?.data?.programmeNames[obj].code,
|
||||
]),
|
||||
faculty
|
||||
).map(listObj => listObj[0])}
|
||||
titles={doctorStats.tableTitles}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
}
|
||||
@@ -1,155 +0,0 @@
|
||||
import { useState } from 'react'
|
||||
import { Divider, Header, Loader, Message } from 'semantic-ui-react'
|
||||
|
||||
import { facultyToolTips } from '@/common/InfoToolTips'
|
||||
import { InfoBox } from '@/components/InfoBox'
|
||||
import { useLanguage } from '@/components/LanguagePicker/useLanguage'
|
||||
import { Toggle } from '@/components/StudyProgramme/Toggle'
|
||||
import {
|
||||
useGetFacultiesQuery,
|
||||
useGetFacultyGraduationTimesQuery,
|
||||
useGetFacultyProgressStatsQuery,
|
||||
} from '@/redux/facultyStats'
|
||||
import { FacultyGraduations } from './FacultyGraduations'
|
||||
import { FacultyProgress } from './FacultyProgress'
|
||||
import '@/components/FacultyStatistics/faculty.css'
|
||||
|
||||
export const FacultyView = ({ faculty }) => {
|
||||
const [graduatedGroup, setGraduatedGroup] = useState(false)
|
||||
const [showMedian, setShowMedian] = useState(false)
|
||||
const studyProgrammeFilter = 'NEW_STUDY_PROGRAMMES'
|
||||
const specials = 'SPECIAL_EXCLUDED'
|
||||
const graduated = graduatedGroup ? 'GRADUATED_EXCLUDED' : 'GRADUATED_INCLUDED'
|
||||
const { getTextIn } = useLanguage()
|
||||
|
||||
const allFaculties = useGetFacultiesQuery()
|
||||
const faculties = allFaculties?.data
|
||||
const facultyDetails = faculties && faculty && faculties.find(f => f.code === faculty)
|
||||
const facultyName = facultyDetails && getTextIn(facultyDetails.name)
|
||||
const progressStats = useGetFacultyProgressStatsQuery(
|
||||
{
|
||||
id: facultyDetails?.id,
|
||||
studyProgrammeFilter,
|
||||
specialGroups: specials,
|
||||
graduated,
|
||||
},
|
||||
{ skip: !facultyDetails }
|
||||
)
|
||||
|
||||
const graduationStats = useGetFacultyGraduationTimesQuery(
|
||||
{ id: facultyDetails?.id, studyProgrammeFilter },
|
||||
{ skip: !facultyDetails }
|
||||
)
|
||||
|
||||
const getDivider = (title, toolTipText, content, cypress = undefined) => (
|
||||
<>
|
||||
<div className="divider">
|
||||
<Divider data-cy={`Section-${toolTipText}`} horizontal>
|
||||
{title}
|
||||
</Divider>
|
||||
</div>
|
||||
{content === 'no-infobox' ? null : <InfoBox content={content} cypress={cypress} />}
|
||||
</>
|
||||
)
|
||||
|
||||
if (allFaculties.isLoading || allFaculties.isFetching) {
|
||||
return <Loader active style={{ marginTop: '10em' }} />
|
||||
}
|
||||
|
||||
if (!facultyDetails) {
|
||||
return (
|
||||
<h3>
|
||||
{getTextIn({
|
||||
en: `Faculty “${faculty}” was not found. Please check the address.`,
|
||||
fi: `Tiedekuntaa ”${faculty}” ei löytynyt. Ole hyvä ja tarkista osoite.`,
|
||||
})}
|
||||
</h3>
|
||||
)
|
||||
}
|
||||
|
||||
const isFetchingOrLoading =
|
||||
progressStats.isLoading || progressStats.isFetching || graduationStats.isLoading || graduationStats.isFetching
|
||||
|
||||
const isError =
|
||||
(progressStats.isError && graduationStats.isError) ||
|
||||
(progressStats.isSuccess && !progressStats.data && graduationStats.isSuccess && !graduationStats.data)
|
||||
|
||||
if (isError) return <h3>Something went wrong, please try refreshing the page.</h3>
|
||||
|
||||
return (
|
||||
<>
|
||||
<div style={{ padding: '30px', textAlign: 'center' }}>
|
||||
<Header>{facultyName}</Header>
|
||||
<span>{faculty}</span>
|
||||
</div>
|
||||
<Message info>
|
||||
<Message.Header>This view is an abridged version of Oodikone's Faculty Overview</Message.Header>
|
||||
<p>
|
||||
In these statistics, all special study rights have been excluded, eg. exchange students and non-degree
|
||||
students.
|
||||
</p>
|
||||
<p>
|
||||
<b>You can find more statistics on this and all other faculties of the university in main Faculty view. </b>
|
||||
The full view includes details such as: how many have graduated or started in each faculty and in its
|
||||
programmes; credits produced by the faculty; populations backgrounds and enrollment statuses. This view
|
||||
provides statistics both on the whole faculty level and a breakdown of how they are spread among the faculty's
|
||||
programmes.
|
||||
</p>
|
||||
<p>Access the full Faculty view by clicking 'Faculty' in the top navigation bar.</p>
|
||||
</Message>
|
||||
<div className="faculty-overview">
|
||||
{isFetchingOrLoading ? (
|
||||
<Loader active style={{ marginTop: '15em' }} />
|
||||
) : (
|
||||
<div className="programmes-overview">
|
||||
{progressStats.isSuccess && progressStats.data && (
|
||||
<>
|
||||
{getDivider(
|
||||
'Progress of students of the faculty ',
|
||||
'bachelorStudentsOfTheFacultyByStartingYear',
|
||||
facultyToolTips.studentProgress,
|
||||
'InfoFacultyProgress'
|
||||
)}
|
||||
<div className="toggle-container">
|
||||
<Toggle
|
||||
cypress="GraduatedToggle"
|
||||
firstLabel="Graduated included"
|
||||
secondLabel="Graduated excluded"
|
||||
setValue={setGraduatedGroup}
|
||||
toolTips={facultyToolTips.graduatedToggle}
|
||||
value={graduatedGroup}
|
||||
/>
|
||||
</div>
|
||||
<FacultyProgress faculty={faculty} getDivider={getDivider} progressStats={progressStats} />
|
||||
</>
|
||||
)}
|
||||
{graduationStats.isSuccess && graduationStats.data && (
|
||||
<>
|
||||
{getDivider(
|
||||
'Average graduation times',
|
||||
'averageGraduationTimes',
|
||||
facultyToolTips.averageGraduationTimes
|
||||
)}
|
||||
<div className="toggle-container">
|
||||
<Toggle
|
||||
cypress="GraduationTimeToggle"
|
||||
firstLabel="Breakdown"
|
||||
secondLabel="Median times"
|
||||
setValue={setShowMedian}
|
||||
value={showMedian}
|
||||
/>
|
||||
</div>
|
||||
<FacultyGraduations
|
||||
faculty={faculty}
|
||||
graduationStats={graduationStats}
|
||||
groupByStartYear={false}
|
||||
showMedian={showMedian}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
@@ -1,216 +0,0 @@
|
||||
import { useState } from 'react'
|
||||
import { Divider, Header, Loader, Message, Segment } from 'semantic-ui-react'
|
||||
|
||||
import { getTargetCreditsForProgramme } from '@/common'
|
||||
import { studyProgrammeToolTips } from '@/common/InfoToolTips'
|
||||
import { calculateStats } from '@/components/FacultyStatistics/facultyHelpers'
|
||||
import { InfoBox } from '@/components/InfoBox'
|
||||
import { useLanguage } from '@/components/LanguagePicker/useLanguage'
|
||||
import { DataTable } from '@/components/StudyProgramme/BasicOverview/DataTable'
|
||||
import { StackedBarChart } from '@/components/StudyProgramme/BasicOverview/StackedBarChart'
|
||||
import { BreakdownBarChart } from '@/components/StudyProgramme/BreakdownBarChart'
|
||||
import { MedianTimeBarChart } from '@/components/StudyProgramme/MedianTimeBarChart'
|
||||
import { ProgressOfStudents } from '@/components/StudyProgramme/StudyTrackOverview/ProgressOfStudents'
|
||||
import { Toggle } from '@/components/StudyProgramme/Toggle'
|
||||
import '@/components/StudyProgramme/studyprogramme.css'
|
||||
import { useGetEvaluationStatsQuery } from '@/redux/studyProgramme'
|
||||
|
||||
export const ProgrammeView = ({ studyprogramme }) => {
|
||||
const { getTextIn } = useLanguage()
|
||||
const [showMedian, setShowMedian] = useState(false)
|
||||
const [academicYear, setAcademicYear] = useState(false)
|
||||
const [graduated, setGraduated] = useState(false)
|
||||
|
||||
const yearType = academicYear ? 'ACADEMIC_YEAR' : 'CALENDAR_YEAR'
|
||||
const grad = graduated ? 'GRADUATED_EXCLUDED' : 'GRADUATED_INCLUDED'
|
||||
|
||||
const statistics = useGetEvaluationStatsQuery({
|
||||
id: studyprogramme,
|
||||
yearType,
|
||||
specialGroups: 'SPECIAL_EXCLUDED',
|
||||
graduated: grad,
|
||||
})
|
||||
|
||||
const progressStats = calculateStats(statistics?.data?.creditCounts, getTargetCreditsForProgramme(studyprogramme))
|
||||
if (progressStats?.chartStats) {
|
||||
progressStats.chartStats.forEach(creditCategory => {
|
||||
const [total, ...years] = creditCategory.data
|
||||
creditCategory.data = [total, ...years.reverse()]
|
||||
})
|
||||
}
|
||||
|
||||
const progressComboStats =
|
||||
Object.keys(statistics?.data?.creditCountsCombo || {}).length > 0
|
||||
? calculateStats(statistics.data.creditCountsCombo, getTargetCreditsForProgramme(studyprogramme) + 180)
|
||||
: null
|
||||
|
||||
if (progressComboStats?.chartStats) {
|
||||
progressComboStats.chartStats.forEach(creditCategory => {
|
||||
const [total, ...years] = creditCategory.data
|
||||
creditCategory.data = [total, ...years.reverse()]
|
||||
})
|
||||
}
|
||||
|
||||
const programmeName = statistics?.data?.programmeName && getTextIn(statistics?.data?.programmeName)
|
||||
|
||||
const graduationData = statistics?.data?.graduations
|
||||
|
||||
const doCombo = graduationData?.doCombo
|
||||
const timesData = graduationData?.graduationTimes
|
||||
|
||||
const getDivider = (title, toolTipText) => (
|
||||
<>
|
||||
<div className="divider">
|
||||
<Divider data-cy={`Section-${toolTipText}`} horizontal>
|
||||
{title}
|
||||
</Divider>
|
||||
</div>
|
||||
<InfoBox content={studyProgrammeToolTips[toolTipText]} />
|
||||
</>
|
||||
)
|
||||
|
||||
const displayMedian = () => (
|
||||
<>
|
||||
{doCombo && (
|
||||
<MedianTimeBarChart
|
||||
byStartYear={false}
|
||||
data={graduationData?.comboTimes?.medians}
|
||||
goal={graduationData?.comboTimes?.goal}
|
||||
title="Bachelor + Master study right"
|
||||
/>
|
||||
)}
|
||||
<MedianTimeBarChart
|
||||
byStartYear={false}
|
||||
data={graduationData?.graduationTimes?.medians}
|
||||
goal={graduationData?.graduationTimes?.goal}
|
||||
title={doCombo ? 'Master study right' : ' '}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
|
||||
const displayBreakdown = () => (
|
||||
<>
|
||||
{doCombo && (
|
||||
<BreakdownBarChart data={graduationData?.comboTimes?.medians} title="Bachelor + Master study right" />
|
||||
)}
|
||||
<BreakdownBarChart data={timesData?.medians} title={doCombo ? 'Master study right' : ' '} />
|
||||
</>
|
||||
)
|
||||
|
||||
const isFetchingOrLoading = statistics.isLoading || statistics.isFetching
|
||||
|
||||
const isError = statistics.isError || (statistics.isSuccess && !statistics.data)
|
||||
|
||||
if (isError) return <h3>Something went wrong, please try refreshing the page.</h3>
|
||||
|
||||
return (
|
||||
<>
|
||||
<div align="center" style={{ padding: '30px' }}>
|
||||
<Header textAlign="center">{programmeName}</Header>
|
||||
<span>{studyprogramme}</span>
|
||||
</div>
|
||||
<div className="studyprogramme-overview">
|
||||
{isFetchingOrLoading ? (
|
||||
<Loader active style={{ marginTop: '10em' }} />
|
||||
) : (
|
||||
<Segment className="contentSegment">
|
||||
<Message info>
|
||||
<Message.Header>This view is an abridged version of Oodikone's Studyprogramme Overview</Message.Header>
|
||||
<p style={{ marginTop: '12px' }}>
|
||||
In these statistics, the following students are excluded: Students whose studyrights{' '}
|
||||
<b>have been transferred away from or into the program</b> as well as exchange students and non-degree
|
||||
students.
|
||||
</p>
|
||||
<p>
|
||||
<b>
|
||||
You can find more statistics on this and other studyprogrammes of the university in main
|
||||
Studyprogramme Overview.{' '}
|
||||
</b>
|
||||
The full view includes details such as: how many have graduated or started in each programme and in its
|
||||
studytracks; credits produced by the programme; population backgrounds and enrollment statuses.
|
||||
</p>
|
||||
<p>
|
||||
Access the full Studyprogramme Overview by clicking 'Programmes' in the top navigation bar and then
|
||||
'Overview'. Alternatively, you can select 'Class statistics' to explore studyprogrammes by starting
|
||||
class with interactive statistics and visualizations.
|
||||
</p>
|
||||
<p>
|
||||
Note that both views have access restrictions. If you can't access either view and feel you should have
|
||||
access, please contact <a href="mailto:oodikone@helsinki.fi">oodikone@helsinki.fi</a>.
|
||||
</p>
|
||||
</Message>
|
||||
<div>
|
||||
{getDivider(
|
||||
'Progress of students of the study programme by starting year',
|
||||
'studyTrackProgressEvaluationOverview'
|
||||
)}
|
||||
<Toggle
|
||||
cypress="GraduatedToggle"
|
||||
firstLabel="Graduated included"
|
||||
secondLabel="Graduated excluded"
|
||||
setValue={setGraduated}
|
||||
toolTips={studyProgrammeToolTips.graduatedToggle}
|
||||
value={graduated}
|
||||
/>
|
||||
<ProgressOfStudents
|
||||
progressComboStats={progressComboStats}
|
||||
progressStats={progressStats}
|
||||
track={studyprogramme}
|
||||
years={statistics.data.years}
|
||||
/>
|
||||
{getDivider('Graduation times', 'averageGraduationTimes')}
|
||||
<div className="toggle-container">
|
||||
<Toggle
|
||||
cypress="GraduationTimeToggle"
|
||||
firstLabel="Breakdown"
|
||||
secondLabel="Median time"
|
||||
setValue={setShowMedian}
|
||||
value={showMedian}
|
||||
/>
|
||||
<Toggle
|
||||
cypress="YearToggle"
|
||||
firstLabel="Calendar year"
|
||||
secondLabel="Academic year"
|
||||
setValue={setAcademicYear}
|
||||
toolTips={studyProgrammeToolTips.yearToggle}
|
||||
value={academicYear}
|
||||
/>
|
||||
</div>
|
||||
<div className={`section-container${doCombo ? '' : '-centered'}`}>
|
||||
{showMedian ? displayMedian() : displayBreakdown()}
|
||||
</div>
|
||||
{graduationData?.programmesBeforeOrAfterGraphStats?.length !== 0 && (
|
||||
<>
|
||||
{getDivider(
|
||||
studyprogramme.includes('KH')
|
||||
? 'Primary master programme studies after this programme'
|
||||
: 'Primary bachelor programme studies before this programme',
|
||||
'programmesBeforeOrAfter'
|
||||
)}
|
||||
<div className="section-container">
|
||||
<StackedBarChart
|
||||
cypress="ProgrammesBeforeOrAfter"
|
||||
data={graduationData?.programmesBeforeOrAfterGraphStats.map(programme => ({
|
||||
...programme,
|
||||
name: getTextIn(programme.name),
|
||||
}))}
|
||||
labels={graduationData?.years}
|
||||
wideTable
|
||||
/>
|
||||
<DataTable
|
||||
data={graduationData?.programmesBeforeOrAfterTableStats.map(programme =>
|
||||
programme.with(2, getTextIn(programme[2]))
|
||||
)}
|
||||
titles={graduationData?.programmesBeforeOrAfterTitles}
|
||||
wideTable
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</Segment>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
@@ -1,153 +0,0 @@
|
||||
import { orderBy } from 'lodash'
|
||||
import { useState } from 'react'
|
||||
import { Link } from 'react-router-dom'
|
||||
import { Divider, Header, Loader, Message } from 'semantic-ui-react'
|
||||
|
||||
import { useTitle } from '@/common/hooks'
|
||||
import { facultyToolTips } from '@/common/InfoToolTips'
|
||||
import '@/components/FacultyStatistics/faculty.css'
|
||||
import { InfoBox } from '@/components/InfoBox'
|
||||
import { useLanguage } from '@/components/LanguagePicker/useLanguage'
|
||||
import { Toggle } from '@/components/StudyProgramme/Toggle'
|
||||
import { useGetAuthorizedUserQuery } from '@/redux/auth'
|
||||
import { useGetAllFacultiesGraduationStatsQuery, useGetAllFacultiesProgressStatsQuery } from '@/redux/facultyStats'
|
||||
import { FacultyGraduations } from './FacultyGraduations'
|
||||
import { FacultyProgress } from './FacultyProgress'
|
||||
|
||||
export const UniversityView = ({ isEvaluationOverview }) => {
|
||||
useTitle('University')
|
||||
const [graduatedGroup, setGraduatedGroup] = useState(false)
|
||||
const [medianMode, setMedianMode] = useState(false)
|
||||
const [excludeSpecials, setIncludeSpecials] = useState(isEvaluationOverview)
|
||||
const { fullAccessToStudentData, roles } = useGetAuthorizedUserQuery()
|
||||
const userHasFacultyRights =
|
||||
fullAccessToStudentData || roles.includes('facultyStatistics') || roles.includes('katselmusViewer')
|
||||
const graduated = graduatedGroup ? 'GRADUATED_EXCLUDED' : 'GRADUATED_INCLUDED'
|
||||
const progressStats = useGetAllFacultiesProgressStatsQuery({
|
||||
graduated,
|
||||
includeSpecials: !excludeSpecials,
|
||||
})
|
||||
const { getTextIn } = useLanguage()
|
||||
const graduationStats = useGetAllFacultiesGraduationStatsQuery()
|
||||
const getDivider = (title, toolTipText, content, cypress = undefined) => (
|
||||
<>
|
||||
<div className="divider">
|
||||
<Divider data-cy={`Section-${toolTipText}`} horizontal>
|
||||
{title}
|
||||
</Divider>
|
||||
</div>
|
||||
{content === 'no-infobox' ? null : <InfoBox content={content} cypress={cypress} />}
|
||||
</>
|
||||
)
|
||||
|
||||
if (graduationStats.isLoading || graduationStats.isFetching || progressStats.isFetching || progressStats.isLoading) {
|
||||
return <Loader active style={{ marginTop: '10em' }} />
|
||||
}
|
||||
|
||||
const getMessage = () => {
|
||||
if (!isEvaluationOverview) {
|
||||
return (
|
||||
<Message info>
|
||||
<p>Programme MH90_001 (Veterinary medicine bachelor + licentiate) is currently excluded.</p>
|
||||
</Message>
|
||||
)
|
||||
}
|
||||
return (
|
||||
<Message info>
|
||||
<Message.Header>This view is a combined version of Oodikone's Faculty Evaluation Overview</Message.Header>
|
||||
<p>
|
||||
In these statistics, <b>all special study rights have been excluded</b>, eg. exchange students and non-degree
|
||||
students.
|
||||
</p>
|
||||
<p>Access the full Faculty view of individual faculties by clicking 'Faculty' in the top navigation bar.</p>
|
||||
<p>
|
||||
<b>Veterinary medicine bachelor + licentiate (MH90_001) is disabled</b> and not visible in the progress stats.
|
||||
It is visible in graduation times, but notice that it is found in "Bachelor + Master" category although it has
|
||||
a target time of 6 years, whereas the other degrees in that category have a target of 5 years.
|
||||
</p>
|
||||
</Message>
|
||||
)
|
||||
}
|
||||
|
||||
const isError =
|
||||
progressStats.isError ||
|
||||
(progressStats.isSuccess && !progressStats.data) ||
|
||||
graduationStats.isError ||
|
||||
!graduationStats.data
|
||||
if (isError) return <h3>Something went wrong, please try refreshing the page.</h3>
|
||||
const allFaculties = Object.values(progressStats.data.programmeNames)
|
||||
|
||||
return (
|
||||
<>
|
||||
<div style={{ padding: '30px', textAlign: 'center' }}>
|
||||
<Header>University-level view</Header>
|
||||
</div>
|
||||
{getMessage()}
|
||||
<div>
|
||||
{userHasFacultyRights && isEvaluationOverview && (
|
||||
<div>
|
||||
<p>
|
||||
<b>Click here to open the corresponding view for an individual faculty</b>
|
||||
</p>
|
||||
<div className="facultyLinkBox">
|
||||
{orderBy(allFaculties, 'code').map(faculty => (
|
||||
<span key={faculty.code}>
|
||||
<Link to={`/evaluationoverview/faculty/${faculty.code}`}>{`${
|
||||
faculty.code
|
||||
} ${getTextIn(faculty)}`}</Link>
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="faculty-overview">
|
||||
<div className="programmes-overview">
|
||||
{getDivider(
|
||||
'Progress of students of the university',
|
||||
'BachelorStudentsOfTheFacultyByStartingYear',
|
||||
facultyToolTips.studentProgress,
|
||||
'InfoFacultyProgress'
|
||||
)}
|
||||
<div className="toggle-container">
|
||||
<Toggle
|
||||
cypress="GraduatedToggle"
|
||||
firstLabel="Graduated included"
|
||||
secondLabel="Graduated excluded"
|
||||
setValue={setGraduatedGroup}
|
||||
toolTips={facultyToolTips.graduatedToggle}
|
||||
value={graduatedGroup}
|
||||
/>
|
||||
{!isEvaluationOverview && (
|
||||
<Toggle
|
||||
cypress="StudentToggle"
|
||||
firstLabel="All study rights"
|
||||
secondLabel="Special study rights excluded"
|
||||
setValue={() => setIncludeSpecials(!excludeSpecials)}
|
||||
toolTips={facultyToolTips.studentToggle}
|
||||
value={excludeSpecials}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<FacultyProgress faculty="ALL" getDivider={getDivider} progressStats={progressStats} />
|
||||
</div>
|
||||
{getDivider('Average graduation times', 'AverageGraduationTimes', facultyToolTips.averageGraduationTimes)}
|
||||
<div className="toggle-container">
|
||||
<Toggle
|
||||
cypress="GraduationTimeToggle"
|
||||
firstLabel="Breakdown"
|
||||
secondLabel="Median times"
|
||||
setValue={() => setMedianMode(!medianMode)}
|
||||
value={medianMode}
|
||||
/>
|
||||
</div>
|
||||
<FacultyGraduations
|
||||
graduationStats={graduationStats}
|
||||
groupByStartYear={false}
|
||||
showMedian={medianMode}
|
||||
universityMode
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
import { Redirect, useParams } from 'react-router-dom'
|
||||
import { Segment } from 'semantic-ui-react'
|
||||
|
||||
import { useTitle } from '@/common/hooks'
|
||||
import { FacultyView } from './FacultyView'
|
||||
import { ProgrammeView } from './ProgrammeView'
|
||||
import { UniversityView } from './UniversityView'
|
||||
|
||||
export const EvaluationOverview = () => {
|
||||
const { id, level } = useParams()
|
||||
useTitle('Evaluation overview')
|
||||
|
||||
if (!['programme', 'faculty', 'university'].includes(level) || (level !== 'university' && !id)) {
|
||||
return <Redirect to="/" />
|
||||
}
|
||||
|
||||
const levelToComponent = {
|
||||
programme: <ProgrammeView studyprogramme={id} />,
|
||||
faculty: <FacultyView faculty={id} />,
|
||||
university: <UniversityView isEvaluationOverview />,
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="segmentContainer">
|
||||
<Segment className="contentSegment">{levelToComponent[level]}</Segment>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -36,9 +36,6 @@ export const ProtectedRoute = ({
|
||||
if (path.includes('languagecenterview')) {
|
||||
return iamGroups.includes('grp-kielikeskus-esihenkilot')
|
||||
}
|
||||
if (path.includes('evaluationoverview')) {
|
||||
return location.pathname.includes('university') ? true : hasRequiredRoles
|
||||
}
|
||||
if (path.includes('teachers')) {
|
||||
return hasRequiredRoles || hasFullAccessToTeacherData(roles, iamGroups)
|
||||
}
|
||||
|
||||
@@ -8,7 +8,6 @@ import { CoursePopulation } from '@/components/CoursePopulation'
|
||||
import { CourseStatistics } from '@/components/CourseStatistics'
|
||||
import { CustomOpenUniPopulation } from '@/components/CustomOpenUniPopulation'
|
||||
import { CustomPopulation } from '@/components/CustomPopulation'
|
||||
import { EvaluationOverview } from '@/components/EvaluationOverview'
|
||||
import { FacultyStatistics } from '@/components/FacultyStatistics'
|
||||
import { LanguageCenterView } from '@/components/LanguageCenterView'
|
||||
import { PopulationStatistics } from '@/components/PopulationStatistics'
|
||||
@@ -38,7 +37,6 @@ const routes = {
|
||||
studyGuidanceGroups: '/studyguidancegroups/:groupid?',
|
||||
faculties: '/faculties/:facultyId?',
|
||||
customOpenUniPopulation: '/openunipopulation',
|
||||
evaluationOverview: '/evaluationoverview/:level?/:id?',
|
||||
university: '/university',
|
||||
completedCoursesSearch: '/completedcoursessearch',
|
||||
languageCenterView: '/languagecenterview',
|
||||
@@ -121,11 +119,6 @@ export const Routes = () => (
|
||||
requiredRoles={['admin']}
|
||||
/>
|
||||
)}
|
||||
<ProtectedRoute
|
||||
component={EvaluationOverview}
|
||||
path={routes.evaluationOverview}
|
||||
requiredRoles={['admin', 'fullSisuAccess', 'katselmusViewer']}
|
||||
/>
|
||||
<ProtectedRoute component={University} path={routes.university} />
|
||||
<ProtectedRoute
|
||||
component={CloseToGraduation}
|
||||
|
||||
@@ -18,10 +18,6 @@ const studyProgrammeApi = RTKApi.injectEndpoints({
|
||||
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}`,
|
||||
@@ -53,7 +49,6 @@ export const {
|
||||
useGetBasicStatsQuery,
|
||||
useGetColorizedTableCourseStatsQuery,
|
||||
useGetCreditStatsQuery,
|
||||
useGetEvaluationStatsQuery,
|
||||
useGetGraduationStatsQuery,
|
||||
useGetStudyTrackStatsQuery,
|
||||
useGetProgrammeCoursesStatsQuery,
|
||||
|
||||
Reference in New Issue
Block a user