diff --git a/WNPRC_EHR/resources/queries/study/anesthesiaRecoveriesFullHistory.sql b/WNPRC_EHR/resources/queries/study/anesthesiaRecoveriesFullHistory.sql
new file mode 100644
index 000000000..8de749e9f
--- /dev/null
+++ b/WNPRC_EHR/resources/queries/study/anesthesiaRecoveriesFullHistory.sql
@@ -0,0 +1,12 @@
+SELECT
+ Id,
+ date,
+ recoveryStartTime,
+ submitterInitials,
+ qcstate,
+ taskid,
+ observation,
+ recoverySpeed,
+ recoveryCondition,
+ totalRecoveryTime
+FROM study.anesthesiaRecovery
\ No newline at end of file
diff --git a/WNPRC_EHR/resources/queries/study/anesthesiaRecovery.query.xml b/WNPRC_EHR/resources/queries/study/anesthesiaRecovery.query.xml
new file mode 100644
index 000000000..3b2684fbd
--- /dev/null
+++ b/WNPRC_EHR/resources/queries/study/anesthesiaRecovery.query.xml
@@ -0,0 +1,75 @@
+
+
+
+
+
+
+ true
+ false
+
+
+
+ true
+ false
+
+
+
+ Recovery Start Time Final
+
+
+
+ Task Id
+
+ ehr
+ tasks
+ taskid
+
+ /ehr/WNPRC/EHR/taskDetails.view?formtype=Anesthesia%20Recovery&taskid=${taskid}
+ true
+ false
+
+
+
+ true
+ false
+
+
+
+ true
+ false
+
+
+
+ true
+ false
+
+
+
+ Recovery Reason Final
+
+
+
+ Group ID Final
+
+
+
+ Cage Final
+
+
+
+ Location Final
+
+
+
+ Room Final
+
+
+
+ Status
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/WNPRC_EHR/resources/queries/study/anesthesiaRecovery/.qview.xml b/WNPRC_EHR/resources/queries/study/anesthesiaRecovery/.qview.xml
new file mode 100644
index 000000000..971cfb1b3
--- /dev/null
+++ b/WNPRC_EHR/resources/queries/study/anesthesiaRecovery/.qview.xml
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/WNPRC_EHR/resources/queries/study/anesthesiaRecovery/Full History.qview.xml b/WNPRC_EHR/resources/queries/study/anesthesiaRecovery/Full History.qview.xml
new file mode 100644
index 000000000..5552f73c2
--- /dev/null
+++ b/WNPRC_EHR/resources/queries/study/anesthesiaRecovery/Full History.qview.xml
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/WNPRC_EHR/resources/queries/study/anesthesiaRecovery/Summary.qview.xml b/WNPRC_EHR/resources/queries/study/anesthesiaRecovery/Summary.qview.xml
new file mode 100644
index 000000000..7d6d023e9
--- /dev/null
+++ b/WNPRC_EHR/resources/queries/study/anesthesiaRecovery/Summary.qview.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/WNPRC_EHR/resources/queries/study/wnprcFullHistory.sql b/WNPRC_EHR/resources/queries/study/wnprcFullHistory.sql
index e1957c577..18fdc6f4a 100644
--- a/WNPRC_EHR/resources/queries/study/wnprcFullHistory.sql
+++ b/WNPRC_EHR/resources/queries/study/wnprcFullHistory.sql
@@ -53,4 +53,23 @@ SELECT
null AS requestid
FROM study.waterTotalByDate
-WHERE TotalWater IS NOT NULL
\ No newline at end of file
+WHERE TotalWater IS NOT NULL
+
+UNION ALL
+SELECT
+ Id AS Id,
+ date,
+ null AS project,
+ 'Anesthesia Recovery' AS dataset,
+ 'anesthesiarecovery' AS DataSetName,
+ 'Animal fully recovered.' AS remark,
+ 'Total Recovery Time: ' || CAST(CEILING(totalRecoveryTime) AS VARCHAR) || ' minutes' || CHR(10) ||
+ 'Recovery Speed: ' || CAST(recoverySpeed AS VARCHAR) || CHR(10) ||
+ 'Recovery Condition: ' || CAST(recoveryCondition AS VARCHAR)
+ AS description,
+ submitterInitials AS performedBy,
+ qcstate AS qcstate,
+ taskid AS taskid,
+ null AS requestid
+FROM study.anesthesiaRecoveriesFullHistory
+WHERE observation = 'Fully Recovered'
\ No newline at end of file
diff --git a/WNPRC_EHR/resources/queries/study/wnprcFullHistory/.qview.xml b/WNPRC_EHR/resources/queries/study/wnprcFullHistory/.qview.xml
index 4c5f0b659..6e80b1c2f 100644
--- a/WNPRC_EHR/resources/queries/study/wnprcFullHistory/.qview.xml
+++ b/WNPRC_EHR/resources/queries/study/wnprcFullHistory/.qview.xml
@@ -16,7 +16,7 @@
-
+
\ No newline at end of file
diff --git a/WNPRC_EHR/resources/queries/wnprc_ios_app/session_log.query.xml b/WNPRC_EHR/resources/queries/wnprc_ios_app/session_log.query.xml
new file mode 100644
index 000000000..6262ff6c1
--- /dev/null
+++ b/WNPRC_EHR/resources/queries/wnprc_ios_app/session_log.query.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/WNPRC_EHR/resources/referenceStudy/study/datasets/datasets_manifest.xml b/WNPRC_EHR/resources/referenceStudy/study/datasets/datasets_manifest.xml
index af54a8e9d..06e96046e 100644
--- a/WNPRC_EHR/resources/referenceStudy/study/datasets/datasets_manifest.xml
+++ b/WNPRC_EHR/resources/referenceStudy/study/datasets/datasets_manifest.xml
@@ -232,5 +232,8 @@
+
+
+
\ No newline at end of file
diff --git a/WNPRC_EHR/resources/referenceStudy/study/datasets/datasets_metadata.xml b/WNPRC_EHR/resources/referenceStudy/study/datasets/datasets_metadata.xml
index 82b520229..e1680dd5d 100644
--- a/WNPRC_EHR/resources/referenceStudy/study/datasets/datasets_metadata.xml
+++ b/WNPRC_EHR/resources/referenceStudy/study/datasets/datasets_metadata.xml
@@ -16334,4 +16334,117 @@
+
+
+
+ varchar
+ Id
+ Subject identifier
+ http://cpas.labkey.com/Study#ParticipantId
+ http://cpas.labkey.com/Study#ParticipantId
+ false
+ /ehr/participantView.view?participantId=${id}
+
+ ptid
+ participantid
+
+
+ study
+ Animal
+ Id
+
+ ALWAYS_OFF
+ 32
+
+
+ integer
+
+
+ timestamp
+
+
+ timestamp
+
+
+ varchar
+
+
+ varchar
+
+
+ varchar
+
+
+ varchar
+
+
+ varchar
+
+
+ varchar
+
+
+ varchar
+
+
+ varchar
+
+
+ varchar
+
+
+ varchar
+
+
+ varchar
+
+
+ varchar
+
+
+ varchar
+
+
+ varchar
+
+
+ varchar
+
+
+ varchar
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/WNPRC_EHR/resources/web/ehr/ext3/ehrGridFormPanel.js b/WNPRC_EHR/resources/web/ehr/ext3/ehrGridFormPanel.js
index 940b0aed6..caf34ab69 100644
--- a/WNPRC_EHR/resources/web/ehr/ext3/ehrGridFormPanel.js
+++ b/WNPRC_EHR/resources/web/ehr/ext3/ehrGridFormPanel.js
@@ -1077,8 +1077,8 @@ EHR.ext.GridFormPanel = Ext.extend(Ext.Panel,
if (extension === 'xlsx' || extension === 'xls') {
// need to get the date it was uploaded,
// since 'record' only provides the date when the actual file was created
- promises.push(getFileHistory(virologyResultsFolder, record.data.name).then((history) => {
- files.push({"name": history[0], "uploaded": history[1][0].data.date})
+ promises.push(getFileHistory(virologyResultsFolder, record.data.name).then((file) => {
+ files.push(file)
}))
}
@@ -1113,6 +1113,10 @@ EHR.ext.GridFormPanel = Ext.extend(Ext.Panel,
importFromFileWindow.removeAll();
importFromFileWindow.add(selectFilePanel);
importFromFileWindow.doLayout();
+ }).catch((e) => {
+ Ext.Msg.hide();
+ console.error(e);
+ Ext.Msg.alert('Error', 'Unable to build the list of files to import.');
})
},
@@ -1130,14 +1134,17 @@ EHR.ext.GridFormPanel = Ext.extend(Ext.Panel,
}
});
function getFileHistory(fileSystem, filename) {
+ // Always resolves so one unreadable file still leaves the rest importable.
return new Promise(resolve => {
fileSystem.getHistory({
path: '/' + filename,
success: function(fileSystem,path,history) {
- resolve([filename,history]);
+ // A file placed on the server outside of an upload has no audit record.
+ resolve({name: filename, uploaded: history && history.length ? history[0].data.date : null});
},
failure: function(f) {
- reject(f);
+ console.error('Unable to read file history for ' + filename, f);
+ resolve({name: filename, uploaded: null});
}
})
});
@@ -1307,7 +1314,7 @@ EHR.ext.GridFormPanel = Ext.extend(Ext.Panel,
html: '' + file.name + ''
},
{
- html: '' + new Date(file.uploaded).format("Y-m-d H:i")+ ''
+ html: '' + (file.uploaded ? new Date(file.uploaded).format("Y-m-d H:i") : 'Unknown') + ''
},
];
diff --git a/WNPRC_EHR/src/org/labkey/wnprc_ehr/WNPRC_EHRController.java b/WNPRC_EHR/src/org/labkey/wnprc_ehr/WNPRC_EHRController.java
index 8b0d6ab21..636574276 100644
--- a/WNPRC_EHR/src/org/labkey/wnprc_ehr/WNPRC_EHRController.java
+++ b/WNPRC_EHR/src/org/labkey/wnprc_ehr/WNPRC_EHRController.java
@@ -18,13 +18,16 @@
import au.com.bytecode.opencsv.CSVWriter;
import jakarta.servlet.ServletOutputStream;
import jakarta.servlet.http.HttpServletResponse;
+import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.text.WordUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
+import org.apache.poi.util.ArrayUtil;
import org.jetbrains.annotations.Nullable;
import org.joda.time.DateTime;
import org.joda.time.LocalDate;
+import org.joda.time.LocalDateTime;
import org.json.JSONArray;
import org.json.JSONObject;
import org.jsoup.Jsoup;
@@ -51,12 +54,16 @@
import org.labkey.api.data.TableInfo;
import org.labkey.api.data.TableSelector;
import org.labkey.api.ehr.EHRDemographicsService;
+import org.labkey.api.ehr.EHRQCState;
import org.labkey.api.ehr.EHRService;
import org.labkey.api.ehr.demographics.AnimalRecord;
import org.labkey.api.exp.property.Domain;
+import org.labkey.api.formSchema.Field;
+import org.labkey.api.ldk.notification.Notification;
import org.labkey.api.module.Module;
import org.labkey.api.module.ModuleLoader;
import org.labkey.api.module.ModuleProperty;
+import org.labkey.api.qc.QCStateManager;
import org.labkey.api.query.BatchValidationException;
import org.labkey.api.query.FieldKey;
import org.labkey.api.query.QueryHelper;
@@ -64,6 +71,7 @@
import org.labkey.api.query.QueryUpdateService;
import org.labkey.api.query.QueryUpdateServiceException;
import org.labkey.api.query.UserSchema;
+import org.labkey.api.query.ValidationException;
import org.labkey.api.reader.ExcelFactory;
import org.labkey.api.resource.DirectoryResource;
import org.labkey.api.resource.FileResource;
@@ -116,6 +124,7 @@
import org.labkey.wnprc_ehr.dataentry.validators.exception.InvalidAnimalIdException;
import org.labkey.wnprc_ehr.dataentry.validators.exception.InvalidProjectException;
import org.labkey.wnprc_ehr.notification.NecropsyEditRequestNotification;
+import org.labkey.wnprc_ehr.notification.NotificationToolkit;
import org.labkey.wnprc_ehr.schemas.WNPRC_Schema;
import org.labkey.wnprc_ehr.service.dataentry.BehaviorDataEntryService;
import org.springframework.validation.BindException;
@@ -130,7 +139,9 @@
import java.sql.Timestamp;
import java.text.ParseException;
import java.text.SimpleDateFormat;
+import java.time.OffsetDateTime;
import java.time.ZoneId;
+import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Date;
@@ -141,6 +152,10 @@
import java.util.Map;
import java.util.Set;
import java.util.UUID;
+import java.util.stream.Collectors;
+
+import org.labkey.api.action.SimpleApiJsonForm;
+import org.springframework.validation.Errors;
import static java.time.temporal.ChronoUnit.DAYS;
@@ -2452,4 +2467,328 @@ public Object execute(NecropsyEditRequestNotificationForm form, BindException er
}
}
+ @RequiresLogin
+ public static class UpdateAnesthesiaRecoveryDatasetAction extends MutatingApiAction {
+
+ @Override
+ public Object execute(SimpleApiJsonForm form, BindException errors) throws Exception {
+ _log.info("UPDATE CALLED: UpdateAnesthesiaRecoveryDatasetAction()");
+
+ // 1. Sets up environment.
+ // 1a. Sets variables.
+ NotificationToolkit notificationToolkit = new NotificationToolkit();
+ JSONObject response = new JSONObject();
+ response.put("success",false);
+ response.put("detailedResponse", "");
+ response.put("rowsUpdated", 0);
+ // 1b. Gets QCState name.
+ var qcStateStarted = EHRService.QCSTATES.Scheduled.getQCState(getContainer()).getRowId();
+ // TODO: Ask labkey why 'started' state isn't working.
+ // - Retrieved 'started' rowid with code below and it works.
+ // - Then I call this later: taskRecord.put("qcstate", qcStateStarted);
+ // - Which throws this error: Insufficient permissions to update: tasks to status: undefined, from: Scheduled
+ // - Why is this so much hassle trying to use the 'started' qc state and why can't I find any usage anywhere.
+// String[] qcStateColumns = new String[]{"rowid"};
+// SimpleFilter qcStateFilter = new SimpleFilter("label", "Started", CompareType.EQUAL);
+// ArrayList> startedQcStateResult = notificationToolkit.getTableMultiRowMultiColumnWithFieldKeys(getContainer(), getUser(), "ehr", "status", qcStateFilter, null, qcStateColumns);
+// if (startedQcStateResult != null || startedQcStateResult.isEmpty()) {
+// qcStateStarted = Integer.parseInt(startedQcStateResult.get(0).get("rowid"));
+// }
+
+
+ // 2. Gets passed-in data.
+ // 2a. Verifies an object with data was passed in.
+ JSONObject inputJson = form.getJsonObject();
+ if (inputJson == null) {
+ response.put("detailedResponse", "No JSON payload provided.");
+ return response;
+ }
+ // 2b. Verifies passed-in object has rows.
+ if (!inputJson.has("rows") || inputJson.getJSONArray("rows").isEmpty()) {
+ response.put("detailedResponse", "No rows provided for the update.");
+ return response;
+ }
+ // 2c. Converts the JSONArray to the row map our loop expects.
+ List