diff --git a/services/oodikone2-frontend/src/components/CourseStatistics/ResultTabs/Panes/passRate.jsx b/services/oodikone2-frontend/src/components/CourseStatistics/ResultTabs/Panes/passRate.jsx index 0a05b5f42f..a4095d3e10 100644 --- a/services/oodikone2-frontend/src/components/CourseStatistics/ResultTabs/Panes/passRate.jsx +++ b/services/oodikone2-frontend/src/components/CourseStatistics/ResultTabs/Panes/passRate.jsx @@ -33,7 +33,6 @@ const getPassRateCumSeriesFromStats = (stats) => { ], relative: [ // eslint-disable-next-line no-unused-vars - getDataObject(`all`, all.map(_ => 1), 'a'), getDataObject(`passed`, passed.map(absoluteToRelative(all)), 'b'), getDataObject(`failed`, failed.map(absoluteToRelative(all)), 'c') ] @@ -73,7 +72,6 @@ const getPassRateStudSeriesFromStats = (stats) => { ], relative: [ // eslint-disable-next-line no-unused-vars - getDataObject(`all`, all.map(_ => 1), 'a'), getDataObject(` passed on first try`, passedFirst.map(absoluteToRelative(all)), 'b'), getDataObject(`passed after retry`, passedRetry.map(absoluteToRelative(all)), 'b'), getDataObject(`failed on first try`, failedFirst.map(absoluteToRelative(all)), 'c'), @@ -95,8 +93,8 @@ const PassRate = ({ primary, comparison, viewMode, isRelative = false }) => { const maxPassRateVal = isRelative ? 1 : getMaxValueOfSeries(passGraphSerie.absolute) const graphOptionsFn = isCumulativeMode ? passRateCumGraphOptions : passRateStudGraphOptions - const primaryGraphOptions = comparison ? graphOptionsFn(statYears, maxPassRateVal, 'Primary pass rate chart') : graphOptionsFn(statYears, maxPassRateVal, 'Pass rate chart') - const comparisonGraphOptions = graphOptionsFn(statYears, maxPassRateVal, 'Comparison pass rate chart') + const primaryGraphOptions = comparison ? graphOptionsFn(statYears, maxPassRateVal, 'Primary pass rate chart', isRelative) : graphOptionsFn(statYears, maxPassRateVal, 'Pass rate chart', isRelative) + const comparisonGraphOptions = graphOptionsFn(statYears, maxPassRateVal, 'Comparison pass rate chart', isRelative) return ( <> diff --git a/services/oodikone2-frontend/src/components/CourseStatistics/ResultTabs/index.jsx b/services/oodikone2-frontend/src/components/CourseStatistics/ResultTabs/index.jsx index 43d49f36ce..ab16318d6f 100644 --- a/services/oodikone2-frontend/src/components/CourseStatistics/ResultTabs/index.jsx +++ b/services/oodikone2-frontend/src/components/CourseStatistics/ResultTabs/index.jsx @@ -41,7 +41,7 @@ class ResultTabs extends Component { comparison={comparison} primary={primary} viewMode={viewMode} - isRelative={isRelative} + isRelative={isRelative && comparison} />) }, { @@ -51,7 +51,7 @@ class ResultTabs extends Component { comparison={comparison} primary={primary} viewMode={viewMode} - isRelative={isRelative} + isRelative={isRelative && comparison} />) } ] @@ -125,6 +125,7 @@ class ResultTabs extends Component { this.setState({ isRelative: !this.state.isRelative })} /> diff --git a/services/oodikone2-frontend/src/components/PopulationFilters/TagFilter.jsx b/services/oodikone2-frontend/src/components/PopulationFilters/TagFilter.jsx index 32d67965ba..50fdbeb3c8 100644 --- a/services/oodikone2-frontend/src/components/PopulationFilters/TagFilter.jsx +++ b/services/oodikone2-frontend/src/components/PopulationFilters/TagFilter.jsx @@ -12,6 +12,7 @@ import { tagFilter } from '../../populationFilters' const TagFilter = ({ setPopulationFilterAction, removePopulationFilterAction, filter, samples }) => { const [options, setOptions] = useState([]) const [selectedTag, setSelectedTag] = useState() + const [selectedComp, setSelectedComp] = useState() const createOptions = () => { const tags = samples.map(s => s.tags.map(t => ({ tagname: t.tag.tagname, tag_id: t.tag.tag_id }))) @@ -26,13 +27,16 @@ const TagFilter = ({ setPopulationFilterAction, removePopulationFilterAction, fi }, []) const handleFilter = () => { - setPopulationFilterAction(tagFilter({ tag: selectedTag })) + setPopulationFilterAction(tagFilter({ tag: selectedTag, comp: selectedComp })) + } + + const handleCompChange = (e, { value }) => { + setSelectedComp(value) } const handleChange = (e, { value }) => { - // any better solutions? - const selection = options.filter(tag => tag.value === value) - setSelectedTag(selection[0]) + const selection = options.find(tag => tag.value === value) + setSelectedTag(selection) } const clearFilter = () => { removePopulationFilterAction(filter.id) @@ -47,7 +51,17 @@ const TagFilter = ({ setPopulationFilterAction, removePopulationFilterAction, fi /> - + + + + + + + - Students that have a tag {filter.params.text} + Students that {filter.params.comp ? 'have' : 'don\'t have'} a tag {filter.params.text} diff --git a/services/oodikone2-frontend/src/components/PopulationStudents/index.jsx b/services/oodikone2-frontend/src/components/PopulationStudents/index.jsx index 8018e13012..8c719dbe56 100644 --- a/services/oodikone2-frontend/src/components/PopulationStudents/index.jsx +++ b/services/oodikone2-frontend/src/components/PopulationStudents/index.jsx @@ -360,7 +360,7 @@ class PopulationStudents extends Component {
{e.label}
), parent: true, - headerProps: { colSpan: labelToMandatoryCourses[e.label].length, title: e.label } + headerProps: { colSpan: labelToMandatoryCourses[e.label].length, title: e.label, ordernumber: e.orderNumber } })) ) } diff --git a/services/oodikone2-frontend/src/components/SortableTable/index.jsx b/services/oodikone2-frontend/src/components/SortableTable/index.jsx index 20970df0e5..bc5bb5083d 100644 --- a/services/oodikone2-frontend/src/components/SortableTable/index.jsx +++ b/services/oodikone2-frontend/src/components/SortableTable/index.jsx @@ -63,20 +63,24 @@ class SortableTable extends Component { const { collapsed } = this.state const defaultColumnCount = showNames ? 6 : 3 if (collapsed) { - const collapsedKeys = collapsed.map(c => c.key) - return collapsedKeys.reduce((acc, curr) => { - const previousCols = columns.filter(c => c.key < curr) + const collapsedOrderNumbers = collapsed.map(c => c.headerProps.ordernumber) + return collapsedOrderNumbers.reduce((acc, curr) => { + const previousCols = columns.filter(c => c.headerProps && c.headerProps.ordernumber < curr) const sumOfPreviousColSpans = previousCols.reduce((a, b) => a + b.headerProps.colSpan, 0) return [ ...acc, - sumOfPreviousColSpans + columns.find(c => c.key === curr).headerProps.colSpan + defaultColumnCount] + sumOfPreviousColSpans + columns.find(c => c.headerProps && c.headerProps.ordernumber === curr).headerProps.colSpan + defaultColumnCount] }, []) } return [] } const { tableProps, getRowProps, columns, getRowKey, collapsingHeaders } = this.props const { selected, direction, collapsed } = this.state - const columnsWithCollapsedHeaders = collapsingHeaders ? [...columns.filter(c => (c.headerProps && (!collapsed.map(cell => cell.headerProps.title).includes(c.headerProps.title) && !c.collapsed))), ...this.state.collapsed].sort((a, b) => a.key - b.key) : columns + const columnsWithCollapsedHeaders = collapsingHeaders ? [...columns.filter(c => ( + c.headerProps && (!collapsed.map(cell => cell.headerProps.title).includes(c.headerProps.title) && !c.collapsed))), + ...this.state.collapsed].sort((a, b) => a.headerProps.ordernumber - b.headerProps.ordernumber) + : + columns const sortDirection = name => (selected === name ? direction : null) diff --git a/services/oodikone2-frontend/src/components/TagStudent/index.jsx b/services/oodikone2-frontend/src/components/TagStudent/index.jsx index 00e78445b0..ec29e06330 100644 --- a/services/oodikone2-frontend/src/components/TagStudent/index.jsx +++ b/services/oodikone2-frontend/src/components/TagStudent/index.jsx @@ -26,13 +26,14 @@ const TagStudent = ({ useEffect(() => { setTags(tags) - const tagIds = studentstags.map(t => ({ id: t.id, tag_id: t.tag.tag_id })) - setStudentsTagIds(tagIds) + const initialStudentsTagIds = studentstags.map(t => ({ id: t.id, tag_id: t.tag.tag_id })) + const tagIds = studentstags.map(t => t.tag.tag_id) const initialTagOptions = tags.filter(tag => !tagIds.includes(tag.tag_id)).map(tag => ({ key: tag.tag_id, text: tag.tagname, value: tag.tag_id })) + setStudentsTagIds(initialStudentsTagIds) setTagOptions(initialTagOptions) }, []) diff --git a/services/oodikone2-frontend/src/constants/index.js b/services/oodikone2-frontend/src/constants/index.js index 048dbd87d2..b20c212984 100644 --- a/services/oodikone2-frontend/src/constants/index.js +++ b/services/oodikone2-frontend/src/constants/index.js @@ -88,11 +88,11 @@ export const API_DATE_FORMAT = 'YYYY.MM.DD' export const TOKEN_NAME = window.location.pathname.includes('staging') ? 'staging_token' : window.location.pathname.includes('/testing') ? 'testing_token' : 'token' //eslint-disable-line -export const passRateCumGraphOptions = (categories, max, title) => ({ +export const passRateCumGraphOptions = (categories, max, title, skipFirstColor) => ({ chart: { type: 'column' }, - colors: [chartblue, green, red], + colors: skipFirstColor ? [green, red] : [chartblue, green, red], title: { text: title @@ -119,11 +119,11 @@ export const passRateCumGraphOptions = (categories, max, title) => ({ } }) -export const passRateStudGraphOptions = (categories, max, title) => ({ +export const passRateStudGraphOptions = (categories, max, title, skipFirstColor) => ({ chart: { type: 'column' }, - colors: [chartblue, chartlgreen, chartdarkg, chartlred, chartdarkred], + colors: skipFirstColor ? [chartlgreen, chartdarkg, chartlred, chartdarkred] : [chartblue, chartlgreen, chartdarkg, chartlred, chartdarkred], title: { text: title diff --git a/services/oodikone2-frontend/src/populationFilters/index.js b/services/oodikone2-frontend/src/populationFilters/index.js index 588befbbc7..c3392c4e6b 100644 --- a/services/oodikone2-frontend/src/populationFilters/index.js +++ b/services/oodikone2-frontend/src/populationFilters/index.js @@ -255,16 +255,20 @@ export const gradeMeanFilter = (params) => { export const tagFilter = (params) => { const { text, value } = params.tag + const { comp } = params return ({ id: uuidv4(), type: 'TagFilter', params: { text, - value + comp }, filter: (student) => { const studentTagIds = student.tags.map(t => t.tag.tag_id) - return studentTagIds.includes(value) + if (comp) { + return studentTagIds.includes(value) + } + return !studentTagIds.includes(value) } }) } diff --git a/services/oodikone2-userservice/src/database/migrations/20190619_populate_faculties.js b/services/oodikone2-userservice/src/database/migrations/20190619_populate_faculties.js deleted file mode 100644 index 15576fef02..0000000000 --- a/services/oodikone2-userservice/src/database/migrations/20190619_populate_faculties.js +++ /dev/null @@ -1,35 +0,0 @@ -const valtiotieteellisen_ohjelmat = [ - 'KH40_001', // Filosofian kandiohjelma - 'KH70_001', // Politiikan ja viestinnän kandiohjelma - 'KH70_002', // Yhteiskunnallisen muutoksen kandiohjelma - 'KH70_003', // Sosiaalitieteiden kandiohjelma - 'KH70_004', // Taloustieteen kandiohjelma - 'MH50_001', // Matematiikan ja tilastotieteen maisteriohjelma - 'MH50_013', // Kaupunkitutkimuksen ja suunnittelun maisteriohjelma - 'MH57_005', // Ympäristömuutoksen ja globaalin kestävyyden maisteriohjelma - 'MH70_001', // Filosofian maisteriohjelma - 'MH70_002', // Politiikan ja viestinnän maisteriohjelma - 'MH70_003', // Globaalin politiikan ja kommunikaation maisteriohjelma - 'MH70_004', // Yhteiskunnallisen muutoksen maisteriohjelma - 'MH70_005', // Nyky-yhteiskunnan tutkimuksen maisteriohjelma - 'MH70_006', // Euroopan ja pohjoismaiden tutkimuksen maisteriohjelma (European and Nordic Studies) - 'MH70_007', // Yhteiskuntatieteiden maisteriohjelma - 'MH70_008', // Sosiaalitieteiden maisteriohjelma - 'MH70_009', // Taloustieteen maisteriohjelma - 'MH70_010' // International Masters in Economy, State & Society -] - -module.exports = { - up: async (queryInterface, Sequelize) => { - await queryInterface.bulkInsert( - 'faculty_programmes', - valtiotieteellisen_ohjelmat.map(code => ({ - faculty_code: 'H70', - programme_code: code, - createdAt: new Date(), - updatedAt: new Date() - })) - ) - }, - down: async () => {} -} diff --git a/services/oodikone2-userservice/src/database/migrations/20190626_populate_faculty_programmes.js b/services/oodikone2-userservice/src/database/migrations/20190626_populate_faculty_programmes.js new file mode 100644 index 0000000000..2e4526e132 --- /dev/null +++ b/services/oodikone2-userservice/src/database/migrations/20190626_populate_faculty_programmes.js @@ -0,0 +1,153 @@ +// Data from helsinki.fi/rapo -> opiskelijat -> Koulutusohjelmat -> Opiskelijat -> Valitse tiedekunta ja/tai koulutusohjelma +const faculty_to_programmes = { + H10: [ + 'MH10_001', + 'MH40_011', + 'KH10_001', + ], + H20: [ + 'KH20_001', + 'MH20_001', + 'MH20_002', + ], + H30: [ + 'KH30_001', + 'KH30_002', + 'MH30_002', + 'MH30_003', + 'MH30_004', + 'MH30_005', + 'MH30_001', + ], + H40: [ + 'KH40_001', + 'KH40_002', + 'KH40_003', + 'KH40_004', + 'KH40_005', + 'KH40_006', + 'MH40_001', + 'MH40_002', + 'MH40_003', + 'MH40_004', + 'MH40_005', + 'MH40_006', + 'MH40_007', + 'MH40_008', + 'MH40_009', + 'MH40_010', + 'MH40_011', + 'MH40_012', + 'MH40_013', + 'MH40_014', + 'MH40_015', + 'MH70_001', + 'MH70_006', + ], + H50: [ + 'KH50_001', + 'KH50_002', + 'KH50_003', + 'KH50_004', + 'KH50_005', + 'KH50_006', + 'KH50_007', + 'MH50_001', + 'MH50_002', + 'MH50_003', + 'MH50_004', + 'MH50_005', + 'MH50_006', + 'MH50_007', + 'MH50_008', + 'MH50_009', + 'MH50_010', + 'MH50_011', + 'MH50_012', + 'MH50_013', + ], + H55: [ + 'KH55_001', + 'MH55_001', + ], + H57: [ + 'KH57_001', + 'KH57_002', + 'KH57_003', + 'MH50_002', + 'MH50_013', + 'MH57_001', + 'MH57_002', + 'MH57_003', + 'MH57_004', + 'MH57_005', + 'MH80_007', + ], + H60: [ + 'KH60_001', + 'MH60_001', + ], + H70: [ + 'KH40_001', + 'KH50_001', + 'KH70_001', + 'KH70_002', + 'KH70_003', + 'KH70_004', + 'MH50_001', + 'MH57_005', + 'MH70_001', + 'MH70_002', + 'MH70_003', + 'MH70_004', + 'MH70_005', + 'MH70_006', + 'MH70_007', + 'MH70_008', + 'MH70_009', + 'MH70_010', + ], + H74: [ + 'KH74_001', + ], + H80: [ + 'KH57_002', + 'KH80_001', + 'KH80_002', + 'KH80_003', + 'KH80_004', + 'MH57_002', + 'MH57_003', + 'MH57_005', + 'MH80_001', + 'MH80_002', + 'MH80_003', + 'MH80_004', + 'MH80_005', + 'MH80_006', + 'MH80_007', + ], + H90: [ + 'KH90_001', + ], +} + +module.exports = { + up: async (queryInterface, Sequelize) => { + await queryInterface.bulkDelete( + 'faculty_programmes' + ) + for (const faculty of Object.keys(faculty_to_programmes)) { + await queryInterface.bulkInsert( + 'faculty_programmes', + faculty_to_programmes[faculty].map(programme => ({ + faculty_code: faculty, + programme_code: programme, + createdAt: new Date(), + updatedAt: new Date() + })) + ) + } + }, + down: async () => {} +}