From 3731e1d46ec7e68119e883a894129c344aea26aa Mon Sep 17 00:00:00 2001 From: Sam Grund Date: Wed, 2 Dec 2020 15:18:55 -0500 Subject: [PATCH 01/22] feat: BIN VALIDATION BITCH (#131) --- .../components/EditReserveCategoryModal.vue | 60 ++++++------------- src/public/components/PriorityOrderPanel.vue | 28 +++++---- src/public/plugins/helpers.js | 27 +++++++-- 3 files changed, 59 insertions(+), 56 deletions(-) diff --git a/src/public/components/EditReserveCategoryModal.vue b/src/public/components/EditReserveCategoryModal.vue index 8edcfb48..e4267285 100644 --- a/src/public/components/EditReserveCategoryModal.vue +++ b/src/public/components/EditReserveCategoryModal.vue @@ -235,36 +235,21 @@ export default { } break case NUMERIC_TYPE: + let numericError = {} if (criteria.max < criteria.min) { - const minMaxError = { - minMax: 'The max must be greater than or equal to the min.', - } - if (!!errors[index]) { - errors[index] = minMaxError - } else { - errors[index] = { - ...errors[index], - ...minMaxError, - } - } + numericError.minMax = + 'The max must be greater than or equal to the min.' } + if (criteria.coarsened) { // confirm that Bin 1 has the correct min - let binError = null - if (!criteria.bins.length) { - binError = { - bins: 'Please enter at least 1 bin.', - } - } else if (criteria.bins[0].min !== criteria.min) { - binError = { - bins: `Bin 1 must have a min of ${criteria.min}.`, - } - } else if ( - criteria.bins[criteria.bins.length - 1].max !== criteria.max - ) { - binError = { - bins: `Bin ${criteria.bins.length} must have a max of ${criteria.max}.`, - } + const bins = criteria.bins + if (!bins.length) { + numericError.bins = 'Please enter at least 1 bin.' + } else if (bins[0].min !== criteria.min) { + numericError.bins = `Bin 1 must have a min of ${criteria.min}.` + } else if (bins[bins.length - 1].max !== criteria.max) { + numericError.bins = `Bin ${bins.length} must have a max of ${criteria.max}.` } else { const binRangeError = checkBinRange({ bins: criteria.bins, @@ -272,21 +257,13 @@ export default { max: criteria.max, }) if (binRangeError) { - binError = { - bins: binRangeError, - } - } - } - - if (!!errors[index] && binError) { - errors[index] = binError - } else if (binError) { - errors[index] = { - ...errors[index], - ...binError, + numericError.bins = binRangeError } } } + if (Object.keys(numericError).length) { + errors[index] = { ...(errors[index] || {}), ...numericError } + } break default: break @@ -301,9 +278,6 @@ export default { setCopyToShow(copyKey) { this.copyToShow = editReserveCategoryCopyMap[copyKey] }, - setHasCriteriaError(hasCriteriaError) { - this.hasCriteriaError = hasCriteriaError - }, saveCategory() { if (!this.hasSizeError && this.reserveCategory.name) { const filteredPriorities = this.reserveCategory.priority.filter( @@ -338,6 +312,9 @@ export default { this.currentCriteria = this.currentCriteria - 1 }) } + this.$nextTick(() => { + this.validatePriorities() + }) }, validateCategoryName() { this.hasNameError = !this.reserveCategory.name @@ -416,6 +393,7 @@ export default { border: 2px solid var(--dark-blue); border-radius: 0 0 18px 18px; height: fit-content; + max-height: 50vh; overflow: auto; position: relative; } diff --git a/src/public/components/PriorityOrderPanel.vue b/src/public/components/PriorityOrderPanel.vue index 6853a743..2cc2dc5d 100644 --- a/src/public/components/PriorityOrderPanel.vue +++ b/src/public/components/PriorityOrderPanel.vue @@ -5,7 +5,7 @@ {{ criteriaErrors.minMax }}
@@ -109,7 +111,7 @@ > @@ -231,7 +233,7 @@ > { + this.validatePriorities() + }) + }, addNewElement() { this.criteria.elements.push({ name: '', @@ -310,6 +317,7 @@ export default { } return acc }, []) + this.runValidations() }, updateNumBins(numBins) { if (numBins < 0) { diff --git a/src/public/plugins/helpers.js b/src/public/plugins/helpers.js index 82463930..380a9cb5 100644 --- a/src/public/plugins/helpers.js +++ b/src/public/plugins/helpers.js @@ -151,17 +151,34 @@ export function toTitleCase(str) { export function checkBinRange({ bins, min, max }) { let binError = null - const rangeCovered = bins.reduce((acc, bin, index) => { + const rangeCovered = bins.forEach((bin, index) => { + const isFirstBin = index === 0 + const isLastBin = index === bins.length - 1 if (!isFloat(bin.min) || !isFloat(bin.max)) { binError = `Bin ${index + 1} must have a valid float.` - return acc } else if (bin.min < min) { binError = `Bin ${index + 1} cannot have a min less than ${min}.` - return acc } else if (bin.max > max) { binError = `Bin ${index + 1} cannot have a max greater than ${max}.` - return acc + } else if (bin.min > bin.max) { + binError = `Bin ${index + 1} cannot have a min greater than ${bin.max}.` + } else if (bins.length > 1) { + if (isFirstBin && bin.max !== bins[index + 1].min) { + binError = `The max of Bin 1 should equal the min of Bin 2` + } else if (index === bins.length - 1 && bin.min !== bins[index - 1].max) { + binError = `The min of Bin ${ + index + 1 + } should equal the max of Bin ${index}` + } else if (!isFirstBin && bin.min !== bins[index - 1].max) { + binError = `The min of Bin ${ + index + 1 + } should equal the max of Bin ${index}` + } else if (!isLastBin && bin.max !== bins[index + 1].min) { + binError = `The max of Bin ${index + 1} should equal the min of Bin ${ + index + 2 + }` + } } - }, []) + }) return binError } From 0af5f2e157e8fe60238253897e09c680fd5a0ec6 Mon Sep 17 00:00:00 2001 From: Sam Grund Date: Wed, 2 Dec 2020 15:51:47 -0500 Subject: [PATCH 02/22] chore: redirect to reserve instances when you arent editing a config (#132) --- src/public/pages/finish.vue | 5 +++++ src/public/pages/load-data.vue | 5 +++++ src/public/pages/specify-reserve.vue | 5 +++++ 3 files changed, 15 insertions(+) diff --git a/src/public/pages/finish.vue b/src/public/pages/finish.vue index 79144622..f42eb0eb 100644 --- a/src/public/pages/finish.vue +++ b/src/public/pages/finish.vue @@ -58,6 +58,11 @@ export default { return this.$store.state.currentConfig }, }, + beforeMount() { + if (!this.$store.state.currentConfig.reserveCategories.length) { + this.$router.push('/reserve-instances') + } + }, methods: { closeViewPriorityOrderModal() { this.viewPriorityOrderModalOpen = false diff --git a/src/public/pages/load-data.vue b/src/public/pages/load-data.vue index 222628ef..9e02805c 100644 --- a/src/public/pages/load-data.vue +++ b/src/public/pages/load-data.vue @@ -70,6 +70,11 @@ export default { return this.$store.state.currentConfig }, }, + beforeMount() { + if (!this.$store.state.currentConfig.reserveCategories.length) { + this.$router.push('/reserve-instances') + } + }, mounted() { this.$refs.fileUpload.addEventListener('change', () => { const file = this.$refs.fileUpload.files[0] diff --git a/src/public/pages/specify-reserve.vue b/src/public/pages/specify-reserve.vue index 0877d109..cc24059c 100644 --- a/src/public/pages/specify-reserve.vue +++ b/src/public/pages/specify-reserve.vue @@ -142,6 +142,11 @@ export default { } }, }, + beforeMount() { + if (!this.$store.state.currentConfig.reserveCategories.length) { + this.$router.push('/reserve-instances') + } + }, mounted() { this.$store.commit('updateSupplySum') }, From c8f910095b89f9f4294dcabad07d374314b1fdd3 Mon Sep 17 00:00:00 2001 From: Sam Grund Date: Wed, 2 Dec 2020 16:00:56 -0500 Subject: [PATCH 03/22] fix: disabled buttons --- src/public/components/EditReserveCategoryModal.vue | 6 +++++- src/public/pages/specify-reserve.vue | 6 ++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/public/components/EditReserveCategoryModal.vue b/src/public/components/EditReserveCategoryModal.vue index e4267285..4773cbce 100644 --- a/src/public/components/EditReserveCategoryModal.vue +++ b/src/public/components/EditReserveCategoryModal.vue @@ -279,7 +279,11 @@ export default { this.copyToShow = editReserveCategoryCopyMap[copyKey] }, saveCategory() { - if (!this.hasSizeError && this.reserveCategory.name) { + if ( + !this.hasSizeError && + this.reserveCategory.name && + !this.hasCriteriaError + ) { const filteredPriorities = this.reserveCategory.priority.filter( (criteria) => criteria.name ) diff --git a/src/public/pages/specify-reserve.vue b/src/public/pages/specify-reserve.vue index cc24059c..f1f7bfa6 100644 --- a/src/public/pages/specify-reserve.vue +++ b/src/public/pages/specify-reserve.vue @@ -183,10 +183,12 @@ export default { this.$store.commit('moveCategory', { category, direction: 'down' }) }, deleteCategory(category) { - this.$store.dispatch('deleteCategory', category) + if (!category.isDefault) { + this.$store.dispatch('deleteCategory', category) + } }, async postConfig() { - if (!this.disableNext) { + if (!this.errorMessage) { try { await this.$store.dispatch('postConfig') this.$router.push('/finish') From f6fe3ac5643a977c60b6a3ce893808330013334c Mon Sep 17 00:00:00 2001 From: "John (Jack) Ferguson" Date: Fri, 4 Dec 2020 21:52:11 -0500 Subject: [PATCH 04/22] refactor: remove lambda process, allow for wasted units (#140) feat: add /sourceFiles/:id/leftOver refs (#138) --- src/api/main/routes/source_files.js | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/src/api/main/routes/source_files.js b/src/api/main/routes/source_files.js index 71eae7db..db942e26 100644 --- a/src/api/main/routes/source_files.js +++ b/src/api/main/routes/source_files.js @@ -36,7 +36,7 @@ router.get('/sourceFiles/:id', async (req, res) => { return res.json(await db.sourceFile.findOne({ where: { id } })) }) -// GET one source file id +// GET nth reserve patients router.get('/sourceFiles/:id/nthReservePatients', async (req, res) => { const { db } = req const id = req.params.id @@ -47,6 +47,16 @@ router.get('/sourceFiles/:id/nthReservePatients', async (req, res) => { ) }) +// GET the number of left over units for reserve instance +router.get('/sourceFiles/:id/leftOver', async (req, res) => { + const { db } = req + const id = req.params.id + return res.json( + (await db.sourceFile.findOne({ where: { id } })).left_over + ) +}) + + // GET all patients for a source file router.get('/sourceFiles/:id/patients', async (req, res) => { const { db } = req @@ -128,17 +138,6 @@ router.post('/sourceFiles/:id/process', async (req, res) => { leftOver += f.size - given }) - const notSelectedPatientsArray = Array.from(notSelectedPatients) - let i = 0 - // give left over to unallocated patients if there are any - while (leftOver > 0 && i < notSelectedPatientsArray.length) { - const pat = notSelectedPatientsArray[i] - selectedPatients.add(pat) - allocatedPatientGroups[pat] = 'None' - leftOver -= 1 - i += 1 - } - // update patients selectedPatients.forEach(async (pId) => { From 395c3e3b75806d7303652e867f3393ed41001520 Mon Sep 17 00:00:00 2001 From: "John (Jack) Ferguson" Date: Sun, 6 Dec 2020 20:52:07 -0500 Subject: [PATCH 05/22] feat: sort nested config parts by their order (#141) feat: create build targets for windows OS --- package.json | 9 ++++++++- src/api/main/routes/configurations.js | 4 ++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index ce50b21e..e93bcb14 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,13 @@ "mac": { "category": "your.app.category.type" }, + "win": { + "target": [ + { + "target": "nsis" + } + ] + }, "files": [ "build/*", "src/**", @@ -33,7 +40,7 @@ "build:client": "cross-env NODE_ENV=production webpack --config build/webpack.client.config.js --progress", "build:server": "cross-env NODE_ENV=production webpack --config build/webpack.server.config.js --progress", "pack": "electron-builder --dir", - "dist": "yarn build && DEBUG=electron-builder electron-builder", + "dist": "yarn build && DEBUG=electron-builder electron-builder --win --mac", "postinstall": "electron-builder install-app-deps" }, "dependencies": { diff --git a/src/api/main/routes/configurations.js b/src/api/main/routes/configurations.js index 7170cb3a..e1136e75 100644 --- a/src/api/main/routes/configurations.js +++ b/src/api/main/routes/configurations.js @@ -24,6 +24,7 @@ router.get("/configurations/:id", async (req, res) => { { model: db.reserveCategory, as: "reserveCategories", + order: [['reserveCatetories.`order`', 'ASC']], include: [ { model: db.priority, @@ -31,6 +32,7 @@ router.get("/configurations/:id", async (req, res) => { { model: db.categoryCriteria, as: "categoryCriteria", + order: [['order', 'ASC']], include: [ { model: db.categoryCriteriaElement, @@ -41,6 +43,7 @@ router.get("/configurations/:id", async (req, res) => { { model: db.numericCriteria, as: "numericCriteria", + order: [['order', 'ASC']], include: [ { model: db.numericCriteriaBucket, @@ -51,6 +54,7 @@ router.get("/configurations/:id", async (req, res) => { ], }, ], + }, ], }) From f9d4869c4342c320f41e34932cb8cea9bf732e81 Mon Sep 17 00:00:00 2001 From: Sam Grund Date: Sun, 6 Dec 2020 21:36:28 -0500 Subject: [PATCH 06/22] fix: issue squashing (#142) --- src/api/main/routes/source_files.js | 23 +++------ src/public/components/ConfigSummary.vue | 2 +- src/public/components/PriorityOrderPanel.vue | 53 ++++++++++++++++++-- src/public/components/constants.js | 2 +- src/public/pages/reserve-instances.vue | 4 +- src/public/plugins/helpers.js | 18 ++++--- 6 files changed, 73 insertions(+), 29 deletions(-) diff --git a/src/api/main/routes/source_files.js b/src/api/main/routes/source_files.js index db942e26..79f1aee5 100644 --- a/src/api/main/routes/source_files.js +++ b/src/api/main/routes/source_files.js @@ -36,7 +36,7 @@ router.get('/sourceFiles/:id', async (req, res) => { return res.json(await db.sourceFile.findOne({ where: { id } })) }) -// GET nth reserve patients +// GET nth reserve patients router.get('/sourceFiles/:id/nthReservePatients', async (req, res) => { const { db } = req const id = req.params.id @@ -47,16 +47,13 @@ router.get('/sourceFiles/:id/nthReservePatients', async (req, res) => { ) }) -// GET the number of left over units for reserve instance +// GET the number of left over units for reserve instance router.get('/sourceFiles/:id/leftOver', async (req, res) => { const { db } = req const id = req.params.id - return res.json( - (await db.sourceFile.findOne({ where: { id } })).left_over - ) + return res.json((await db.sourceFile.findOne({ where: { id } })).left_over) }) - // GET all patients for a source file router.get('/sourceFiles/:id/patients', async (req, res) => { const { db } = req @@ -65,7 +62,7 @@ router.get('/sourceFiles/:id/patients', async (req, res) => { if (req.query.givenUnit) filterLosers += `and ${ req.query.givenUnit === 'false' ? 'not' : '' - } given_unit` + } given_unit` return res.json(await getPatientsWithAttributes(db, id, filterLosers)) }) @@ -95,7 +92,6 @@ router.post('/sourceFiles/:id/process', async (req, res) => { }) ) - const patients = await Promise.all( ( await db.patient.findAll({ @@ -115,17 +111,13 @@ router.post('/sourceFiles/:id/process', async (req, res) => { let given = 0 let i = 0 while (i < f.patients.length) { - - if (given < f.size && !selectedPatients.has(f.patients[i])) { - selectedPatients.add(f.patients[i]) allocatedPatientGroups[f.patients[i]] = f.name given += 1 notSelectedPatients.delete(f.patients[i]) if (given == f.size) { - nthReservePatients.push({ name: f.name, nthRecipientPrimaryId: f.patients[i], @@ -140,7 +132,6 @@ router.post('/sourceFiles/:id/process', async (req, res) => { // update patients selectedPatients.forEach(async (pId) => { - const patient = await db.patient.findOne({ where: { id: pId } }) patient.given_unit = true patient.group_allocated_under = allocatedPatientGroups[pId] @@ -149,9 +140,9 @@ router.post('/sourceFiles/:id/process', async (req, res) => { const nthReservePatientsWithNames = await Promise.all( nthReservePatients.map(async (f) => { - const name = ( - await db.patient.findOne({ where: { id: f.nthRecipientPrimaryId } }) - ) + const name = await db.patient.findOne({ + where: { id: f.nthRecipientPrimaryId }, + }) return { name: f.name, nthRecipientId: name.dataValues.recipient_id } }) diff --git a/src/public/components/ConfigSummary.vue b/src/public/components/ConfigSummary.vue index 2064e820..2d653706 100644 --- a/src/public/components/ConfigSummary.vue +++ b/src/public/components/ConfigSummary.vue @@ -115,7 +115,7 @@ export default { }, } -