From 257d796ee1d6e067a3226ebe2d47290f610d8b07 Mon Sep 17 00:00:00 2001 From: tangollama Date: Tue, 15 Mar 2016 13:18:34 -0700 Subject: [PATCH 01/56] Patient Note object. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now, we’re associating to a visit always. --- app/models/patient-note.js | 54 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 app/models/patient-note.js diff --git a/app/models/patient-note.js b/app/models/patient-note.js new file mode 100644 index 0000000000..20fdd83660 --- /dev/null +++ b/app/models/patient-note.js @@ -0,0 +1,54 @@ +import AbstractModel from 'hospitalrun/models/abstract'; +import DS from 'ember-data'; + +export default AbstractModel.extend({ + //if the note was written by one person but dictated / given on behalf of another, otherwise, this and createdBy are the same + attribution: DS.attr('string'), + content: DS.attr('string'), + createdBy: DS.attr('string'), + date: DS.attr('date'), + //custom list of noteTypes of mixins/patient-note-types + noteType: DS.attr(), + //who is this note about? + patient: DS.belongsTo('patient', { + async: false + }), + //if this note is related to a visit, make sure it's noted. + visit: DS.belongsTo('visit', { + async: false + }), + //if this note is related to an appointment, make sure it's noted. + appointment: DS.belongsTo('appointment', { + async: false + }), + //if this note is related to an imaging request, make sure it's noted. + imaging: DS.belongsTo('imaging', { + async: false + }), + //if this note is related to a lab, make sure it's noted. + lab: DS.belongsTo('lab', { + async: false + }), + //if this note is related to a medication request, make sure it's noted. + medication: DS.belongsTo('medication', { + async: false + }), + //if this note is related to a procedure, make sure it's noted. + procedure: DS.belongsTo('procedure', { + async: false + }), + validations: { + patient: { + presence: true + }, + visit: { + presence: true + }, + noteType: { + presence: true + }, + content: { + presence: true + } + } +}); \ No newline at end of file From 2cb0949abccdfb65ce4db6b09adb0848e4004c33 Mon Sep 17 00:00:00 2001 From: tangollama Date: Wed, 16 Mar 2016 08:35:04 -0700 Subject: [PATCH 02/56] add_note label --- app/locales/en/translations.js | 1 + 1 file changed, 1 insertion(+) diff --git a/app/locales/en/translations.js b/app/locales/en/translations.js index 4e73eb5137..0ec403bbb4 100644 --- a/app/locales/en/translations.js +++ b/app/locales/en/translations.js @@ -178,6 +178,7 @@ export default { delete: 'Delete', new_user: 'New User', add_value: 'Add Value', + add_note: 'Add Note', import: 'Import', load_file: 'Load File', new_request: 'New Request', From 591f41685927132c31f2bd3fa13451b8b21bcfa1 Mon Sep 17 00:00:00 2001 From: tangollama Date: Wed, 16 Mar 2016 08:35:25 -0700 Subject: [PATCH 03/56] add and delete note permissions --- app/mixins/user-session.js | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/app/mixins/user-session.js b/app/mixins/user-session.js index be01bed744..faa4e285e8 100644 --- a/app/mixins/user-session.js +++ b/app/mixins/user-session.js @@ -437,6 +437,20 @@ export default Ember.Mixin.create({ users: [ 'User Administrator', 'System Administrator' + ], + add_note: [ + 'Doctor', + 'Medical Records Officer', + 'Nurse', + 'Nurse Manager', + 'Patient Administration', + 'System Administrator' + ], + delete_note: [ + 'Medical Records Officer', + 'Nurse Manager', + 'Patient Administration', + 'System Administrator' ] }, From 2afedfba6cd20ac4a42a47a12d0e81db81292959 Mon Sep 17 00:00:00 2001 From: tangollama Date: Wed, 16 Mar 2016 10:54:36 -0700 Subject: [PATCH 04/56] Initial Patient History and Patient Notes Checked in for collaboration purposes. --- app/locales/en/translations.js | 15 ++++- app/mixins/patient-notes.js | 50 +++++++++++++++ app/models/patient-note.js | 10 ++- app/models/visit.js | 2 + app/patients/edit/controller.js | 3 +- app/patients/edit/template.hbs | 106 ++++++++++++++++++++++++++++++- app/patients/notes/controller.js | 46 ++++++++++++++ app/patients/notes/template.hbs | 27 ++++++++ app/visits/edit/controller.js | 10 ++- 9 files changed, 261 insertions(+), 8 deletions(-) create mode 100644 app/mixins/patient-notes.js create mode 100644 app/patients/notes/controller.js create mode 100644 app/patients/notes/template.hbs diff --git a/app/locales/en/translations.js b/app/locales/en/translations.js index 0ec403bbb4..49a521a512 100644 --- a/app/locales/en/translations.js +++ b/app/locales/en/translations.js @@ -95,6 +95,7 @@ export default { } }, labels: { + cptcode: 'CPT Code', name: 'Name', patient: 'Patient', quantity: 'Quantity', @@ -110,6 +111,9 @@ export default { action: 'Action', notes: 'Notes', edit: 'Edit', + image_orders: 'Image Orders', + lab_orders: 'Lab Orders', + patient_history: 'Patient History', imaging_type: 'Imaging Type', result: 'Result', results: 'Results', @@ -117,6 +121,7 @@ export default { requests: 'Requests', completed: 'Completed', id: 'Id', + on: 'on', sex: 'Sex', age: 'Age', username: 'Username', @@ -153,7 +158,11 @@ export default { location: 'Location', provider: 'Provider', with: 'With', - all_day: 'All Day' + all_day: 'All Day', + physician: 'Physician', + assisting: 'Assisting', + anesthesia: 'Anesthesia', + procedures: 'Procedures' }, messages: { no_items_found: 'No items found.', @@ -163,7 +172,9 @@ export default { are_you_sure_delete: 'Are you sure you wish to delete the user {{user}}?', user_has_been_saved: 'The user has been saved.', user_saved: 'User Saved', - new_patient_has_to_be_created: 'A new patient needs to be created...Please wait..' + on_behalf_of: 'on behalf of', + new_patient_has_to_be_created: 'A new patient needs to be created...Please wait..', + no_notes_available: 'No notes available for this visit.' }, alerts: { please_wait: 'Please Wait' diff --git a/app/mixins/patient-notes.js b/app/mixins/patient-notes.js new file mode 100644 index 0000000000..6f555076c1 --- /dev/null +++ b/app/mixins/patient-notes.js @@ -0,0 +1,50 @@ +import Ember from 'ember'; + +export default Ember.Mixin.create({ + + canAddNote: function() { + return this.currentUserCan('add_note'); + }, + + canDeleteNote: function() { + return this.currentUserCan('delete_note'); + }, + + _computeNoteType: function(visit) { + switch (visit.get('visitType')) { + case 'Admission': + if (Ember.isEmpty(visit.get('procedure')) { + return 'Pre-op'; + } else { + return 'Post-op'; + } + break; + case 'Clinic': + case 'Followup': + return 'General'; + break; + default: + return visit.get('visitType'); + break; + } + }, + + _setNoteType: function() { + var model = this.get('model'); + if (model.get('noteType') == null) { + model.set('noteType', this._computeNoteType(model.get('visit'))); + } + }, + + actions: { + showAddPatientNote: function(model) { + if (Ember.isEmpty(model)) { + model = this.get('store').createRecord('patient-note', { + patient: this.get('model') + }); + } + this.send('openModal', 'patients.notes', model); + } + } + +}); diff --git a/app/models/patient-note.js b/app/models/patient-note.js index 20fdd83660..976f77f23f 100644 --- a/app/models/patient-note.js +++ b/app/models/patient-note.js @@ -1,11 +1,19 @@ +import { translationMacro as t } from 'ember-i18n'; import AbstractModel from 'hospitalrun/models/abstract'; import DS from 'ember-data'; export default AbstractModel.extend({ + authoredBy: function() { + if (!Ember.isEmpty(this.get('attribution')) { + return this.get('attribution')+' '+i18n.t('messages.on_behalf_of')+' '+this.get('createdBy'); + } else { + return this.get('createdBy'); + } + }.property('attribution', 'createdBy'), //if the note was written by one person but dictated / given on behalf of another, otherwise, this and createdBy are the same attribution: DS.attr('string'), content: DS.attr('string'), - createdBy: DS.attr('string'), + createdBy: DS.attr('string'), date: DS.attr('date'), //custom list of noteTypes of mixins/patient-note-types noteType: DS.attr(), diff --git a/app/models/visit.js b/app/models/visit.js index 9b26298205..19e8aec008 100644 --- a/app/models/visit.js +++ b/app/models/visit.js @@ -33,7 +33,9 @@ export default AbstractModel.extend({ labs: DS.hasMany('lab', { async: true }), location: DS.attr('string'), medication: DS.hasMany('medication', { async: true }), + //this field is being deprecated in favor of patient-note notes: DS.attr('string'), + patientNotes: DS.hasMany('patient-note', { async: true }), outPatient: DS.attr('boolean'), patient: DS.belongsTo('patient', { async: false diff --git a/app/patients/edit/controller.js b/app/patients/edit/controller.js index b3b38a8b94..3aca4d5f32 100644 --- a/app/patients/edit/controller.js +++ b/app/patients/edit/controller.js @@ -1,10 +1,11 @@ import AbstractEditController from 'hospitalrun/controllers/abstract-edit-controller'; import BloodTypes from 'hospitalrun/mixins/blood-types'; import Ember from 'ember'; +import PatientNotes from 'hospitalrun/mixins/patient-notes'; import ReturnTo from 'hospitalrun/mixins/return-to'; import SelectValues from 'hospitalrun/utils/select-values'; import UserSession from 'hospitalrun/mixins/user-session'; -export default AbstractEditController.extend(BloodTypes, ReturnTo, UserSession, { +export default AbstractEditController.extend(BloodTypes, ReturnTo, UserSession, PatientNotes, { canAddAppointment: function() { return this.currentUserCan('add_appointment'); }.property(), diff --git a/app/patients/edit/template.hbs b/app/patients/edit/template.hbs index 30b45edcf7..5190b9f24e 100644 --- a/app/patients/edit/template.hbs +++ b/app/patients/edit/template.hbs @@ -1,9 +1,10 @@ {{#edit-panel editPanelProps=editPanelProps}} {{#em-form model=model submitButton=false bubbles=false }} {{#unless isNewOrDeleted}} - {{patient-summary patient=model visits=model.visits patientProcedures=patientProcedures disablePatientLink=true }} + {{patient-summary patient=model visits=model.visits patientProcedures=patientProcedures disablePatientLink=true store=store }} {{/unless}}
-
+ {{#unless isNewOrDeleted}} +
+
+
+

+ {{t 'labels.patient_history'}} + {{#if canAddNote}} + + {{/if}} +

+
+
+ {{#each model.visits as |visit|}} +
+

{{visit.visitType}} {{t 'labels.on'}} {{visit.visitDate}}

+ {{#if visit.history}} +
+
History
+ {{visit.history}} +
+ {{/if}} + {{#if visit.historySince}} +
+
History Since
+ {{visit.historySince}} +
+ {{/if}} + {{#if visit.procedures}} +
+
{{t 'labels.procedures' }}
+ {{#each visit.procedures as |procedure|}} +
+
{{date-format procedure.procedureDate}}: + {{#if procedure.cptCode}} + [{{t 'labels.cptcode' }} - {{procedure.cptCode}}] + {{/if}} + {{procedure.description}} +
+
+ {{t 'labels.physician'}}: {{procedure.physician}} + {{#if procedure.assistant}} + , {{t 'labels.assisting'}}: {{procedure.assistant}} + {{/if}} + {{#if procedure.anesthesiologist}} + , {{t 'labels.anesthesia'}}: {{procedure.anesthesiologist}} + {{/if}} +
+ {{procedure.notes}} +
+ {{/each}} +
+ {{/if}} + {{#if visit.imaging}} +
+
{{t 'labels.image_orders' }}
+ {{#each visit.imaging as |imaging|}} +
+
{{date-format imaging.imagingDate}}: {{imaging.imagingType.name}}
+
{{imaging.result}}
+
{{imaging.notes}}
+
+ {{/each}} +
+ {{/if}} + {{#if visit.labs}} +
+
{{t 'labels.lab_orders' }}
+ {{#each visit.labs as |lab|}} +
+
{{date-format lab.labDate}}: {{lab.labType.name}}
+
{{lab.result}}
+
{{lab.notes}}
+
+ {{/each}} +
+ {{/if}} + {{#if visit.patientNotes}} +
+
{{t 'labels.notes'}}
+ {{#each visit.patientNotes as |note|}} +
+
{{note.authoredBy}}
+ {{date-format note.date}}[{{note.noteType}}]: {{note.content}} +
+ {{/each}} +
+ {{else}} +
+ {{t 'messages.no_notes_available'}} +
+ {{/if}} +
+ {{/each}} +
+
+
+ {{/unless}} +

diff --git a/app/patients/notes/controller.js b/app/patients/notes/controller.js new file mode 100644 index 0000000000..07aab691b1 --- /dev/null +++ b/app/patients/notes/controller.js @@ -0,0 +1,46 @@ +import AbstractEditController from 'hospitalrun/controllers/abstract-edit-controller'; +import Ember from 'ember'; +import IsUpdateDisabled from 'hospitalrun/mixins/is-update-disabled'; +import PatientSubmodule from 'hospitalrun/mixins/patient-submodule'; +import PatientNotes from 'hospitalrun/mixins/patient-notes'; +import SelectValues from 'hospitalrun/utils/select-values'; +import UserSession from 'hospitalrun/mixins/user-session'; +export default AbstractEditController.extend(IsUpdateDisabled, UserSession, PatientSubmodule, PatientNotes, { + cancelAction: 'closeModal', + //editController: Ember.inject.controller('patients/edit'), + physicianList: Ember.computed.map('patientsController.physicianList.value', SelectValues.selectValuesMap), + title: function() { + if (this.get('model.isNew')) { + return 'New Note for ' + this.get('model.patient.displayName'); + } else { + return 'Updating Note from '+(moment(this.get('model.date')).format('MM/DD/YYYY'))+' for ' + this.get('model.patient.displayName'); + } + }.property('model.patient.displayName'), + updateCapability: 'add_note', + beforeUpdate: function() { + this.set('model.date', new Date()); + this.set('model.createdBy', this.getUserName()); + return Ember.RSVP.Promise.resolve(); + }, + afterUpdate: function() { + //this.get('editController').send('updateNote', this.get('model')); + this.send(this.get('cancelAction')); + }, + actions: { + changeVisit: function() { + const selectEl = $('select[name="note-visits"]')[0]; + const selectedIndex = selectEl.selectedIndex; + const content = this.get('patientVisitsForSelect'); + + // decrement index by 1 if we have a prompt + const contentIndex = selectedIndex - 1; + + const selection = content[contentIndex].selectObject; + + // set the local, shadowed selection to avoid leaking + // changes to `selection` out via 2-way binding + this.get('model').set('visit', selection); + this._setNoteType(); + } + } +}); \ No newline at end of file diff --git a/app/patients/notes/template.hbs b/app/patients/notes/template.hbs new file mode 100644 index 0000000000..1bde360d80 --- /dev/null +++ b/app/patients/notes/template.hbs @@ -0,0 +1,27 @@ +{{#modal-dialog + hideCancelButton=hideCancelButton + hideUpdateButton=hideUpdateButton + isUpdateDisabled=isUpdateDisabled + title=title + updateButtonAction=updateButtonAction + updateButtonText=updateButtonText }} + {{#em-form model=model submitButton=false }} + {{em-text label="Note" property="content" rows=3}} + + + + {{em-select className="col-sm-3" property="attribution" + label="On Behalf Of" content=physicianList prompt=" " + }} + {{/em-form}} +{{/modal-dialog}} \ No newline at end of file diff --git a/app/visits/edit/controller.js b/app/visits/edit/controller.js index 2c234a5d70..3814ddf484 100644 --- a/app/visits/edit/controller.js +++ b/app/visits/edit/controller.js @@ -1,12 +1,13 @@ import AbstractEditController from 'hospitalrun/controllers/abstract-edit-controller'; import ChargeActions from 'hospitalrun/mixins/charge-actions'; import Ember from 'ember'; +import PatientNotes from 'hospitalrun/mixins/patient-notes'; import PatientSubmodule from 'hospitalrun/mixins/patient-submodule'; import SelectValues from 'hospitalrun/utils/select-values'; import UserSession from 'hospitalrun/mixins/user-session'; import VisitTypes from 'hospitalrun/mixins/visit-types'; -export default AbstractEditController.extend(ChargeActions, PatientSubmodule, UserSession, VisitTypes, { +export default AbstractEditController.extend(ChargeActions, PatientSubmodule, PatientNotes, UserSession, VisitTypes, { visitsController: Ember.inject.controller('visits'), canAddAppointment: function() { @@ -273,6 +274,13 @@ export default AbstractEditController.extend(ChargeActions, PatientSubmodule, Us }); this.send('openModal', 'visits.vitals.edit', newVitals); }, + + showAddPatientNote: function(model) { + if (Ember.isEmpty(model)) { + model = this.get('store').createRecord('patient-note', { patient: this.get('model') }); + } + this.send('openModal', 'patients.notes', model); + }, newAppointment: function() { this._addChildObject('appointments.edit'); From 5c962b81b5c04803fa064cd08242a32ed9bf00ad Mon Sep 17 00:00:00 2001 From: tangollama Date: Wed, 16 Mar 2016 11:16:17 -0700 Subject: [PATCH 05/56] bug is bad --- app/mixins/patient-notes.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/mixins/patient-notes.js b/app/mixins/patient-notes.js index 6f555076c1..fbb7514fc4 100644 --- a/app/mixins/patient-notes.js +++ b/app/mixins/patient-notes.js @@ -13,7 +13,7 @@ export default Ember.Mixin.create({ _computeNoteType: function(visit) { switch (visit.get('visitType')) { case 'Admission': - if (Ember.isEmpty(visit.get('procedure')) { + if (Ember.isEmpty(visit.get('procedure'))) { return 'Pre-op'; } else { return 'Post-op'; From b74f4d0a6b4642721294cc0d5a8713155dfac2ee Mon Sep 17 00:00:00 2001 From: tangollama Date: Wed, 16 Mar 2016 11:35:00 -0700 Subject: [PATCH 06/56] missing paren --- app/models/patient-note.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/patient-note.js b/app/models/patient-note.js index 976f77f23f..57e878dd05 100644 --- a/app/models/patient-note.js +++ b/app/models/patient-note.js @@ -4,7 +4,7 @@ import DS from 'ember-data'; export default AbstractModel.extend({ authoredBy: function() { - if (!Ember.isEmpty(this.get('attribution')) { + if (!Ember.isEmpty(this.get('attribution'))) { return this.get('attribution')+' '+i18n.t('messages.on_behalf_of')+' '+this.get('createdBy'); } else { return this.get('createdBy'); From db759f115a1d7755c5ab0e712de3aada66ee19d0 Mon Sep 17 00:00:00 2001 From: tangollama Date: Wed, 16 Mar 2016 11:37:26 -0700 Subject: [PATCH 07/56] Cleanup from JSHint --- app/mixins/patient-notes.js | 2 -- app/models/patient-note.js | 4 ++-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/app/mixins/patient-notes.js b/app/mixins/patient-notes.js index fbb7514fc4..7b242687c5 100644 --- a/app/mixins/patient-notes.js +++ b/app/mixins/patient-notes.js @@ -22,10 +22,8 @@ export default Ember.Mixin.create({ case 'Clinic': case 'Followup': return 'General'; - break; default: return visit.get('visitType'); - break; } }, diff --git a/app/models/patient-note.js b/app/models/patient-note.js index 57e878dd05..26b43965ac 100644 --- a/app/models/patient-note.js +++ b/app/models/patient-note.js @@ -1,11 +1,11 @@ import { translationMacro as t } from 'ember-i18n'; import AbstractModel from 'hospitalrun/models/abstract'; +import Ember from 'ember'; import DS from 'ember-data'; - export default AbstractModel.extend({ authoredBy: function() { if (!Ember.isEmpty(this.get('attribution'))) { - return this.get('attribution')+' '+i18n.t('messages.on_behalf_of')+' '+this.get('createdBy'); + return this.get('attribution')+' '+t('messages.on_behalf_of')+' '+this.get('createdBy'); } else { return this.get('createdBy'); } From ffb1744feab56bd1e94b3847d7d299466d91ca3d Mon Sep 17 00:00:00 2001 From: tangollama Date: Wed, 16 Mar 2016 12:36:38 -0700 Subject: [PATCH 08/56] fixing the show status for tabs in NEW --- app/patients/edit/template.hbs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/patients/edit/template.hbs b/app/patients/edit/template.hbs index 5190b9f24e..139ee1f777 100644 --- a/app/patients/edit/template.hbs +++ b/app/patients/edit/template.hbs @@ -115,7 +115,7 @@

{{/unless}} -
+

From 93065f227fe2c5919a133c732e9d8853a46f275a Mon Sep 17 00:00:00 2001 From: tangollama Date: Wed, 16 Mar 2016 16:09:02 -0700 Subject: [PATCH 09/56] Adding notes to visits now works. --- app/locales/en/translations.js | 28 ++++++ app/mixins/patient-notes.js | 11 --- app/patients/edit/controller.js | 9 ++ app/patients/edit/template.hbs | 156 ++++++++++++++++--------------- app/patients/notes/controller.js | 4 +- app/visits/edit/controller.js | 10 +- app/visits/edit/template.hbs | 80 ++++++++++++---- 7 files changed, 188 insertions(+), 110 deletions(-) diff --git a/app/locales/en/translations.js b/app/locales/en/translations.js index 49a521a512..a5b92f9e71 100644 --- a/app/locales/en/translations.js +++ b/app/locales/en/translations.js @@ -166,6 +166,7 @@ export default { }, messages: { no_items_found: 'No items found.', + no_history_available: 'No history available.', create_new_record: 'Create a new record?', create_new_user: 'Create a new user?', no_users_found: 'No users found.', @@ -293,5 +294,32 @@ export default { buttons: { new_button: '+ new appointment' } + }, + visits: { + edit: { + edit: 'Edit', + date: 'Date', + authored_by: 'Authored By', + note: 'Note', + notes: 'Notes', + new_note: 'New Note', + visit_information: 'Visit Information', + new_appointment: 'New Appointment', + add_diagnosis: 'Add Diagnosis', + diagnosis: 'Diagnosis', + delete: 'Delete', + procedure: 'Procedure', + procedures: 'Procedures', + new_procedure: 'New Procedure', + labs: 'Procedures', + new_lab: 'New Procedure', + imaging: 'Imaging', + new_imaging: 'New Imaging', + medication: 'Medication', + new_medication: 'New Medication' + } + }, + common: { + actions: 'Actions' } }; diff --git a/app/mixins/patient-notes.js b/app/mixins/patient-notes.js index 7b242687c5..ddecb44801 100644 --- a/app/mixins/patient-notes.js +++ b/app/mixins/patient-notes.js @@ -32,17 +32,6 @@ export default Ember.Mixin.create({ if (model.get('noteType') == null) { model.set('noteType', this._computeNoteType(model.get('visit'))); } - }, - - actions: { - showAddPatientNote: function(model) { - if (Ember.isEmpty(model)) { - model = this.get('store').createRecord('patient-note', { - patient: this.get('model') - }); - } - this.send('openModal', 'patients.notes', model); - } } }); diff --git a/app/patients/edit/controller.js b/app/patients/edit/controller.js index 3aca4d5f32..e3d08c4bf7 100644 --- a/app/patients/edit/controller.js +++ b/app/patients/edit/controller.js @@ -358,6 +358,15 @@ export default AbstractEditController.extend(BloodTypes, ReturnTo, UserSession, isNew: true }); }, + + showAddPatientNote: function(model) { + if (Ember.isEmpty(model)) { + model = this.get('store').createRecord('patient-note', { + patient: this.get('model') + }); + } + this.send('openModal', 'patients.notes', model); + }, showDeleteAppointment: function(appointment) { appointment.set('deleteFromPatient', true); diff --git a/app/patients/edit/template.hbs b/app/patients/edit/template.hbs index 139ee1f777..5f16336dc2 100644 --- a/app/patients/edit/template.hbs +++ b/app/patients/edit/template.hbs @@ -30,87 +30,91 @@

- {{#each model.visits as |visit|}} -
-

{{visit.visitType}} {{t 'labels.on'}} {{visit.visitDate}}

- {{#if visit.history}} -
-
History
- {{visit.history}} -
- {{/if}} - {{#if visit.historySince}} + {{#if model.visits}} + {{#each model.visits as |visit|}}
-
History Since
- {{visit.historySince}} -
- {{/if}} - {{#if visit.procedures}} -
-
{{t 'labels.procedures' }}
- {{#each visit.procedures as |procedure|}} -
-
{{date-format procedure.procedureDate}}: - {{#if procedure.cptCode}} - [{{t 'labels.cptcode' }} - {{procedure.cptCode}}] - {{/if}} - {{procedure.description}} -
-
- {{t 'labels.physician'}}: {{procedure.physician}} - {{#if procedure.assistant}} - , {{t 'labels.assisting'}}: {{procedure.assistant}} - {{/if}} - {{#if procedure.anesthesiologist}} - , {{t 'labels.anesthesia'}}: {{procedure.anesthesiologist}} - {{/if}} -
- {{procedure.notes}} -
- {{/each}} -
- {{/if}} - {{#if visit.imaging}} +

{{visit.visitType}} {{t 'labels.on'}} {{visit.visitDate}}

+ {{#if visit.history}}
-
{{t 'labels.image_orders' }}
- {{#each visit.imaging as |imaging|}} -
-
{{date-format imaging.imagingDate}}: {{imaging.imagingType.name}}
-
{{imaging.result}}
-
{{imaging.notes}}
-
- {{/each}} +
History
+ {{visit.history}}
- {{/if}} - {{#if visit.labs}} -
-
{{t 'labels.lab_orders' }}
- {{#each visit.labs as |lab|}} -
-
{{date-format lab.labDate}}: {{lab.labType.name}}
-
{{lab.result}}
-
{{lab.notes}}
-
- {{/each}} -
- {{/if}} - {{#if visit.patientNotes}} -
-
{{t 'labels.notes'}}
- {{#each visit.patientNotes as |note|}} -
-
{{note.authoredBy}}
- {{date-format note.date}}[{{note.noteType}}]: {{note.content}} -
- {{/each}} -
- {{else}} + {{/if}} + {{#if visit.historySince}}
- {{t 'messages.no_notes_available'}} +
History Since
+ {{visit.historySince}}
- {{/if}} -
- {{/each}} + {{/if}} + {{#if visit.procedures}} +
+
{{t 'labels.procedures' }}
+ {{#each visit.procedures as |procedure|}} +
+
{{date-format procedure.procedureDate}}: + {{#if procedure.cptCode}} + [{{t 'labels.cptcode' }} - {{procedure.cptCode}}] + {{/if}} + {{procedure.description}} +
+
+ {{t 'labels.physician'}}: {{procedure.physician}} + {{#if procedure.assistant}} + , {{t 'labels.assisting'}}: {{procedure.assistant}} + {{/if}} + {{#if procedure.anesthesiologist}} + , {{t 'labels.anesthesia'}}: {{procedure.anesthesiologist}} + {{/if}} +
+ {{procedure.notes}} +
+ {{/each}} +
+ {{/if}} + {{#if visit.imaging}} +
+
{{t 'labels.image_orders' }}
+ {{#each visit.imaging as |imaging|}} +
+
{{date-format imaging.imagingDate}}: {{imaging.imagingType.name}}
+
{{imaging.result}}
+
{{imaging.notes}}
+
+ {{/each}} +
+ {{/if}} + {{#if visit.labs}} +
+
{{t 'labels.lab_orders' }}
+ {{#each visit.labs as |lab|}} +
+
{{date-format lab.labDate}}: {{lab.labType.name}}
+
{{lab.result}}
+
{{lab.notes}}
+
+ {{/each}} +
+ {{/if}} + {{#if visit.patientNotes}} +
+
{{t 'labels.notes'}}
+ {{#each visit.patientNotes as |note|}} +
+
{{note.authoredBy}}
+ {{date-format note.date}}[{{note.noteType}}]: {{note.content}} +
+ {{/each}} +
+ {{else}} +
+ {{t 'messages.no_notes_available'}} +
+ {{/if}} +
+ {{/each}} + {{else}} + {{t 'messages.no_history_available''}} + {{/if}}
diff --git a/app/patients/notes/controller.js b/app/patients/notes/controller.js index 07aab691b1..4cbe2c119a 100644 --- a/app/patients/notes/controller.js +++ b/app/patients/notes/controller.js @@ -7,7 +7,7 @@ import SelectValues from 'hospitalrun/utils/select-values'; import UserSession from 'hospitalrun/mixins/user-session'; export default AbstractEditController.extend(IsUpdateDisabled, UserSession, PatientSubmodule, PatientNotes, { cancelAction: 'closeModal', - //editController: Ember.inject.controller('patients/edit'), + editController: Ember.inject.controller('visits/edit'), physicianList: Ember.computed.map('patientsController.physicianList.value', SelectValues.selectValuesMap), title: function() { if (this.get('model.isNew')) { @@ -23,7 +23,7 @@ export default AbstractEditController.extend(IsUpdateDisabled, UserSession, Pati return Ember.RSVP.Promise.resolve(); }, afterUpdate: function() { - //this.get('editController').send('updateNote', this.get('model')); + this.get('editController').send('updateNote', this.get('model')); this.send(this.get('cancelAction')); }, actions: { diff --git a/app/visits/edit/controller.js b/app/visits/edit/controller.js index 41f07182c2..61b32896a4 100644 --- a/app/visits/edit/controller.js +++ b/app/visits/edit/controller.js @@ -275,10 +275,18 @@ export default AbstractEditController.extend(ChargeActions, PatientSubmodule, Pa showAddPatientNote: function(model) { if (Ember.isEmpty(model)) { - model = this.get('store').createRecord('patient-note', { patient: this.get('model') }); + model = this.get('store').createRecord('patient-note', { + visit: this.get('model'), + patient: this.get('model').get('patient'), + noteType: this._computeNoteType(this.get('model')) + }); } this.send('openModal', 'patients.notes', model); }, + + updateNote: function(patientNote) { + this.send('update', true); + }, newAppointment: function() { this._addChildObject('appointments.edit'); diff --git a/app/visits/edit/template.hbs b/app/visits/edit/template.hbs index f21e50e17e..3ab30832fc 100644 --- a/app/visits/edit/template.hbs +++ b/app/visits/edit/template.hbs @@ -4,11 +4,11 @@

- Visit Information + {{t 'visits.edit.visit_information' }} {{#if canAddAppointment}} {{/if}}

@@ -60,7 +60,7 @@

- +

{{/if}} @@ -71,9 +71,9 @@ - - - + + + {{#each model.additionalDiagnoses as |diagnosis|}} @@ -82,7 +82,7 @@ @@ -92,7 +92,6 @@ {{/if}} {{em-text label="Patient History" property="history" rows=3 }} {{em-text label="History since last seen" property="historySince" rows=3 }} - {{em-text label="Notes" property="notes" rows=3 }} {{/em-form}} @@ -102,9 +101,50 @@ +
+
+
DateDiagnosisDelete{{t 'visits.edit.date' }}{{t 'visits.edit.diagnosis' }}{{t 'visits.edit.actions' }}
{{#if canDeleteDiagnosis}} {{/if}}
+ + + + + + + {{#each model.patientNotes as |note|}} + + + + + + + {{/each}} +
{{t 'visits.edit.date'}}{{t 'visits.edit.authored_by'}}{{t 'visits.edit.note'}}{{t 'common.actions'}}
{{date-format note.date}}{{note.authoredBy}}{{note.noteType}}: {{note.content}} + {{#if canAddNote}} + + {{/if}} + {{#if canDeleteNote}} + + {{/if}} +
+
+
+
+
+
+

+ + {{t 'visits.edit.procedures' }} {{#if canAddProcedure}} - + {{/if}}

@@ -113,9 +153,9 @@
- - - + + + {{#each model.procedures as |procedure|}} @@ -127,7 +167,7 @@ {{/if}} {{#if canDeleteProcedure}} {{/if}} @@ -141,9 +181,9 @@

- Medication + {{t 'visits.edit.medication' }} {{#if canAddMedication}} - + {{/if}}

@@ -158,10 +198,10 @@

- Labs + {{t 'visits.edit.labs' }} {{#if canAddLab}} {{/if}} @@ -177,10 +217,10 @@

- Imaging + {{t 'visits.edit.imaging' }} {{#if canAddImaging}} {{/if}} From 48ba12679178a0c2d88d55981a2fed8fa604ec55 Mon Sep 17 00:00:00 2001 From: tangollama Date: Wed, 16 Mar 2016 17:51:18 -0700 Subject: [PATCH 10/56] functional patient-notes I HAVE MADE FIRE!!! Seriously though, the patient-notes feature is functional. --- app/mixins/patient-notes.js | 2 +- app/patients/edit/controller.js | 2 +- app/patients/edit/route.js | 5 +++++ app/patients/edit/template.hbs | 4 ++-- app/patients/notes/controller.js | 5 +++-- app/visits/edit/controller.js | 4 ---- app/visits/edit/route.js | 6 ++++++ 7 files changed, 18 insertions(+), 10 deletions(-) diff --git a/app/mixins/patient-notes.js b/app/mixins/patient-notes.js index ddecb44801..092c3e63d7 100644 --- a/app/mixins/patient-notes.js +++ b/app/mixins/patient-notes.js @@ -13,7 +13,7 @@ export default Ember.Mixin.create({ _computeNoteType: function(visit) { switch (visit.get('visitType')) { case 'Admission': - if (Ember.isEmpty(visit.get('procedure'))) { + if (Ember.isEmpty(visit.get('procedures'))) { return 'Pre-op'; } else { return 'Post-op'; diff --git a/app/patients/edit/controller.js b/app/patients/edit/controller.js index e3d08c4bf7..a7412db11d 100644 --- a/app/patients/edit/controller.js +++ b/app/patients/edit/controller.js @@ -474,7 +474,7 @@ export default AbstractEditController.extend(BloodTypes, ReturnTo, UserSession, this.send('update', true); this.send('closeModal'); }, - + updatePhoto: function(photo) { photo.save().then(function() { this.send('closeModal'); diff --git a/app/patients/edit/route.js b/app/patients/edit/route.js index 6220189d48..092439a3f4 100644 --- a/app/patients/edit/route.js +++ b/app/patients/edit/route.js @@ -10,6 +10,11 @@ export default AbstractEditRoute.extend(PatientId, PatientVisits, PouchDbMixin, photos: null, actions: { + updateNote: function(note) { + note.get('visit').save().then(function() { + //noop + }); + }, appointmentDeleted: function(model) { this.controller.send('appointmentDeleted', model); }, diff --git a/app/patients/edit/template.hbs b/app/patients/edit/template.hbs index 5f16336dc2..061898831c 100644 --- a/app/patients/edit/template.hbs +++ b/app/patients/edit/template.hbs @@ -113,13 +113,13 @@

{{/each}} {{else}} - {{t 'messages.no_history_available''}} + {{t 'messages.no_history_available'}} {{/if}}

{{/unless}} -
+

diff --git a/app/patients/notes/controller.js b/app/patients/notes/controller.js index 4cbe2c119a..8d277dee3d 100644 --- a/app/patients/notes/controller.js +++ b/app/patients/notes/controller.js @@ -7,7 +7,7 @@ import SelectValues from 'hospitalrun/utils/select-values'; import UserSession from 'hospitalrun/mixins/user-session'; export default AbstractEditController.extend(IsUpdateDisabled, UserSession, PatientSubmodule, PatientNotes, { cancelAction: 'closeModal', - editController: Ember.inject.controller('visits/edit'), + updateAction: 'updateNote', physicianList: Ember.computed.map('patientsController.physicianList.value', SelectValues.selectValuesMap), title: function() { if (this.get('model.isNew')) { @@ -23,7 +23,8 @@ export default AbstractEditController.extend(IsUpdateDisabled, UserSession, Pati return Ember.RSVP.Promise.resolve(); }, afterUpdate: function() { - this.get('editController').send('updateNote', this.get('model')); + //this.get('editController').send('updateNote', this.get('model')); + this.send(this.get('updateAction'), this.get('model')); this.send(this.get('cancelAction')); }, actions: { diff --git a/app/visits/edit/controller.js b/app/visits/edit/controller.js index 61b32896a4..680dd8f8d2 100644 --- a/app/visits/edit/controller.js +++ b/app/visits/edit/controller.js @@ -284,10 +284,6 @@ export default AbstractEditController.extend(ChargeActions, PatientSubmodule, Pa this.send('openModal', 'patients.notes', model); }, - updateNote: function(patientNote) { - this.send('update', true); - }, - newAppointment: function() { this._addChildObject('appointments.edit'); }, diff --git a/app/visits/edit/route.js b/app/visits/edit/route.js index b650e11fce..78de53e4a2 100644 --- a/app/visits/edit/route.js +++ b/app/visits/edit/route.js @@ -13,6 +13,12 @@ export default AbstractEditRoute.extend(ChargeRoute, { startDate: new Date(), status: 'Admitted' }); + }, + + actions: { + updateNote: function() { + this.controller.send('update', true); + } } }); From 0b545df33449cfd1cdd9333d215fa38a78e6a949 Mon Sep 17 00:00:00 2001 From: tangollama Date: Thu, 17 Mar 2016 08:30:22 -0700 Subject: [PATCH 11/56] corrections to labels and acceptance tests --- app/locales/en/translations.js | 6 +- app/patients/edit/template.hbs | 2 +- tests/acceptance/appointments-test.js | 1 + tests/acceptance/patient-notes-test.js | 79 ++++++++++++++++++++++++++ 4 files changed, 84 insertions(+), 4 deletions(-) create mode 100644 tests/acceptance/patient-notes-test.js diff --git a/app/locales/en/translations.js b/app/locales/en/translations.js index a5b92f9e71..863c24ad0e 100644 --- a/app/locales/en/translations.js +++ b/app/locales/en/translations.js @@ -190,7 +190,7 @@ export default { delete: 'Delete', new_user: 'New User', add_value: 'Add Value', - add_note: 'Add Note', + new_note: 'New Note', import: 'Import', load_file: 'Load File', new_request: 'New Request', @@ -311,8 +311,8 @@ export default { procedure: 'Procedure', procedures: 'Procedures', new_procedure: 'New Procedure', - labs: 'Procedures', - new_lab: 'New Procedure', + labs: 'Labs', + new_lab: 'New Lab', imaging: 'Imaging', new_imaging: 'New Imaging', medication: 'Medication', diff --git a/app/patients/edit/template.hbs b/app/patients/edit/template.hbs index 061898831c..4f35892821 100644 --- a/app/patients/edit/template.hbs +++ b/app/patients/edit/template.hbs @@ -24,7 +24,7 @@ {{t 'labels.patient_history'}} {{#if canAddNote}} {{/if}}

diff --git a/tests/acceptance/appointments-test.js b/tests/acceptance/appointments-test.js index 248095bc09..83c8c90c53 100644 --- a/tests/acceptance/appointments-test.js +++ b/tests/acceptance/appointments-test.js @@ -88,6 +88,7 @@ test('Adding a visit to an appointment', function(assert) { }); click('button:contains(Ok)'); andThen(() => { + findWithAssert('button:contains(New Note)'); findWithAssert('button:contains(New Procedure)'); findWithAssert('button:contains(New Medication)'); findWithAssert('button:contains(New Lab)'); diff --git a/tests/acceptance/patient-notes-test.js b/tests/acceptance/patient-notes-test.js new file mode 100644 index 0000000000..9ef59abe5d --- /dev/null +++ b/tests/acceptance/patient-notes-test.js @@ -0,0 +1,79 @@ +import Ember from 'ember'; +import { module, test } from 'qunit'; +import startApp from 'hospitalrun/tests/helpers/start-app'; + +module('Acceptance | patient notes', { + beforeEach: function() { + this.application = startApp(); + }, + + afterEach: function() { + Ember.run(this.application, 'destroy'); + } +}); + +function tabTest(tabName, tabTitle) { + click(`[data-test-selector=${tabName}]`); + andThen(function() { + findWithAssert(`.active .panel-title:contains(${tabTitle})`); + }); +} + +test('visiting /patients new note route', function(assert) { + runWithPouchDump('default', function() { + authenticateUser(); + visit('/patients'); + + visit('/patients/edit/new'); + andThen(function() { + assert.equal(currentURL(), '/patients/edit/new'); + }); + + fillIn('.test-first-name input', 'John'); + fillIn('.test-last-name input', 'Doe'); + click('.panel-footer button:contains(Add)'); + waitToAppear('.modal-dialog'); + andThen(function() { + assert.equal(find('.modal-title').text(), 'Patient Saved', 'Patient record has been saved'); + assert.equal(find('.modal-body').text().trim(), 'The patient record for John Doe has been saved.', 'Record has been saved'); + }); + click('button:contains(Close)'); + waitToAppear('.patient-summary'); + + andThen(function() { + findWithAssert('.patient-summary'); + }); + + andThen(function() { + tabTest('appointments-tab', 'Visits'); + click('button:contains(New Visit)'); + }); + + andThen(() => { + assert.equal(currentURL(), '/visits/edit/new', 'Now in add visiting information route'); + }); + click('.panel-footer button:contains(Add)'); + waitToAppear('.modal-dialog'); + andThen(() => { + assert.equal(find('.modal-title').text(), 'Visit Saved', 'New visit has been saved'); + }); + click('button:contains(Ok)'); + andThen(() => { + findWithAssert('button:contains(New Note)'); + findWithAssert('button:contains(New Procedure)'); + findWithAssert('button:contains(New Medication)'); + findWithAssert('button:contains(New Lab)'); + findWithAssert('button:contains(New Imaging)'); + findWithAssert('button:contains(New Vitals)'); + findWithAssert('button:contains(Add Item)'); + }); + + andThen(function() { + assert.equal(find('button:contains(New Note)').length, 1, 'Add Note button in visible'); + click('button:contains(New Note)'); + }); + andThen(function() { + assert.equal(find('label:contains(Note)').length, 1, 'Notes modal appeared.'); + }); + }); +}); \ No newline at end of file From 88e7a37adec465f3ff665e10a6be0c05bb2483c3 Mon Sep 17 00:00:00 2001 From: tangollama Date: Thu, 17 Mar 2016 09:48:26 -0700 Subject: [PATCH 12/56] Adding the security checks into the controller for assistance with the patient history. @jkleinsc I want to talk to you about this change. --- app/patients/edit/controller.js | 60 ++++++++++++++++---------- app/patients/edit/template.hbs | 10 ++--- tests/acceptance/patient-notes-test.js | 8 ++-- 3 files changed, 45 insertions(+), 33 deletions(-) diff --git a/app/patients/edit/controller.js b/app/patients/edit/controller.js index a7412db11d..4a7ecce0bb 100644 --- a/app/patients/edit/controller.js +++ b/app/patients/edit/controller.js @@ -285,33 +285,41 @@ export default AbstractEditController.extend(BloodTypes, ReturnTo, UserSession, }, editAppointment: function(appointment) { - appointment.set('returnToPatient', true); - appointment.set('returnTo', null); - this.transitionToRoute('appointments.edit', appointment); + if (this.get('canAddAppointment')) { + appointment.set('returnToPatient', true); + appointment.set('returnTo', null); + this.transitionToRoute('appointments.edit', appointment); + } }, editImaging: function(imaging) { - if (imaging.get('canEdit')) { - imaging.setProperties({ - 'returnToPatient': true - }); - this.transitionToRoute('imaging.edit', imaging); + if (this.get('canAddImaging')) { + if (imaging.get('canEdit')) { + imaging.setProperties({ + 'returnToPatient': true + }); + this.transitionToRoute('imaging.edit', imaging); + } } }, editLab: function(lab) { - if (lab.get('canEdit')) { - lab.setProperties({ - 'returnToPatient': true - }); - this.transitionToRoute('labs.edit', lab); + if (this.get('canAddLab')) { + if (lab.get('canEdit')) { + lab.setProperties({ + 'returnToPatient': true + }); + this.transitionToRoute('labs.edit', lab); + } } }, editMedication: function(medication) { - if (medication.get('canEdit')) { - medication.set('returnToPatient', true); - this.transitionToRoute('medication.edit', medication); + if (this.get('canAddMedication')) { + if (medication.get('canEdit')) { + medication.set('returnToPatient', true); + this.transitionToRoute('medication.edit', medication); + } } }, @@ -320,11 +328,15 @@ export default AbstractEditController.extend(BloodTypes, ReturnTo, UserSession, }, editProcedure: function(procedure) { - this.transitionToRoute('procedures.edit', procedure); + if (this.get('canAddVisit')) { + this.transitionToRoute('procedures.edit', procedure); + } }, editVisit: function(visit) { - this.transitionToRoute('visits.edit', visit); + if (this.get('canAddVisit')) { + this.transitionToRoute('visits.edit', visit); + } }, newAppointment: function() { @@ -360,12 +372,14 @@ export default AbstractEditController.extend(BloodTypes, ReturnTo, UserSession, }, showAddPatientNote: function(model) { - if (Ember.isEmpty(model)) { - model = this.get('store').createRecord('patient-note', { - patient: this.get('model') - }); + if (this.get('canAddNote')) { + if (Ember.isEmpty(model)) { + model = this.get('store').createRecord('patient-note', { + patient: this.get('model') + }); + } + this.send('openModal', 'patients.notes', model); } - this.send('openModal', 'patients.notes', model); }, showDeleteAppointment: function(appointment) { diff --git a/app/patients/edit/template.hbs b/app/patients/edit/template.hbs index 4f35892821..e43e6d13f4 100644 --- a/app/patients/edit/template.hbs +++ b/app/patients/edit/template.hbs @@ -33,7 +33,7 @@ {{#if model.visits}} {{#each model.visits as |visit|}}
-

{{visit.visitType}} {{t 'labels.on'}} {{visit.visitDate}}

+

{{visit.visitType}} {{t 'labels.on'}} {{visit.visitDate}}

{{#if visit.history}}
History
@@ -50,7 +50,7 @@
{{t 'labels.procedures' }}
{{#each visit.procedures as |procedure|}} -
+
{{date-format procedure.procedureDate}}: {{#if procedure.cptCode}} [{{t 'labels.cptcode' }} - {{procedure.cptCode}}] @@ -75,7 +75,7 @@
{{t 'labels.image_orders' }}
{{#each visit.imaging as |imaging|}} -
+
{{date-format imaging.imagingDate}}: {{imaging.imagingType.name}}
{{imaging.result}}
{{imaging.notes}}
@@ -87,7 +87,7 @@
{{t 'labels.lab_orders' }}
{{#each visit.labs as |lab|}} -
+
{{date-format lab.labDate}}: {{lab.labType.name}}
{{lab.result}}
{{lab.notes}}
@@ -99,7 +99,7 @@
{{t 'labels.notes'}}
{{#each visit.patientNotes as |note|}} -
+
{{note.authoredBy}}
{{date-format note.date}}[{{note.noteType}}]: {{note.content}}
diff --git a/tests/acceptance/patient-notes-test.js b/tests/acceptance/patient-notes-test.js index 9ef59abe5d..0747ad2c65 100644 --- a/tests/acceptance/patient-notes-test.js +++ b/tests/acceptance/patient-notes-test.js @@ -35,7 +35,6 @@ test('visiting /patients new note route', function(assert) { waitToAppear('.modal-dialog'); andThen(function() { assert.equal(find('.modal-title').text(), 'Patient Saved', 'Patient record has been saved'); - assert.equal(find('.modal-body').text().trim(), 'The patient record for John Doe has been saved.', 'Record has been saved'); }); click('button:contains(Close)'); waitToAppear('.patient-summary'); @@ -46,10 +45,9 @@ test('visiting /patients new note route', function(assert) { andThen(function() { tabTest('appointments-tab', 'Visits'); - click('button:contains(New Visit)'); }); - - andThen(() => { + andThen(function() { + click('button:contains(New Visit)'); assert.equal(currentURL(), '/visits/edit/new', 'Now in add visiting information route'); }); click('.panel-footer button:contains(Add)'); @@ -69,7 +67,7 @@ test('visiting /patients new note route', function(assert) { }); andThen(function() { - assert.equal(find('button:contains(New Note)').length, 1, 'Add Note button in visible'); + assert.equal(find('button:contains(New Note)').length, 1, 'New Note button in visible'); click('button:contains(New Note)'); }); andThen(function() { From 28c8975f039efb608019432f2439e1ffad604107 Mon Sep 17 00:00:00 2001 From: tangollama Date: Sun, 20 Mar 2016 23:33:23 -0400 Subject: [PATCH 13/56] adding date of birth to the patient summary --- app/locales/en/translations.js | 2 ++ app/templates/components/patient-summary.hbs | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/app/locales/en/translations.js b/app/locales/en/translations.js index 863c24ad0e..ce3791d054 100644 --- a/app/locales/en/translations.js +++ b/app/locales/en/translations.js @@ -101,6 +101,8 @@ export default { quantity: 'Quantity', requested_on: 'Requested On', date: 'Date', + date_of_birth: 'Date of Birth', + date_of_birth_short: 'DoB', date_requested: 'Date Requested', date_completed: 'Date Completed', requested_by: 'Requested By', diff --git a/app/templates/components/patient-summary.hbs b/app/templates/components/patient-summary.hbs index d38398a9e2..86da7b7609 100644 --- a/app/templates/components/patient-summary.hbs +++ b/app/templates/components/patient-summary.hbs @@ -17,7 +17,7 @@
- {{patient.age}} + {{patient.age}} [{{t 'labels.date_of_birth_short'}}: {{date-format patient.dateOfBirth}}]
From b788cc2f86f817b38d3160c19dec5b0ec56035b7 Mon Sep 17 00:00:00 2001 From: tangollama Date: Mon, 21 Mar 2016 08:26:10 -0400 Subject: [PATCH 14/56] date of birth change Aligning the date of birth display with the implied standard from the procedure and diagnosis references. --- app/templates/components/patient-summary.hbs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/templates/components/patient-summary.hbs b/app/templates/components/patient-summary.hbs index 86da7b7609..7a87e3948c 100644 --- a/app/templates/components/patient-summary.hbs +++ b/app/templates/components/patient-summary.hbs @@ -17,7 +17,7 @@
- {{patient.age}} [{{t 'labels.date_of_birth_short'}}: {{date-format patient.dateOfBirth}}] + {{patient.age}} ({{date-format patient.dateOfBirth}})
From 1876608d215ee13272d7e02b02cb09a597a7cf2e Mon Sep 17 00:00:00 2001 From: Joel Glovier Date: Mon, 21 Mar 2016 08:42:08 -0400 Subject: [PATCH 15/56] tweak patient id styling --- app/styles/components/_patient_summary.scss | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/styles/components/_patient_summary.scss b/app/styles/components/_patient_summary.scss index ba3dc3962d..729bb6407e 100644 --- a/app/styles/components/_patient_summary.scss +++ b/app/styles/components/_patient_summary.scss @@ -8,11 +8,11 @@ &.patient-id { position: absolute; - top: 0; - right: 0; + top: -10px; + right: -10px; border-radius: 3px; background: $blue_lightest; - padding: 0 10px; + padding: 10px 15px; text-align: center; .ps-info-label { From 475aa60a38a9db52329c97f04041bee440d92fbe Mon Sep 17 00:00:00 2001 From: Joel Glovier Date: Mon, 21 Mar 2016 09:06:30 -0400 Subject: [PATCH 16/56] fix for missing classname --- app/patients/edit/template.hbs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/patients/edit/template.hbs b/app/patients/edit/template.hbs index be092424f0..92402c3269 100644 --- a/app/patients/edit/template.hbs +++ b/app/patients/edit/template.hbs @@ -2,7 +2,7 @@ {{#em-form model=model submitButton=false bubbles=false }} {{#unless isNewOrDeleted}} {{patient-summary patient=model visits=model.visits patientProcedures=patientProcedures disablePatientLink=true store=store }} -
DateProcedure{{t 'labels.actions'}}{{t 'visits.edit.date' }}{{t 'visits.edit.procedure' }}{{t 'common.actions'}}
+ + + + + + + + + {{#each model.appointments as |appointment|}} + + + + + + + + + {{/each}} +
DateExaminerLocationTypeStatus{{t 'labels.actions'}}
{{appointment.formattedAppointmentDate}}{{appointment.provider}}{{appointment.location}}{{appointment.appointmentType}}{{appointment.displayStatus}} + {{#if canAddAppointment}} + + {{/if}} + {{#if canDeleteAppointment}} + + {{/if}} +
-
+
{{#if canAddVisit}} @@ -353,44 +368,46 @@
+ +
+
+ {{#if canAddMedication}} +
+ +
+ {{/if}} +
+ {{partial 'patients/medication'}} +
+
+
+
- {{#if canAddAppointment}} + {{#if canAddImaging}}
-
{{/if}}
- - - - - - - - - - {{#each model.appointments as |appointment|}} - - - - - - - - - {{/each}} -
DateExaminerLocationTypeStatus{{t 'labels.actions'}}
{{appointment.formattedAppointmentDate}}{{appointment.provider}}{{appointment.location}}{{appointment.appointmentType}}{{appointment.displayStatus}} - {{#if canAddAppointment}} - - {{/if}} - {{#if canDeleteAppointment}} - - {{/if}} -
+ {{partial 'patients/imaging'}} +
+
+
+
+
+ {{#if canAddLab}} +
+ +
+ {{/if}} +
+ {{partial 'patients/labs'}}
From 9461679c3b5b5bba818cc0347f5457e0978af6a1 Mon Sep 17 00:00:00 2001 From: tangollama Date: Tue, 22 Mar 2016 21:12:07 -0400 Subject: [PATCH 27/56] more adjustments to the history --- app/patients/edit/template.hbs | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/app/patients/edit/template.hbs b/app/patients/edit/template.hbs index 21be4aa8c1..e6415082de 100644 --- a/app/patients/edit/template.hbs +++ b/app/patients/edit/template.hbs @@ -271,21 +271,7 @@ -
-
- {{#if canAddMedication}} -
- -
- {{/if}} -
- {{partial 'patients/medication'}} -
-
-
-
+
{{#if canAddAppointment}}
From 8084f94b20a0fb7b16ff965ef043c06391bfd8e3 Mon Sep 17 00:00:00 2001 From: tangollama Date: Tue, 22 Mar 2016 21:40:46 -0400 Subject: [PATCH 28/56] correction on translation bundle error. --- app/locales/en/translations.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/locales/en/translations.js b/app/locales/en/translations.js index 2408072b26..7e9fef832e 100644 --- a/app/locales/en/translations.js +++ b/app/locales/en/translations.js @@ -222,7 +222,7 @@ export default { user_saved: 'User Saved', on_behalf_of: 'on behalf of', new_patient_has_to_be_created: 'A new patient needs to be created...Please wait..', - no_notes_available: 'No additional clinical notes are available for this visit.' + no_notes_available: 'No additional clinical notes are available for this visit.', sorry: 'Sorry, something went wrong...' }, alerts: { From d6373e8e6e85a6a2f612bf4caec6bf64b85442fd Mon Sep 17 00:00:00 2001 From: tangollama Date: Tue, 22 Mar 2016 22:10:40 -0400 Subject: [PATCH 29/56] building in patient notes migration to patient edit route When visits are loaded, migrate the patient Notes. --- app/mixins/patient-notes.js | 13 +++++++++++++ app/patients/edit/route.js | 9 ++++++++- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/app/mixins/patient-notes.js b/app/mixins/patient-notes.js index 092c3e63d7..0a1b2c27ec 100644 --- a/app/mixins/patient-notes.js +++ b/app/mixins/patient-notes.js @@ -32,6 +32,19 @@ export default Ember.Mixin.create({ if (model.get('noteType') == null) { model.set('noteType', this._computeNoteType(model.get('visit'))); } + }, + + migrateNote: function(visit) { + if (Ember.isEmpty(visit.get('patientNotes')) && !Ember.isEmpty(visit.get('notes'))) { + var note = this.get('store').createRecord('patient-note', { + createdBy: visit.get('examiner'), + date: visit.get('lastModified'), + content: visit.get('notes'), + visit: visit, + patient: visit.get('patient'), + noteType: this._computeNoteType(visit) + }); + } } }); diff --git a/app/patients/edit/route.js b/app/patients/edit/route.js index 092439a3f4..13fc44f4a3 100644 --- a/app/patients/edit/route.js +++ b/app/patients/edit/route.js @@ -2,8 +2,9 @@ import AbstractEditRoute from 'hospitalrun/routes/abstract-edit-route'; import Ember from 'ember'; import PatientId from 'hospitalrun/mixins/patient-id'; import PatientVisits from 'hospitalrun/mixins/patient-visits'; +import PatientNotes from 'hospitalrun/mixins/patient-notes'; import PouchDbMixin from 'hospitalrun/mixins/pouchdb'; -export default AbstractEditRoute.extend(PatientId, PatientVisits, PouchDbMixin, { +export default AbstractEditRoute.extend(PatientId, PatientVisits, PouchDbMixin, PatientNotes, { editTitle: 'Edit Patient', modelName: 'patient', newTitle: 'New Patient', @@ -66,7 +67,13 @@ export default AbstractEditRoute.extend(PatientId, PatientVisits, PouchDbMixin, model.set('friendlyId', externalId); } this._super(controller, model); + var self = this; this.getPatientVisits(model).then(function(visits) { + if (!Ember.isEmpty(visits)) { + visits.forEach(function(visit) { + self.migrateNote(visit); + }); + } model.set('visits', visits); }); this.store.query('appointment', { From 1535654ea3718c08ed594977ad53edae283099bc Mon Sep 17 00:00:00 2001 From: tangollama Date: Tue, 22 Mar 2016 22:15:57 -0400 Subject: [PATCH 30/56] white space warnings --- app/mixins/patient-notes.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/app/mixins/patient-notes.js b/app/mixins/patient-notes.js index 0a1b2c27ec..eba4b90933 100644 --- a/app/mixins/patient-notes.js +++ b/app/mixins/patient-notes.js @@ -36,15 +36,15 @@ export default Ember.Mixin.create({ migrateNote: function(visit) { if (Ember.isEmpty(visit.get('patientNotes')) && !Ember.isEmpty(visit.get('notes'))) { - var note = this.get('store').createRecord('patient-note', { + var note = this.get('store').createRecord('patient-note', { createdBy: visit.get('examiner'), - date: visit.get('lastModified'), + date: (visit.get('endDate') != null ? visit.get('endDate') : visit.get('lastModified')), content: visit.get('notes'), - visit: visit, + visit: visit, patient: visit.get('patient'), noteType: this._computeNoteType(visit) - }); + }); } } - -}); + +}); \ No newline at end of file From 600f062750136c11d4ee6a89f659b5a823b24c02 Mon Sep 17 00:00:00 2001 From: tangollama Date: Tue, 22 Mar 2016 22:38:59 -0400 Subject: [PATCH 31/56] more formatting corrections --- app/mixins/patient-notes.js | 10 +++++----- app/models/patient-note.js | 28 ++++++++++++++-------------- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/app/mixins/patient-notes.js b/app/mixins/patient-notes.js index eba4b90933..8ee45f12e7 100644 --- a/app/mixins/patient-notes.js +++ b/app/mixins/patient-notes.js @@ -1,7 +1,7 @@ import Ember from 'ember'; export default Ember.Mixin.create({ - + canAddNote: function() { return this.currentUserCan('add_note'); }, @@ -9,7 +9,7 @@ export default Ember.Mixin.create({ canDeleteNote: function() { return this.currentUserCan('delete_note'); }, - + _computeNoteType: function(visit) { switch (visit.get('visitType')) { case 'Admission': @@ -26,14 +26,14 @@ export default Ember.Mixin.create({ return visit.get('visitType'); } }, - + _setNoteType: function() { var model = this.get('model'); if (model.get('noteType') == null) { model.set('noteType', this._computeNoteType(model.get('visit'))); } }, - + migrateNote: function(visit) { if (Ember.isEmpty(visit.get('patientNotes')) && !Ember.isEmpty(visit.get('notes'))) { var note = this.get('store').createRecord('patient-note', { @@ -44,7 +44,7 @@ export default Ember.Mixin.create({ patient: visit.get('patient'), noteType: this._computeNoteType(visit) }); + return note; } } - }); \ No newline at end of file diff --git a/app/models/patient-note.js b/app/models/patient-note.js index 26b43965ac..50557e0b37 100644 --- a/app/models/patient-note.js +++ b/app/models/patient-note.js @@ -5,43 +5,43 @@ import DS from 'ember-data'; export default AbstractModel.extend({ authoredBy: function() { if (!Ember.isEmpty(this.get('attribution'))) { - return this.get('attribution')+' '+t('messages.on_behalf_of')+' '+this.get('createdBy'); + return this.get('attribution') + ' ' + t('messages.on_behalf_of') + ' '+this.get('createdBy'); } else { return this.get('createdBy'); } }.property('attribution', 'createdBy'), - //if the note was written by one person but dictated / given on behalf of another, otherwise, this and createdBy are the same - attribution: DS.attr('string'), + // if the note was written by one person but dictated / given on behalf of another, otherwise, this and createdBy are the same + attribution: DS.attr('string'), content: DS.attr('string'), - createdBy: DS.attr('string'), + createdBy: DS.attr('string'), date: DS.attr('date'), - //custom list of noteTypes of mixins/patient-note-types + // custom list of noteTypes of mixins/patient-note-types noteType: DS.attr(), - //who is this note about? + // who is this note about? patient: DS.belongsTo('patient', { async: false - }), - //if this note is related to a visit, make sure it's noted. + }), + // if this note is related to a visit, make sure it's noted. visit: DS.belongsTo('visit', { async: false - }), - //if this note is related to an appointment, make sure it's noted. + }), + // if this note is related to an appointment, make sure it's noted. appointment: DS.belongsTo('appointment', { async: false }), - //if this note is related to an imaging request, make sure it's noted. + // if this note is related to an imaging request, make sure it's noted. imaging: DS.belongsTo('imaging', { async: false }), - //if this note is related to a lab, make sure it's noted. + // if this note is related to a lab, make sure it's noted. lab: DS.belongsTo('lab', { async: false }), - //if this note is related to a medication request, make sure it's noted. + // if this note is related to a medication request, make sure it's noted. medication: DS.belongsTo('medication', { async: false }), - //if this note is related to a procedure, make sure it's noted. + // if this note is related to a procedure, make sure it's noted. procedure: DS.belongsTo('procedure', { async: false }), From c75f2b71b6c8f80aedf1e21ea52f30136884b012 Mon Sep 17 00:00:00 2001 From: Joel Glovier Date: Wed, 23 Mar 2016 08:43:23 -0400 Subject: [PATCH 32/56] reduce font weight on note copy --- app/styles/components/_patient_history.scss | 1 + 1 file changed, 1 insertion(+) diff --git a/app/styles/components/_patient_history.scss b/app/styles/components/_patient_history.scss index fd94683dbc..088513f4bf 100644 --- a/app/styles/components/_patient_history.scss +++ b/app/styles/components/_patient_history.scss @@ -8,6 +8,7 @@ .ph-note-item { margin-top: 15px; + font-weight: 300; } .ph-note-heading { From 2b1394e147c4637b2baf99174c8b466017d74bfa Mon Sep 17 00:00:00 2001 From: tangollama Date: Thu, 24 Mar 2016 16:49:56 -0400 Subject: [PATCH 33/56] removing the lazy migration for patient-notes --- app/mixins/patient-notes.js | 14 -------------- app/patients/edit/route.js | 5 ----- 2 files changed, 19 deletions(-) diff --git a/app/mixins/patient-notes.js b/app/mixins/patient-notes.js index 8ee45f12e7..e4af953591 100644 --- a/app/mixins/patient-notes.js +++ b/app/mixins/patient-notes.js @@ -32,19 +32,5 @@ export default Ember.Mixin.create({ if (model.get('noteType') == null) { model.set('noteType', this._computeNoteType(model.get('visit'))); } - }, - - migrateNote: function(visit) { - if (Ember.isEmpty(visit.get('patientNotes')) && !Ember.isEmpty(visit.get('notes'))) { - var note = this.get('store').createRecord('patient-note', { - createdBy: visit.get('examiner'), - date: (visit.get('endDate') != null ? visit.get('endDate') : visit.get('lastModified')), - content: visit.get('notes'), - visit: visit, - patient: visit.get('patient'), - noteType: this._computeNoteType(visit) - }); - return note; - } } }); \ No newline at end of file diff --git a/app/patients/edit/route.js b/app/patients/edit/route.js index 13fc44f4a3..4082f066d4 100644 --- a/app/patients/edit/route.js +++ b/app/patients/edit/route.js @@ -69,11 +69,6 @@ export default AbstractEditRoute.extend(PatientId, PatientVisits, PouchDbMixin, this._super(controller, model); var self = this; this.getPatientVisits(model).then(function(visits) { - if (!Ember.isEmpty(visits)) { - visits.forEach(function(visit) { - self.migrateNote(visit); - }); - } model.set('visits', visits); }); this.store.query('appointment', { From 0fde46a281608766c9e518b8a8c4b5e6a1db0769 Mon Sep 17 00:00:00 2001 From: tangollama Date: Thu, 24 Mar 2016 22:38:56 -0400 Subject: [PATCH 34/56] KISS + listing errors --- app/models/patient-note.js | 20 -------------------- app/patients/edit/route.js | 5 ++--- 2 files changed, 2 insertions(+), 23 deletions(-) diff --git a/app/models/patient-note.js b/app/models/patient-note.js index 50557e0b37..6c0aa02e92 100644 --- a/app/models/patient-note.js +++ b/app/models/patient-note.js @@ -25,26 +25,6 @@ export default AbstractModel.extend({ visit: DS.belongsTo('visit', { async: false }), - // if this note is related to an appointment, make sure it's noted. - appointment: DS.belongsTo('appointment', { - async: false - }), - // if this note is related to an imaging request, make sure it's noted. - imaging: DS.belongsTo('imaging', { - async: false - }), - // if this note is related to a lab, make sure it's noted. - lab: DS.belongsTo('lab', { - async: false - }), - // if this note is related to a medication request, make sure it's noted. - medication: DS.belongsTo('medication', { - async: false - }), - // if this note is related to a procedure, make sure it's noted. - procedure: DS.belongsTo('procedure', { - async: false - }), validations: { patient: { presence: true diff --git a/app/patients/edit/route.js b/app/patients/edit/route.js index 4082f066d4..0eb7db4f49 100644 --- a/app/patients/edit/route.js +++ b/app/patients/edit/route.js @@ -13,8 +13,8 @@ export default AbstractEditRoute.extend(PatientId, PatientVisits, PouchDbMixin, actions: { updateNote: function(note) { note.get('visit').save().then(function() { - //noop - }); + // noop + }); }, appointmentDeleted: function(model) { this.controller.send('appointmentDeleted', model); @@ -67,7 +67,6 @@ export default AbstractEditRoute.extend(PatientId, PatientVisits, PouchDbMixin, model.set('friendlyId', externalId); } this._super(controller, model); - var self = this; this.getPatientVisits(model).then(function(visits) { model.set('visits', visits); }); From 4dd87e6a12b7237d5302ff7e235401fe43347b3d Mon Sep 17 00:00:00 2001 From: tangollama Date: Thu, 24 Mar 2016 23:02:28 -0400 Subject: [PATCH 35/56] formatting and whitespace errors --- app/locales/en/translations.js | 2 +- app/models/patient-note.js | 2 +- app/models/visit.js | 2 +- app/patients/edit/controller.js | 14 +++++++------- app/patients/notes/controller.js | 5 ++--- app/visits/edit/controller.js | 6 +++--- app/visits/edit/route.js | 2 +- tests/acceptance/patient-notes-test.js | 7 +------ 8 files changed, 17 insertions(+), 23 deletions(-) diff --git a/app/locales/en/translations.js b/app/locales/en/translations.js index 7e9fef832e..f901c621e9 100644 --- a/app/locales/en/translations.js +++ b/app/locales/en/translations.js @@ -575,5 +575,5 @@ export default { }, common: { actions: 'Actions' - } + } }; diff --git a/app/models/patient-note.js b/app/models/patient-note.js index 6c0aa02e92..80cc2609d7 100644 --- a/app/models/patient-note.js +++ b/app/models/patient-note.js @@ -5,7 +5,7 @@ import DS from 'ember-data'; export default AbstractModel.extend({ authoredBy: function() { if (!Ember.isEmpty(this.get('attribution'))) { - return this.get('attribution') + ' ' + t('messages.on_behalf_of') + ' '+this.get('createdBy'); + return this.get('attribution') + ' ' + t('messages.on_behalf_of') + ' ' + this.get('createdBy'); } else { return this.get('createdBy'); } diff --git a/app/models/visit.js b/app/models/visit.js index 19e8aec008..25f1b0f538 100644 --- a/app/models/visit.js +++ b/app/models/visit.js @@ -33,7 +33,7 @@ export default AbstractModel.extend({ labs: DS.hasMany('lab', { async: true }), location: DS.attr('string'), medication: DS.hasMany('medication', { async: true }), - //this field is being deprecated in favor of patient-note + // this field is being deprecated in favor of patient-note notes: DS.attr('string'), patientNotes: DS.hasMany('patient-note', { async: true }), outPatient: DS.attr('boolean'), diff --git a/app/patients/edit/controller.js b/app/patients/edit/controller.js index 4a7ecce0bb..d047298c2e 100644 --- a/app/patients/edit/controller.js +++ b/app/patients/edit/controller.js @@ -288,12 +288,12 @@ export default AbstractEditController.extend(BloodTypes, ReturnTo, UserSession, if (this.get('canAddAppointment')) { appointment.set('returnToPatient', true); appointment.set('returnTo', null); - this.transitionToRoute('appointments.edit', appointment); + this.transitionToRoute('appointments.edit', appointment); } }, editImaging: function(imaging) { - if (this.get('canAddImaging')) { + if (this.get('canAddImaging')) { if (imaging.get('canEdit')) { imaging.setProperties({ 'returnToPatient': true @@ -315,7 +315,7 @@ export default AbstractEditController.extend(BloodTypes, ReturnTo, UserSession, }, editMedication: function(medication) { - if (this.get('canAddMedication')) { + if (this.get('canAddMedication')) { if (medication.get('canEdit')) { medication.set('returnToPatient', true); this.transitionToRoute('medication.edit', medication); @@ -329,7 +329,7 @@ export default AbstractEditController.extend(BloodTypes, ReturnTo, UserSession, editProcedure: function(procedure) { if (this.get('canAddVisit')) { - this.transitionToRoute('procedures.edit', procedure); + this.transitionToRoute('procedures.edit', procedure); } }, @@ -370,11 +370,11 @@ export default AbstractEditController.extend(BloodTypes, ReturnTo, UserSession, isNew: true }); }, - + showAddPatientNote: function(model) { if (this.get('canAddNote')) { if (Ember.isEmpty(model)) { - model = this.get('store').createRecord('patient-note', { + model = this.get('store').createRecord('patient-note', { patient: this.get('model') }); } @@ -488,7 +488,7 @@ export default AbstractEditController.extend(BloodTypes, ReturnTo, UserSession, this.send('update', true); this.send('closeModal'); }, - + updatePhoto: function(photo) { photo.save().then(function() { this.send('closeModal'); diff --git a/app/patients/notes/controller.js b/app/patients/notes/controller.js index 8d277dee3d..d88c7805f6 100644 --- a/app/patients/notes/controller.js +++ b/app/patients/notes/controller.js @@ -13,8 +13,8 @@ export default AbstractEditController.extend(IsUpdateDisabled, UserSession, Pati if (this.get('model.isNew')) { return 'New Note for ' + this.get('model.patient.displayName'); } else { - return 'Updating Note from '+(moment(this.get('model.date')).format('MM/DD/YYYY'))+' for ' + this.get('model.patient.displayName'); - } + return 'Updating Note from ' + (moment(this.get('model.date')).format('MM/DD/YYYY')) + ' for ' + this.get('model.patient.displayName'); + } }.property('model.patient.displayName'), updateCapability: 'add_note', beforeUpdate: function() { @@ -23,7 +23,6 @@ export default AbstractEditController.extend(IsUpdateDisabled, UserSession, Pati return Ember.RSVP.Promise.resolve(); }, afterUpdate: function() { - //this.get('editController').send('updateNote', this.get('model')); this.send(this.get('updateAction'), this.get('model')); this.send(this.get('cancelAction')); }, diff --git a/app/visits/edit/controller.js b/app/visits/edit/controller.js index 680dd8f8d2..1fde71c1aa 100644 --- a/app/visits/edit/controller.js +++ b/app/visits/edit/controller.js @@ -272,10 +272,10 @@ export default AbstractEditController.extend(ChargeActions, PatientSubmodule, Pa }); this.send('openModal', 'visits.vitals.edit', newVitals); }, - + showAddPatientNote: function(model) { if (Ember.isEmpty(model)) { - model = this.get('store').createRecord('patient-note', { + model = this.get('store').createRecord('patient-note', { visit: this.get('model'), patient: this.get('model').get('patient'), noteType: this._computeNoteType(this.get('model')) @@ -283,7 +283,7 @@ export default AbstractEditController.extend(ChargeActions, PatientSubmodule, Pa } this.send('openModal', 'patients.notes', model); }, - + newAppointment: function() { this._addChildObject('appointments.edit'); }, diff --git a/app/visits/edit/route.js b/app/visits/edit/route.js index 78de53e4a2..065b0c4691 100644 --- a/app/visits/edit/route.js +++ b/app/visits/edit/route.js @@ -14,7 +14,7 @@ export default AbstractEditRoute.extend(ChargeRoute, { status: 'Admitted' }); }, - + actions: { updateNote: function() { this.controller.send('update', true); diff --git a/tests/acceptance/patient-notes-test.js b/tests/acceptance/patient-notes-test.js index 0747ad2c65..fe3be9544b 100644 --- a/tests/acceptance/patient-notes-test.js +++ b/tests/acceptance/patient-notes-test.js @@ -23,12 +23,10 @@ test('visiting /patients new note route', function(assert) { runWithPouchDump('default', function() { authenticateUser(); visit('/patients'); - visit('/patients/edit/new'); andThen(function() { assert.equal(currentURL(), '/patients/edit/new'); }); - fillIn('.test-first-name input', 'John'); fillIn('.test-last-name input', 'Doe'); click('.panel-footer button:contains(Add)'); @@ -38,16 +36,14 @@ test('visiting /patients new note route', function(assert) { }); click('button:contains(Close)'); waitToAppear('.patient-summary'); - andThen(function() { findWithAssert('.patient-summary'); }); - andThen(function() { tabTest('appointments-tab', 'Visits'); }); andThen(function() { - click('button:contains(New Visit)'); + click('button:contains(New Visit)'); assert.equal(currentURL(), '/visits/edit/new', 'Now in add visiting information route'); }); click('.panel-footer button:contains(Add)'); @@ -65,7 +61,6 @@ test('visiting /patients new note route', function(assert) { findWithAssert('button:contains(New Vitals)'); findWithAssert('button:contains(Add Item)'); }); - andThen(function() { assert.equal(find('button:contains(New Note)').length, 1, 'New Note button in visible'); click('button:contains(New Note)'); From faf297a862eeb6463d8223ae96d098ca92c31d96 Mon Sep 17 00:00:00 2001 From: tangollama Date: Fri, 25 Mar 2016 13:23:23 -0400 Subject: [PATCH 36/56] updated test for updated interface --- tests/acceptance/patient-notes-test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/acceptance/patient-notes-test.js b/tests/acceptance/patient-notes-test.js index fe3be9544b..edb7ab6a89 100644 --- a/tests/acceptance/patient-notes-test.js +++ b/tests/acceptance/patient-notes-test.js @@ -40,7 +40,7 @@ test('visiting /patients new note route', function(assert) { findWithAssert('.patient-summary'); }); andThen(function() { - tabTest('appointments-tab', 'Visits'); + tabTest('visits-tab', 'Visits'); }); andThen(function() { click('button:contains(New Visit)'); From 850954d5fe6131b0f8d8fd134c03919d2dc46357 Mon Sep 17 00:00:00 2001 From: tangollama Date: Fri, 25 Mar 2016 14:17:10 -0400 Subject: [PATCH 37/56] test cleanup --- tests/acceptance/patient-notes-test.js | 8 ++++---- tests/acceptance/patients-test.js | 7 ------- 2 files changed, 4 insertions(+), 11 deletions(-) diff --git a/tests/acceptance/patient-notes-test.js b/tests/acceptance/patient-notes-test.js index edb7ab6a89..0a492893dd 100644 --- a/tests/acceptance/patient-notes-test.js +++ b/tests/acceptance/patient-notes-test.js @@ -12,10 +12,10 @@ module('Acceptance | patient notes', { } }); -function tabTest(tabName, tabTitle) { +function tabTest(tabName, tabId) { click(`[data-test-selector=${tabName}]`); andThen(function() { - findWithAssert(`.active .panel-title:contains(${tabTitle})`); + findWithAssert(`#${tabId}`); }); } @@ -40,10 +40,10 @@ test('visiting /patients new note route', function(assert) { findWithAssert('.patient-summary'); }); andThen(function() { - tabTest('visits-tab', 'Visits'); + tabTest('visits-tab', 'visits'); }); + click('button:contains(New Visit)'); andThen(function() { - click('button:contains(New Visit)'); assert.equal(currentURL(), '/visits/edit/new', 'Now in add visiting information route'); }); click('.panel-footer button:contains(Add)'); diff --git a/tests/acceptance/patients-test.js b/tests/acceptance/patients-test.js index 2bb99d24d6..e7417ede3d 100644 --- a/tests/acceptance/patients-test.js +++ b/tests/acceptance/patients-test.js @@ -98,13 +98,6 @@ test('Adding a new patient record', function(assert) { }); }); -/*function tabTest(tabName, tabTitle) { - click(`[data-test-selector=${tabName}]`); - andThen(function() { - findWithAssert(`[data-test-selector=${tabName}] .active`); - }); -}*/ - function testSimpleReportForm(reportName) { test(`View reports tab | ${reportName} shows start and end dates`, function(assert) { runWithPouchDump('default', function() { From b310fe684844c626ed99c1e94e2063bbadb9e459 Mon Sep 17 00:00:00 2001 From: tangollama Date: Fri, 25 Mar 2016 15:28:42 -0400 Subject: [PATCH 38/56] canAddNote assumes there's a visit to tie to. --- app/mixins/patient-notes.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/mixins/patient-notes.js b/app/mixins/patient-notes.js index e4af953591..8e1c460c8f 100644 --- a/app/mixins/patient-notes.js +++ b/app/mixins/patient-notes.js @@ -3,7 +3,7 @@ import Ember from 'ember'; export default Ember.Mixin.create({ canAddNote: function() { - return this.currentUserCan('add_note'); + return this.currentUserCan('add_note') && !Ember.isEmpty(this.get('visits')); }, canDeleteNote: function() { From 14c305c590ac333d1e3fe771362633b65aa39672 Mon Sep 17 00:00:00 2001 From: tangollama Date: Fri, 25 Mar 2016 15:28:54 -0400 Subject: [PATCH 39/56] New html-line-break helper --- app/helpers/html-line-break.js | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 app/helpers/html-line-break.js diff --git a/app/helpers/html-line-break.js b/app/helpers/html-line-break.js new file mode 100644 index 0000000000..bb8925a970 --- /dev/null +++ b/app/helpers/html-line-break.js @@ -0,0 +1,4 @@ +import Ember from 'ember'; +export default Ember.Helper.helper(function([text]) { + return new Ember.Handlebars.SafeString(text.replace(/\n/g, '
')); +}); From 5776715d6761834c8744f31195e6ad87e0c7c33a Mon Sep 17 00:00:00 2001 From: tangollama Date: Fri, 25 Mar 2016 15:29:12 -0400 Subject: [PATCH 40/56] add html-line-break --- app/patients/edit/template.hbs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/app/patients/edit/template.hbs b/app/patients/edit/template.hbs index e6415082de..95f94bef1f 100644 --- a/app/patients/edit/template.hbs +++ b/app/patients/edit/template.hbs @@ -40,14 +40,14 @@ {{#if visit.history}}
History
- {{visit.history}} + {{html-line-break visit.history}}
{{/if}} {{#if visit.historySince}}
History Since
- {{visit.historySince}} + {{html-line-break visit.historySince}}
{{/if}} @@ -71,7 +71,7 @@ , {{t 'labels.anesthesia'}}: {{procedure.anesthesiologist}} {{/if}} - {{procedure.notes}} + {{html-line-break procedure.notes}}
{{/each}}
@@ -83,7 +83,7 @@
{{date-format imaging.imagingDate}}: {{imaging.imagingType.name}}
{{imaging.result}}
-
{{imaging.notes}}
+
{{html-line-break imaging.notes}}
{{/each}}
@@ -95,7 +95,7 @@
{{date-format lab.labDate}}: {{lab.labType.name}}
{{lab.result}}
-
{{lab.notes}}
+
{{html-line-break lab.notes}}
{{/each}}
@@ -106,7 +106,7 @@ {{#each visit.patientNotes as |note|}}
{{note.authoredBy}}
- {{date-format note.date}}[{{note.noteType}}]: {{note.content}} + {{date-format note.date}}[{{note.noteType}}]: {{html-line-break note.content}}
{{/each}} From d02154d87449c660ef52ea5a904a96ffbd5112d4 Mon Sep 17 00:00:00 2001 From: tangollama Date: Fri, 25 Mar 2016 15:47:47 -0400 Subject: [PATCH 41/56] checking for undefined --- app/helpers/html-line-break.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/app/helpers/html-line-break.js b/app/helpers/html-line-break.js index bb8925a970..58a4d326f9 100644 --- a/app/helpers/html-line-break.js +++ b/app/helpers/html-line-break.js @@ -1,4 +1,8 @@ import Ember from 'ember'; export default Ember.Helper.helper(function([text]) { - return new Ember.Handlebars.SafeString(text.replace(/\n/g, '
')); -}); + if (text !== null && typeof(text) != 'undefined') { + return new Ember.Handlebars.SafeString(text.replace(/\n/g, '
')); + } else { + return null; + } +}); \ No newline at end of file From 53f73ba7ea77734d53bff74c536c30812295418c Mon Sep 17 00:00:00 2001 From: tangollama Date: Fri, 25 Mar 2016 16:51:24 -0400 Subject: [PATCH 42/56] jslinting errors in travis build MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Not happening locally… hmmm… --- app/helpers/html-line-break.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/helpers/html-line-break.js b/app/helpers/html-line-break.js index 58a4d326f9..6548762c01 100644 --- a/app/helpers/html-line-break.js +++ b/app/helpers/html-line-break.js @@ -1,6 +1,6 @@ import Ember from 'ember'; export default Ember.Helper.helper(function([text]) { - if (text !== null && typeof(text) != 'undefined') { + if (text !== null && typeof text !== 'undefined') { return new Ember.Handlebars.SafeString(text.replace(/\n/g, '
')); } else { return null; From 187caaccf650ec87c3489e055e0516e8ac6fe8cd Mon Sep 17 00:00:00 2001 From: tangollama Date: Fri, 25 Mar 2016 17:02:45 -0400 Subject: [PATCH 43/56] updating content security policy --- config/environment.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/config/environment.js b/config/environment.js index e467a343b0..7a3e2b5948 100644 --- a/config/environment.js +++ b/config/environment.js @@ -19,12 +19,14 @@ module.exports = function(environment) { } }; + ENV.contentSecurityPolicy = { - 'script-src': "'self' 'unsafe-inline' 'unsafe-eval'", 'connect-src': "'self'", + 'default-src': "'self'", 'frame-src': "'self'", - 'style-src': "'self' 'unsafe-inline'", - 'img-src': "'self' data:" + 'img-src': "'self' filesystem: data:", + 'script-src': "'self' 'unsafe-inline' 'unsafe-eval'", + 'style-src': "'self' 'unsafe-inline'" }; if (environment === 'test') { From 2665d991ca332f512bb0d24c953b92f12b41a259 Mon Sep 17 00:00:00 2001 From: tangollama Date: Sat, 26 Mar 2016 15:41:16 -0400 Subject: [PATCH 44/56] mistakenly checked in our new relic config. --- newrelic.js | 514 ---------------------------------------------------- 1 file changed, 514 deletions(-) delete mode 100644 newrelic.js diff --git a/newrelic.js b/newrelic.js deleted file mode 100644 index 75e601bb97..0000000000 --- a/newrelic.js +++ /dev/null @@ -1,514 +0,0 @@ -/** - * This file includes all of the configuration variables used by the Node.js - * module. If there's a configurable element of the module and it's not - * described in here, there's been a terrible mistake. - */ -exports.config = { - /** - * Array of application names. - * - * @env NEW_RELIC_APP_NAME - */ - app_name: ['HospitalRun Joel Worrall dev'], - /** - * The user's license key. Must be set by per-app configuration file. - * - * @env NEW_RELIC_LICENSE_KEY - */ - license_key: '840ce085b68aa062d333c4d7e8529d6f5ae4a9fe', - /** - * Hostname for the New Relic collector proxy. - * - * You shouldn't need to change this. - * - * @env NEW_RELIC_HOST - */ - host: 'collector.newrelic.com', - /** - * The port on which the collector proxy will be listening. - * - * You shouldn't need to change this. - * - * @env NEW_RELIC_PORT - */ - port: 443, - /** - * Whether or not to use SSL to connect to New Relic's servers. - * - * @env NEW_RELIC_USE_SSL - */ - ssl: true, - /** - * Proxy url - * - * A proxy url can be used in place of setting - * proxy_host, proxy_port, proxy_user, and proxy_pass. - * - * e.g. http://user:pass@host:port/ - * - * Setting proxy will override other proxy settings. - * - * @env NEW_RELIC_PROXY_URL - */ - proxy: '', - /** - * Proxy host to use to connect to the internet. - * - * @env NEW_RELIC_PROXY_HOST - */ - proxy_host: '', - /** - * Proxy port to use to connect to the internet. - * - * @env NEW_RELIC_PROXY_PORT - */ - proxy_port: '', - /** - * Proxy user name when required. - * - * @env NEW_RELIC_PROXY_USER - */ - proxy_user: '', - /** - * Proxy password when required. - * - * @env NEW_RELIC_PROXY_PASS - */ - proxy_pass: '', - /** - * Custom SSL certificates - * - * If your proxy uses a custom SSL certificate, you can add the CA text to - * this array, one entry per certificate. - * - * The easiest way to do this is with `fs.readFileSync` e.g. - * - * certificates: [ - * require('fs').readFileSync('custom.crt', 'utf8') // don't forget the utf8 - * ] - * - */ - certificates: [], - /** - * You may want more control over how the module is configured and want to - * disallow the use of New Relic's server-side configuration. To do so, set - * this parameter to true. Some configuration information is required to make - * the module work properly with the rest of New Relic, but settings such as - * apdex_t and capture_params will not be override-able by New Relic with this - * setting in effect. - * - * @env NEW_RELIC_IGNORE_SERVER_CONFIGURATION - */ - ignore_server_configuration: false, - /** - * Whether the module is enabled. - * - * @env NEW_RELIC_ENABLED - */ - agent_enabled: true, - /** - * The default Apdex tolerating / threshold value for applications, in - * seconds. The default for Node is apdexT to 100 milliseconds, which is - * lower than New Relic standard, but Node.js applications tend to be more - * latency-sensitive than most. - * - * @env NEW_RELIC_APDEX - */ - apdex_t: 0.100, - /** - * Whether to capture parameters in the request URL in slow transaction - * traces and error traces. Because this can pass sensitive data, it's - * disabled by default. If there are specific parameters you want ignored, - * use ignored_params. - * - * @env NEW_RELIC_CAPTURE_PARAMS - */ - capture_params: false, - /** - * Array of parameters you don't want captured off request URLs in slow - * transaction traces and error traces. - * - * @env NEW_RELIC_IGNORED_PARAMS - */ - ignored_params: [], - logging: { - /** - * Verbosity of the module's logging. This module uses bunyan - * (https://github.com/trentm/node-bunyan) for its logging, and as such the - * valid logging levels are 'fatal', 'error', 'warn', 'info', 'debug' and - * 'trace'. Logging at levels 'info' and higher is very terse. For support - * requests, attaching logs captured at 'trace' level are extremely helpful - * in chasing down bugs. - * - * @env NEW_RELIC_LOG_LEVEL - */ - level: 'trace', - /** - * Where to put the log file -- by default just uses process.cwd + - * 'newrelic_agent.log'. A special case is a filepath of 'stdout', - * in which case all logging will go to stdout, or 'stderr', in which - * case all logging will go to stderr. - * - * @env NEW_RELIC_LOG - */ - filepath: require('path').join(process.cwd(), 'newrelic_agent.log'), - /** - * Whether to write to a log file at all - * - * @env NEW_RELIC_LOG_ENABLED - */ - enabled: true - }, - /** - * Whether to collect & submit error traces to New Relic. - * - * @env NEW_RELIC_ERROR_COLLECTOR_ENABLED - */ - error_collector: { - /** - * Disabling the error tracer just means that errors aren't collected - * and sent to New Relic -- it DOES NOT remove any instrumentation. - */ - enabled: true, - /** - * List of HTTP error status codes the error tracer should disregard. - * Ignoring a status code means that the transaction is not renamed to - * match the code, and the request is not treated as an error by the error - * collector. - * - * Defaults to 404 NOT FOUND. - * - * @env NEW_RELIC_ERROR_COLLECTOR_IGNORE_ERROR_CODES - */ - ignore_status_codes: [404], - /** - * Whether error events are collected. - */ - capture_events: true, - /** - * The agent will collect all error events up to this number per minute. - * If there are more than that, a statistical sampling will be collected. - * Currently this uses a reservoir sampling algorithm. - * - * By increasing this setting you are both increasing the memory - * requirements of the agent as well as increasing the payload to the New - * Relic servers. The memory concerns are something you should consider for - * your own server's sake. The payload of events is compressed, but if it - * grows too large the New Relic servers may reject it. - */ - max_event_samples_stored: 100 - }, - /** - * Options regarding collecting system information. Used for system - * utilization based pricing scheme. - */ - utilization: { - /** - * This flag dictates whether the agent attempts to reach out to AWS - * to get info about the vm the process is running on. - * - * @env NEW_RELIC_UTILIZATION_DETECT_AWS - */ - detect_aws: true, - /** - * This flag dictates whether the agent attempts to reach out to AWS - * to get info about the container the process is running in. - * - * @env NEW_RELIC_UTILIZATION_DETECT_DOCKER - */ - detect_docker: true - }, - transaction_tracer: { - /** - * Whether to collect & submit slow transaction traces to New Relic. The - * instrumentation is loaded regardless of this setting, as it's necessary - * to gather metrics. Disable the agent to prevent the instrumentation from - * loading. - * - * @env NEW_RELIC_TRACER_ENABLED - */ - enabled: true, - /** - * The duration at below which the slow transaction tracer should collect a - * transaction trace. If set to 'apdex_f', the threshold will be set to - * 4 * apdex_t, which with a default apdex_t value of 500 milliseconds will - * be 2 seconds. - * - * If a time is provided, it is set in seconds. - * - * @env NEW_RELIC_TRACER_THRESHOLD - */ - transaction_threshold: 'apdex_f', - /** - * Increase this parameter to increase the diversity of the slow - * transaction traces recorded by your application over time. Confused? - * Read on. - * - * Transactions are named based on the request (see the README for the - * details of how requests are mapped to transactions), and top_n refers to - * the "top n slowest transactions" grouped by these names. The module will - * only replace a recorded trace with a new trace if the new trace is - * slower than the previous slowest trace of that name. The default value - * for this setting is 20, as the transaction trace view page also defaults - * to showing the 20 slowest transactions. - * - * If you want to record the absolute slowest transaction over the last - * minute, set top_n to 0 or 1. This used to be the default, and has a - * problem in that it will allow one very slow route to dominate your slow - * transaction traces. - * - * The module will always record at least 5 different slow transactions in - * the reporting periods after it starts up, and will reset its internal - * slow trace aggregator if no slow transactions have been recorded for the - * last 5 harvest cycles, restarting the aggregation process. - * - * @env NEW_RELIC_TRACER_TOP_N - */ - top_n: 20, - - /** - * This option affects both slow-queries and record_sql for transaction - * traces. It can have one of 3 values: 'off', 'obfuscated' or 'raw' - * When it is 'off' no slow queries will be captured, and backtraces - * and sql will not be included in transaction traces. If it is 'raw' - * or 'obfuscated' and other criteria (slow_sql.enabled etc) are met - * for a query. The raw or obfuscated sql will be included in the - * transaction trace and a slow query sample will be collected. - */ - record_sql: 'off', - - /** - * This option affects both slow-queries and record_sql for transaction - * traces. This is the minimum duration a query must take (in ms) for it - * to be considered for for slow query and inclusion in transaction traces. - */ - explain_threshold: 500 - }, - /** - * Whether to enable internal supportability metrics and diagnostics. You're - * welcome to turn these on, but they will probably be most useful to the - * New Relic node engineering team. - */ - debug: { - /** - * Whether to collect and submit internal supportability metrics alongside - * application performance metrics. - * - * @env NEW_RELIC_DEBUG_METRICS - */ - internal_metrics: true, - /** - * Traces the execution of the transaction tracer. Requires logging.level - * to be set to 'trace' to provide any useful output. - * - * WARNING: The tracer tracing data is likely only to be intelligible to a - * small number of people inside New Relic, so you should probably only - * enable tracer tracing if asked to by New Relic, because it will affect - * performance significantly. - * - * @env NEW_RELIC_DEBUG_TRACER - */ - tracer_tracing: true - }, - /** - * Rules for naming or ignoring transactions. - */ - rules: { - /** - * A list of rules of the format {pattern: 'pattern', name: 'name'} for - * matching incoming request URLs and naming the associated New Relic - * transactions. Both pattern and name are required. Additional attributes - * are ignored. Patterns may have capture groups (following JavaScript - * conventions), and names will use $1-style replacement strings. See - * the documentation for addNamingRule for important caveats. - * - * @env NEW_RELIC_NAMING_RULES - */ - name: [], - /** - * A list of patterns for matching incoming request URLs to be ignored by - * the agent. Patterns may be strings or regular expressions. - * - * @env NEW_RELIC_IGNORING_RULES - */ - ignore: [] - }, - /** - * By default, any transactions that are not affected by other bits of - * naming logic (the API, rules, or metric normalization rules) will - * have their names set to 'NormalizedUri/*'. Setting this value to - * false will set them instead to Uri/path/to/resource. Don't change - * this setting unless you understand the implications of New Relic's - * metric grouping issues and are confident your application isn't going - * to run afoul of them. Your application could end up getting black holed! - * Nobody wants that. - * - * @env NEW_RELIC_ENFORCE_BACKSTOP - */ - enforce_backstop: true, - /** - * Browser Monitoring - * - * Browser monitoring lets you correlate transactions between the server and browser - * giving you accurate data on how long a page request takes, from request, - * through the server response, up until the actual page render completes. - */ - browser_monitoring: { - - /** - * Enable browser monitoring header generation. - * - * This does not auto-instrument, rather it enables the agent to generate headers. - * The newrelic module can generate the appropriate header necessary for Browser Monitoring - * This script must be manually injected into your templates, as high as possible - * in the header, but _after_ any X-UA-COMPATIBLE HTTP-EQUIV meta tags. - * Otherwise you may hurt IE! - * - * This method must be called _during_ a transaction, and must be called every - * time you want to generate the headers. - * - * Do *not* reuse the headers between users, or even between requests. - * - * @env NEW_RELIC_BROWSER_MONITOR_ENABLE - */ - enable: true, - - /** - * Request un-minified sources from the server. - * - * @env NEW_RELIC_BROWSER_MONITOR_DEBUG - */ - debug: false - }, - /** - * Transaction Events - * - * Transaction events are sent to New Relic Insights. This event data - * includes transaction timing, transaction name, and any custom parameters. - * - * Read more here: http://newrelic.com/insights - */ - transaction_events: { - /** - * If this is disabled, the agent does not collect, nor try to send, - * analytic data. - */ - enabled: true, - - /** - * The agent will collect all events up to this number per minute. If - * there are more than that, a statistical sampling will be collected. - */ - max_samples_per_minute: 10000, - - /** - * This is used if the agent is unable to send events to the collector. - * The values from the previous harvest cycle will be merged into the next - * one with this option as the limit. - * - * This should be *greater* than max_samples_per_minute or you'll see odd - * behavior. You probably want at least double the value, but more is okay - * as long as you can handle the memory overhead. - */ - max_samples_stored: 20000 - }, - - /** - * Custom Insights Events - * - * Custom insights events are JSON object that are sent to New Relic - * Insights. You can tell the agent to send your custom events via the - * `newrelic.recordCustomEvent()` API. These events are sampled once the max - * reservoir size is reached. You can tune this setting below. - * - * Read more here: http://newrelic.com/insights - */ - custom_insights_events: { - /** - * If this is disabled, the agent does not collect, nor try to send, custom - * event data. - */ - enabled: true, - /** - * The agent will collect all events up to this number per minute. If there - * are more than that, a statistical sampling will be collected. Current - * this uses a reservoir sampling algorithm. - * - * By increasing this setting you are both increasing the memory - * requirements of the agent as well as increasing the payload to the New - * Relic servers. The memory concerns are something you should consider for - * your own server's sake. The payload of events is compressed, but if it - * grows too large the New Relic servers may reject it. - */ - max_samples_stored: 1000 - }, - /** - * This is used to configure properties about the user's host name. - */ - process_host: { - /** - * Configurable display name for hosts - * - * @env NEW_RELIC_PROCESS_HOST_DISPLAY_NAME - */ - display_name: '', - /** - * ip address preference when creating hostnames - * - * @env NEW_RELIC_IPV_PREFERENCE - */ - ipv_preference: '4' - }, - - - /** - * High Security - * - * High security mode (v2) is a setting which prevents any sensitive data from - * being sent to New Relic. The local setting must match the server setting. - * If there is a mismatch the agent will log a message and act as if it is - * disabled. - * - * Attributes of high security mode (when enabled): - * * requires SSL - * * does not allow capturing of http params - * * does not allow custom params - * - * To read more see: https://docs.newrelic.com/docs/subscriptions/high-security - */ - high_security: false, - - /** - * Labels - * - * An object of label names and values that will be applied to the data sent - * from this agent. Both label names and label values have a maximum length of - * 255 characters. This object should contain at most 64 labels. - */ - labels: {}, - - /** - * These options control behavior for slow queries, but do not affect sql - * nodes in transaction traces. - * slow_sql.enabled enables and disables slow_sql recording - * slow_sql.max_samples sets the maximum number of slow query samples that - * will be collected in a single harvest cycle. - */ - slow_sql: { - enabled: false, - max_samples: 10 - } -} From af24000a10441b09e183eeadd5a15cbe00451fb0 Mon Sep 17 00:00:00 2001 From: tangollama Date: Sun, 27 Mar 2016 01:13:37 -0400 Subject: [PATCH 45/56] updated test for CRUD exercises --- tests/acceptance/patient-notes-test.js | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/tests/acceptance/patient-notes-test.js b/tests/acceptance/patient-notes-test.js index 0a492893dd..b4435104b5 100644 --- a/tests/acceptance/patient-notes-test.js +++ b/tests/acceptance/patient-notes-test.js @@ -19,7 +19,7 @@ function tabTest(tabName, tabId) { }); } -test('visiting /patients new note route', function(assert) { +test('patient notes crud testing', function(assert) { runWithPouchDump('default', function() { authenticateUser(); visit('/patients'); @@ -68,5 +68,19 @@ test('visiting /patients new note route', function(assert) { andThen(function() { assert.equal(find('label:contains(Note)').length, 1, 'Notes modal appeared.'); }); + fillIn('.test-note-content textarea', 'This is a note.'); + fillIn('.test-note-attribution input', 'Dr. Nick'); + click('.modal-footer button:contains(Add)'); + andThen(function(){ + assert.equal(find('#visit-notes table tr td:contains(This is a note.)').length, 1, 'Successfully added note.'); + }); + andThen(function() { + click('#visit-notes table tr td button:contains(Delete)'); + waitToAppear('.modal-dialog'); + click('.modal-footer button:contains(Ok)'); + }); + andThen(function() { + assert.equal(find('#visit-notes table tr td:contains(This is a note.)').length, 0, 'Successfully deleted note.'); + }); }); }); \ No newline at end of file From 2b0ca5f5ab97556234d84d6c99d5eb5e612256ce Mon Sep 17 00:00:00 2001 From: tangollama Date: Sun, 27 Mar 2016 01:15:13 -0400 Subject: [PATCH 46/56] updated canAddNote logic --- app/mixins/patient-notes.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/mixins/patient-notes.js b/app/mixins/patient-notes.js index 8e1c460c8f..cb13e8cbfd 100644 --- a/app/mixins/patient-notes.js +++ b/app/mixins/patient-notes.js @@ -1,9 +1,8 @@ import Ember from 'ember'; - export default Ember.Mixin.create({ canAddNote: function() { - return this.currentUserCan('add_note') && !Ember.isEmpty(this.get('visits')); + return this.currentUserCan('add_note') && (!Ember.isEmpty(this.get('visits')) || !Ember.isEmpty(this.get('model.visits'))); }, canDeleteNote: function() { From 7ddc045233e99f063af4167543fb8bbde268a1a5 Mon Sep 17 00:00:00 2001 From: tangollama Date: Sun, 27 Mar 2016 21:10:07 -0400 Subject: [PATCH 47/56] Injecting the translation service into models I needed it for a computed property in patient-note. --- app/initializers/i18n.js | 1 + 1 file changed, 1 insertion(+) diff --git a/app/initializers/i18n.js b/app/initializers/i18n.js index 02511aad45..3f727d9ec2 100644 --- a/app/initializers/i18n.js +++ b/app/initializers/i18n.js @@ -7,5 +7,6 @@ export default { app.inject('route', 'i18n', 'service:i18n'); app.inject('controller', 'i18n', 'service:i18n'); app.inject('mixin', 'i18n', 'service:i18n'); + app.inject('model', 'i18n', 'service:i18n'); } }; \ No newline at end of file From 5260f75ef2273fd0a00fa48cf05e269f48d4f43a Mon Sep 17 00:00:00 2001 From: tangollama Date: Sun, 27 Mar 2016 21:24:37 -0400 Subject: [PATCH 48/56] translations and type-ahead Added the translations to the patient note and a type-ahead search for the physician list. --- app/patients/notes/template.hbs | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/app/patients/notes/template.hbs b/app/patients/notes/template.hbs index 1bde360d80..087915f057 100644 --- a/app/patients/notes/template.hbs +++ b/app/patients/notes/template.hbs @@ -6,11 +6,11 @@ updateButtonAction=updateButtonAction updateButtonText=updateButtonText }} {{#em-form model=model submitButton=false }} - {{em-text label="Note" property="content" rows=3}} + {{em-text label=(t 'patients.notes.note_label') property="content" rows=3 class="test-note-content required form-input-group"}} - - {{em-select className="col-sm-3" property="attribution" - label="On Behalf Of" content=physicianList prompt=" " + {{select-or-typeahead + property="attribution" + label=(t 'patients.notes.on_behalf_of_label' ) + list=physicianList + selection=attribution + className="form-input-group test-note-attribution col-sm-3" }} {{/em-form}} {{/modal-dialog}} \ No newline at end of file From 71ed560471d025bf8ce79e07e2a5b2c3a3ba87ca Mon Sep 17 00:00:00 2001 From: tangollama Date: Sun, 27 Mar 2016 21:48:13 -0400 Subject: [PATCH 49/56] added actions deletePatientNote and showDeletePatientNote --- app/visits/edit/controller.js | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/app/visits/edit/controller.js b/app/visits/edit/controller.js index 1fde71c1aa..58b64039fc 100644 --- a/app/visits/edit/controller.js +++ b/app/visits/edit/controller.js @@ -340,6 +340,24 @@ export default AbstractEditController.extend(ChargeActions, PatientSubmodule, Pa showEditVitals: function(vitals) { this.send('openModal', 'visits.vitals.edit', vitals); + }, + + showDeletePatientNote: function(note) { + this.send('openModal', 'dialog', Ember.Object.create({ + confirmAction: 'deletePatientNote', + title: 'Delete Note', + message: 'Are you sure you want to delete this note?', + noteToDelete: note, + updateButtonAction: 'confirm', + updateButtonText: 'Ok' + })); + }, + + deletePatientNote: function(model) { + var note = model.get('noteToDelete'); + var patientNotes = this.get('model.patientNotes'); + patientNotes.removeObject(note); + this.send('update', true); } } }); From 9eba2145d4c79a8bd8df10cc47f94bf88040dd86 Mon Sep 17 00:00:00 2001 From: tangollama Date: Sun, 27 Mar 2016 21:48:32 -0400 Subject: [PATCH 50/56] add route-level action for delete deletePatientNote --- app/visits/edit/route.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/app/visits/edit/route.js b/app/visits/edit/route.js index 065b0c4691..ccbe9dfeec 100644 --- a/app/visits/edit/route.js +++ b/app/visits/edit/route.js @@ -18,7 +18,9 @@ export default AbstractEditRoute.extend(ChargeRoute, { actions: { updateNote: function() { this.controller.send('update', true); + }, + deletePatientNote: function(model) { + this.controller.send('deletePatientNote', model); } } - -}); +}); \ No newline at end of file From 6f0002757c4d71fff63c709148d67f98555757dc Mon Sep 17 00:00:00 2001 From: tangollama Date: Sun, 27 Mar 2016 21:49:09 -0400 Subject: [PATCH 51/56] baking translations into the model authoredBy computed property --- app/locales/en/translations.js | 8 ++++++++ app/models/patient-note.js | 4 ++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/app/locales/en/translations.js b/app/locales/en/translations.js index f901c621e9..7e994a6d44 100644 --- a/app/locales/en/translations.js +++ b/app/locales/en/translations.js @@ -575,5 +575,13 @@ export default { }, common: { actions: 'Actions' + }, + patients: { + notes: { + on_behalf_of_label: 'On Behalf Of', + on_behalf_of_copy: 'on behalf of', + please_select_a_visit: 'Please select a visit', + note_label: 'Note' + } } }; diff --git a/app/models/patient-note.js b/app/models/patient-note.js index 80cc2609d7..84e3b6c827 100644 --- a/app/models/patient-note.js +++ b/app/models/patient-note.js @@ -1,11 +1,11 @@ -import { translationMacro as t } from 'ember-i18n'; import AbstractModel from 'hospitalrun/models/abstract'; import Ember from 'ember'; import DS from 'ember-data'; export default AbstractModel.extend({ authoredBy: function() { if (!Ember.isEmpty(this.get('attribution'))) { - return this.get('attribution') + ' ' + t('messages.on_behalf_of') + ' ' + this.get('createdBy'); + let i18n = this.get('i18n'); + return this.get('createdBy') + ' ' + i18n.t('patients.notes.on_behalf_of_copy') + ' ' + this.get('attribution'); } else { return this.get('createdBy'); } From a0e226f8b09c9e17b97fddd9c4effe3503ea0616 Mon Sep 17 00:00:00 2001 From: tangollama Date: Sun, 27 Mar 2016 21:49:40 -0400 Subject: [PATCH 52/56] Adding physicianList --- app/patients/notes/controller.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/app/patients/notes/controller.js b/app/patients/notes/controller.js index d88c7805f6..3425fb1871 100644 --- a/app/patients/notes/controller.js +++ b/app/patients/notes/controller.js @@ -3,12 +3,17 @@ import Ember from 'ember'; import IsUpdateDisabled from 'hospitalrun/mixins/is-update-disabled'; import PatientSubmodule from 'hospitalrun/mixins/patient-submodule'; import PatientNotes from 'hospitalrun/mixins/patient-notes'; -import SelectValues from 'hospitalrun/utils/select-values'; import UserSession from 'hospitalrun/mixins/user-session'; export default AbstractEditController.extend(IsUpdateDisabled, UserSession, PatientSubmodule, PatientNotes, { cancelAction: 'closeModal', updateAction: 'updateNote', - physicianList: Ember.computed.map('patientsController.physicianList.value', SelectValues.selectValuesMap), + moduleController: Ember.inject.controller('patients'), + physicianList: Ember.computed.alias('moduleController.physicianList'), + lookupListsToUpdate: [{ + name: 'physicianList', + property: 'model.attribution', + id: 'physician_list' + }], title: function() { if (this.get('model.isNew')) { return 'New Note for ' + this.get('model.patient.displayName'); From 9fef7709cf4587f36e03eacdfc62b9c49a8accf1 Mon Sep 17 00:00:00 2001 From: tangollama Date: Sun, 27 Mar 2016 21:50:12 -0400 Subject: [PATCH 53/56] new asserts for CRUD Added an insert, update, and delete assertions. --- tests/acceptance/patient-notes-test.js | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/tests/acceptance/patient-notes-test.js b/tests/acceptance/patient-notes-test.js index b4435104b5..a02a49b1d5 100644 --- a/tests/acceptance/patient-notes-test.js +++ b/tests/acceptance/patient-notes-test.js @@ -71,16 +71,27 @@ test('patient notes crud testing', function(assert) { fillIn('.test-note-content textarea', 'This is a note.'); fillIn('.test-note-attribution input', 'Dr. Nick'); click('.modal-footer button:contains(Add)'); - andThen(function(){ + andThen(function() { assert.equal(find('#visit-notes table tr td:contains(This is a note.)').length, 1, 'Successfully added note.'); }); + // update note + andThen(function() { + click('#visit-notes table tr td button:contains(Edit)'); + waitToAppear('.modal-dialog'); + fillIn('.test-note-content textarea', 'This is an updated note.'); + click('.modal-footer button:contains(Update)'); + }); + andThen(function() { + assert.equal(find('#visit-notes table tr td:contains(This is an updated note.)').length, 1, 'Successfully updated note.'); + }); + // delete note andThen(function() { click('#visit-notes table tr td button:contains(Delete)'); waitToAppear('.modal-dialog'); - click('.modal-footer button:contains(Ok)'); + click('.modal-footer button:contains(Ok)'); }); andThen(function() { - assert.equal(find('#visit-notes table tr td:contains(This is a note.)').length, 0, 'Successfully deleted note.'); + assert.equal(find('#visit-notes table tr td:contains(This is an updated note.)').length, 0, 'Successfully deleted note.'); }); }); }); \ No newline at end of file From c1a16dd68c3ace23537e31d31fe498009ffa0817 Mon Sep 17 00:00:00 2001 From: tangollama Date: Sun, 27 Mar 2016 22:09:55 -0400 Subject: [PATCH 54/56] updating test timing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit An assertion failed in the travis build but passed in my environment. I’m guessing that’s an execution issue on my part. Hoping this resolves it. --- tests/acceptance/patient-notes-test.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/acceptance/patient-notes-test.js b/tests/acceptance/patient-notes-test.js index a02a49b1d5..07d44df69c 100644 --- a/tests/acceptance/patient-notes-test.js +++ b/tests/acceptance/patient-notes-test.js @@ -71,6 +71,7 @@ test('patient notes crud testing', function(assert) { fillIn('.test-note-content textarea', 'This is a note.'); fillIn('.test-note-attribution input', 'Dr. Nick'); click('.modal-footer button:contains(Add)'); + waitToAppear('#visit-notes table tr td:contains(This is a note.)'); andThen(function() { assert.equal(find('#visit-notes table tr td:contains(This is a note.)').length, 1, 'Successfully added note.'); }); @@ -82,10 +83,12 @@ test('patient notes crud testing', function(assert) { click('.modal-footer button:contains(Update)'); }); andThen(function() { + waitToAppear('#visit-notes table tr td:contains(This is an updated note.)'); assert.equal(find('#visit-notes table tr td:contains(This is an updated note.)').length, 1, 'Successfully updated note.'); }); // delete note andThen(function() { + waitToAppear('#visit-notes table tr td'); click('#visit-notes table tr td button:contains(Delete)'); waitToAppear('.modal-dialog'); click('.modal-footer button:contains(Ok)'); From 44c83296f43909a1438d8c5c8a34a4f3edb60935 Mon Sep 17 00:00:00 2001 From: tangollama Date: Mon, 28 Mar 2016 15:27:48 -0400 Subject: [PATCH 55/56] more adjustments for timing The test passes locally. Hoping it will checked in as well. --- tests/acceptance/patient-notes-test.js | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/tests/acceptance/patient-notes-test.js b/tests/acceptance/patient-notes-test.js index 07d44df69c..c709667428 100644 --- a/tests/acceptance/patient-notes-test.js +++ b/tests/acceptance/patient-notes-test.js @@ -68,17 +68,21 @@ test('patient notes crud testing', function(assert) { andThen(function() { assert.equal(find('label:contains(Note)').length, 1, 'Notes modal appeared.'); }); - fillIn('.test-note-content textarea', 'This is a note.'); - fillIn('.test-note-attribution input', 'Dr. Nick'); - click('.modal-footer button:contains(Add)'); - waitToAppear('#visit-notes table tr td:contains(This is a note.)'); andThen(function() { + fillIn('.test-note-content textarea', 'This is a note.'); + fillIn('.test-note-attribution input', 'Dr. Nick'); + click('.modal-footer button:contains(Add)'); + }); + andThen(function() { + waitToAppear('#visit-notes table tr td:contains(This is a note.)'); assert.equal(find('#visit-notes table tr td:contains(This is a note.)').length, 1, 'Successfully added note.'); }); // update note andThen(function() { click('#visit-notes table tr td button:contains(Edit)'); waitToAppear('.modal-dialog'); + }); + andThen(function() { fillIn('.test-note-content textarea', 'This is an updated note.'); click('.modal-footer button:contains(Update)'); }); @@ -90,6 +94,8 @@ test('patient notes crud testing', function(assert) { andThen(function() { waitToAppear('#visit-notes table tr td'); click('#visit-notes table tr td button:contains(Delete)'); + }); + andThen(function() { waitToAppear('.modal-dialog'); click('.modal-footer button:contains(Ok)'); }); From c5e07067b2e2985f8807b497650e716ffee1b55c Mon Sep 17 00:00:00 2001 From: tangollama Date: Tue, 29 Mar 2016 01:44:01 -0400 Subject: [PATCH 56/56] Fixing formatting and display issues MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Per issues pointed out by @jkleinsc, now resolved the size of the On Behalf Of input as well as the “undefined” issue with the background display. Two-way data binding for the win! Now… let’s merge this sucker. --- .gitignore | 2 ++ app/patients/edit/controller.js | 3 ++- app/patients/notes/template.hbs | 2 +- app/visits/edit/controller.js | 1 + 4 files changed, 6 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index bad375e368..71ac584da7 100644 --- a/.gitignore +++ b/.gitignore @@ -27,3 +27,5 @@ server/config.js .brackets.json /app/nbproject/private/ newrelic_agent.log + +newrelic.js diff --git a/app/patients/edit/controller.js b/app/patients/edit/controller.js index d047298c2e..5ef22f5d90 100644 --- a/app/patients/edit/controller.js +++ b/app/patients/edit/controller.js @@ -375,7 +375,8 @@ export default AbstractEditController.extend(BloodTypes, ReturnTo, UserSession, if (this.get('canAddNote')) { if (Ember.isEmpty(model)) { model = this.get('store').createRecord('patient-note', { - patient: this.get('model') + patient: this.get('model'), + createdBy: this.getUserName() }); } this.send('openModal', 'patients.notes', model); diff --git a/app/patients/notes/template.hbs b/app/patients/notes/template.hbs index 087915f057..361467c33c 100644 --- a/app/patients/notes/template.hbs +++ b/app/patients/notes/template.hbs @@ -24,7 +24,7 @@ label=(t 'patients.notes.on_behalf_of_label' ) list=physicianList selection=attribution - className="form-input-group test-note-attribution col-sm-3" + className="form-input-group test-note-attribution" }} {{/em-form}} {{/modal-dialog}} \ No newline at end of file diff --git a/app/visits/edit/controller.js b/app/visits/edit/controller.js index 58b64039fc..572e86d5d8 100644 --- a/app/visits/edit/controller.js +++ b/app/visits/edit/controller.js @@ -277,6 +277,7 @@ export default AbstractEditController.extend(ChargeActions, PatientSubmodule, Pa if (Ember.isEmpty(model)) { model = this.get('store').createRecord('patient-note', { visit: this.get('model'), + createdBy: this.getUserName(), patient: this.get('model').get('patient'), noteType: this._computeNoteType(this.get('model')) });