Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
[FEMR-117] Prevented users from entering conflicting age information
about a patient
[FEMR-280] Added specific message when age and age group are conflicting
[FEMR-71] Allowed entering only 1 value for height to save a patient
[FEMR-21] Enhanced height input to convert large inch/cm values to
feet/m
[FEMR-360] Added range values to vital validation, showing errors when
out of range values were entered
Added files to support manual deployment with AWS CodeBuild and ElasticBeanstalk
  • Loading branch information
kdunlap committed Jul 25, 2019
1 parent 8a3b958 commit 19f7a0e
Show file tree
Hide file tree
Showing 27 changed files with 468 additions and 209 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Expand Up @@ -42,3 +42,5 @@ credentials.yml
util/PhotoMigration$Photo.class
util/PhotoMigration.class

#development database
docker-compose.yml
4 changes: 2 additions & 2 deletions app/femr/ui/controllers/TriageController.java
Expand Up @@ -155,8 +155,8 @@ public Result indexPopulatedGet(int patientId) {
*/
public Result indexPost(int id) {

final Form<IndexViewModelPost> IndexViewModelForm = formFactory.form(IndexViewModelPost.class);
IndexViewModelPost viewModel = IndexViewModelForm.bindFromRequest().get();
final Form<IndexViewModelPost> IndexViewModelForm = formFactory.form(IndexViewModelPost.class).bindFromRequest();
IndexViewModelPost viewModel = IndexViewModelForm.get();
CurrentUser currentUser = sessionService.retrieveCurrentUserSession();

//create a new patient
Expand Down
2 changes: 0 additions & 2 deletions app/femr/ui/models/triage/IndexViewModelPost.java
Expand Up @@ -248,8 +248,6 @@ public String getIsDiabetesScreenPerformed() {
return isDiabetesScreenPerformed;
}

// Osman

public Integer getSmoker() {return smoker;}
public void setSmoker(Integer smoker){this.smoker = smoker;}

Expand Down
115 changes: 61 additions & 54 deletions app/femr/ui/views/medical/newVitals.scala.html
Expand Up @@ -3,32 +3,34 @@
<link rel="stylesheet" href="@assets.path("css/medical/newVitals.css")" xmlns="http://www.w3.org/1999/xhtml">
<script type="text/javascript" src="@assets.path("js/medical/newVitals.js")"></script>
<script type="text/javascript" src="@assets.path("js/shared/vitalClientValidation.js")"></script>
<div id="all">
<div id="vitalContainer">

<div id="left">
<label>BP</label>
<br/>
<input type="number" class="fInput" id="newSystolic" placeholder="systolic"/>
<input type="number" class="fInput" id="newDiastolic" placeholder="diastolic"/>
<br/>
<label>HR</label>
<br/>
<input type="number" class="fInput" id="newHeartRate" placeholder="bpm"/>
<br/>
<label>T</label>
<br/>
@if(viewModel.getSettings.isMetric) { <!--- Alaa Serhan -->
<input type="number" class="fInput" id="newTemperature" placeholder="C"/>
} else {
<input type="number" class="fInput" id="newTemperature" placeholder="F"/>
}
<br/>
<label>RR</label>
<br/>
<input type="number" class="fInput" id="newRespiratoryRate" placeholder="bpm"/>

<!--Osman-->
<br/>
<div class="vitalWrap">
<label>BP</label>
<br/>
<input type="number" class="fInput" id="newSystolic" placeholder="systolic"/>
<input type="number" class="fInput" id="newDiastolic" placeholder="diastolic"/>
</div>
<div class="vitalWrap">
<label>HR</label>
<br/>
<input type="number" class="fInput" id="newHeartRate" placeholder="bpm"/>
</div>
<div class="vitalWrap">
<label>T</label>
<br/>
@if(viewModel.getSettings.isMetric) { <!--- Alaa Serhan -->
<input type="number" class="fInput" id="newTemperature" placeholder="C"/>
} else {
<input type="number" class="fInput" id="newTemperature" placeholder="F"/>
}
</div>
<div class="vitalWrap">
<label>RR</label>
<br/>
<input type="number" class="fInput" id="newRespiratoryRate" placeholder="bpm"/>
</div>
<label class="btn btn-default" for="newSmoker">Smoking
<input type="checkbox" class="fButton" id="newSmoker" name="smoker" value="1" />
</label>
Expand All @@ -45,36 +47,41 @@

</div>
<div id="right">
<label>Gluc</label>
<br/>
<input type="number" class="fInput" id="newGlucose" placeholder="mg/dl"/>
<br/>
<label>SpO2</label>
<br/>
<input type="number" class="fInput" id="newOxygen" placeholder="%"/>
<br/>
<label>Ht</label>
<br/>
@if(viewModel.getSettings.isMetric) { <!--- Alaa Serhan -->
<input type="number" class="fInput" id="newHeightFeet" placeholder="m"/>
<input type="number" class="fInput" id="newHeightInches" placeholder="cm"/>
} else {
<input type="number" class="fInput" id="newHeightFeet" placeholder="ft"/>
<input type="number" class="fInput" id="newHeightInches" placeholder="in"/>
}
<br/>
<label>Wt</label>
<br/>
@if(viewModel.getSettings.isMetric) { <!--- Alaa Serhan -->
<input type="number" class="fInput" id="newWeight" placeholder="kgs"/>
} else {
<input type="number" class="fInput" id="newWeight" placeholder="lbs"/>
}
<br/>
<label>WP</label> <!--- Sam Zanni -->
<br/>
<input type="number" class="fInput" id="weeksPreg" placeholder="weeks"/>
<br/>
<div class="vitalWrap">
<label>Gluc</label>
<br/>
<input type="number" class="fInput" id="newGlucose" placeholder="mg/dl"/>
</div>
<div class="vitalWrap">
<label>SpO2</label>
<br/>
<input type="number" class="fInput" id="newOxygen" placeholder="%"/>
</div>
<div class="vitalWrap">
<label>Ht</label>
<br/>
@if(viewModel.getSettings.isMetric) { <!--- Alaa Serhan -->
<input type="number" class="fInput" id="newHeightFeet" placeholder="m"/>
<input type="number" class="fInput" id="newHeightInches" placeholder="cm"/>
} else {
<input type="number" class="fInput" id="newHeightFeet" placeholder="ft"/>
<input type="number" class="fInput" id="newHeightInches" placeholder="in"/>
}
</div>
<div class="vitalWrap">
<label>Wt</label>
<br/>
@if(viewModel.getSettings.isMetric) { <!--- Alaa Serhan -->
<input type="number" class="fInput" id="newWeight" placeholder="kgs"/>
} else {
<input type="number" class="fInput" id="newWeight" placeholder="lbs"/>
}
</div>
<div class="vitalWrap">
<label>WP</label> <!--- Sam Zanni -->
<br/>
<input type="number" class="fInput" id="weeksPreg" placeholder="weeks"/>
</div>
</div>
<div id="theButtons">
<button type="button" id="saveVitalsBtn" class="fButton">Save</button>
Expand Down
2 changes: 1 addition & 1 deletion app/femr/ui/views/partials/triage/inputButton.scala.html
Expand Up @@ -9,7 +9,7 @@
} else {
@if(Boolean2boolean(active)) {
<label class="btn btn-primary active disabled width-50">
<input type="radio" name="@forInput" id="@id" value="@value">
<input type="radio" name="@forInput" id="@id" value="@value" checked="checked">
@name
</label>
} else {
Expand Down
4 changes: 2 additions & 2 deletions app/femr/ui/views/partials/triage/inputDate.scala.html
@@ -1,10 +1,10 @@
@(name: String, forInput: String, value: Date)
@(name: String, forInput: String, value: Date, max: Date=new Date())
@inputBlock = {
<div class="generalInfoInput">
<label for="@forInput">@name</label>

@if(value == null) {
<input type="date" class="fInput" id="@forInput" name="@forInput" placeholder="yyyy-mm-dd">
<input type="date" class="fInput" id="@forInput" name="@forInput" placeholder="yyyy-mm-dd" @if(max != null){ max="@max.format("yyyy-MM-dd")" }>
} else {
<input type="date" class="fInput" id="readOnlyBirthDate" name="@forInput" value="@value.format("yyyy-MM-dd")" readonly/>
}
Expand Down
2 changes: 1 addition & 1 deletion app/femr/ui/views/partials/triage/inputGender.scala.html
Expand Up @@ -2,7 +2,7 @@
@import femr.ui.views.html.partials.triage.inputButton
@inputBlock = {
<div class="generalInfoInput">
<label>Gender</label>
<label>Gender <span class="red bold">*</span></label>
<div class="btn-group" id="genderBtns" data-toggle="buttons">
@inputButton("Male", "sex", "maleBtn",
if(viewModel != null) viewModel.getPatient.getSex == "" || viewModel.getPatient.getSex == null else true,
Expand Down
9 changes: 6 additions & 3 deletions app/femr/ui/views/triage/index.scala.html
Expand Up @@ -39,7 +39,7 @@
}
<h2 class="text-center">Check In - Triage</h2>

@helper.form(action = TriageController.indexPost(viewModel.getPatient.getId), 'class -> "form-horizontal", 'enctype -> "multipart/form-data") {
@helper.form(action = TriageController.indexPost(viewModel.getPatient.getId), 'class -> "form-horizontal triage-form", 'enctype -> "multipart/form-data") {
<div id="genInfoWrap" class="sectionBackground backgroundForWrap">

<input class="hidden" type="text" id="patientId" value="@viewModel.getPatient.getId" />
Expand All @@ -63,6 +63,9 @@ <h2>General Info</h2>

<div id="ageClassificationWrap">
<label>Age<span class="red bold">*</span></label>

<label id="conflictingAgeMessage" class="error-message" style="display: none">Birth Date and Age group are conflicting</label>

@inputAge("Age", "Years", "years", "Months", "months", if(viewModel != null) viewModel.getPatient else null)
<span class="orSpan">OR</span>
@inputDate("Birth Date", "age", if(viewModel != null) viewModel.getPatient.getBirth else null)
Expand Down Expand Up @@ -204,10 +207,10 @@ <h2>Vitals</h2>
<div class="doubleVital">
@if(viewModel.getSettings.isMetric) { <!--- Alaa Serhan -->
<input type="number" step="number" min="0" class="fInput" id="@viewModel.getVitalNames.get(4).getName" placeholder="Meters" name="@viewModel.getVitalNames.get(4).getName"/>
<input type="number" step="number" min="0" max="99" class="fInput" id="@viewModel.getVitalNames.get(5).getName" placeholder="Centimeters" name="@viewModel.getVitalNames.get(5).getName"/>
<input type="number" step="number" min="0" class="fInput" id="@viewModel.getVitalNames.get(5).getName" placeholder="Centimeters" name="@viewModel.getVitalNames.get(5).getName"/>
} else {
<input type="number" step="number" min="0" class="fInput" id="@viewModel.getVitalNames.get(4).getName" placeholder="Feet" name="@viewModel.getVitalNames.get(4).getName"/>
<input type="number" step="number" min="0" max="11" class="fInput" id="@viewModel.getVitalNames.get(5).getName" placeholder="Inches" name="@viewModel.getVitalNames.get(5).getName"/>
<input type="number" step="number" min="0" class="fInput" id="@viewModel.getVitalNames.get(5).getName" placeholder="Inches" name="@viewModel.getVitalNames.get(5).getName"/>
}
</div>
</div>
Expand Down
31 changes: 31 additions & 0 deletions ci/aws/README.md
@@ -0,0 +1,31 @@

## `dist` Folder
- manually put in S3 for now, maybe track in a repo later
- mirror femr defaults, but configurable via ENV vars
- Folder Structure
- `public/img/defaultProfile.png`
- `Uploads/CSV`
- `Procfile` - tells EB how to run the app
- `web: ./bin/femr -Dhttp.port=5000 -Dconfig.file=conf/demo.conf`


## Code Pipeline Setup
- Code Build
- buildspec.yml: what does it do
- Setup environment
- run tests
- run build
- package build artifacts
- start EB deployment
- How to setup initially
- manually add buildsepc: `ci/aws/buildspec.yml`
- Secondary Sources: `DistFolder` name in setup matters?
- Approval Step

## Elastic Beanstalk Setup
- How the deployment works, what tasks are performed
- How to setup in EB initially


## TODO
- run this whole thing with code files and remove manual setups
20 changes: 20 additions & 0 deletions ci/aws/buildspec.yml
@@ -0,0 +1,20 @@
version: 0.2

phases:
install:
runtime-versions:
java: openjdk8
pre_build:
commands:
- sbt test
build:
commands:
- sbt clean compile dist
post_build:
commands:
- unzip $CODEBUILD_SRC_DIR/target/universal/femr-*.zip -d $CODEBUILD_SRC_DIR
- cp -R $CODEBUILD_SRC_DIR_DistFolder/dist/* $CODEBUILD_SRC_DIR/femr-*
- cd $CODEBUILD_SRC_DIR/femr-* && mkdir -p Upload/CSV
artifacts:
files:
- femr-*/**/*
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
24 changes: 24 additions & 0 deletions conf/demo.conf
@@ -0,0 +1,24 @@
include "application.conf"

# Should be set to the EB hostname
#play.filters.hosts {
# allowed = ["localhost:5000", "127.0.0.1:5000", "femr-demo.us-east-1.elasticbeanstalk.com"]
#}

default.admin.username=${?DEFAULT_ADMIN_USERNAME}
default.admin.password=${?DEFAULT_ADMIN_PASSWORD}

default.superuser.username=${?DEFAULT_SUPERUSER_USERNAME}
default.superuser.password=${?DEFAULT_SUPERUSER_PASSWORD}
play.http.secret.key=${?PLAY_HTTP_SECRET_KEY}

db.default.url=${?DB_DEFAULT_URL}
db.default.username=${?DB_DEFAULT_USERNAME}
db.default.password=${?DB_DEFAULT_PASSWORD}

# If needed, but EB will default to application.conf values
photos.useDbStorage=${?PHOTOS_USE_DB_STORAGE}
photos.path=${?PHOTOS_PATH}
photos.encounterPath=${?PHOTOS_ENCOUNTER_PATH}
photos.defaultProfilePhoto=${?DEFAULT_PROFILE_PHOTO}
csv.path=${?CSV_PATH}
20 changes: 20 additions & 0 deletions public/css/medical/newVitals.css
Expand Up @@ -22,4 +22,24 @@ input {
.ui-widget-header {
background: none;
border: none;
}

#newVitalsDialog label{
margin-bottom: 3px;
}

#newVitalsDialog .has-errors label{
color: red;
}

#newVitalsDialog .has-errors label.range-message{
padding-left: 10px;
font-size: 0.85em;
margin: 2px 0;
clear: both;
}

#newVitalsDialog .has-errors input,
#newVitalsDialog .has-errors select{
border-color: red;
}
27 changes: 27 additions & 0 deletions public/css/triage.css
Expand Up @@ -129,6 +129,33 @@
overflow: hidden;
}

.triage-form .error-message{
display: block;
color: red;
text-align: center;
border: 1px solid red;
padding: 5px;
border-radius: 4px;
background-color: #f7dddd;
margin: 0 auto;
}

.triage-form .has-errors label{
color: red;
}

.triage-form .has-errors label.range-message{
padding-left: 10px;
font-size: 0.85em;
margin: 2px 0;
clear: both;
}

.triage-form .has-errors input,
.triage-form .has-errors select{
border-color: red;
}

.generalInfoInput input[type="text"], input[type="tel"], .generalInfoInput input[type="date"] {
float: right;
margin-right: 120px;
Expand Down

0 comments on commit 19f7a0e

Please sign in to comment.