From 6fa283343fc9626ca8e08e7f0c480614e525746e Mon Sep 17 00:00:00 2001 From: Vivek Singh Date: Fri, 3 May 2024 16:52:08 +0530 Subject: [PATCH 01/24] #1147 - show organisation category in listing and in home page title --- src/adminApp/Organisation.js | 1 + src/rootApp/ducks.js | 3 ++- src/rootApp/views/Homepage.js | 24 +++++++----------------- 3 files changed, 10 insertions(+), 18 deletions(-) diff --git a/src/adminApp/Organisation.js b/src/adminApp/Organisation.js index 90e8f7ae8..d385b7255 100644 --- a/src/adminApp/Organisation.js +++ b/src/adminApp/Organisation.js @@ -52,6 +52,7 @@ export const OrganisationList = ({ history, ...props }) => { }> + diff --git a/src/rootApp/ducks.js b/src/rootApp/ducks.js index e76d36ee1..e26712ae3 100644 --- a/src/rootApp/ducks.js +++ b/src/rootApp/ducks.js @@ -110,7 +110,8 @@ export default function(state = initialState, action) { organisation: { id: action.payload.organisationId, name: action.payload.organisationName, - usernameSuffix: action.payload.usernameSuffix + usernameSuffix: action.payload.usernameSuffix, + organisationCategory: action.payload.organisationCategory }, userInfo: action.payload }; diff --git a/src/rootApp/views/Homepage.js b/src/rootApp/views/Homepage.js index 38dc85d37..a4b01ac78 100644 --- a/src/rootApp/views/Homepage.js +++ b/src/rootApp/views/Homepage.js @@ -20,17 +20,14 @@ import { Help } from "@material-ui/icons"; -const Homepage = ({ userInfo }) => { +const Homepage = ({ userInfo, organisation }) => { httpClient.saveAuthTokenForAnalyticsApp(); const showAnalytics = UserInfo.hasPrivilege(userInfo, Privilege.PrivilegeType.Analytics); - const showDataEntryApp = UserInfo.hasPrivilege( - userInfo, - Privilege.PrivilegeType.ViewEditEntitiesOnDataEntryApp - ); + const showDataEntryApp = UserInfo.hasPrivilege(userInfo, Privilege.PrivilegeType.ViewEditEntitiesOnDataEntryApp); return ( - + { name={"Translations"} customIconComponent={} /> - } - /> + } /> {showDataEntryApp && ( { )} {showAnalytics && ( } /> @@ -96,6 +85,7 @@ const Homepage = ({ userInfo }) => { }; const mapStateToProps = state => ({ - userInfo: state.app.userInfo + userInfo: state.app.userInfo, + organisation: state.app.organisation }); export default connect(mapStateToProps)(Homepage); From 011ce171b692a4ddeb5de170ef4d293b4fd8c283 Mon Sep 17 00:00:00 2001 From: himeshr Date: Fri, 3 May 2024 18:01:18 +0530 Subject: [PATCH 02/24] #1133 | Allow adding questionGroup only if none of the existing ones are empty --- package.json | 2 +- src/dataEntryApp/components/QuestionGroupFormElement.js | 2 +- .../components/RepeatableQuestionGroupElement.js | 7 +++++-- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index ae7e7ba9d..39cabef6d 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "material-table": "1.43.0", "moment": "^2.22.2", "openchs-idi": "git+https://github.com/avniproject/openchs-idi#b6c57e051b91ed4bc2634f4f087dba51cc3a01c8", - "openchs-models": "1.31.64", + "openchs-models": "1.31.69", "popper.js": "^1.14.3", "prismjs": "^1.17.1", "prop-types": "^15.7.2", diff --git a/src/dataEntryApp/components/QuestionGroupFormElement.js b/src/dataEntryApp/components/QuestionGroupFormElement.js index 9ff35d172..45107551b 100644 --- a/src/dataEntryApp/components/QuestionGroupFormElement.js +++ b/src/dataEntryApp/components/QuestionGroupFormElement.js @@ -72,7 +72,7 @@ export default function QuestionGroupFormElement({ concept={childFormElement.concept} obsHolder={obsHolder} value={value} - validationResults={validationResults.filter(itr => itr.questionGroupIndex === questionGroupIndex)} + validationResults={validationResults} uuid={childFormElement.uuid} update={newValue => { updateObs(formElement, newValue, childFormElement, questionGroupIndex); diff --git a/src/dataEntryApp/components/RepeatableQuestionGroupElement.js b/src/dataEntryApp/components/RepeatableQuestionGroupElement.js index 205f9a54d..32923154d 100644 --- a/src/dataEntryApp/components/RepeatableQuestionGroupElement.js +++ b/src/dataEntryApp/components/RepeatableQuestionGroupElement.js @@ -31,8 +31,11 @@ export function RepeatableQuestionGroupElement({ if (hasNoObservation) repeatableQuestionGroup = new RepeatableQuestionGroup(); const repeatableQuestionGroupValue = repeatableQuestionGroup.getValue(); const hasMultipleElements = repeatableQuestionGroupValue.length > 1; + const oneOfTheQuestionGroupObservationsIsEmpty = _.some(repeatableQuestionGroupValue, x => _.isEmpty(x.groupObservations)); return repeatableQuestionGroupValue.map((x, index) => { - const isLastElement = !hasNoObservation && repeatableQuestionGroupValue.length === index + 1; + const isLastElement = + !hasNoObservation && !oneOfTheQuestionGroupObservationsIsEmpty && repeatableQuestionGroupValue.length === index + 1; + const quesGrpValidationResults = validationResults.filter(itr => itr.questionGroupIndex === index); return (
Date: Mon, 6 May 2024 13:41:19 +0530 Subject: [PATCH 03/24] #1133 | Handle missing or invalid media unsigned url values in create/edit form / summary page --- src/adminApp/service/MediaService.js | 8 +- src/dataEntryApp/components/MediaUploader.js | 105 +++++-------- src/dataEntryApp/components/Observations.js | 147 +++++-------------- 3 files changed, 74 insertions(+), 186 deletions(-) diff --git a/src/adminApp/service/MediaService.js b/src/adminApp/service/MediaService.js index f12ec7753..53967ed41 100644 --- a/src/adminApp/service/MediaService.js +++ b/src/adminApp/service/MediaService.js @@ -1,8 +1,12 @@ import http from "../../common/utils/httpClient"; class MediaService { - static getMedia(url) { - return http.get(http.withParams(`/media/signedUrl`, { url: url })).then(res => res.data); + static async getMedia(url) { + try { + return await http.get(http.withParams(`/media/signedUrl`, { url: url })).then(res => res.data); + } catch (exception) { + return "Unable to fetch media. Value: " + url; + } } } diff --git a/src/dataEntryApp/components/MediaUploader.js b/src/dataEntryApp/components/MediaUploader.js index c6b298363..a3fc5b62f 100644 --- a/src/dataEntryApp/components/MediaUploader.js +++ b/src/dataEntryApp/components/MediaUploader.js @@ -1,5 +1,5 @@ import React, { Fragment, useEffect, useState } from "react"; -import { get, isEmpty, includes, lowerCase, isArrayLikeObject, omit } from "lodash"; +import { get, isEmpty, includes, lowerCase, isArrayLikeObject, omit, startsWith } from "lodash"; import { Box, Button, Grid, makeStyles, Typography } from "@material-ui/core"; import FormControl from "@material-ui/core/FormControl"; import http from "../../common/utils/httpClient"; @@ -51,9 +51,7 @@ const isValidFile = (allowedTypes, type) => { }; const isValidType = (formElement, type, isFile) => { - return isFile - ? isValidFile(formElement.allowedTypes, type) - : includes(type, lowerCase(formElement.getType())); + return isFile ? isValidFile(formElement.allowedTypes, type) : includes(type, lowerCase(formElement.getType())); }; function addObsResultsToPreview(observationValue, setPreview) { @@ -91,13 +89,7 @@ function invokeUpdate(update, mediaUrl) { update(mediaUrl); } -function addMediaUrlToLocalObsValue( - update, - fileName, - isMultiSelect, - localObsValue, - setLocalObsValue -) { +function addMediaUrlToLocalObsValue(update, fileName, isMultiSelect, localObsValue, setLocalObsValue) { invokeUpdate(update, fileName); if (isMultiSelect) { setLocalObsValue(locObsValue => @@ -110,13 +102,7 @@ function addMediaUrlToLocalObsValue( } } -function removeMediaUrlFromLocalObsValue( - update, - fileName, - isMultiSelect, - localObsValue, - setLocalObsValue -) { +function removeMediaUrlFromLocalObsValue(update, fileName, isMultiSelect, localObsValue, setLocalObsValue) { invokeUpdate(update, fileName); if (isMultiSelect && isArrayLikeObject(localObsValue)) { setLocalObsValue(locObsValue => locObsValue.filter(item => item !== fileName)); @@ -128,15 +114,12 @@ function removeMediaUrlFromLocalObsValue( function consolidateAlerts(etFiles, formElement, isFileDataType, alerts) { etFiles.forEach(file => { if (!isValidType(formElement, file.type, isFileDataType)) { - alerts.push( - `Selected files type not supported for file ${file.name}. Please choose proper files.\n` - ); + alerts.push(`Selected files type not supported for file ${file.name}. Please choose proper files.\n`); } if (isFileDataType && isBiggerFile(formElement, file.size)) { const oneMBInBytes = 1000000; alerts.push( - `Selected file size ${file.size / - oneMBInBytes} MB is more than the set max file size ${formElement.allowedMaxSize / + `Selected file size ${file.size / oneMBInBytes} MB is more than the set max file size ${formElement.allowedMaxSize / oneMBInBytes} MB for file ${file.name}.\n` ); } @@ -161,18 +144,10 @@ function uploadMediaAndUpdateObservationValue( .uploadFile("/web/uploadMedia", file) .then(r => { setUploadButtonClicked(oldValue => oldValue - 1); - addMediaUrlToLocalObsValue( - update, - r.data, - isMultiSelect, - localObsValue, - setLocalObsValue - ); + addMediaUrlToLocalObsValue(update, r.data, isMultiSelect, localObsValue, setLocalObsValue); }) .catch(r => { - const error = `${get(r, "response.data") || - get(r, "message") || - "Unknown error occurred while uploadButtonClicked media"}`; + const error = `${get(r, "response.data") || get(r, "message") || "Unknown error occurred while uploadButtonClicked media"}`; setUploadButtonClicked(oldValue => oldValue - 1); onDelete(file.name); alert(error); @@ -181,6 +156,7 @@ function uploadMediaAndUpdateObservationValue( }); } +const MissingSignedMediaMessage = "Unable to fetch media. Value: "; export const MediaUploader = ({ label, obsValue, mediaType, update, formElement }) => { const classes = useStyles(); const Icon = iconMap[mediaType]; @@ -216,38 +192,16 @@ export const MediaUploader = ({ label, obsValue, mediaType, update, formElement alert(alerts); return; } - uploadMediaAndUpdateObservationValue( - etFiles, - setUploadButtonClicked, - setLocalObsValue, - isMultiSelect, - localObsValue, - update, - onDelete - ); + uploadMediaAndUpdateObservationValue(etFiles, setUploadButtonClicked, setLocalObsValue, isMultiSelect, localObsValue, update, onDelete); }; const onDelete = fileName => { - removeMediaUrlFromLocalObsValue( - update, - fileName, - isMultiSelect, - localObsValue, - setLocalObsValue - ); + removeMediaUrlFromLocalObsValue(update, fileName, isMultiSelect, localObsValue, setLocalObsValue); removeFileFromPreview(fileName, preview, setPreview); }; - const mediaPreviewMap = fileToPreview => ({ - image: ( - {label} setOpenImage(fileToPreview)} - /> - ), + const mediaPreviewMap = (fileToPreview, label) => ({ + image: {label} setOpenImage(fileToPreview)} />, video: (