Skip to content

Commit

Permalink
close #19 Support creating and editing groups of observations.
Browse files Browse the repository at this point in the history
  • Loading branch information
mgurley committed Oct 21, 2016
1 parent ca4ada9 commit 9bb000f
Show file tree
Hide file tree
Showing 34 changed files with 1,375 additions and 17 deletions.
1 change: 1 addition & 0 deletions app/assets/javascripts/application.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,5 @@
//= require interleave.condition_occurrence
//= require interleave.drug_exposure
//= require interleave.measurement
//= require interleave.observation
//= require interleave.procedure_occurrence
68 changes: 68 additions & 0 deletions app/assets/javascripts/interleave.observation.js.coffee
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
class Interleave.Observation
constructor: () ->
render: (link) ->
$(link).on 'click', (e) ->
$modal = $('#observation_modal')
$observation = $('#observation_modal .observation')
$.ajax(this.href).done (response) ->
$observation.html(response)
$modal.foundation 'open'
$('.datepicker').datepicker
onClose: (dateText, inst) ->
$(inst.input).focusout()
return
changeMonth: true
changeYear: true
interleaveDatapointConceptsUrl = $('#concepts_interleave_datapoint_url').attr('href')
$('.observation_form').enableClientSideValidations()
if $('.observation_concept_id_select').length
$('#observation_observation_concept_id').select2
ajax:
url: interleaveDatapointConceptsUrl
dataType: 'json'
delay: 250
data: (params) ->
{
q: params.term
page: params.page
}
processResults: (data, params) ->
params.page = params.page or 1
results = $.map(data.concepts, (obj) ->
obj.id = obj.concept_id
obj.text = obj.text
obj
)

{
results: results
pagination: more: params.page * 10 < data.total
}
cache: true
escapeMarkup: (markup) ->
markup
minimumInputLength: 2

$('#observation_condition_concept_id').on 'select2:select', (e) ->
$(this).blur()
return

$('.observation_form').on('ajax:success', (e, data, status, xhr) ->
$modal.foundation 'close'
Turbolinks.visit(location.toString())
$('.observations_list').fadeOut()
).on 'ajax:error', (e, xhr, status, error) ->

$('.observation_form .cancel-link').on 'click', (e) ->
$modal.foundation 'close'
e.preventDefault()

return
e.preventDefault()
return
return

$(document).on 'page:load ready', ->
return unless $('.observations.index').length > 0
ui = new Interleave.Observation
ui.render('.observation_link')
1 change: 1 addition & 0 deletions app/assets/stylesheets/application.scss
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,6 @@
@import "drug_exposures";
@import "measurements";
@import "procedure_occurrences";
@import "observations";
@import "jquery.ui.override";
@import "select2";
129 changes: 129 additions & 0 deletions app/assets/stylesheets/observations.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
#observations {
@include grid-row();

.interleave_datapoint {
@include grid-column(
$columns: 20
);
}

.observations_list {
@include grid-column(
$columns: 24
);

th .current {
padding-right: 2em;
background-repeat: no-repeat;
background-position: right center;
}

th .asc {
background-image: asset_url("drop25.png");
}

th .desc {
background-image: asset_url("drop27.png");
}

table {
@include grid-column(
$columns: 24
);
}
}
}

#observation_modal {
position: fixed;
bottom: 0;
top: 30% !important;
right: 0;
left: 0;
width: 100%;
}

#observation {
@include grid-row();

.ui-autocomplete-input {
width: 90%;
height: 2.5rem;
}
.ui-button {
width: 5%;
height: 2.5rem;
}

.observation_date {
@include grid-column(
$columns: 12
);
input {
margin-bottom: 0;
}
}

.observation_type_concept_id {
label {
display: block;
}
@include grid-column(
$columns: 12
);
select {
margin-bottom: 0;
}

.select2 {
width: 100% !important;
}
}

.observation_value {
label {
display: block;
}
@include grid-column(
$columns: 12
);
input {
margin-bottom: 0;
}
}

.interleave_sub_datapoint {
label {
display: block;
}
@include grid-column(
$columns: 12
);
input {
margin-bottom: 0;
}
}

.interleave_sub_datapoints {
.left {
@include grid-column(
$columns: 12
);

}

.right {
@include grid-column(
$columns: 12
);
}
}

.navigation {
padding: 1rem;
@include grid-column-offset(12);
@include grid-column(
$columns: 12
);
}
}
80 changes: 80 additions & 0 deletions app/controllers/observations_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
class ObservationsController < ApplicationController
helper_method :sort_column, :sort_direction
before_filter :load_interleave_registry, only: [:index, :new, :create, :edit]
before_filter :load_interleave_person, only: [:index, :new, :create, :edit]
before_filter :load_observation, only: [:edit, :update]
before_filter :load_interleave_datapoint, only: [:new, :edit]

def index
@datapoint = @registry.interleave_datapoints.find(params[:datapoint_id])
params[:page]||= 1
options = {}
options[:sort_column] = sort_column
options[:sort_direction] = sort_direction
add_breadcrumbs(registry: @registry, interleave_person: @interleave_person, datapoint: @datapoint)
@observations = Observation.by_person(@interleave_person.person.person_id).by_interleave_data_point(@datapoint.id, options).paginate(per_page: 10, page: params[:page])
end

def new
@observation = Observation.new()
@observation.interleave_datapoint = @datapoint
@datapoint.initialize_defaults(@observation)
@concepts = []
@type_concepts = load_concepts('observation_type_concept_id')
@sub_datapoints = @datapoint.initialize_sub_datapoint_entities
respond_to do |format|
format.html { render :layout => false }
end
end

def create
@observation = Observation.new(observation_params)
interleave_registry_cdm_source = @registry.interleave_registry_cdm_sources.where(cdm_source_name: InterleaveRegistryCdmSource::CDM_SOURCE_EX_NIHILO).first
@observation.person = @interleave_person.person

respond_to do |format|
if @observation.create_with_sub_datapoints!(interleave_registry_cdm_source, observations: params[:observations])
format.js { }
else
format.js { render json: { errors: @observation.errors.full_messages }, status: :unprocessable_entity }
end
end
end

def edit
@observation.interleave_datapoint = @datapoint
@concepts = [[@observation.observation_concept.concept_name, @observation.observation_concept_id]]
@type_concepts = load_concepts('observation_type_concept_id')
@sub_datapoints = @datapoint.initialize_sub_datapoint_entities(@observation.interleave_entity)
respond_to do |format|
format.html { render :layout => false }
end
end

def update
respond_to do |format|
if @observation.update_with_sub_datapoints!(observation_params, observations: params[:observations])
format.js { }
else
format.js { render json: { errors: @observation.errors.full_messages }, status: :unprocessable_entity }
end
end
end

private
def observation_params
params.require(:observation).permit(:interleave_datapoint_id, :observation_concept_id, :observation_date, :observation_time, :observation_type_concept_id, :value_as_number, :value_as_string, :value_as_concept_id, :qualifier_concept_id, :unit_concept_id)
end

def load_observation
@observation = Observation.find(params[:id])
end

def sort_column
['observation_date'].concat(@datapoint.interleave_sub_datapoints.map { |interleave_sub_datapoint| interleave_sub_datapoint.id.to_s }).include?(params[:sort]) ? params[:sort] : "#{@datapoint.id}"
end

def sort_direction
%w[asc desc].include?(params[:direction]) ? params[:direction] : 'asc'
end
end
4 changes: 4 additions & 0 deletions app/helpers/application_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@ def generate_datapoint_url(registry, interleave_person, datapoint, domain_id)
haml_tag(:li, class: active?('active', 'measurements', 'index', 'datapoint_id' => datapoint.id.to_s)) do
concat link_to datapoint.name, interleave_registry_interleave_person_measurements_url(registry, interleave_person, datapoint_id: datapoint.id), class: 'datapoint'
end
when 'Observation'
haml_tag(:li, class: active?('active', 'observations', 'index', 'datapoint_id' => datapoint.id.to_s)) do
concat link_to datapoint.group_name, interleave_registry_interleave_person_observations_url(registry, interleave_person, datapoint_id: datapoint.id), class: 'datapoint'
end
when 'Procedure'
haml_tag(:li, class: active?('active', 'procedure_occurrences', 'index', 'datapoint_id' => datapoint.id.to_s)) do
concat link_to datapoint.name, interleave_registry_interleave_person_procedure_occurrences_url(registry, interleave_person, datapoint_id: datapoint.id)
Expand Down
10 changes: 9 additions & 1 deletion app/models/concept.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ class Concept < ActiveRecord::Base
VOCABULARY_ID_GENDER = 'Gender'
VOCABULARY_ID_LOINC = 'LOINC'
VOCABULARY_ID_MEAS_TYPE = 'Meas Type'
VOCABULARY_ID_OBSERVATION_TYPE = 'Observation Type'
VOCABULARY_ID_PROCEDURE_TYPE = 'Procedure Type'
VOCABULARY_ID_RACE = 'Race'
VOCABULARY_ID_RELATIONSHIP = 'Relationship'
Expand All @@ -25,13 +26,14 @@ class Concept < ActiveRecord::Base
DOMAIN_ID_MEASUREMENT = 'Measurement'
DOMAIN_ID_MEAS_VALUE = 'Meas Value'
DOMAIN_ID_METADATA = 'Metadata'
DOMAIN_ID_OBSERVATION = 'Observation'
DOMAIN_ID_PROCEDURE = 'Procedure'
DOMAIN_ID_RACE = 'Race'
DOMAIN_ID_RELATIONSHIP = 'Relationship'
DOMAIN_ID_ROUTE = 'Route'
DOMAIN_ID_TYPE_CONCEPT = 'Type Concept'
DOMAIN_ID_UNIT = 'Unit'
DOMAIN_IDS = [DOMAIN_ID_CONDITION, DOMAIN_ID_GENDER, DOMAIN_ID_ETHNICITY, DOMAIN_ID_MEASUREMENT, DOMAIN_ID_METADATA, DOMAIN_ID_PROCEDURE, DOMAIN_ID_RACE, DOMAIN_ID_RELATIONSHIP, DOMAIN_ID_ROUTE, DOMAIN_ID_TYPE_CONCEPT, DOMAIN_ID_UNIT]
DOMAIN_IDS = [DOMAIN_ID_CONDITION, DOMAIN_ID_GENDER, DOMAIN_ID_ETHNICITY, DOMAIN_ID_MEASUREMENT, DOMAIN_ID_METADATA, DOMAIN_ID_OBSERVATION, DOMAIN_ID_PROCEDURE, DOMAIN_ID_RACE, DOMAIN_ID_RELATIONSHIP, DOMAIN_ID_ROUTE, DOMAIN_ID_TYPE_CONCEPT, DOMAIN_ID_UNIT]

CONCEPT_CLASS_ANSWER = 'Answer'
CONCEPT_CLASS_CLINICAL_FINDING = 'Clinical Finding'
Expand All @@ -45,10 +47,12 @@ class Concept < ActiveRecord::Base
CONCEPT_CLASS_INGREDIENT = 'Ingredient'
CONCEPT_CLASS_LAB_TEST = 'Lab Test'
CONCEPT_CLASS_MEAS_TYPE = 'Meas Type'
CONCEPT_CLASS_OBSERVATION_TYPE = 'Observation Type'
CONCEPT_CLASS_PROCEDURE_TYPE = 'Procedure Type'
CONCEPT_CLASS_QUALIFIER_VALUE = 'Qualifier Value'
CONCEPT_CLASS_RACE = 'Race'
CONCEPT_CLASS_RELATIONSHIP = 'Relationship'
CONCEPT_CLASS_SURVEY = 'Survey'
CONCEPT_CLASS_UNIT = 'Unit'
CONCEPT_CLASSES = [CONCEPT_CLASS_ANSWER, CONCEPT_CLASS_CLINICAL_FINDING, CONCEPT_CLASS_CONDITION_TYPE, CONCEPT_CLASS_DRUG_TYPE, CONCEPT_CLASS_CPT4, CONCEPT_CLASS_DOMAIN, CONCEPT_CLASS_GENDER, CONCEPT_CLASS_ETHNICITY, CONCEPT_CLASS_LAB_TEST, CONCEPT_CLASS_MEAS_TYPE, CONCEPT_CLASS_PROCEDURE_TYPE, CONCEPT_CLASS_QUALIFIER_VALUE, CONCEPT_CLASS_RACE, CONCEPT_CLASS_RELATIONSHIP, CONCEPT_CLASS_UNIT]

Expand Down Expand Up @@ -76,6 +80,10 @@ def self.measurement_types
valid.where(domain_id: Concept::DOMAIN_ID_TYPE_CONCEPT, vocabulary_id: Concept::VOCABULARY_ID_MEAS_TYPE , concept_class_id: Concept::CONCEPT_CLASS_MEAS_TYPE)
end

def self.observation_types
valid.where(domain_id: Concept::DOMAIN_ID_TYPE_CONCEPT, vocabulary_id: Concept::VOCABULARY_ID_OBSERVATION_TYPE , concept_class_id: Concept::CONCEPT_CLASS_OBSERVATION_TYPE)
end

def self.procedure_types
valid.where(domain_id: Concept::DOMAIN_ID_TYPE_CONCEPT, vocabulary_id: Concept::VOCABULARY_ID_PROCEDURE_TYPE , concept_class_id: Concept::CONCEPT_CLASS_PROCEDURE_TYPE)
end
Expand Down
3 changes: 3 additions & 0 deletions app/models/concept_relationship.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
class ConceptRelationship < ActiveRecord::Base
self.table_name = 'concept_relationship'
end
Loading

0 comments on commit 9bb000f

Please sign in to comment.