├── .editorconfig
├── .env
├── .eslintignore
├── .eslintrc
├── .github
├── PULL_REQUEST_TEMPLATE.md
└── workflows
│ └── deploy-workflow.yaml
├── .gitignore
├── .travis.yml
├── LICENSE
├── README.md
├── config-overrides.js
├── deploy.yml
├── design
├── readme.md
└── shr_fluxnotes_concept_v11.3_screens_components_v1.pdf
├── docs
├── FluxNotesManual_v0.1.docx
├── Structured Phrase Format Descriptions.pptx
└── fluxArchitecture.vpp
├── package.json
├── public
├── DebraHernandez672.jpg
├── DebraHernandez672.png
├── EllaOrtiz111.png
├── JaneBradshaw146.png
├── ServerConfig.json
├── WEB-INF
│ └── web.xml
├── WesWelker83.png
├── clinicalTrialEnrollmentSheet.pdf
├── clinicalTrialUnenrolledSheet.pdf
├── compass-logo.png
├── config.js
├── deceasedSheet.pdf
├── diseaseStatusSheet.pdf
├── fluxnotes_logo_b&w.png
├── fluxnotes_logo_color.png
├── icare_logo_b&w.png
├── icare_logo_color.png
├── icons
│ ├── angled-pencil.svg
│ ├── icon_arrow_left.svg
│ ├── icon_view_left.png
│ ├── icon_view_left.svg
│ ├── icon_view_middle.png
│ ├── icon_view_middle.svg
│ ├── icon_view_right.png
│ └── icon_view_right.svg
├── index.html
├── landing
│ ├── fluxnotes_compass.gif
│ ├── fluxnotes_full.gif
│ ├── fluxnotes_gif_fullSize.gif
│ ├── fluxnotes_poc.gif
│ ├── grid_background.png
│ ├── icon_efficacy_research.png
│ ├── icon_efficacy_research.svg
│ ├── icon_market_surveillance.png
│ ├── icon_market_surveillance.svg
│ ├── icon_provider_burden.png
│ ├── icon_provider_burden.svg
│ ├── icon_rare_diseases.png
│ ├── icon_rare_diseases.svg
│ ├── icon_regimen_analysis.png
│ ├── icon_regimen_analysis.svg
│ ├── icon_utilization.png
│ ├── icon_utilization.svg
│ └── img_fluxnotes_lite.jpg
├── logos
│ ├── ASCO.png
│ ├── Alliance.png
│ ├── BWH.png
│ ├── Browserstack-logo.png
│ ├── DanaFarber.png
│ ├── FluxNotesLogo.png
│ ├── ICARE.png
│ ├── MITRE.png
│ ├── SHR.png
│ ├── codex-Logo.png
│ ├── favicon-16x16.png
│ ├── favicon-32x32.png
│ ├── favicon.ico
│ └── mCODE-Logo.png
├── mapper.js
├── pathology-report.pdf
├── spa.jsp
├── stagingSheet.pdf
└── toxicitySheet.pdf
├── scripts
└── check-version.js
├── src
├── __test__
│ ├── TestPatient2V09.json
│ ├── TestPatientV09.json
│ ├── backend
│ │ ├── config
│ │ │ └── ConfigManager.test.js
│ │ ├── dashboard
│ │ │ └── DashboardManager.test.js
│ │ ├── dataaccess
│ │ │ ├── DataAccess.test.js
│ │ │ └── McodeV09SmartOnFhirDataSource.test.js
│ │ ├── lib
│ │ │ ├── cql-execution
│ │ │ │ └── CQLExecutionEngine.test.js
│ │ │ ├── progression_lookup.test.js
│ │ │ ├── staging.test.js
│ │ │ ├── tnmstage_lookup.test.js
│ │ │ └── toxicreaction_lookup.test.js
│ │ ├── mcode
│ │ │ ├── BarChart.test.js
│ │ │ ├── OptionsCheckboxList.test.js
│ │ │ ├── TreatmentOptionsActions.test.js
│ │ │ ├── TreatmentOptionsOutcome.test.js
│ │ │ ├── TreatmentOptionsReducers.test.js
│ │ │ ├── mock-data
│ │ │ │ ├── index.js
│ │ │ │ ├── patients.json
│ │ │ │ └── testoptions.json
│ │ │ └── services
│ │ │ │ ├── CLQOutcomesService.test.js
│ │ │ │ ├── filter.json
│ │ │ │ ├── processed.js
│ │ │ │ ├── response.json
│ │ │ │ └── rows.js
│ │ ├── model
│ │ │ ├── CodeableConceptUtils.test.js
│ │ │ ├── actor
│ │ │ │ └── FluxDeceased.disabled.js
│ │ │ ├── lab
│ │ │ │ └── FluxTest.disabled.js
│ │ │ ├── medication
│ │ │ │ └── FluxMedicationPrescription.disabled.js
│ │ │ ├── oncology
│ │ │ │ ├── FluxEstrogenReceptorStatus.disabled.js
│ │ │ │ ├── FluxHistologicGrade.disabled.js
│ │ │ │ ├── FluxHumanEpiduralGrowthFactorReceptor2Status.disabled.js
│ │ │ │ ├── FluxProgesteroneReceptorStatus.disabled.js
│ │ │ │ ├── FluxProgression.disabled.js
│ │ │ │ ├── FluxTNMStage.disabled.js
│ │ │ │ └── FluxTumorSize.disabled.js
│ │ │ ├── procedure
│ │ │ │ └── FluxProcedure.disabled.js
│ │ │ └── research
│ │ │ │ └── FluxStudy.disabled.js
│ │ ├── noteparser
│ │ │ ├── NoteParser.test.js
│ │ │ └── NoteParserUtils.js
│ │ ├── patient
│ │ │ ├── FakeDataElement.js
│ │ │ └── Patient.test.js
│ │ ├── patientControl
│ │ │ ├── FakePatient.js
│ │ │ └── PatientControl.test.js
│ │ └── views
│ │ │ ├── AppManager.test.js
│ │ │ ├── FullApp.test.js
│ │ │ ├── Landing.test.js
│ │ │ ├── LaunchPage.test.js
│ │ │ └── SlimApp.test.js
│ ├── testHelper.js
│ └── ui
│ │ ├── FullApp.js
│ │ └── SlimApp.js
├── actions
│ ├── mcode.js
│ └── types.js
├── apps
│ └── AppManager.jsx
├── clinicalTrials
│ └── ClinicalTrialsList.jsx
├── components
│ ├── LandingPage.jsx
│ ├── LaunchPage.jsx
│ └── WithTracker.jsx
├── config
│ ├── ConfigManager.js
│ └── ServiceManager.js
├── containers
│ ├── App.jsx
│ ├── CompassApp.jsx
│ ├── FullApp.jsx
│ ├── Pilot2MvpApp.jsx
│ ├── PointOfCareApp.jsx
│ ├── SlimApp.jsx
│ ├── SmartCompassApp.jsx
│ ├── SmartFullApp.jsx
│ ├── SmartPilot2MvpApp.jsx
│ └── WithSmartData.jsx
├── context
│ ├── Context.jsx
│ ├── ContextCalendar.jsx
│ ├── ContextGetHelp.jsx
│ ├── ContextGetHelp.scss
│ ├── ContextItem.jsx
│ ├── ContextItem.scss
│ ├── ContextListOptions.jsx
│ ├── ContextListOptions.scss
│ ├── ContextManager.jsx
│ ├── ContextOptions.jsx
│ ├── ContextOptions.scss
│ ├── ContextTray.jsx
│ ├── ContextTray.scss
│ ├── EditorPortal.jsx
│ ├── EditorPortal.scss
│ ├── PatientContext.jsx
│ ├── PlaceholderViewModeContent.jsx
│ ├── ShortcutSearch.jsx
│ ├── ShortcutViewModeContent.jsx
│ ├── ShortcutViewModeContent.scss
│ ├── SnippetViewModeContent.jsx
│ └── SnippetViewModeContent.scss
├── dashboard
│ ├── ClinicianDashboard.css
│ ├── ClinicianDashboard.jsx
│ ├── CompassAppDashboard.jsx
│ ├── CompassAppDashboard.scss
│ ├── DashboardManager.jsx
│ ├── NextPatientButton.jsx
│ ├── NextPatientButton.scss
│ ├── PointOfCareDashboard.jsx
│ └── PointOfCareDashboard.scss
├── dataaccess
│ ├── BreastMainTreatmentDebraV09.json
│ ├── BreastMainTreatmentDiabetesHypertensionJaneV09.json
│ ├── BreastMainTreatmentDiabetesHypertensionJaneV09_02.json
│ ├── BreastMainTreatmentDiabetesHypertensionJaneV09_03.json
│ ├── BreastMainTreatmentTry3EllaV09.json
│ ├── DataAccess.js
│ ├── FHIRApiDataSource.js
│ ├── GenericSmartOnFhirDstu2DataSource.js
│ ├── GistAdjuvantIhanosV09.json
│ ├── HardCodedConvertedFHIRPatient.json
│ ├── HardCodedConvertedFHIRPatientV09.json
│ ├── HardCodedFHIRPatient.json
│ ├── HardCodedMcodeV09DataSource.js
│ ├── HardcodedTabletMcodeV09DataSource.js
│ ├── IDataSource.js
│ ├── McodeV05EntryMapper.js
│ ├── McodeV09SmartOnFhirDataSource.js
│ ├── NewPatientOnlyDataSource.js
│ ├── RestApiDataSource.js
│ ├── mappers
│ │ ├── CernerSandboxMapper.js
│ │ └── index.js
│ ├── sample_curation_output.json
│ └── utils
│ │ └── fhir-entry-processor.js
├── elements
│ ├── Button.js
│ ├── ChoiceButton.js
│ ├── MenuItem.js
│ ├── SearchBar.jsx
│ ├── SearchBar.scss
│ └── Select.js
├── forms
│ ├── ClinicalTrialEnrollmentForm.css
│ ├── ClinicalTrialEnrollmentForm.jsx
│ ├── ClinicalTrialUnenrolledForm.css
│ ├── ClinicalTrialUnenrolledForm.jsx
│ ├── DataCaptureForm.css
│ ├── DataCaptureForm.jsx
│ ├── DatePicker.css
│ ├── DatePicker.jsx
│ ├── DeceasedForm.css
│ ├── DeceasedForm.jsx
│ ├── FormList.css
│ ├── FormList.jsx
│ ├── FormSearch.css
│ ├── FormSearch.jsx
│ ├── LandingPageForm.css
│ ├── LandingPageForm.jsx
│ ├── MultiChoiceButton.jsx
│ ├── MultiChoiceButton.scss
│ ├── ProgressionForm.css
│ ├── ProgressionForm.jsx
│ ├── SingleChoiceButton.jsx
│ ├── SingleChoiceButton.scss
│ ├── StagingForm.css
│ ├── StagingForm.jsx
│ ├── ToxicityForm.css
│ ├── ToxicityForm.jsx
│ └── index.js
├── index.css
├── index.js
├── lib
│ ├── FHIRMapper.js
│ ├── MedicationInformationService.jsx
│ ├── ValueSetManager.jsx
│ ├── cancer_lookup.jsx
│ ├── clinicaltrial_lookup.jsx
│ ├── cql-execution
│ │ ├── CQLExecutionEngine.js
│ │ ├── README.md
│ │ ├── codeservice
│ │ │ ├── CodeService.js
│ │ │ ├── README.md
│ │ │ ├── valueSetDownloader.js
│ │ │ └── vsac_cache
│ │ │ │ └── valueset-db.json
│ │ └── example
│ │ │ ├── cql
│ │ │ ├── BreastCancer.cql
│ │ │ ├── BreastCancer.js
│ │ │ ├── DiabeticFootExam.cql
│ │ │ ├── DiabeticFootExam.js
│ │ │ ├── DiabeticFootExam.json
│ │ │ ├── PALLASEligibility.cql
│ │ │ ├── PALLASEligibility.json
│ │ │ ├── PatinaEligibility.cql
│ │ │ ├── PatinaEligibility.json
│ │ │ ├── age.cql
│ │ │ ├── age.js
│ │ │ ├── age.js.map
│ │ │ ├── example.js
│ │ │ ├── example.js.map
│ │ │ ├── gender.cql
│ │ │ └── gender.js
│ │ │ └── patients
│ │ │ ├── No_Foot_Exam.json
│ │ │ ├── Old_Foot_Exam.json
│ │ │ ├── PALLASPatient.json
│ │ │ ├── PATINAPatient.json
│ │ │ └── examplePatientSource.json
│ ├── progression_lookup.jsx
│ ├── react-minimap
│ │ ├── components
│ │ │ └── Child.js
│ │ ├── index.js
│ │ ├── react-minimap.js
│ │ └── react-minimap.scss
│ ├── receptor_lookup.jsx
│ ├── slate-suggestions-dist
│ │ ├── caret-position.js
│ │ ├── constants.js
│ │ ├── current-word.js
│ │ ├── index.js
│ │ ├── suggestion-item.js
│ │ └── suggestion-portal.js
│ ├── slate
│ │ ├── Readme.md
│ │ ├── components
│ │ │ ├── Readme.md
│ │ │ ├── content.js
│ │ │ ├── editor.js
│ │ │ ├── leaf.js
│ │ │ ├── node.js
│ │ │ ├── placeholder.js
│ │ │ └── void.js
│ │ ├── constants
│ │ │ ├── Readme.md
│ │ │ ├── environment.js
│ │ │ ├── is-dev.js
│ │ │ └── types.js
│ │ ├── index.js
│ │ ├── models
│ │ │ ├── Readme.md
│ │ │ ├── block.js
│ │ │ ├── character.js
│ │ │ ├── data.js
│ │ │ ├── document.js
│ │ │ ├── inline.js
│ │ │ ├── mark.js
│ │ │ ├── node.js
│ │ │ ├── range.js
│ │ │ ├── schema.js
│ │ │ ├── selection.js
│ │ │ ├── stack.js
│ │ │ ├── state.js
│ │ │ ├── text.js
│ │ │ └── transform.js
│ │ ├── plugins
│ │ │ ├── Readme.md
│ │ │ └── core.js
│ │ ├── schemas
│ │ │ ├── Readme.md
│ │ │ └── core.js
│ │ ├── serializers
│ │ │ ├── Readme.md
│ │ │ ├── base-64.js
│ │ │ ├── html.js
│ │ │ ├── plain.js
│ │ │ └── raw.js
│ │ ├── transforms
│ │ │ ├── Readme.md
│ │ │ ├── apply-operation.js
│ │ │ ├── at-current-range.js
│ │ │ ├── at-range.js
│ │ │ ├── by-key.js
│ │ │ ├── call.js
│ │ │ ├── index.js
│ │ │ ├── normalize.js
│ │ │ ├── on-history.js
│ │ │ ├── on-selection.js
│ │ │ └── operations.js
│ │ └── utils
│ │ │ ├── Readme.md
│ │ │ ├── extend-selection.js
│ │ │ ├── find-closest-node.js
│ │ │ ├── find-deepest-node.js
│ │ │ ├── find-dom-node.js
│ │ │ ├── generate-key.js
│ │ │ ├── get-point.js
│ │ │ ├── get-transfer-data.js
│ │ │ ├── is-in-range.js
│ │ │ ├── is-react-component.js
│ │ │ ├── memoize.js
│ │ │ ├── noop.js
│ │ │ ├── normalize-node-and-offset.js
│ │ │ ├── normalize.js
│ │ │ ├── offset-key.js
│ │ │ ├── scroll-to-selection.js
│ │ │ ├── string.js
│ │ │ └── warn.js
│ ├── staging.jsx
│ ├── tnmstage_lookup.jsx
│ └── toxicreaction_lookup.jsx
├── loading
│ ├── LoadingAnimation.jsx
│ └── LoadingError.jsx
├── mcode-pilot
│ ├── components
│ │ ├── OptionsCheckboxList
│ │ │ ├── OptionsCheckboxList.jsx
│ │ │ └── OptionsCheckboxList.scss
│ │ ├── OptionsCheckboxUnit
│ │ │ └── OptionsCheckboxUnit.jsx
│ │ ├── OptionsRangeSelector
│ │ │ ├── OptionsRangeSelector.jsx
│ │ │ └── OptionsRangeSelector.scss
│ │ ├── SimilarPatientsSelector
│ │ │ ├── SimilarPatientsSelector.jsx
│ │ │ └── SimilarPatientsSelector.scss
│ │ ├── TreatmentOptionsOutcomes
│ │ │ ├── TreatmentOptionsOutcomes.jsx
│ │ │ └── TreatmentOptionsOutcomes.scss
│ │ ├── TreatmentOptionsOutcomesIcons
│ │ │ ├── TreatmentOptionsOutcomesIcons.jsx
│ │ │ └── TreatmentOptionsOutcomesIcons.scss
│ │ ├── TreatmentOptionsOutcomesTable
│ │ │ ├── CompareSelectedIcon.jsx
│ │ │ ├── CompareUnselectedIcon.jsx
│ │ │ ├── PersonIcon.jsx
│ │ │ ├── TreatmentOptionsOutcomesHeaders.jsx
│ │ │ ├── TreatmentOptionsOutcomesTable.jsx
│ │ │ └── TreatmentOptionsOutcomesTable.scss
│ │ ├── TreatmentOptionsSelector
│ │ │ ├── TreatmentOptionsSelector.jsx
│ │ │ └── TreatmentOptionsSelector.scss
│ │ └── TreatmentsPopover
│ │ │ ├── TreatmentsPopover.jsx
│ │ │ └── TreatmentsPopover.scss
│ ├── containers
│ │ └── TreatmentOptionsVisualizer
│ │ │ ├── TreatmentOptionsVisualizer.jsx
│ │ │ └── TreatmentOptionsVisualizer.scss
│ ├── mock-data
│ │ ├── mock-data-update.js
│ │ ├── mock-data.json
│ │ └── transformedDataModel.json
│ ├── services
│ │ └── outcomes
│ │ │ ├── CLQOutcomesService.js
│ │ │ ├── IOutcomesService.js
│ │ │ ├── StaticOutcomesService.js
│ │ │ └── race_codes.js
│ ├── utils
│ │ ├── FilterOptions.js
│ │ ├── arrayOperations.js
│ │ ├── filterTreatmentData.js
│ │ ├── numberWithCommas.js
│ │ ├── recordToProps.js
│ │ ├── serviceResultsProcessing.js
│ │ └── sideEffects.js
│ └── visualizations
│ │ ├── BarChart
│ │ ├── BarChart.jsx
│ │ └── BarChart.scss
│ │ ├── IconsChart
│ │ ├── IconsChart.jsx
│ │ └── IconsChart.scss
│ │ └── TableLegend
│ │ ├── TableLegend.jsx
│ │ └── TableLegend.scss
├── model
│ ├── ClassRegistry.js
│ ├── CodeableConceptUtils.js
│ ├── FluxObjectFactory.js
│ ├── ObjectFactory.js
│ ├── Reference.js
│ ├── brca
│ │ ├── AverageCEP17SignalsPerCell.js
│ │ ├── AverageHER2SignalsPerCell.js
│ │ ├── BrcaObjectFactory.js
│ │ ├── BreastCancerCondition.js
│ │ ├── BreastCancerHistologicGrade.js
│ │ ├── BreastClinicalLymphNodeInvolvement.js
│ │ ├── BreastLymphNodeBodyLocation.js
│ │ ├── BreastLymphNodeInvolvement.js
│ │ ├── BreastPathologicalLymphNodeInvolvement.js
│ │ ├── BreastSite.js
│ │ ├── BreastSpecimen.js
│ │ ├── BreastTNMPathologicStageGroup.js
│ │ ├── BreastTNMPrognosticClinicalStageGroup.js
│ │ ├── ColdIschemiaTime.js
│ │ ├── CompleteMembraneStainingPercent.js
│ │ ├── DCISNuclearGrade.js
│ │ ├── EstrogenReceptorAverageStainingIntensity.js
│ │ ├── EstrogenReceptorNuclearPositivity.js
│ │ ├── EstrogenReceptorStatus.js
│ │ ├── ExtraCapsularExtensionOfNodalTumorStatus.js
│ │ ├── HER2ReceptorStatus.js
│ │ ├── HER2byFISH.js
│ │ ├── HER2byIHC.js
│ │ ├── HER2toCEP17Ratio.js
│ │ ├── LymphNodeMobility.js
│ │ ├── LymphNodeSamplingMethod.js
│ │ ├── LymphNodeSize.js
│ │ ├── MammaprintRecurrenceScore.js
│ │ ├── MitoticCountScore.js
│ │ ├── NuclearPleomorphismScore.js
│ │ ├── NumberOfLymphNodesWithIsolatedTumorCells.js
│ │ ├── NumberOfLymphNodesWithMacrometastases.js
│ │ ├── NumberOfLymphNodesWithMicrometastases.js
│ │ ├── NumberOfRegionalLymphNodes.js
│ │ ├── NumberOfSentinelLymphNodes.js
│ │ ├── OncotypeDxDCISRecurrenceScore.js
│ │ ├── OncotypeDxInvasiveRecurrenceScore.js
│ │ ├── ProgesteroneReceptorAverageStainingIntensity.js
│ │ ├── ProgesteroneReceptorNuclearPositivity.js
│ │ ├── ProgesteroneReceptorStatus.js
│ │ ├── ProsignaRecurrenceScore.js
│ │ ├── TotalNumberOfLymphNodesExamined.js
│ │ └── TubuleFormationScore.js
│ ├── fluxExtensions
│ │ ├── BloodPressureFix.js
│ │ ├── CancerReasonReferenceFix.js
│ │ ├── CodeableConceptFix.js
│ │ ├── CodingFix.js
│ │ ├── DataValueFix.js
│ │ ├── EntryFix.js
│ │ ├── ExpectedPerformanceTimeFix.js
│ │ ├── MedicationCodeOrReferenceFix.js
│ │ ├── MedicationRequestFix.js
│ │ ├── PrimaryCancerConditionFix.js
│ │ ├── ReasonReferenceFix.js
│ │ ├── RelatedCancerConditionFix.js
│ │ ├── TNMClinicalStageGroupFix.js
│ │ ├── TNMPathologicStageGroupFix.js
│ │ └── TumorMarkerTestDataValueFix.js
│ ├── fluxWrappers
│ │ ├── base
│ │ │ └── FluxEntry.js
│ │ ├── core
│ │ │ ├── FluxAdverseDrugReaction.js
│ │ │ ├── FluxAllergyIntolerance.js
│ │ │ ├── FluxBloodPressure.js
│ │ │ ├── FluxBodyTemperature.js
│ │ │ ├── FluxBodyWeight.js
│ │ │ ├── FluxClinicalNote.js
│ │ │ ├── FluxCondition.js
│ │ │ ├── FluxCoreObjectFactory.js
│ │ │ ├── FluxDiagnosticReport.js
│ │ │ ├── FluxECOGPerformanceStatus.js
│ │ │ ├── FluxEncounter.js
│ │ │ ├── FluxHeartRate.js
│ │ │ ├── FluxImagingProcedure.js
│ │ │ ├── FluxKarnofskyPerformanceStatus.js
│ │ │ ├── FluxMedicationBase.js
│ │ │ ├── FluxMedicationRequest.js
│ │ │ ├── FluxMedicationStatement.js
│ │ │ ├── FluxObservation.js
│ │ │ ├── FluxPatient.js
│ │ │ ├── FluxPerson.js
│ │ │ ├── FluxProcedure.js
│ │ │ ├── FluxProcedureRequest.js
│ │ │ ├── FluxQuestionnaireResponse.js
│ │ │ ├── FluxQuestionnaireResponseItem.js
│ │ │ ├── FluxReferralRequest.js
│ │ │ ├── FluxResearchStudy.js
│ │ │ └── FluxResearchSubject.js
│ │ ├── onco
│ │ │ └── core
│ │ │ │ ├── FluxCancerCondition.js
│ │ │ │ ├── FluxCancerDiseaseStatus.js
│ │ │ │ ├── FluxCancerHistologicGrade.js
│ │ │ │ ├── FluxCancerStageCategory.js
│ │ │ │ ├── FluxEvidenceType.js
│ │ │ │ ├── FluxGeneticMutationTestResult.js
│ │ │ │ ├── FluxGenomicsReport.js
│ │ │ │ ├── FluxOncocoreObjectFactory.js
│ │ │ │ ├── FluxTNMClinicalDistantMetastasesCategory.js
│ │ │ │ ├── FluxTNMClinicalPrimaryTumorCategory.js
│ │ │ │ ├── FluxTNMClinicalRegionalNodesCategory.js
│ │ │ │ ├── FluxTNMClinicalStageGroup.js
│ │ │ │ ├── FluxTNMPathologicStageGroup.js
│ │ │ │ ├── FluxTNMStageGroup.js
│ │ │ │ └── FluxTumorMarkerTest.js
│ │ ├── oncocore
│ │ │ └── FluxCancerHistologicType.js
│ │ └── tumor
│ │ │ ├── FluxTumorDimensions.js
│ │ │ ├── FluxTumorMargins.js
│ │ │ └── FluxTumorObjectFactory.js
│ ├── hpi-configuration.json
│ ├── init.js
│ ├── json-helper.js
│ ├── onco
│ │ └── core
│ │ │ ├── CancerCondition.js
│ │ │ ├── CancerDiseaseStatus.js
│ │ │ ├── CancerHistologicGrade.js
│ │ │ ├── CancerReasonReference.js
│ │ │ ├── CancerRelatedRadiationProcedure.js
│ │ │ ├── CancerRelatedSurgicalProcedure.js
│ │ │ ├── CancerStageCategory.js
│ │ │ ├── CancerStageGroup.js
│ │ │ ├── CancerStagingSystem.js
│ │ │ ├── EvidenceType.js
│ │ │ ├── GeneStudied.js
│ │ │ ├── GeneticMutationTestResult.js
│ │ │ ├── GeneticVariantFound.js
│ │ │ ├── GenomicSourceClass.js
│ │ │ ├── GenomicsReport.js
│ │ │ ├── HistologyMorphologyBehavior.js
│ │ │ ├── IsPrimaryTumor.js
│ │ │ ├── MutationTested.js
│ │ │ ├── OncoCoreObjectFactory.js
│ │ │ ├── PractitionerInformationSource.js
│ │ │ ├── PrimaryCancerCondition.js
│ │ │ ├── RegionStudied.js
│ │ │ ├── RelatedCancerCondition.js
│ │ │ ├── RelatedTumor.js
│ │ │ ├── SecondaryCancerCondition.js
│ │ │ ├── SizeOfGrossTumorBed.js
│ │ │ ├── TNMClinicalDistantMetastasesCategory.js
│ │ │ ├── TNMClinicalPrimaryTumorCategory.js
│ │ │ ├── TNMClinicalRegionalNodesCategory.js
│ │ │ ├── TNMClinicalStageGroup.js
│ │ │ ├── TNMPathologicDistantMetastasesCategory.js
│ │ │ ├── TNMPathologicPrimaryTumorCategory.js
│ │ │ ├── TNMPathologicRegionalNodesCategory.js
│ │ │ ├── TNMPathologicStageGroup.js
│ │ │ ├── Tumor.js
│ │ │ ├── TumorDimension2.js
│ │ │ ├── TumorDimension3.js
│ │ │ ├── TumorDimensions.js
│ │ │ ├── TumorInvolvementAtSurgicalMargin.js
│ │ │ ├── TumorLongestDimension.js
│ │ │ ├── TumorMarkerTest.js
│ │ │ ├── TumorMarkerTestDataValue.js
│ │ │ ├── VariantDescription.js
│ │ │ ├── VariantFoundDescription.js
│ │ │ ├── VariantFoundHGVSName.js
│ │ │ ├── VariantFoundIdentifier.js
│ │ │ ├── VariantHGVSName.js
│ │ │ └── VariantIdentifier.js
│ ├── shr
│ │ ├── base
│ │ │ ├── Entry.js
│ │ │ ├── EntryId.js
│ │ │ ├── EntryType.js
│ │ │ ├── ShrBaseObjectFactory.js
│ │ │ └── ShrId.js
│ │ ├── core
│ │ │ ├── Abatement.js
│ │ │ ├── AccessTime.js
│ │ │ ├── AccessionIdentifier.js
│ │ │ ├── ActionPerformed.js
│ │ │ ├── ActionRequested.js
│ │ │ ├── ActionStatement.js
│ │ │ ├── ActionTaken.js
│ │ │ ├── Actual.js
│ │ │ ├── AdditionalDosageInstruction.js
│ │ │ ├── Additive.js
│ │ │ ├── Address.js
│ │ │ ├── AddressLine.js
│ │ │ ├── AdministrativeGender.js
│ │ │ ├── AdverseDrugReaction.js
│ │ │ ├── AdverseEvent.js
│ │ │ ├── AdverseEventCondition.js
│ │ │ ├── AdverseEventRecorder.js
│ │ │ ├── AdverseEventSubjectOfRecord.js
│ │ │ ├── Affiliation.js
│ │ │ ├── Age.js
│ │ │ ├── AgeGroup.js
│ │ │ ├── Alias.js
│ │ │ ├── AllergyIntolerance.js
│ │ │ ├── AllergyIntoleranceReaction.js
│ │ │ ├── AllergyRecorder.js
│ │ │ ├── AlleviatingFactor.js
│ │ │ ├── Altitude.js
│ │ │ ├── AmountOrSize.js
│ │ │ ├── AnatomicalDirection.js
│ │ │ ├── Annotation.js
│ │ │ ├── AnnotationAuthor.js
│ │ │ ├── AnonymizedFlag.js
│ │ │ ├── Answer.js
│ │ │ ├── AnswerOption.js
│ │ │ ├── AnswerValue.js
│ │ │ ├── AnswerValueSet.js
│ │ │ ├── ApplicableAgeRange.js
│ │ │ ├── ApplicableSubpopulation.js
│ │ │ ├── Appointment.js
│ │ │ ├── AppointmentParticipant.js
│ │ │ ├── AppointmentParticipation.js
│ │ │ ├── ApprovalDate.js
│ │ │ ├── AsNeededIndicator.js
│ │ │ ├── AssociatedStudy.js
│ │ │ ├── Attachment.js
│ │ │ ├── Authenticator.js
│ │ │ ├── BeginDateTime.js
│ │ │ ├── BinaryData.js
│ │ │ ├── BirthSex.js
│ │ │ ├── BloodPressure.js
│ │ │ ├── BloodPressureCuffSize.js
│ │ │ ├── BodyHeight.js
│ │ │ ├── BodyLength.js
│ │ │ ├── BodyLocation.js
│ │ │ ├── BodyMassIndex.js
│ │ │ ├── BodyPosition.js
│ │ │ ├── BodyStructure.js
│ │ │ ├── BodyTemperature.js
│ │ │ ├── BodyWeight.js
│ │ │ ├── Brand.js
│ │ │ ├── BrandName.js
│ │ │ ├── Capacity.js
│ │ │ ├── CareContext.js
│ │ │ ├── CareManager.js
│ │ │ ├── Category.js
│ │ │ ├── CausalAttribution.js
│ │ │ ├── CauseCategory.js
│ │ │ ├── Certainty.js
│ │ │ ├── City.js
│ │ │ ├── ClassHistory.js
│ │ │ ├── ClinicalContext.js
│ │ │ ├── ClinicalNote.js
│ │ │ ├── ClinicalStatement.js
│ │ │ ├── ClinicalStatus.js
│ │ │ ├── ClockFaceDirection.js
│ │ │ ├── Code.js
│ │ │ ├── CodeSet.js
│ │ │ ├── CodeSetConcept.js
│ │ │ ├── CodeSetFilter.js
│ │ │ ├── CodeSystem.js
│ │ │ ├── CodeSystemVersion.js
│ │ │ ├── CodeValue.js
│ │ │ ├── CodeableConcept.js
│ │ │ ├── CodedLaboratoryObservation.js
│ │ │ ├── CodedNonLaboratoryObservation.js
│ │ │ ├── CodedObservationComponent.js
│ │ │ ├── CodedSocialHistoryObservation.js
│ │ │ ├── Coding.js
│ │ │ ├── CollectionMethod.js
│ │ │ ├── CollectionSite.js
│ │ │ ├── CollectionSource.js
│ │ │ ├── CollectionTime.js
│ │ │ ├── CommentOrDescription.js
│ │ │ ├── Communication.js
│ │ │ ├── CommunicationMethod.js
│ │ │ ├── ComorbidCondition.js
│ │ │ ├── Comparator.js
│ │ │ ├── ComponentOnlyNonLaboratoryObservation.js
│ │ │ ├── Components.js
│ │ │ ├── Composition.js
│ │ │ ├── Conclusion.js
│ │ │ ├── Condition.js
│ │ │ ├── ConditionCause.js
│ │ │ ├── CongenitalAbnormality.js
│ │ │ ├── ContactDetail.js
│ │ │ ├── ContactPoint.js
│ │ │ ├── ContemporaneousPatientInformation.js
│ │ │ ├── ContentLogicalDefinition.js
│ │ │ ├── ContentType.js
│ │ │ ├── ContextValue.js
│ │ │ ├── Copyright.js
│ │ │ ├── CorrectionFactor.js
│ │ │ ├── Count.js
│ │ │ ├── CountPerInterval.js
│ │ │ ├── Country.js
│ │ │ ├── CountryOfIssue.js
│ │ │ ├── CreationDateTime.js
│ │ │ ├── Criticality.js
│ │ │ ├── DailyLifeEvent.js
│ │ │ ├── DataAbsentReason.js
│ │ │ ├── DataAsString.js
│ │ │ ├── DataValue.js
│ │ │ ├── DateOfBirth.js
│ │ │ ├── DateOfDiagnosis.js
│ │ │ ├── DayOfWeek.js
│ │ │ ├── Deceased.js
│ │ │ ├── Denominator.js
│ │ │ ├── DescriptionMarkdown.js
│ │ │ ├── Designation.js
│ │ │ ├── DetailsLink.js
│ │ │ ├── Device.js
│ │ │ ├── DeviceUdi.js
│ │ │ ├── DiagnosisCode.js
│ │ │ ├── DiagnosticImaging.js
│ │ │ ├── DiagnosticReport.js
│ │ │ ├── DiagnosticReportParticipant.js
│ │ │ ├── DiastolicPressure.js
│ │ │ ├── Dimensions.js
│ │ │ ├── DisplayText.js
│ │ │ ├── Distance.js
│ │ │ ├── District.js
│ │ │ ├── DocumentAuthor.js
│ │ │ ├── DocumentReference.js
│ │ │ ├── DocumentReferenced.js
│ │ │ ├── DocumentStatus.js
│ │ │ ├── DomainResource.js
│ │ │ ├── Dosage.js
│ │ │ ├── DosageBodyLocation.js
│ │ │ ├── DosageInstructionsText.js
│ │ │ ├── DosageMethod.js
│ │ │ ├── DoseAmount.js
│ │ │ ├── DoseForm.js
│ │ │ ├── DriversLicenseInformation.js
│ │ │ ├── DriversLicenseNumber.js
│ │ │ ├── Duration.js
│ │ │ ├── DurationRange.js
│ │ │ ├── ECOGPerformanceStatus.js
│ │ │ ├── EffectiveTimePeriod.js
│ │ │ ├── EmbeddedContent.js
│ │ │ ├── EnableWhen.js
│ │ │ ├── Encounter.js
│ │ │ ├── EncounterClass.js
│ │ │ ├── EncounterDiagnosis.js
│ │ │ ├── EncounterLocation.js
│ │ │ ├── EncounterOrEpisode.js
│ │ │ ├── EncounterParticipant.js
│ │ │ ├── EndDateTime.js
│ │ │ ├── Enrollment.js
│ │ │ ├── Entity.js
│ │ │ ├── EntityOrRole.js
│ │ │ ├── EpisodeOfCare.js
│ │ │ ├── Ethnicity.js
│ │ │ ├── EthnicityCode.js
│ │ │ ├── EthnicityDetail.js
│ │ │ ├── Event.js
│ │ │ ├── EventDuration.js
│ │ │ ├── Evidence.js
│ │ │ ├── ExacerbatingFactor.js
│ │ │ ├── ExcludeCodes.js
│ │ │ ├── ExcludeFlag.js
│ │ │ ├── ExpansionCoding.js
│ │ │ ├── ExpansionParameter.js
│ │ │ ├── ExpectedPerformanceTime.js
│ │ │ ├── ExpectedPerformer.js
│ │ │ ├── ExpectedPerformerType.js
│ │ │ ├── ExpirationDate.js
│ │ │ ├── FacilityType.js
│ │ │ ├── FamilyName.js
│ │ │ ├── FathersName.js
│ │ │ ├── FictionalPersonFlag.js
│ │ │ ├── FillerOrderNumber.js
│ │ │ ├── FocalDevice.js
│ │ │ ├── FocusOfResponse.js
│ │ │ ├── Formalism.js
│ │ │ ├── Frames.js
│ │ │ ├── Frequency.js
│ │ │ ├── Geoposition.js
│ │ │ ├── GestationalAge.js
│ │ │ ├── GestationalTimePeriod.js
│ │ │ ├── GivenName.js
│ │ │ ├── Group.js
│ │ │ ├── GroupCharacteristic.js
│ │ │ ├── GroupCharacteristicValue.js
│ │ │ ├── HandlingRisk.js
│ │ │ ├── HasAnswer.js
│ │ │ ├── Hash.js
│ │ │ ├── HeadCircumference.js
│ │ │ ├── HeadlessLaboratoryPanel.js
│ │ │ ├── HeadlessPanel.js
│ │ │ ├── HeartRate.js
│ │ │ ├── HumanName.js
│ │ │ ├── Identifier.js
│ │ │ ├── IdentifierString.js
│ │ │ ├── ImagingProcedure.js
│ │ │ ├── ImagingSubstance.js
│ │ │ ├── ImplicitRules.js
│ │ │ ├── Inactive.js
│ │ │ ├── InactiveFlag.js
│ │ │ ├── IncludeCodes.js
│ │ │ ├── IncludeInactiveCodes.js
│ │ │ ├── Indication.js
│ │ │ ├── Ingredient.js
│ │ │ ├── IngredientAmount.js
│ │ │ ├── IntegerQuantity.js
│ │ │ ├── Interpretation.js
│ │ │ ├── IsActiveIngredient.js
│ │ │ ├── IsBrand.js
│ │ │ ├── IsExperimental.js
│ │ │ ├── IsExtensible.js
│ │ │ ├── IsImmutable.js
│ │ │ ├── IsReadOnly.js
│ │ │ ├── IsRequired.js
│ │ │ ├── Issuer.js
│ │ │ ├── Jurisdiction.js
│ │ │ ├── KarnofskyPerformanceStatus.js
│ │ │ ├── LaboratoryObservation.js
│ │ │ ├── LaboratoryPanel.js
│ │ │ ├── LaboratoryProcedure.js
│ │ │ ├── LandmarkLocation.js
│ │ │ ├── LandmarkToBodyLocationDirection.js
│ │ │ ├── LandmarkToBodyLocationDistance.js
│ │ │ ├── LandmarkType.js
│ │ │ ├── Language.js
│ │ │ ├── LanguageQualifier.js
│ │ │ ├── LastReviewedDate.js
│ │ │ ├── LastUpdated.js
│ │ │ ├── Laterality.js
│ │ │ ├── Latitude.js
│ │ │ ├── LifeEventOffset.js
│ │ │ ├── Location.js
│ │ │ ├── LocationCode.js
│ │ │ ├── LocationName.js
│ │ │ ├── LockedDate.js
│ │ │ ├── Longitude.js
│ │ │ ├── LotNumber.js
│ │ │ ├── LowerBound.js
│ │ │ ├── LowerLimit.js
│ │ │ ├── ManagingOrganization.js
│ │ │ ├── Manifestation.js
│ │ │ ├── ManufactureDate.js
│ │ │ ├── Manufacturer.js
│ │ │ ├── ManufacturerName.js
│ │ │ ├── MaritalStatus.js
│ │ │ ├── MasterIdentifier.js
│ │ │ ├── MaterialUsed.js
│ │ │ ├── MaxCount.js
│ │ │ ├── MaxTextLength.js
│ │ │ ├── MaximumDosePerTimePeriod.js
│ │ │ ├── MayRepeat.js
│ │ │ ├── Media.js
│ │ │ ├── MediaSubjectOfRecord.js
│ │ │ ├── MedicalInterpreter.js
│ │ │ ├── MedicalInterpreterNeeded.js
│ │ │ ├── Medication.js
│ │ │ ├── MedicationAdministration.js
│ │ │ ├── MedicationCodeOrReference.js
│ │ │ ├── MedicationDispense.js
│ │ │ ├── MedicationExposure.js
│ │ │ ├── MedicationNonAdherenceReason.js
│ │ │ ├── MedicationNonadherence.js
│ │ │ ├── MedicationRequest.js
│ │ │ ├── MedicationRequester.js
│ │ │ ├── MedicationStatement.js
│ │ │ ├── MedicationStatementInformationSource.js
│ │ │ ├── MedicationStatementRelatedRequest.js
│ │ │ ├── Member.js
│ │ │ ├── MemberParticipation.js
│ │ │ ├── Metadata.js
│ │ │ ├── Method.js
│ │ │ ├── MiddleName.js
│ │ │ ├── MillisecondsBetweenSamples.js
│ │ │ ├── MinCount.js
│ │ │ ├── MobileFacility.js
│ │ │ ├── Mode.js
│ │ │ ├── Money.js
│ │ │ ├── MostRecentOccurrenceTime.js
│ │ │ ├── MothersMaidenName.js
│ │ │ ├── MultipleBirth.js
│ │ │ ├── Name.js
│ │ │ ├── NameAsText.js
│ │ │ ├── Narrative.js
│ │ │ ├── NarrativeQualifier.js
│ │ │ ├── NarrativeText.js
│ │ │ ├── NationalProviderIdentifier.js
│ │ │ ├── Need.js
│ │ │ ├── NonLaboratoryObservation.js
│ │ │ ├── NonOccurrenceTimeOrPeriod.js
│ │ │ ├── NonSelectable.js
│ │ │ ├── Number.js
│ │ │ ├── NumberOfRefillsAllowed.js
│ │ │ ├── NumberOfRepeats.js
│ │ │ ├── NumberOfSecondsDuration.js
│ │ │ ├── Numerator.js
│ │ │ ├── Observation.js
│ │ │ ├── ObservationComponent.js
│ │ │ ├── ObservationOrProcedure.js
│ │ │ ├── ObservationSubjectOfRecord.js
│ │ │ ├── OccurrenceDuration.js
│ │ │ ├── OccurrencePeriod.js
│ │ │ ├── OccurrenceTime.js
│ │ │ ├── OccurrenceTimeOrPeriod.js
│ │ │ ├── Offset.js
│ │ │ ├── OnBehalfOf.js
│ │ │ ├── Onset.js
│ │ │ ├── Operation.js
│ │ │ ├── OperationalStatus.js
│ │ │ ├── Organization.js
│ │ │ ├── OrganizationName.js
│ │ │ ├── Orientation.js
│ │ │ ├── Origin.js
│ │ │ ├── OriginalReport.js
│ │ │ ├── Outcome.js
│ │ │ ├── OverTheCounter.js
│ │ │ ├── OxygenSaturation.js
│ │ │ ├── Package.js
│ │ │ ├── Panel.js
│ │ │ ├── PanelMembers.js
│ │ │ ├── ParameterValue.js
│ │ │ ├── ParsableContent.js
│ │ │ ├── PartOf.js
│ │ │ ├── Participant.js
│ │ │ ├── Participation.js
│ │ │ ├── ParticipationPeriod.js
│ │ │ ├── ParticipationType.js
│ │ │ ├── PassportInformation.js
│ │ │ ├── PassportNumber.js
│ │ │ ├── Patient.js
│ │ │ ├── PatientSubjectOfRecord.js
│ │ │ ├── Percentage.js
│ │ │ ├── Performer.js
│ │ │ ├── Person.js
│ │ │ ├── PersonInformationSource.js
│ │ │ ├── PersonParticipant.js
│ │ │ ├── PhotographicImage.js
│ │ │ ├── PhysicalType.js
│ │ │ ├── PixelHeight.js
│ │ │ ├── PixelWidth.js
│ │ │ ├── PlaceOfBirth.js
│ │ │ ├── PlacerOrderNumber.js
│ │ │ ├── PossibleCause.js
│ │ │ ├── PossibleDrugCause.js
│ │ │ ├── PostalCode.js
│ │ │ ├── Practitioner.js
│ │ │ ├── PractitionerOrOrganizationPerformer.js
│ │ │ ├── PractitionerPerformer.js
│ │ │ ├── PractitionerProcedureParticipant.js
│ │ │ ├── Precondition.js
│ │ │ ├── Preferred.js
│ │ │ ├── Prefix.js
│ │ │ ├── PrepopulateValue.js
│ │ │ ├── PrincipalInvestigator.js
│ │ │ ├── PriorityCode.js
│ │ │ ├── PriorityRank.js
│ │ │ ├── PriorityRankUnsignedInt.js
│ │ │ ├── Procedure.js
│ │ │ ├── ProcedureParticipant.js
│ │ │ ├── ProcedureRequest.js
│ │ │ ├── ProcedureRequester.js
│ │ │ ├── Profile.js
│ │ │ ├── Property.js
│ │ │ ├── PublisherName.js
│ │ │ ├── Purpose.js
│ │ │ ├── PurposeMarkdown.js
│ │ │ ├── Qualification.js
│ │ │ ├── QuantitativeLaboratoryObservation.js
│ │ │ ├── QuantitativeNonLaboratoryObservation.js
│ │ │ ├── QuantitativeObservationComponent.js
│ │ │ ├── Quantity.js
│ │ │ ├── QuantityPerDispense.js
│ │ │ ├── Question.js
│ │ │ ├── Questionnaire.js
│ │ │ ├── QuestionnaireItem.js
│ │ │ ├── QuestionnaireResponse.js
│ │ │ ├── QuestionnaireResponseItem.js
│ │ │ ├── QuestionnaireResponseRecorder.js
│ │ │ ├── Race.js
│ │ │ ├── RaceCode.js
│ │ │ ├── RaceDetail.js
│ │ │ ├── RadiationDosePerFraction.js
│ │ │ ├── RadiationFractionsDelivered.js
│ │ │ ├── RadiationProcedure.js
│ │ │ ├── Range.js
│ │ │ ├── Ratio.js
│ │ │ ├── ReasonCode.js
│ │ │ ├── ReasonReference.js
│ │ │ ├── ReceivedTime.js
│ │ │ ├── Recipient.js
│ │ │ ├── RecurrenceInterval.js
│ │ │ ├── RecurrencePattern.js
│ │ │ ├── RecurrenceRange.js
│ │ │ ├── ReferenceRange.js
│ │ │ ├── ReferralOrProcedureRequest.js
│ │ │ ├── ReferralRecipient.js
│ │ │ ├── ReferralRequest.js
│ │ │ ├── ReferralRequester.js
│ │ │ ├── ReferralSubjectOfRecord.js
│ │ │ ├── RelatedDocument.js
│ │ │ ├── RelatedInformation.js
│ │ │ ├── RelatedPerson.js
│ │ │ ├── RelatedRequest.js
│ │ │ ├── RelationToLandmark.js
│ │ │ ├── Relationship.js
│ │ │ ├── RelationshipToPatient.js
│ │ │ ├── RelevantTime.js
│ │ │ ├── Replaces.js
│ │ │ ├── RequestIntent.js
│ │ │ ├── ResearchStudy.js
│ │ │ ├── ResearchSubject.js
│ │ │ ├── Resource.js
│ │ │ ├── ResourceLocation.js
│ │ │ ├── ResourceSize.js
│ │ │ ├── RespiratoryRate.js
│ │ │ ├── Role.js
│ │ │ ├── RouteIntoBody.js
│ │ │ ├── SampledData.js
│ │ │ ├── Section.js
│ │ │ ├── SecurityLabel.js
│ │ │ ├── SequenceNumber.js
│ │ │ ├── Seriousness.js
│ │ │ ├── ServiceCategory.js
│ │ │ ├── ServiceType.js
│ │ │ ├── Setting.js
│ │ │ ├── Severity.js
│ │ │ ├── ShrCoreObjectFactory.js
│ │ │ ├── Signatory.js
│ │ │ ├── Signature.js
│ │ │ ├── SignatureType.js
│ │ │ ├── SimpleCodedLaboratoryObservation.js
│ │ │ ├── SimpleCodedNonLaboratoryObservation.js
│ │ │ ├── SimpleLaboratoryObservation.js
│ │ │ ├── SimpleNonLaboratoryObservation.js
│ │ │ ├── SimpleQuantitativeLaboratoryObservation.js
│ │ │ ├── SimpleQuantity.js
│ │ │ ├── SituationStatement.js
│ │ │ ├── SocialHistoryObservation.js
│ │ │ ├── SocialSecurityNumber.js
│ │ │ ├── SpecialHandling.js
│ │ │ ├── Specialty.js
│ │ │ ├── Specimen.js
│ │ │ ├── SpecimenContainer.js
│ │ │ ├── SpecimenQuantity.js
│ │ │ ├── SpecimenTreatment.js
│ │ │ ├── SpecimenType.js
│ │ │ ├── SpokenLanguageProficiency.js
│ │ │ ├── Sponsor.js
│ │ │ ├── StageDetail.js
│ │ │ ├── StageInformation.js
│ │ │ ├── StageSummary.js
│ │ │ ├── State.js
│ │ │ ├── StateOfIssue.js
│ │ │ ├── StatementDateTime.js
│ │ │ ├── Statistic.js
│ │ │ ├── StatisticType.js
│ │ │ ├── Status.js
│ │ │ ├── StatusHistory.js
│ │ │ ├── StudyArm.js
│ │ │ ├── SubjectOfInformationCode.js
│ │ │ ├── SubjectOfRecord.js
│ │ │ ├── SubjectType.js
│ │ │ ├── Substance.js
│ │ │ ├── SubstanceCategory.js
│ │ │ ├── SubstanceCode.js
│ │ │ ├── SubstanceOrCode.js
│ │ │ ├── SubstitutionAllowed.js
│ │ │ ├── SubstitutionReason.js
│ │ │ ├── Subtype.js
│ │ │ ├── Suffix.js
│ │ │ ├── SupplementalOxygenConcentration.js
│ │ │ ├── SupplementalOxygenFlowrate.js
│ │ │ ├── SupplyDuration.js
│ │ │ ├── SurgicalBodyLocation.js
│ │ │ ├── SurgicalBodyLocationRole.js
│ │ │ ├── SurgicalProcedure.js
│ │ │ ├── SystolicPressure.js
│ │ │ ├── Tag.js
│ │ │ ├── TaxIdentificationNumber.js
│ │ │ ├── TelecomNumberOrAddress.js
│ │ │ ├── TerminationReason.js
│ │ │ ├── Text.js
│ │ │ ├── TimeOfDay.js
│ │ │ ├── TimePeriod.js
│ │ │ ├── Timing.js
│ │ │ ├── TimingCode.js
│ │ │ ├── TimingOfDoses.js
│ │ │ ├── Title.js
│ │ │ ├── TotalCount.js
│ │ │ ├── TotalRadiationDoseDelivered.js
│ │ │ ├── TreatmentIntent.js
│ │ │ ├── Type.js
│ │ │ ├── UnitedStatesAddress.js
│ │ │ ├── UnitedStatesState.js
│ │ │ ├── Units.js
│ │ │ ├── UpperBound.js
│ │ │ ├── UpperLimit.js
│ │ │ ├── Url.js
│ │ │ ├── UseContext.js
│ │ │ ├── ValueSet.js
│ │ │ ├── ValueSetExpansion.js
│ │ │ ├── ValueSetUri.js
│ │ │ ├── VendorModelNumber.js
│ │ │ ├── VersionId.js
│ │ │ ├── VersionString.js
│ │ │ ├── View.js
│ │ │ ├── VitalSign.js
│ │ │ ├── VitalSignsPanel.js
│ │ │ ├── WhenClinicallyRecognized.js
│ │ │ └── WrittenLanguageProficiency.js
│ │ ├── fhx
│ │ │ ├── ConditionOutcome.js
│ │ │ ├── FamilyMember.js
│ │ │ ├── FamilyMemberCondition.js
│ │ │ ├── FamilyMemberHistory.js
│ │ │ └── ShrFhxObjectFactory.js
│ │ ├── financial
│ │ │ ├── Beneficiary.js
│ │ │ ├── Coverage.js
│ │ │ ├── CoverageType.js
│ │ │ ├── PolicyHolder.js
│ │ │ ├── ShrFinancialObjectFactory.js
│ │ │ ├── Subscriber.js
│ │ │ └── SubscriberId.js
│ │ ├── lab
│ │ │ ├── AlanineAminotransferaseCCncPtSerPlasQnLabObs.js
│ │ │ ├── AlbuminGlobulinMRtoPtSerPlasQnLabObs.js
│ │ │ ├── AlbuminMCncPtSerPlasQnLabObs.js
│ │ │ ├── AlkalinePhosphataseCCncPtSerPlasQnLabObs.js
│ │ │ ├── AniongapSCncPtSerPlasQnLabObs.js
│ │ │ ├── AspartateAminotransferaseCCncPtSerPlasQnLabObs.js
│ │ │ ├── Basophils100WBCNFrPtBldQnAutoCntLabObs.js
│ │ │ ├── BasophilsNCncPtBldQnAutoCntLabObs.js
│ │ │ ├── BicarbonateSCncPtSerPlasQnLabObs.js
│ │ │ ├── BilirubinDirectMCncPtSerPlasQnLabObs.js
│ │ │ ├── BilirubinMCncPtSerPlasQnLabObs.js
│ │ │ ├── Blasts100WBCNFrPtBldQnManCntLabObs.js
│ │ │ ├── BlastsNCncPtBldQnLabObs.js
│ │ │ ├── CBCWAutoDifferentialPanel.js
│ │ │ ├── CalciumMCncPtSerPlasQnLabObs.js
│ │ │ ├── CarbonDioxideSCncPtSerPlasQnLabObs.js
│ │ │ ├── ChlorideSCncPtSerPlasQnLabObs.js
│ │ │ ├── ComprehensiveMetabolic2000SerumOrPlasmaPanel.js
│ │ │ ├── CreatinineMCncPtSerPlasQnLabObs.js
│ │ │ ├── Eosinophils100WBCNFrPtBldQnAutoCntLabObs.js
│ │ │ ├── EosinophilsNCncPtBldQnAutoCntLabObs.js
│ │ │ ├── ErythrocyteDistributionWidthEntVolPtRBCQnLabObs.js
│ │ │ ├── ErythrocyteDistributionWidthRatioPtRBCQnAutoCntLabObs.js
│ │ │ ├── ErythrocyteMCHCMCncPtRBCQnAutoCntLabObs.js
│ │ │ ├── ErythrocyteMCHEntMassPtRBCQnAutoCntLabObs.js
│ │ │ ├── ErythrocytesNCncPtBldQnAutoCntLabObs.js
│ │ │ ├── ErythrocytesNucleated100WBCRatioPtBldQnAutoCntLabObs.js
│ │ │ ├── ErythrocytesNucleated100WBCRatioPtBldQnLabObs.js
│ │ │ ├── ErythrocytesNucleatedNCncPtBldQnLabObs.js
│ │ │ ├── GFR173sqMPredArVRatPtSerPlasQnMDRDLabObs.js
│ │ │ ├── GFR173sqMPredBlackArVRatPtSerPlasBldQnMDRDLabObs.js
│ │ │ ├── GFR173sqMPredFemaleArVRatPtSerPlasBldQnMDRDLabObs.js
│ │ │ ├── GFR173sqMPredNonBlackArVRatPtSerPlasBldQnMDRDLabObs.js
│ │ │ ├── GlobulinMCncPtSerQnCalculatedLabObs.js
│ │ │ ├── GlucoseMCncPtSerPlasQnLabObs.js
│ │ │ ├── Granulocytes100WBCNFrPtBldQnAutoCntLabObs.js
│ │ │ ├── GranulocytesImmature100WBCNFrPtBldQnAutoCntLabObs.js
│ │ │ ├── GranulocytesImmatureNCncPtBldQnAutoCntLabObs.js
│ │ │ ├── HematocritVFrPtBldQnAutoCntLabObs.js
│ │ │ ├── HemoglobinMCncPtBldQnLabObs.js
│ │ │ ├── LeukocytesNCncPtBldQnAutoCntLabObs.js
│ │ │ ├── LeukocytesOtherNCncPtBldQnAutoCntLabObs.js
│ │ │ ├── Lymphocytes100WBCNFrPtBldQnAutoCntLabObs.js
│ │ │ ├── LymphocytesNCncPtBldQnAutoCntLabObs.js
│ │ │ ├── LymphocytesVariant100WBCNFrPtBldQnAutoCntLabObs.js
│ │ │ ├── LymphocytesVariant100WBCNFrPtBldQnLabObs.js
│ │ │ ├── LymphocytesVariantNCncPtBldQnAutoCntLabObs.js
│ │ │ ├── MeanCorpuscularVolumeEntVolPtRBCQnAutoCntLabObs.js
│ │ │ ├── Metamyelocytes100WBCNFrPtBldQnManCntLabObs.js
│ │ │ ├── MetamyelocytesNCncPtBldQnLabObs.js
│ │ │ ├── Monocytes100WBCNFrPtBldQnAutoCntLabObs.js
│ │ │ ├── MonocytesNCncPtBldQnAutoCntLabObs.js
│ │ │ ├── MorphologyImpPtBldNarLabObs.js
│ │ │ ├── Myelocytes100WBCNFrPtBldQnManCntLabObs.js
│ │ │ ├── MyelocytesNCncPtBldQnLabObs.js
│ │ │ ├── Neutrophils100WBCNFrPtBldQnAutoCntLabObs.js
│ │ │ ├── NeutrophilsBandForm100WBCNFrPtBldQnAutoCntLabObs.js
│ │ │ ├── NeutrophilsBandForm100WBCNFrPtBldQnManCntLabObs.js
│ │ │ ├── NeutrophilsBandFormNCncPtBldQnAutoCntLabObs.js
│ │ │ ├── NeutrophilsBandFormNCncPtBldQnLabObs.js
│ │ │ ├── NeutrophilsNCncPtBldQnAutoCntLabObs.js
│ │ │ ├── OtherCells100WBCNFrPtBldQnAutoCntLabObs.js
│ │ │ ├── OtherCellsNCncPtBldQnAutoCntLabObs.js
│ │ │ ├── PlateletDistributionWidthEntVolPtBldQnAutoCntLabObs.js
│ │ │ ├── PlateletMeanVolumeEntVolPtBldQnAutoCntLabObs.js
│ │ │ ├── PlateletMeanVolumeEntVolPtBldQnReesEckerLabObs.js
│ │ │ ├── PlateletsNCncPtBldQnAutoCntLabObs.js
│ │ │ ├── PotassiumSCncPtSerPlasQnLabObs.js
│ │ │ ├── Promyelocytes100WBCNFrPtBldQnManCntLabObs.js
│ │ │ ├── PromyelocytesNCncPtBldQnLabObs.js
│ │ │ ├── ProteinMCncPtSerPlasQnLabObs.js
│ │ │ ├── QuantityWithRequiredUnits.js
│ │ │ ├── ShrLabObjectFactory.js
│ │ │ ├── SimpleQuantLabWithRequiredUnits.js
│ │ │ ├── SodiumSCncPtSerPlasQnLabObs.js
│ │ │ ├── UreaNitrogenCreatinineMRtoPtSerPlasQnLabObs.js
│ │ │ └── UreaNitrogenMCncPtSerPlasQnLabObs.js
│ │ └── sdoh
│ │ │ ├── AlcoholBingeEpisodes.js
│ │ │ ├── AlcoholUse.js
│ │ │ ├── AnimalExposure.js
│ │ │ ├── Coinhabitant.js
│ │ │ ├── DomesticViolence.js
│ │ │ ├── EducationalAttainment.js
│ │ │ ├── EmotionalSafety.js
│ │ │ ├── ExposureAmount.js
│ │ │ ├── ExposureMode.js
│ │ │ ├── ExposureReason.js
│ │ │ ├── ExposureRoute.js
│ │ │ ├── FinancialStability.js
│ │ │ ├── ForeignCountryOfTravelTwoYears.js
│ │ │ ├── HomeEnvironmentRisk.js
│ │ │ ├── HouseholdIncome.js
│ │ │ ├── HouseholdSize.js
│ │ │ ├── HousingSecurity.js
│ │ │ ├── IncomeAdequacy.js
│ │ │ ├── IncomeSource.js
│ │ │ ├── IntravenousDrugUse.js
│ │ │ ├── NicotineExposure.js
│ │ │ ├── NonCashBenefit.js
│ │ │ ├── NumberOfDependents.js
│ │ │ ├── PhysicalSafety.js
│ │ │ ├── PrenatalExposure.js
│ │ │ ├── ShrSdohObjectFactory.js
│ │ │ ├── SubstanceOrAgent.js
│ │ │ ├── SubstanceUse.js
│ │ │ ├── TobaccoSmokingStatusNHIS.js
│ │ │ ├── TransportationAvailability.js
│ │ │ ├── TroubleAffordingChildCare.js
│ │ │ ├── TroubleAffordingDentalCare.js
│ │ │ ├── TroubleAffordingFood.js
│ │ │ ├── TroubleAffordingHousing.js
│ │ │ ├── TroubleAffordingMedication.js
│ │ │ ├── TroubleAffordingTransportation.js
│ │ │ ├── TroubleAffordingUtilities.js
│ │ │ └── UnprescribedExposure.js
│ └── valueSets.js
├── nav
│ ├── NavBar.css
│ └── NavBar.jsx
├── noteparser
│ ├── NoteParser.js
│ ├── app.js
│ └── samples
│ │ ├── note1.txt
│ │ ├── note10.txt
│ │ ├── note11.txt
│ │ ├── note12.txt
│ │ ├── note13.txt
│ │ ├── note14.txt
│ │ ├── note2.txt
│ │ ├── note3.txt
│ │ ├── note4.txt
│ │ ├── note5.txt
│ │ ├── note6.txt
│ │ ├── note7.txt
│ │ ├── note8.txt
│ │ └── note9.txt
├── notes
│ ├── ActiveContextsBreadcrumbs.jsx
│ ├── ActiveContextsBreadcrumbs.scss
│ ├── CompletionComponentFactory.js
│ ├── CompletionPortalPlugin.jsx
│ ├── EditorToolbar.css
│ ├── EditorToolbar.jsx
│ ├── FillPlaceholder.jsx
│ ├── FillPlaceholder.scss
│ ├── FluxNotesEditor.jsx
│ ├── FluxNotesEditor.scss
│ ├── InMemoryClinicalNote.jsx
│ ├── KeyboardShortcutsPlugin.js
│ ├── KeywordStructuredFieldPlugin.jsx
│ ├── NLPHashtagPlugin.jsx
│ ├── NoteAssistant.jsx
│ ├── NoteAssistant.scss
│ ├── PointOfCare.css
│ ├── PointOfCare.jsx
│ ├── StructuredFieldPlugin.jsx
│ ├── SuggestionPortalPlaceholderSearchIndex.jsx
│ ├── SuggestionPortalSearchIndex.jsx
│ ├── SuggestionPortalShortcutSearchIndex.jsx
│ └── fillFieldComponents
│ │ ├── ButtonSetFillFieldForPlaceholder.jsx
│ │ ├── MenuItemSetFillForPlaceholder.jsx
│ │ ├── MenuItemSetFillForPlaceholder.scss
│ │ ├── MultiButtonSetFillFieldForPlaceholder.jsx
│ │ ├── SearchableListForPlaceholder.css
│ │ └── SearchableListForPlaceholder.jsx
├── panels
│ ├── NotesPanel.jsx
│ ├── NotesPanel.scss
│ ├── PatientControlPanel.jsx
│ ├── PatientControlPanel.scss
│ ├── PickListOptionsPanel.jsx
│ ├── TargetedDataPanel.jsx
│ └── TargetedDataPanel.scss
├── patient-date-updater
│ └── app.js
├── patient
│ └── PatientRecord.jsx
├── patientControl
│ ├── BaseIndexer.js
│ ├── ClusterPointsIndexer.js
│ ├── ColumnsIndexer.js
│ ├── DiseaseStatusValuesIndexer.js
│ ├── EventsIndexer.js
│ ├── MedicationsIndexer.js
│ ├── NameValuePairsIndexer.js
│ ├── NoteContentIndexer.js
│ ├── NotesIndexer.js
│ ├── PatientSearch.jsx
│ ├── PatientSearch.scss
│ ├── PatientSelectionModal.jsx
│ ├── PatientSelectionModal.scss
│ ├── ReviewOfSystemsValuesIndexer.js
│ ├── SearchIndex.js
│ ├── SearchSuggestion.jsx
│ ├── SearchSuggestion.scss
│ └── ValueOverTimeIndexer.js
├── preferences
│ ├── IPreferenceStore.jsx
│ ├── LocalStoragePreferenceStore.jsx
│ └── PreferenceManager.jsx
├── reducers
│ ├── index.js
│ └── mcode.js
├── security
│ ├── SecurityManager.jsx
│ └── UserProfile.jsx
├── shortcuts
│ ├── CreatorBase.jsx
│ ├── CreatorChild.jsx
│ ├── CreatorIntermediary.jsx
│ ├── EntryShortcut.jsx
│ ├── InsertValue.jsx
│ ├── NLPHashtag.jsx
│ ├── Placeholder.jsx
│ ├── Shortcut.jsx
│ ├── ShortcutManager.js
│ ├── ShortcutUtils.js
│ ├── Shortcuts.json
│ ├── StructuredFieldMapManager.js
│ └── UpdaterBase.jsx
├── store
│ └── configureStore.js
├── styles
│ ├── CompassApp.css
│ ├── FullApp.scss
│ ├── LandingPage.scss
│ ├── Pilot2MvpApp.scss
│ ├── PointOfCareApp.scss
│ ├── SlimApp.css
│ ├── _variables.scss
│ └── mixins
│ │ ├── _colors.scss
│ │ └── _media-queries.scss
├── summary
│ ├── .gitignore
│ ├── BandedLineChartVisualizer.jsx
│ ├── BandedLineChartVisualizer.scss
│ ├── ClinicalEventSelection.css
│ ├── ClinicalEventSelection.jsx
│ ├── CompassAppSummaryMetadata.jsx
│ ├── ConditionSelection.jsx
│ ├── ConditionSelection.scss
│ ├── ExpandedTableVisualizer.jsx
│ ├── ExpandedTableVisualizer.scss
│ ├── FormatMedicationChange.js
│ ├── FormatTabularListVisualizer.css
│ ├── LongitudinalTable.jsx
│ ├── LongitudinalTable.scss
│ ├── LongitudinalTableVisualizer.jsx
│ ├── MedicationRangeChartVisualizer.jsx
│ ├── MedicationRangeChartVisualizer.scss
│ ├── NarrativeNameValuePairsVisualizer.jsx
│ ├── NarrativeNameValuePairsVisualizer.scss
│ ├── Pilot2MvpAppSummaryMetadata.jsx
│ ├── ProgressionLineChartVisualizer.jsx
│ ├── ProgressionLineChartVisualizer.scss
│ ├── RangeChart.css
│ ├── RangeChart.jsx
│ ├── ScatterPlotVisualizer.css
│ ├── ScatterPlotVisualizer.jsx
│ ├── SummaryHeader.jsx
│ ├── SummaryHeader.scss
│ ├── SummaryMetadata.jsx
│ ├── TabularListVisualizer.jsx
│ ├── TabularListVisualizer.scss
│ ├── TabularListVisualizerTable.jsx
│ ├── TargetedDataSection.jsx
│ ├── TargetedDataSection.scss
│ ├── TargetedDataSubpanel.css
│ ├── TargetedDataSubpanel.jsx
│ ├── TreatmentData.js
│ ├── Visualizer.jsx
│ ├── VisualizerManager.jsx
│ ├── VisualizerMenu.jsx
│ ├── activeTreatmentSummary
│ │ ├── ActiveTreatmentSummaryObjectFactory.js
│ │ ├── CancerDisorderPresentActiveTreatmentSummary.js
│ │ └── IActiveTreatmentSummary.js
│ ├── matchers
│ │ ├── AlwaysMatcher.js
│ │ ├── FunctionMatcher.js
│ │ ├── Matcher.js
│ │ └── StringMatcher.js
│ └── metadata
│ │ ├── ActiveConditionsSection.jsx
│ │ ├── ActiveConditionsSubsection.jsx
│ │ ├── ActiveTreatmentsSubsection.jsx
│ │ ├── AllergiesSection.jsx
│ │ ├── BloodPressureSubsection.jsx
│ │ ├── BreastCancerMetadata.jsx
│ │ ├── ClinicalTrialsSection.jsx
│ │ ├── DefaultCompassAppMetadata.jsx
│ │ ├── DefaultMetadata.jsx
│ │ ├── DefaultPilot2MvpAppMetadata.jsx
│ │ ├── DetailedTreatmentOptionsSection.jsx
│ │ ├── DiseaseStatusSection.jsx
│ │ ├── GeneralCancerSummarySection.jsx
│ │ ├── HeartRateSubsection.jsx
│ │ ├── HemoglobinSubsection.jsx
│ │ ├── ImagingSection.jsx
│ │ ├── KeyDatesSubsection.jsx
│ │ ├── LabTestSubsection.jsx
│ │ ├── McodeMetadata.jsx
│ │ ├── MedicationsColumnsSection.jsx
│ │ ├── MedicationsSection.jsx
│ │ ├── MetadataSection.jsx
│ │ ├── MostRecentVisitsSubsection.jsx
│ │ ├── NeutrophilCountSubsection.jsx
│ │ ├── PathologySection.jsx
│ │ ├── Pilot2MvpMetadata.jsx
│ │ ├── PlateletSubsection.jsx
│ │ ├── ProceduresSection.jsx
│ │ ├── RecentLabResultsSubsection.jsx
│ │ ├── RecentToxicitiesSubsection.jsx
│ │ ├── ReviewOfSystemsSection.jsx
│ │ ├── SarcomaCompassAppMetadata.jsx
│ │ ├── SarcomaConditionSummarySection.jsx
│ │ ├── SarcomaLabsSection.jsx
│ │ ├── SarcomaMetadata.jsx
│ │ ├── SarcomaNursePractitionerMetadata.jsx
│ │ ├── SarcomaPatientSummarySection.jsx
│ │ ├── SarcomaSummarySection.jsx
│ │ ├── TemperatureSubsection.jsx
│ │ ├── TimelineSection.jsx
│ │ ├── TreatmentOptionsSection.jsx
│ │ ├── VisitReasonPostEncounterSection.jsx
│ │ ├── VisitReasonPreEncounterSection.jsx
│ │ ├── VitalsSection.jsx
│ │ ├── VitalsSubsection.jsx
│ │ ├── WeightSubsection.jsx
│ │ └── WhiteBloodCellCountSubsection.jsx
├── templates
│ ├── TemplateOption.jsx
│ ├── TemplateOption.scss
│ ├── TemplateOptionPreviewButton.jsx
│ ├── TemplateOptionPreviewButton.scss
│ ├── TemplateSelectionView.jsx
│ └── TemplateSelectionView.scss
├── timeline
│ ├── HoverItem.css
│ ├── HoverItem.jsx
│ ├── Item.jsx
│ ├── Timeline.scss
│ ├── TimelineEventsVisualizer.jsx
│ ├── TimelineEventsVisualizer.scss
│ ├── TimelineLegend.css
│ ├── TimelineLegend.jsx
│ └── util.js
└── viewer
│ ├── ShortcutViewer.css
│ └── ShortcutViewer.jsx
└── yarn.lock
/.editorconfig:
--------------------------------------------------------------------------------
1 | # EditorConfig helps developers define and maintain consistent
2 | # coding styles between different editors and IDEs
3 | # editorconfig.org
4 |
5 | root = true
6 |
7 | [*]
8 | end_of_line = lf
9 | charset = utf-8
10 | trim_trailing_whitespace = true
11 | insert_final_newline = true
12 | indent_style = space
13 | indent_size = 4
14 |
15 | [*.md]
16 | trim_trailing_whitespace = false
17 |
--------------------------------------------------------------------------------
/.env:
--------------------------------------------------------------------------------
1 | BROWSER=http://localhost:3000/pilot1
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | src/lib/slate/*
2 | src/lib/slate-suggestions-dist/*
3 | src/lib/react-minimap/*
4 | src/model/*
5 | src/dataaccess/mcodev0.1-datasource/model/*
6 | src/__test__/*
7 | src/lib/cql-execution/*
8 | src/lib/FHIRMapper.js
9 | src/mcode-pilot/mock-data/mock-data.js
10 | src/summary/TreatmentData.js
11 |
--------------------------------------------------------------------------------
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "react-app",
3 | "rules": {
4 | "arrow-spacing": "warn",
5 | "block-spacing": "warn",
6 | "key-spacing": "warn",
7 | "keyword-spacing": "warn",
8 | "indent": ["warn", 4, { "SwitchCase": 1 }],
9 | "no-trailing-spaces": "warn",
10 | "no-var": "warn",
11 | "prefer-const": "warn",
12 | "semi": "warn",
13 | "semi-spacing": "warn",
14 | "space-before-blocks": "warn",
15 | "space-in-parens": "warn"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 |
3 | node_js:
4 | - 10.14.1
5 |
6 | script:
7 | - yarn build-css && yarn test-ci
8 | - yarn build
9 |
10 | notifications:
11 | email:
12 | on_failure: change
13 |
14 | after_success: 'npm run coveralls'
15 |
16 | cache:
17 | yarn: true
18 | directories:
19 | - node_modules
20 |
--------------------------------------------------------------------------------
/config-overrides.js:
--------------------------------------------------------------------------------
1 | const CopyWebpackPlugin = require('copy-webpack-plugin');
2 | const {
3 | override,
4 | useEslintRc,
5 | addWebpackExternals,
6 | addWebpackPlugin
7 | } = require("customize-cra");
8 |
9 |
10 | module.exports = override(
11 | useEslintRc(),
12 | addWebpackExternals({
13 | 'fhir-mapper': "Mapper",
14 | 'babel-polyfill': "_babelPolyfill"
15 | }),
16 | addWebpackPlugin(new CopyWebpackPlugin([
17 | { context:'node_modules/fhir-mapper/dist/', from: 'app.bundle.js*', to: 'static/js/fhir-mapper' }
18 | ]))
19 | );
20 |
--------------------------------------------------------------------------------
/design/readme.md:
--------------------------------------------------------------------------------
1 | # FLUX NOTES DESIGNS
2 |
3 | Design files associated with Flux Notes have been uploaded periodically throughout the project (workflow diagrams, UI mockups, interaction concepts, among other deliverables). To view them, please go to the following link:
4 | https://github.com/standardhealth/shr_design/tree/master/Flux%20Notes
5 |
--------------------------------------------------------------------------------
/design/shr_fluxnotes_concept_v11.3_screens_components_v1.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FluxNotes/flux/dcfa6d78442cb9ca51ec627eb5cd193bd76a38db/design/shr_fluxnotes_concept_v11.3_screens_components_v1.pdf
--------------------------------------------------------------------------------
/docs/FluxNotesManual_v0.1.docx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FluxNotes/flux/dcfa6d78442cb9ca51ec627eb5cd193bd76a38db/docs/FluxNotesManual_v0.1.docx
--------------------------------------------------------------------------------
/docs/Structured Phrase Format Descriptions.pptx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FluxNotes/flux/dcfa6d78442cb9ca51ec627eb5cd193bd76a38db/docs/Structured Phrase Format Descriptions.pptx
--------------------------------------------------------------------------------
/docs/fluxArchitecture.vpp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FluxNotes/flux/dcfa6d78442cb9ca51ec627eb5cd193bd76a38db/docs/fluxArchitecture.vpp
--------------------------------------------------------------------------------
/public/DebraHernandez672.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FluxNotes/flux/dcfa6d78442cb9ca51ec627eb5cd193bd76a38db/public/DebraHernandez672.jpg
--------------------------------------------------------------------------------
/public/DebraHernandez672.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FluxNotes/flux/dcfa6d78442cb9ca51ec627eb5cd193bd76a38db/public/DebraHernandez672.png
--------------------------------------------------------------------------------
/public/EllaOrtiz111.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FluxNotes/flux/dcfa6d78442cb9ca51ec627eb5cd193bd76a38db/public/EllaOrtiz111.png
--------------------------------------------------------------------------------
/public/JaneBradshaw146.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FluxNotes/flux/dcfa6d78442cb9ca51ec627eb5cd193bd76a38db/public/JaneBradshaw146.png
--------------------------------------------------------------------------------
/public/ServerConfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "baseURL": "http://localhost:3001/api"
3 | }
--------------------------------------------------------------------------------
/public/WesWelker83.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FluxNotes/flux/dcfa6d78442cb9ca51ec627eb5cd193bd76a38db/public/WesWelker83.png
--------------------------------------------------------------------------------
/public/clinicalTrialEnrollmentSheet.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FluxNotes/flux/dcfa6d78442cb9ca51ec627eb5cd193bd76a38db/public/clinicalTrialEnrollmentSheet.pdf
--------------------------------------------------------------------------------
/public/clinicalTrialUnenrolledSheet.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FluxNotes/flux/dcfa6d78442cb9ca51ec627eb5cd193bd76a38db/public/clinicalTrialUnenrolledSheet.pdf
--------------------------------------------------------------------------------
/public/compass-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FluxNotes/flux/dcfa6d78442cb9ca51ec627eb5cd193bd76a38db/public/compass-logo.png
--------------------------------------------------------------------------------
/public/deceasedSheet.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FluxNotes/flux/dcfa6d78442cb9ca51ec627eb5cd193bd76a38db/public/deceasedSheet.pdf
--------------------------------------------------------------------------------
/public/diseaseStatusSheet.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FluxNotes/flux/dcfa6d78442cb9ca51ec627eb5cd193bd76a38db/public/diseaseStatusSheet.pdf
--------------------------------------------------------------------------------
/public/fluxnotes_logo_b&w.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FluxNotes/flux/dcfa6d78442cb9ca51ec627eb5cd193bd76a38db/public/fluxnotes_logo_b&w.png
--------------------------------------------------------------------------------
/public/fluxnotes_logo_color.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FluxNotes/flux/dcfa6d78442cb9ca51ec627eb5cd193bd76a38db/public/fluxnotes_logo_color.png
--------------------------------------------------------------------------------
/public/icare_logo_b&w.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FluxNotes/flux/dcfa6d78442cb9ca51ec627eb5cd193bd76a38db/public/icare_logo_b&w.png
--------------------------------------------------------------------------------
/public/icare_logo_color.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FluxNotes/flux/dcfa6d78442cb9ca51ec627eb5cd193bd76a38db/public/icare_logo_color.png
--------------------------------------------------------------------------------
/public/icons/angled-pencil.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/public/icons/icon_arrow_left.svg:
--------------------------------------------------------------------------------
1 |
10 |
--------------------------------------------------------------------------------
/public/icons/icon_view_left.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FluxNotes/flux/dcfa6d78442cb9ca51ec627eb5cd193bd76a38db/public/icons/icon_view_left.png
--------------------------------------------------------------------------------
/public/icons/icon_view_left.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/public/icons/icon_view_middle.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FluxNotes/flux/dcfa6d78442cb9ca51ec627eb5cd193bd76a38db/public/icons/icon_view_middle.png
--------------------------------------------------------------------------------
/public/icons/icon_view_middle.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/public/icons/icon_view_right.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FluxNotes/flux/dcfa6d78442cb9ca51ec627eb5cd193bd76a38db/public/icons/icon_view_right.png
--------------------------------------------------------------------------------
/public/icons/icon_view_right.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/public/landing/fluxnotes_compass.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FluxNotes/flux/dcfa6d78442cb9ca51ec627eb5cd193bd76a38db/public/landing/fluxnotes_compass.gif
--------------------------------------------------------------------------------
/public/landing/fluxnotes_full.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FluxNotes/flux/dcfa6d78442cb9ca51ec627eb5cd193bd76a38db/public/landing/fluxnotes_full.gif
--------------------------------------------------------------------------------
/public/landing/fluxnotes_gif_fullSize.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FluxNotes/flux/dcfa6d78442cb9ca51ec627eb5cd193bd76a38db/public/landing/fluxnotes_gif_fullSize.gif
--------------------------------------------------------------------------------
/public/landing/fluxnotes_poc.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FluxNotes/flux/dcfa6d78442cb9ca51ec627eb5cd193bd76a38db/public/landing/fluxnotes_poc.gif
--------------------------------------------------------------------------------
/public/landing/grid_background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FluxNotes/flux/dcfa6d78442cb9ca51ec627eb5cd193bd76a38db/public/landing/grid_background.png
--------------------------------------------------------------------------------
/public/landing/icon_efficacy_research.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FluxNotes/flux/dcfa6d78442cb9ca51ec627eb5cd193bd76a38db/public/landing/icon_efficacy_research.png
--------------------------------------------------------------------------------
/public/landing/icon_market_surveillance.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FluxNotes/flux/dcfa6d78442cb9ca51ec627eb5cd193bd76a38db/public/landing/icon_market_surveillance.png
--------------------------------------------------------------------------------
/public/landing/icon_provider_burden.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FluxNotes/flux/dcfa6d78442cb9ca51ec627eb5cd193bd76a38db/public/landing/icon_provider_burden.png
--------------------------------------------------------------------------------
/public/landing/icon_rare_diseases.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FluxNotes/flux/dcfa6d78442cb9ca51ec627eb5cd193bd76a38db/public/landing/icon_rare_diseases.png
--------------------------------------------------------------------------------
/public/landing/icon_regimen_analysis.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FluxNotes/flux/dcfa6d78442cb9ca51ec627eb5cd193bd76a38db/public/landing/icon_regimen_analysis.png
--------------------------------------------------------------------------------
/public/landing/icon_utilization.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FluxNotes/flux/dcfa6d78442cb9ca51ec627eb5cd193bd76a38db/public/landing/icon_utilization.png
--------------------------------------------------------------------------------
/public/landing/img_fluxnotes_lite.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FluxNotes/flux/dcfa6d78442cb9ca51ec627eb5cd193bd76a38db/public/landing/img_fluxnotes_lite.jpg
--------------------------------------------------------------------------------
/public/logos/ASCO.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FluxNotes/flux/dcfa6d78442cb9ca51ec627eb5cd193bd76a38db/public/logos/ASCO.png
--------------------------------------------------------------------------------
/public/logos/Alliance.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FluxNotes/flux/dcfa6d78442cb9ca51ec627eb5cd193bd76a38db/public/logos/Alliance.png
--------------------------------------------------------------------------------
/public/logos/BWH.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FluxNotes/flux/dcfa6d78442cb9ca51ec627eb5cd193bd76a38db/public/logos/BWH.png
--------------------------------------------------------------------------------
/public/logos/Browserstack-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FluxNotes/flux/dcfa6d78442cb9ca51ec627eb5cd193bd76a38db/public/logos/Browserstack-logo.png
--------------------------------------------------------------------------------
/public/logos/DanaFarber.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FluxNotes/flux/dcfa6d78442cb9ca51ec627eb5cd193bd76a38db/public/logos/DanaFarber.png
--------------------------------------------------------------------------------
/public/logos/FluxNotesLogo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FluxNotes/flux/dcfa6d78442cb9ca51ec627eb5cd193bd76a38db/public/logos/FluxNotesLogo.png
--------------------------------------------------------------------------------
/public/logos/ICARE.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FluxNotes/flux/dcfa6d78442cb9ca51ec627eb5cd193bd76a38db/public/logos/ICARE.png
--------------------------------------------------------------------------------
/public/logos/MITRE.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FluxNotes/flux/dcfa6d78442cb9ca51ec627eb5cd193bd76a38db/public/logos/MITRE.png
--------------------------------------------------------------------------------
/public/logos/SHR.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FluxNotes/flux/dcfa6d78442cb9ca51ec627eb5cd193bd76a38db/public/logos/SHR.png
--------------------------------------------------------------------------------
/public/logos/codex-Logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FluxNotes/flux/dcfa6d78442cb9ca51ec627eb5cd193bd76a38db/public/logos/codex-Logo.png
--------------------------------------------------------------------------------
/public/logos/favicon-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FluxNotes/flux/dcfa6d78442cb9ca51ec627eb5cd193bd76a38db/public/logos/favicon-16x16.png
--------------------------------------------------------------------------------
/public/logos/favicon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FluxNotes/flux/dcfa6d78442cb9ca51ec627eb5cd193bd76a38db/public/logos/favicon-32x32.png
--------------------------------------------------------------------------------
/public/logos/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FluxNotes/flux/dcfa6d78442cb9ca51ec627eb5cd193bd76a38db/public/logos/favicon.ico
--------------------------------------------------------------------------------
/public/logos/mCODE-Logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FluxNotes/flux/dcfa6d78442cb9ca51ec627eb5cd193bd76a38db/public/logos/mCODE-Logo.png
--------------------------------------------------------------------------------
/public/mapper.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FluxNotes/flux/dcfa6d78442cb9ca51ec627eb5cd193bd76a38db/public/mapper.js
--------------------------------------------------------------------------------
/public/pathology-report.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FluxNotes/flux/dcfa6d78442cb9ca51ec627eb5cd193bd76a38db/public/pathology-report.pdf
--------------------------------------------------------------------------------
/public/spa.jsp:
--------------------------------------------------------------------------------
1 | <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%><%
2 | response.setStatus(200);
3 | %><%@include file="./index.html"%>
4 |
--------------------------------------------------------------------------------
/public/stagingSheet.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FluxNotes/flux/dcfa6d78442cb9ca51ec627eb5cd193bd76a38db/public/stagingSheet.pdf
--------------------------------------------------------------------------------
/public/toxicitySheet.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FluxNotes/flux/dcfa6d78442cb9ca51ec627eb5cd193bd76a38db/public/toxicitySheet.pdf
--------------------------------------------------------------------------------
/scripts/check-version.js:
--------------------------------------------------------------------------------
1 | const LTS_VERSION = "v10.14.1"
2 |
3 | if (process.version !== LTS_VERSION) {
4 | console.log(`
5 | **********
6 | * WARNING: Your version of node doesn't match our LTS: Expected ${LTS_VERSION}, got ${process.version}
7 | **********
8 | `);
9 | } else {
10 | console.log("Version of Node checks out");
11 | }
12 |
--------------------------------------------------------------------------------
/src/__test__/backend/config/ConfigManager.test.js:
--------------------------------------------------------------------------------
1 | import ConfigManager from '../../../config/ConfigManager';
2 | import {expect} from 'chai';
3 | const nock = require('nock');
4 |
5 | describe("ConfigManager", function () {
6 | it('should aquire defaults from global.CONFIG object if available', function () {
7 | global.CONFIG = {foo:"bar"};
8 | let cm = new ConfigManager();
9 |
10 | expect(cm.config)
11 | .to.deep.equal(global.CONFIG);
12 | });
13 |
14 | it('should be able to load a config file from a url', function () {
15 | let config = {foo: 'BAR'};
16 | const scope = nock('http://localhost/')
17 | .get('/config.json')
18 | .reply(200, config);
19 |
20 | global.CONFIG = {};
21 | let cm = new ConfigManager();
22 | expect(cm.config)
23 | .to.deep.equal(global.CONFIG);
24 | cm.loadConfiguration("/config.json").then(()=> {
25 | expect(cm.config)
26 | .to.deep.equal(config);
27 | });
28 | });
29 | });
30 |
--------------------------------------------------------------------------------
/src/__test__/backend/dashboard/DashboardManager.test.js:
--------------------------------------------------------------------------------
1 | import DashboardManager from '../../../dashboard/DashboardManager';
2 | import {expect} from 'chai'
3 |
4 | // Create one das
5 | const emptyDashboardManager = new DashboardManager([]);
6 | const dashboardManager = new DashboardManager();
7 |
8 | describe("getPossibleSuperRoles", function () {
9 | it('should return an empty list if there are no defined superRoles', function () {
10 | const allRoles = emptyDashboardManager.getPossibleSuperRoles();
11 | expect(allRoles)
12 | .to.be.an("array")
13 | .and.to.be.empty;
14 | });
15 |
16 | it('should return a list containing Clinician and Patient as default superRoles', function () {
17 | const expectedRoles = ['Clinician', 'Patient'];
18 | const actualRoles = dashboardManager.getPossibleSuperRoles();
19 | expect(actualRoles)
20 | .to.have.same.members(expectedRoles);
21 | })
22 | });
--------------------------------------------------------------------------------
/src/__test__/backend/lib/cql-execution/CQLExecutionEngine.test.js:
--------------------------------------------------------------------------------
1 | import {expect} from 'chai';
2 | import * as CQLExecutionEngine from '../../../../lib/cql-execution/CQLExecutionEngine.js';
3 | import PALLAScql from '../../../../lib/cql-execution/example/cql/PALLASEligibility.json';
4 | import PALLAS_eligiblePatient from '../../../../lib/cql-execution/example/patients/PALLASPatient.json';
5 | import PALLAS_ineligiblePatient from '../../../../lib/cql-execution/example/patients/PATINAPatient.json';
6 |
7 |
8 | describe('getPALLASeligibility', function () {
9 | it('should return a boolean - true if FHIR patient passes PALLAS eligibility criteria', function () {
10 | const result = CQLExecutionEngine.getCQLResults(PALLAScql, [PALLAS_eligiblePatient, PALLAS_ineligiblePatient]);
11 | expect(result.patientResults['93d8b432-f097-4c82-b111-8577e1d9d89f'].meetsInclusionCriteria)
12 | .to.be.true;
13 | expect(result.patientResults['3cb09ecb-e927-4946-82b3-89957e193215'].meetsInclusionCriteria)
14 | .to.be.false;
15 |
16 | });
17 | });
18 |
--------------------------------------------------------------------------------
/src/__test__/backend/mcode/services/filter.json:
--------------------------------------------------------------------------------
1 | {
2 | "demographics": {
3 | "gender": {
4 | "codeSystem": "SNOMEDCT",
5 | "displayName": "Female",
6 | "code": "703118005"
7 | },
8 | "age": {
9 | "min": 43,
10 | "max": 63
11 | },
12 | "age_at_diagnosis": {
13 | "min": 42,
14 | "max": 62
15 | },
16 | "race": {
17 | "codeSystemName": "HL7 v3 Code System Race",
18 | "codeSystem": "2.16.840.1.113883.5.104",
19 | "displayName": "White",
20 | "code" : "2106-3"
21 | }
22 |
23 | },
24 | "diagnosis" : { "stage": "IA", "grade": 3, "tnm": { "t": "T1c", "m": "M0",
25 | "n" : "N0" } },
26 | "tumorMarkers": [{
27 | "code": "16112-5",
28 | "codeSystem": "http://fhir.loinc.org",
29 | "displayName": "Estrogen Receptor",
30 | "value": "Positive"
31 | },
32 | {
33 | "code": "16113-3",
34 | "codeSystem": "http://fhir.loinc.org",
35 | "displayName": "Progesterone Receptor",
36 | "value": "Negative"
37 | },
38 | {
39 | "code": "48676-1",
40 | "codeSystem": "http://fhir.loinc.org",
41 | "displayName": "HER2 Receptor",
42 | "value": "Positive"
43 | }
44 | ]
45 | }
--------------------------------------------------------------------------------
/src/__test__/backend/mcode/services/rows.js:
--------------------------------------------------------------------------------
1 | export default [{
2 | "id": "row_1",
3 | "displayName": "A & B",
4 | "treatments": [{
5 | "code": "A",
6 | "displayName": "A",
7 | "codeSystem": "2.16.840.1.113883.6.88",
8 | "codeSystemName": "RXNORM"
9 | }, {
10 | "code": "B",
11 | "displayName": "B",
12 | "codeSystem": "2.16.840.1.113883.6.88",
13 | "codeSystemName": "RXNORM"
14 | }],
15 | "totalPatients": 2039,
16 | "survivorsPerYear": [,100,,99,,98],
17 | "sideEffects": {
18 | "totalReporting": 0,
19 | "effects": {}
20 | }
21 | }, {
22 | "id": "row_2",
23 | "displayName": "A",
24 | "treatments": [{
25 | "code": "A",
26 | "displayName": "A",
27 | "codeSystem": "2.16.840.1.113883.6.88",
28 | "codeSystemName": "RXNORM"
29 | }],
30 | "totalPatients": 4028,
31 | "survivorsPerYear": [,200, ,201,,200],
32 | "sideEffects": {
33 | "totalReporting": 0,
34 | "effects": {}
35 | }
36 | }]
--------------------------------------------------------------------------------
/src/__test__/backend/model/CodeableConceptUtils.test.js:
--------------------------------------------------------------------------------
1 | import {expect} from 'chai';
2 | import * as codeableConceptUtils from '../../../model/CodeableConceptUtils';
3 |
4 | describe('getCodeableConceptFromTuple', function() {
5 | const tuple = {
6 | value: 'test',
7 | codeSystem: '1234',
8 | displayText: 'display!'
9 | };
10 | const concept = codeableConceptUtils.getCodeableConceptFromTuple(tuple);
11 |
12 | it('should return CodeableConcept object with corresponding code, codeySystem, and displayText', function() {
13 | expect(concept)
14 | .to.be.an('object');
15 | expect(concept.displayText.value)
16 | .to.be.a('string')
17 | .eql(tuple.displayText);
18 | expect(concept.coding)
19 | .to.be.an('array')
20 | .that.is.not.empty;
21 | expect(concept.coding[0].codeValue.code)
22 | .to.be.a('string')
23 | .eql(tuple.value);
24 | expect(concept.coding[0].codeSystem.value)
25 | .to.be.a('string')
26 | .eql(tuple.codeSystem);
27 | });
28 | });
29 |
--------------------------------------------------------------------------------
/src/__test__/backend/model/actor/FluxDeceased.disabled.js:
--------------------------------------------------------------------------------
1 | // import FluxDeceased from '../../../../model/actor/FluxDeceased';
2 | // import {expect} from 'chai';
3 | // import util from 'util';
4 |
5 | // let deceased = new FluxDeceased();
6 | // deceased.dateOfDeath = '11 Nov 2017';
7 |
8 | // describe('getDateOfDeath()', function() {
9 | // it('should return "11 Nov 2017"', function() {
10 | // expect(deceased.dateOfDeath)
11 | // .to.be.a('string')
12 | // .eql('11 Nov 2017');
13 | // });
14 | // });
15 |
16 | // describe('setDateOfDeath()', function() {
17 | // it('should set dateOfDeath to "1 Oct 2017"', function() {
18 | // deceased.dateOfDeath = '1 Oct 2017';
19 | // expect(deceased.dateOfDeath)
20 | // .to.be.a('string')
21 | // .eql('1 Oct 2017');
22 | // });
23 | // });
--------------------------------------------------------------------------------
/src/__test__/backend/model/oncology/FluxEstrogenReceptorStatus.disabled.js:
--------------------------------------------------------------------------------
1 | // import FluxEstrogenReceptorStatus from '../../../../model/oncology/FluxEstrogenReceptorStatus';
2 | // import {expect} from 'chai';
3 | // import util from 'util';
4 |
5 | // let erstatus = new FluxEstrogenReceptorStatus();
6 | // erstatus.status = 'Positive';
7 |
8 | // describe('getStatus()', function() {
9 | // it('should return "Positive"', function() {
10 | // expect(erstatus.status)
11 | // .to.be.a('string')
12 | // .eql('Positive');
13 | // });
14 | // });
15 |
16 | // describe('setStatus()', function() {
17 | // it('should set status to "Negative"', function() {
18 | // erstatus.status = 'Negative';
19 | // expect(erstatus.status)
20 | // .to.be.a('string')
21 | // .eql('Negative');
22 | // });
23 | // });
--------------------------------------------------------------------------------
/src/__test__/backend/model/oncology/FluxHistologicGrade.disabled.js:
--------------------------------------------------------------------------------
1 | // import FluxHistologicGrade from '../../../../model/oncology/FluxHistologicGrade';
2 | // import {expect} from 'chai';
3 | // import util from 'util';
4 |
5 | // const gradeJson = {
6 | // "entryType": [ "http://standardhealthrecord.org/oncology/HistologicGrade",
7 | // "http://standardhealthrecord.org/observation/Observation",
8 | // "http://standardhealthrecord.org/base/Action" ],
9 | // "value": {"coding": [{"value": "369792005", "codeSystem": {"value":"http://snomed.info/sct"}, "displayText": "High grade or poorly differentiated"}]},
10 | // "status": "final",
11 | // "_issue": "stricly speaking, the observations in this list are elements and not entries so entryType shouldn't exist but how would you know which concrete type this represents otherwise? Problem is bigger for choices where some or all choices are just elements"
12 | // };
13 |
14 | // let grade = new FluxHistologicGrade(gradeJson);
15 |
16 | // describe('getGrade()', function() {
17 | // it('should return "High grade or poorly differentiated"', function() {
18 | // expect(grade.grade)
19 | // .to.be.a('string')
20 | // .eql('High grade or poorly differentiated');
21 | // });
22 | // });
23 |
--------------------------------------------------------------------------------
/src/__test__/backend/model/oncology/FluxHumanEpiduralGrowthFactorReceptor2Status.disabled.js:
--------------------------------------------------------------------------------
1 | // import FluxHumanEpiduralGrowthFactorReceptor2Status from '../../../../model/oncology/FluxHumanEpiduralGrowthFactorReceptor2Status';
2 | // import {expect} from 'chai';
3 | // import util from 'util';
4 |
5 | // let her2status = new FluxHumanEpiduralGrowthFactorReceptor2Status();
6 | // her2status.status = 'Positive';
7 |
8 | // describe('getStatus()', function() {
9 | // it('should return "Positive"', function() {
10 | // expect(her2status.status)
11 | // .to.be.a('string')
12 | // .eql('Positive');
13 | // });
14 | // });
15 |
16 | // describe('setStatus()', function() {
17 | // it('should set status to "Negative"', function() {
18 | // her2status.status = 'Negative';
19 | // expect(her2status.status)
20 | // .to.be.a('string')
21 | // .eql('Negative');
22 | // });
23 | // });
--------------------------------------------------------------------------------
/src/__test__/backend/model/oncology/FluxProgesteroneReceptorStatus.disabled.js:
--------------------------------------------------------------------------------
1 | // import FluxProgesteroneReceptorStatus from '../../../../model/oncology/FluxProgesteroneReceptorStatus';
2 | // import {expect} from 'chai';
3 | // import util from 'util';
4 |
5 | // let prstatus = new FluxProgesteroneReceptorStatus();
6 | // prstatus.status = 'Positive';
7 |
8 | // describe('getStatus()', function() {
9 | // it('should return "Positive"', function() {
10 | // expect(prstatus.status)
11 | // .to.be.a('string')
12 | // .eql('Positive');
13 | // });
14 | // });
15 |
16 | // describe('setStatus()', function() {
17 | // it('should set status to "Negative"', function() {
18 | // prstatus.status = 'Negative';
19 | // expect(prstatus.status)
20 | // .to.be.a('string')
21 | // .eql('Negative');
22 | // });
23 | // });
--------------------------------------------------------------------------------
/src/__test__/backend/model/oncology/FluxTumorSize.disabled.js:
--------------------------------------------------------------------------------
1 | // import FluxTumorSize from '../../../../model/oncology/FluxTumorSize';
2 | // import {expect} from 'chai';
3 | // import util from 'util';
4 |
5 | // const tumorJson = {
6 | // "entryType": [ "http://standardhealthrecord.org/oncology/TumorSize",
7 | // "http://standardhealthrecord.org/observation/Observation",
8 | // "http://standardhealthrecord.org/base/Action" ],
9 | // "value": {"value": 30.0, "units": {"value": "mm"}},
10 | // "specificType": {"value": {"coding": [{"value": "C0475440", "codeSystem": {"value":"http://ncimeta.nci.nih.gov"}, "displayText": "Tumor Size"}]}},
11 | // "status": "final",
12 | // "_issue": "strictly speaking, the observations in this list are elements and not entries so entryType shouldn't exist but how would you know which concrete type this represents otherwise? Problem is bigger for choices where some or all choices are just elements"
13 | // };
14 |
15 | // let tumorSize = new FluxTumorSize(tumorJson);
16 |
17 | // describe('getQuantity()', function() {
18 | // it('should return an object with value and unit', function() {
19 | // const expectedQuantity = {
20 | // value: 30.0,
21 | // unit: "mm"
22 | // };
23 | // expect(tumorSize.quantity)
24 | // .to.be.a('object')
25 | // .eql(expectedQuantity);
26 | // });
27 | // });
28 |
--------------------------------------------------------------------------------
/src/__test__/backend/model/research/FluxStudy.disabled.js:
--------------------------------------------------------------------------------
1 | // import FluxStudy from '../../../../model/research/FluxStudy';
2 | // import {expect} from 'chai';
3 | // import util from 'util';
4 |
5 | // let study = new FluxStudy();
6 | // study.title = 'PATINA';
7 | // study.identifier = '123';
8 |
9 | // describe('getTitle()', function() {
10 | // it('should return "PATINA"', function() {
11 | // expect(study.title)
12 | // .to.be.a('string')
13 | // .eql('PATINA');
14 | // });
15 | // });
16 |
17 | // describe('setTitle()', function() {
18 | // it('should set title to "ICARE"', function() {
19 | // study.title = 'ICARE';
20 | // expect(study.title)
21 | // .to.be.a('string')
22 | // .eql('ICARE');
23 | // });
24 | // });
25 |
26 | // describe('getIdentifier()', function() {
27 | // it('should return "123"', function() {
28 | // expect(study.identifier)
29 | // .to.be.a('string')
30 | // .eql('123');
31 | // });
32 | // });
33 |
34 | // describe('setIdentifier()', function() {
35 | // it('should set title to "235"', function() {
36 | // study.identifier = '235';
37 | // expect(study.identifier)
38 | // .to.be.a('string')
39 | // .eql('235');
40 | // });
41 | // });
--------------------------------------------------------------------------------
/src/__test__/backend/patient/FakeDataElement.js:
--------------------------------------------------------------------------------
1 | /** Fake Data Element */
2 | class FakeDataElement {
3 |
4 | get value() {
5 | return this.something;
6 | }
7 |
8 | set value(val) {
9 | this.something = val;
10 | }
11 | }
12 |
13 | export default FakeDataElement;
14 |
--------------------------------------------------------------------------------
/src/__test__/backend/patientControl/FakePatient.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FluxNotes/flux/dcfa6d78442cb9ca51ec627eb5cd193bd76a38db/src/__test__/backend/patientControl/FakePatient.js
--------------------------------------------------------------------------------
/src/__test__/backend/views/Landing.test.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Enzyme, { shallow } from 'enzyme';
3 | import Adapter from 'enzyme-adapter-react-15';
4 | import { expect } from 'chai';
5 |
6 | import LandingPage from '../../../components/LandingPage';
7 |
8 | Enzyme.configure({ adapter: new Adapter() });
9 |
10 | describe('Landing', function() {
11 | it('Can navigate to pages', () => {
12 | const wrapper = shallow();
13 | const fullAppDiv = wrapper.find('#link-to-full');
14 | expect(fullAppDiv.prop('href')).to.equal('/pilot1')
15 | });
16 | });
--------------------------------------------------------------------------------
/src/__test__/testHelper.js:
--------------------------------------------------------------------------------
1 | import {ConfigManagerInstance} from '../config/ConfigManager';
2 | import fs from 'fs';
3 | const JSON5 = require('json5');
4 | const data = new String(fs.readFileSync('./public/config.js'));
5 | const config = JSON5.parse(data.substring(data.indexOf("{")-1));
6 | ConfigManagerInstance.addConfiguration(config);
7 |
--------------------------------------------------------------------------------
/src/actions/types.js:
--------------------------------------------------------------------------------
1 | // ------------------------- MCODE ----------------------------------------- //
2 |
3 | export const INITIALIZE_SIMILAR_PATIENT_PROPS = 'INITIALIZE_SIMILAR_PATIENT_PROPS';
4 | export const SELECT_ALL_CATEGORY_SIMILAR_PATIENT_OPTIONS = 'SELECT_ALL_CATEGORY_SIMILAR_PATIENT_OPTIONS';
5 | export const SELECT_ALL_SIMILAR_PATIENT_OPTIONS = 'SELECT_ALL_SIMILAR_PATIENT_OPTIONS';
6 | export const SELECT_SIMILAR_PATIENT_OPTION = 'SELECT_SIMILAR_PATIENT_OPTION';
7 | export const SELECT_SIMILAR_PATIENT_OPTION_RANGE = 'SELECT_SIMILAR_PATIENT_OPTION_RANGE';
8 | export const SELECT_TREATMENTS = 'SELECT_TREATMENTS';
9 | export const UPDATE_PATIENT_OUTCOMES = 'UPDATE_PATIENT_OUTCOMES';
10 | export const SET_SELECTED_TREATMENT = 'SET_SELECTED_TREATMENT';
11 | export const SET_SELECTED_SIDE_EFFECTS = 'SET_SELECTED_SIDE_EFFECTS';
12 |
--------------------------------------------------------------------------------
/src/apps/AppManager.jsx:
--------------------------------------------------------------------------------
1 | import { CompassApp } from '../containers/CompassApp';
2 | import SmartCompassApp from '../containers/SmartCompassApp';
3 | import { FullApp } from '../containers/FullApp';
4 | import SmartFullApp from '../containers/SmartFullApp';
5 | import SlimApp from '../containers/SlimApp';
6 | import PointOfCareApp from '../containers/PointOfCareApp';
7 | import Pilot2MvpApp from '../containers/Pilot2MvpApp';
8 | import SmartPilot2MvpApp from '../containers/SmartPilot2MvpApp';
9 | import LandingPage from '../components/LandingPage';
10 | import LaunchPage from '../components/LaunchPage';
11 | import {ConfigManagerInstance} from '../config/ConfigManager';
12 |
13 | const APPS = {
14 | 'SlimApp': SlimApp,
15 | 'FullApp': FullApp,
16 | 'SmartFullApp': SmartFullApp,
17 | 'LaunchPage': LaunchPage,
18 | 'LandingPage': LandingPage,
19 | 'CompassApp': CompassApp,
20 | 'SmartCompassApp': SmartCompassApp,
21 | 'PointOfCareApp': PointOfCareApp,
22 | 'Pilot2MvpApp': Pilot2MvpApp,
23 | 'SmartPilot2MvpApp': SmartPilot2MvpApp,
24 | };
25 |
26 | export default class AppManager {
27 | constructor() {
28 | this.apps = ConfigManagerInstance.get('apps').map((appConfig) => {
29 | appConfig.app = APPS[appConfig.app];
30 | return appConfig;
31 | });
32 | }
33 | getSupportedApps() {
34 | return this.apps;
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/components/WithTracker.jsx:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import PropTypes from 'prop-types';
3 | import ReactGA from 'react-ga';
4 |
5 | ReactGA.initialize('UA-82650858-3');
6 |
7 | const WithTracker = (WrappedComponent, options = {}) => {
8 | const trackPage = page => {
9 | ReactGA.set({
10 | page,
11 | ...options,
12 | });
13 | ReactGA.pageview(page);
14 | };
15 |
16 | const HOC = class extends Component {
17 | componentDidMount() {
18 | const page = this.props.location.pathname;
19 | trackPage(page);
20 | }
21 |
22 | componentWillReceiveProps(nextProps) {
23 | const currentPage = this.props.location.pathname;
24 | const nextPage = nextProps.location.pathname;
25 |
26 | if (currentPage !== nextPage) {
27 | trackPage(nextPage);
28 | }
29 | }
30 |
31 | render() {
32 | return ;
33 | }
34 | };
35 |
36 | HOC.propTypes = {
37 | path: PropTypes.string.isRequired,
38 | location: PropTypes.object.isRequired,
39 | display: PropTypes.string.isRequired,
40 | // App is a react component, which is itself a function
41 | app: PropTypes.func.isRequired,
42 | isExact: PropTypes.bool.isRequired
43 | };
44 |
45 | return HOC;
46 | };
47 |
48 | export default WithTracker;
49 |
--------------------------------------------------------------------------------
/src/config/ConfigManager.js:
--------------------------------------------------------------------------------
1 | import axios from 'axios';
2 |
3 | export default class ConfigManager {
4 | constructor(config = {}) {
5 | this.config = global.CONFIG ? { ...global.CONFIG , ...config } : { ...config };
6 | }
7 |
8 | addConfiguration(conf) {
9 | if (conf) {
10 | this.config = {
11 | ...this.config,
12 | ...conf
13 | };
14 | }
15 | }
16 |
17 | async loadConfiguration(url) {
18 | const response = await axios.get(url);
19 | if (response) {
20 | this.addConfiguration(response.data);
21 | }
22 | }
23 |
24 | get(name, defaultValue) {
25 | const parts = name.split('.');
26 | let context = this.config;
27 | let value = null;
28 | for (const i in parts) {
29 | const part = parts[i];
30 | value = context[part];
31 | context = value;
32 | }
33 | return value || defaultValue;
34 | }
35 | }
36 |
37 | const instance = new ConfigManager();
38 | export { instance as ConfigManagerInstance };
39 |
--------------------------------------------------------------------------------
/src/config/ServiceManager.js:
--------------------------------------------------------------------------------
1 | import { ConfigManagerInstance } from './ConfigManager';
2 | import StaticOutcomesService from '../mcode-pilot/services/outcomes/StaticOutcomesService';
3 | import CLQOutcomesService from '../mcode-pilot/services/outcomes/CLQOutcomesService';
4 |
5 | const SERVICES = {
6 | 'StaticOutcomesService': StaticOutcomesService,
7 | 'CLQOutcomesService': CLQOutcomesService
8 | };
9 |
10 | export default class ServiceManager {
11 | constructor() {
12 | this.services = ConfigManagerInstance.get('services', {});
13 | const keys = Object.keys(this.services);
14 | for (const key of keys) {
15 | const serviceConfig = this.services[key];
16 | if (typeof serviceConfig === 'string') {
17 | const type = SERVICES[serviceConfig];
18 | this.services[key] = new type();
19 | } else if (serviceConfig && serviceConfig.name) {
20 | const type = SERVICES[serviceConfig.name];
21 | this.services[key] = new type(serviceConfig);
22 | }
23 | }
24 | }
25 |
26 | getService(name) {
27 | return this.services[name];
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/containers/App.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Route } from 'react-router-dom';
3 | import 'fhirclient';
4 | import AppManager from '../apps/AppManager';
5 | import WithTracker from '../components/WithTracker';
6 |
7 | const appManager = new AppManager();
8 | const apps = appManager.getSupportedApps();
9 |
10 |
11 | const App = () => (
12 |
13 | {apps.map((appObject, i) =>
14 | {
15 | return React.createElement(WithTracker(appObject.app), { ...props, ...appObject });
16 | }} key={i}/>
17 | )}
18 |
19 | );
20 |
21 | export default App;
22 |
--------------------------------------------------------------------------------
/src/containers/SmartCompassApp.jsx:
--------------------------------------------------------------------------------
1 | import { CompassApp } from "./CompassApp";
2 | import WithSmartData from './WithSmartData';
3 |
4 | const SmartCompassApp = WithSmartData(CompassApp);
5 | export default SmartCompassApp;
--------------------------------------------------------------------------------
/src/containers/SmartFullApp.jsx:
--------------------------------------------------------------------------------
1 | import { FullApp } from "./FullApp";
2 | import WithSmartData from './WithSmartData';
3 |
4 | const SmartFullApp = WithSmartData(FullApp);
5 | export default SmartFullApp;
--------------------------------------------------------------------------------
/src/containers/SmartPilot2MvpApp.jsx:
--------------------------------------------------------------------------------
1 | import { Pilot2MvpApp } from "./Pilot2MvpApp";
2 | import WithSmartData from './WithSmartData';
3 |
4 | const SmartPilot2MvpApp = WithSmartData(Pilot2MvpApp);
5 | export default SmartPilot2MvpApp;
6 |
--------------------------------------------------------------------------------
/src/context/ContextGetHelp.scss:
--------------------------------------------------------------------------------
1 | @import '../styles/variables';
2 |
3 | ul.context-get-help {
4 | max-height: 250px;
5 | overflow-y: auto;
6 | overflow-x: hidden;
7 | list-style-type: none;
8 | padding: 0;
9 | margin: 0;
10 | background-color: $background;
11 |
12 | li {
13 | padding: 5px 10px;
14 | display: flex;
15 | justify-content: space-between;
16 | & > * {
17 | display: block;
18 | }
19 | }
20 |
21 | li[data-active="true"] {
22 | background-color: $interface-blue;
23 | color: $background;
24 | }
25 |
26 | .context-get-help-li {
27 | margin-top: 5px;
28 | margin-bottom: 5px;
29 |
30 | .context-get-help-text {
31 | span.fa-angle-up, span.fa-angle-down {
32 | padding: 0;
33 | padding-left: 15px;
34 | }
35 | }
36 | .context-information-text {
37 | span.fa-info-circle {
38 | padding: 0 5px 0 0;
39 | }
40 | }
41 | }
42 |
43 | .context-get-help-options {
44 | li:last-child {
45 | margin-bottom: 5px;
46 | }
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/src/context/ContextItem.scss:
--------------------------------------------------------------------------------
1 | @import "../styles/variables";
2 |
3 | .context-menu-item {
4 | padding: 5px 10px;
5 | width: 300px;
6 | display: flex;
7 | justify-content: space-between;
8 | & > * {
9 | display:block;
10 | }
11 | }
12 |
13 | .context-menu-item[data-active="true"] {
14 | background-color: $interface-blue;
15 | color: #fff;
16 | }
17 |
18 | .right-aligned {
19 | padding-left: 15px;
20 | }
--------------------------------------------------------------------------------
/src/context/ContextListOptions.scss:
--------------------------------------------------------------------------------
1 | ul.context-list-options {
2 | max-height: 250px;
3 | overflow-y: auto;
4 | overflow-x: hidden;
5 | list-style-type: none;
6 | padding: 0;
7 | margin: 0;
8 | background-color: #fff;
9 | li:first-child {
10 | margin-top: 10px;
11 | }
12 | li:last-child {
13 | margin-bottom: 10px;
14 | }
15 | }
--------------------------------------------------------------------------------
/src/context/ContextOptions.scss:
--------------------------------------------------------------------------------
1 | @import "../styles/variables";
2 |
3 | .context-option {
4 | margin: 1px 0;
5 | cursor: pointer;
6 | font-size: $size-m;
7 | color: $body-gray;
8 | }
9 |
10 | .context-option:last-of-type {
11 | margin-bottom: 0;
12 | }
13 |
14 | .context-option:hover {
15 | color: $body-black;
16 | font-weight: $weight-semibold;
17 | }
18 |
19 | .context-options-section {
20 | padding-left: $note-assistant-overhang;
21 | }
22 |
23 | .context-options-list {
24 | overflow-y: hidden;
25 | overflow-x: hidden;
26 | font-weight: $weight-regular;
27 | }
28 |
29 | .hidden {
30 | display: none;
31 | }
32 |
33 | /*
34 | * Tooltip Styling
35 | */
36 |
37 | .context-panel-tooltip{
38 | .rc-tooltip-inner{
39 | width: 150px;
40 | min-height: 22px;
41 | text-align: center;
42 | border-radius: 6px;
43 | }
44 |
45 | .large .rc-tooltip-inner{
46 | width: 220px;
47 | }
48 | }
49 |
50 | .context-options-header {
51 | margin-top: $size-s;
52 | font-style: italic;
53 | font-size: $size-m;
54 | color: $state;
55 | }
56 |
--------------------------------------------------------------------------------
/src/context/ContextTray.scss:
--------------------------------------------------------------------------------
1 | @import "../styles/variables";
2 |
3 |
4 | .context-tray {
5 | margin: 5px 0px 20px 0;
6 | color: $body-gray;
7 |
8 | .view-mode-section-item {
9 | margin: 3px 0;
10 | font-size: $size-m;
11 | color: $state;
12 | cursor: pointer;
13 | text-overflow: ellipsis;
14 | overflow: hidden;
15 | white-space: nowrap;
16 | }
17 |
18 | .view-mode-section-item:hover,
19 | .view-mode-section-item.selected {
20 | font-weight: $weight-semibold;
21 | color: $body-gray;
22 | }
23 |
24 | .view-mode-section-menu {
25 | padding: 5px 0px 5px 0px+$note-assistant-overhang;
26 | border-bottom: 1px solid $line-gray;
27 | }
28 |
29 | .view-mode-section-item-disabled {
30 | margin: 3px 0px 3px 26px;
31 | font-size: $size-m;
32 | text-overflow: ellipsis;
33 | overflow: hidden;
34 | white-space: nowrap;
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/context/EditorPortal.scss:
--------------------------------------------------------------------------------
1 | @import '../styles/variables.scss';
2 |
3 | .completion-portal {
4 | box-sizing: border-box;
5 | border-radius: 2px;
6 | -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
7 | box-shadow: rgba(0, 0, 0, 0.12) 0px 1px 6px, rgba(0, 0, 0, 0.12) 0px 1px 4px;
8 | transition: all 450ms cubic-bezier(0.23, 1, 0.32, 1) 0ms;
9 | margin-top: 30px;
10 | z-index: 1111;
11 | background-color: $background;
12 | opacity: 1;
13 | }
14 |
--------------------------------------------------------------------------------
/src/context/PatientContext.jsx:
--------------------------------------------------------------------------------
1 | import Context from './Context';
2 | /*import NameInserter from '../shortcuts/NameInserter';
3 | import DateOfBirthInserter from '../shortcuts/DateOfBirthInserter';
4 | import AgeInserter from '../shortcuts/AgeInserter';
5 | import GenderInserter from '../shortcuts/GenderInserter';
6 | import PatientInserter from '../shortcuts/PatientInserter';
7 | import ConditionInserter from '../shortcuts/ConditionInserter';
8 | import DeceasedCreator from '../shortcuts/DeceasedCreator';
9 | import ClinicalTrialCreator from '../shortcuts/ClinicalTrialCreator';
10 | */
11 |
12 | class PatientContext extends Context {
13 | constructor(patient) {
14 | super();
15 | this.patient = patient;
16 | }
17 |
18 | getValidChildShortcuts(recurse = false) {
19 | /*let result = [ NameInserter, DateOfBirthInserter, AgeInserter, GenderInserter, PatientInserter, ConditionInserter, ClinicalTrialCreator, DeceasedCreator ];
20 | if (recurse) {
21 | this.getChildren().forEach((subcontext) => {
22 | result = result.concat(subcontext.getValidChildShortcuts(true));
23 | });
24 | }
25 | return result;*/
26 |
27 | }
28 |
29 | getDisplayText() {
30 | return 'Patient';
31 | }
32 | getId() {
33 | return "Patient";
34 | }
35 | }
36 |
37 | export default PatientContext;
38 |
--------------------------------------------------------------------------------
/src/context/PlaceholderViewModeContent.jsx:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import PropTypes from 'prop-types';
3 |
4 | export default class PlaceholderViewModeContent extends Component {
5 | handleClick(e, placeholderText) {
6 | const { onClick } = this.props;
7 |
8 | e.preventDefault();
9 | onClick(placeholderText);
10 | }
11 |
12 | renderPlaceholder(placeholder) {
13 | const placeholderText = `<${placeholder.name}>`;
14 |
15 | return (
16 | this.handleClick(e, placeholderText)}
20 | >
21 | {placeholderText}
22 |
23 | );
24 | }
25 |
26 | render() {
27 | const { placeholders } = this.props;
28 |
29 | return (
30 |
31 | {placeholders.map((placeholder) => {
32 | return this.renderPlaceholder(placeholder);
33 | })}
34 |
35 | );
36 | }
37 | }
38 |
39 | PlaceholderViewModeContent.propTypes = {
40 | onClick: PropTypes.func.isRequired,
41 | placeholders: PropTypes.array.isRequired,
42 | };
43 |
--------------------------------------------------------------------------------
/src/context/ShortcutSearch.jsx:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import PropTypes from 'prop-types';
3 | import TextField from 'material-ui/TextField';
4 |
5 | import './ShortcutSearch.css';
6 |
7 | export default class ShortcutSearch extends Component {
8 | render() {
9 | return (
10 |
11 |
12 | this.props.handleSearch(event.target.value)}
16 | />
17 |
18 |
19 | );
20 | }
21 | }
22 |
23 | ShortcutSearch.propTypes = {
24 | handleSearch: PropTypes.func.isRequired,
25 | };
26 |
--------------------------------------------------------------------------------
/src/context/ShortcutViewModeContent.scss:
--------------------------------------------------------------------------------
1 | @import '../styles/variables.scss';
2 |
3 | .condition-contexts,
4 | .section-active {
5 | margin-left: 5px;
6 | }
7 |
8 | #shortcut-search-container {
9 | width: 100%;
10 | padding: 0 $note-assistant-overhang 15px $note-assistant-overhang;
11 | border-bottom: 1px solid $line-gray;
12 | background-color: $background;
13 | }
--------------------------------------------------------------------------------
/src/context/SnippetViewModeContent.jsx:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import PropTypes from 'prop-types';
3 | import './SnippetViewModeContent.css';
4 |
5 | export default class SnippetViewModeContent extends Component {
6 |
7 | // These don't need to be stored as state since they're not being updated
8 | snippets = [
9 | { name: 'Disease Status', content: '#disease status is #status based on #reasons #as of #date' },
10 | ];
11 |
12 | // Insert the content of the template as you would a shortcut
13 | insertSnippet = (snippet) => {
14 | // Insert this snippets content
15 | this.props.onClick(snippet.content);
16 | }
17 |
18 | // Just render the form for the snippets; if additional information was to rendered, we would do it here.
19 | render() {
20 | return (
21 |
22 | {this.snippets.map((snippet, index) => {
23 | return (
24 |
this.insertSnippet(snippet)}
28 | >
29 | {snippet.name}
30 |
31 | );
32 | })}
33 |
34 | );
35 | }
36 | }
37 |
38 | SnippetViewModeContent.propTypes = {
39 | onClick: PropTypes.func.isRequired,
40 | };
41 |
--------------------------------------------------------------------------------
/src/context/SnippetViewModeContent.scss:
--------------------------------------------------------------------------------
1 | @import "../styles/variables";
2 |
3 | .snippet {
4 | margin: 5px 0 5px $note-assistant-overhang;
5 | font-size: $size-m;
6 | color: $body-gray;
7 | cursor: pointer;
8 |
9 | &:hover {
10 | color: $body-gray;
11 | font-weight: $weight-semibold;
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/dashboard/ClinicianDashboard.css:
--------------------------------------------------------------------------------
1 | #clinician-dashboard-content {
2 | margin-top: 15px;
3 | }
4 |
5 | #clinician-dashboard-content .fitted-panel {
6 | overflow-y: auto;
7 | overflow-x: hidden;
8 | text-align: left;
9 | /* 92px is the height of the on large screens Patient Control Panel, 20px is the height of the top margin of post encounter view content and a little extra for potential scroll bars*/
10 | max-height: calc(100vh - 92px - 20px);
11 | min-height: 400px !important;
12 | }
13 |
14 | #clinician-dashboard-content .right-border-box {
15 | border-right: 1px dashed #ddd;
16 | padding-right: 1px;
17 | }
18 |
19 | #clinician-dashboard-content .full-panel {
20 | height: auto;
21 | }
22 |
23 | @media only screen and (max-width: 1200px) {
24 | #clinician-dashboard-content .fitted-panel {
25 | /* 117px is the height of the on large screens Patient Control Panel, 20px is the height of the top margin of post encounter view content and a little extra for potential scroll bars*/
26 | max-height: calc(100vh - 117px - 20px);
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/dashboard/CompassAppDashboard.scss:
--------------------------------------------------------------------------------
1 | #compass-app-dashboard-content {
2 | margin-top: 15px;
3 |
4 | .fitted-panel {
5 | overflow-y: auto;
6 | overflow-x: hidden;
7 | text-align: left;
8 | /* 106px is the height of the on large screens Patient Control Panel, 20px is the height of the top margin of post encounter view content and a little extra for potential scroll bars*/
9 | max-height: calc(100vh - 92px - 20px);
10 | min-height: 400px !important;
11 | }
12 |
13 | .right-border-box {
14 | border-right: 2px dashed #ddd;
15 | }
16 |
17 | .full-panel {
18 | height: auto;
19 | }
20 | }
21 |
22 | @media only screen and (max-width: 1200px) {
23 | #compass-app-dashboard-content .fitted-panel {
24 | /* 117px is the height of the on large screens Patient Control Panel, 20px is the height of the top margin of post encounter view content and a little extra for potential scroll bars*/
25 | max-height: calc(100vh - 117px - 20px);
26 | }
27 | }
--------------------------------------------------------------------------------
/src/dashboard/NextPatientButton.scss:
--------------------------------------------------------------------------------
1 | @import '../styles/variables';
2 |
3 | .patient-div {
4 | position: absolute;
5 | bottom: -1px;
6 | left: 0;
7 | width: 120px;
8 | height: 100px;
9 | background-color: #32556C;
10 | border-style: solid;
11 | border-color: #E1E1E1;
12 | border-left: none;
13 | border-bottom: none;
14 | border-radius: 0 50px 0 0;
15 | display: -webkit-flex;
16 | display: flex;
17 | -webkit-align-items: center;
18 | align-items: center;
19 | -webkit-justify-content: center;
20 | justify-content: center;
21 | text-align: center;
22 | z-index: 5 !important;
23 | &:hover {
24 | cursor: pointer;
25 | }
26 | }
27 | .inside {
28 | display: flex;
29 | align-items: center;
30 | justify-content: center;
31 | flex-grow: 1;
32 | height: 100%;
33 | border-radius: 0 50px 0 0;
34 | &:hover {
35 | background-color: rgba(0, 0, 0, 0.12);
36 | }
37 | }
38 | .patient-icon {
39 | color: white;
40 | display: inline-block;
41 | }
--------------------------------------------------------------------------------
/src/dataaccess/GenericSmartOnFhirDstu2DataSource.js:
--------------------------------------------------------------------------------
1 | import McodeV09SmartOnFhirDataSource from "./McodeV09SmartOnFhirDataSource";
2 | import processFHIRResources from './utils/fhir-entry-processor';
3 | import mappers from './mappers';
4 |
5 | class GenericSmartOnFhirDstu2DataSource extends McodeV09SmartOnFhirDataSource {
6 | constructor(props) {
7 | super(props);
8 | if (props && props.mapper) {
9 | const mapperClass = typeof props.mapper === 'string' ? mappers[props.mapper] : props.mapper;
10 | this.mapper = new mapperClass(props.mapperVariables);
11 | }
12 | }
13 |
14 | getPatient(id, callback) {
15 | super.fetchResources()
16 | .then(resources => callback(processFHIRResources(resources, this._client.patient.id, this.mapper)));
17 | }
18 | }
19 |
20 | export default GenericSmartOnFhirDstu2DataSource;
--------------------------------------------------------------------------------
/src/dataaccess/IDataSource.js:
--------------------------------------------------------------------------------
1 | class IDataSource {
2 | getPatient(id, optionalCallback) {
3 | throw new Error("getPatient not implemented by " + this.constructor.name);
4 | }
5 | getListOfPatients() {
6 | throw new Error("getListOfPatients not implemented by " + this.constructor.name);
7 | }
8 |
9 | newPatient() {
10 | throw new Error("newPatient not implemented by " + this.constructor.name);
11 | }
12 |
13 | savePatient(patient) {
14 | throw new Error("savePatient not implemented by " + this.constructor.name);
15 | }
16 |
17 | // On the origins of this term see: https://en.wikipedia.org/wiki/Gestalt_(Mac_OS)
18 | getGestalt() {
19 | //
20 | // Shape of the gestalt : {
21 | // create: {
22 | // sync: bool,
23 | // async: bool
24 | // }
25 | // read: {
26 | // sync: bool,
27 | // async: bool
28 | // }
29 | // update: {
30 | // sync: bool,
31 | // async: bool
32 | // }
33 | // delete: {
34 | // sync: bool,
35 | // async: bool
36 | // }
37 | // }
38 | //
39 | throw new Error("getGestalt not implemented by " + this.constructor.name);
40 | }
41 | }
42 |
43 | export default IDataSource;
--------------------------------------------------------------------------------
/src/dataaccess/NewPatientOnlyDataSource.js:
--------------------------------------------------------------------------------
1 | import IDataSource from './IDataSource';
2 | import PatientRecord from '../patient/PatientRecord';
3 |
4 | class NewPatientOnlyDataSource extends IDataSource {
5 | constructor() {
6 | super();
7 | this._gestalt = {
8 | create: {
9 | async: false,
10 | sync: true
11 | },
12 | read: {
13 | async: false,
14 | sync: false
15 | },
16 | update: {
17 | async: false,
18 | sync: false
19 | },
20 | delete: {
21 | async: false,
22 | sync: false
23 | }
24 | };
25 | }
26 | getGestalt() {
27 | return this._gestalt;
28 | }
29 | getPatient(id) {
30 | console.error("loading of patients is not implemented in new patient only data source.");
31 | }
32 | getListOfPatients() {
33 | console.error("listing of patients is not implemented in new patient only data source.");
34 | }
35 |
36 | newPatient() {
37 | return new PatientRecord(null);
38 | }
39 |
40 | savePatient(patient) {
41 | console.error("saving of patients is not implemented in new patient only data source.");
42 | }
43 | }
44 |
45 | export default NewPatientOnlyDataSource;
--------------------------------------------------------------------------------
/src/dataaccess/mappers/index.js:
--------------------------------------------------------------------------------
1 | import {mappers} from 'fhir-mapper';
2 | import CernerSandboxMapper from './CernerSandboxMapper';
3 | export default {...mappers, CernerSandboxMapper};
--------------------------------------------------------------------------------
/src/elements/Button.js:
--------------------------------------------------------------------------------
1 | import { withStyles } from 'material-ui/styles';
2 | import Button from 'material-ui/Button';
3 |
4 | const styles = {
5 | root: {
6 | fontFamily: '"Open Sans", Arial, sans-serif',
7 | padding: '0px',
8 | margin: '2px'
9 | }
10 | };
11 |
12 | export default withStyles(styles)(Button);
13 |
--------------------------------------------------------------------------------
/src/elements/ChoiceButton.js:
--------------------------------------------------------------------------------
1 | import { withStyles } from 'material-ui/styles';
2 | import Button from './Button';
3 |
4 | const styles = {
5 | root: {
6 | fontSize: '.8rem',
7 | height: "50px",
8 | margin: 0.5,
9 | width: "130px",
10 | backgroundColor: "white",
11 | textTransform: "none"
12 | }
13 | };
14 |
15 | export default withStyles(styles)(Button);
16 |
--------------------------------------------------------------------------------
/src/elements/MenuItem.js:
--------------------------------------------------------------------------------
1 | import { withStyles } from 'material-ui/styles';
2 | import MenuItem from 'material-ui/Menu/MenuItem';
3 | import variable from '../styles/_variables.scss';
4 |
5 | const styles = {
6 | root: {
7 | border: 0,
8 | fontFamily: '"Open Sans", Arial, sans-serif',
9 | fontSize: "0.8em",
10 | color: "#555",
11 | '&:hover': {
12 | backgroundColor: variable.state
13 | }
14 | }
15 |
16 | };
17 |
18 | export default withStyles(styles)(MenuItem);
19 |
--------------------------------------------------------------------------------
/src/elements/SearchBar.jsx:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import PropTypes from 'prop-types';
3 | import TextField from 'material-ui/TextField';
4 |
5 | import './SearchBar.css';
6 |
7 | export default class SearchBar extends Component {
8 | render () {
9 | return (
10 |
11 |
12 | this.props.handleSearch(event.target.value)}
17 | />
18 |
19 | );
20 | }
21 | }
22 |
23 | SearchBar.propTypes = {
24 | searchString: PropTypes.string,
25 | handleSearch: PropTypes.func.isRequired,
26 | label: PropTypes.string.isRequired,
27 | };
28 |
--------------------------------------------------------------------------------
/src/elements/SearchBar.scss:
--------------------------------------------------------------------------------
1 | @import "../styles/variables";
2 |
3 | #search-container {
4 | font-size: $size-m;
5 | color: $state;
6 | text-align: left;
7 | position: relative;
8 | display: inline-flex;
9 | align-items: flex-end;
10 | width: 100%;
11 | .search-icon {
12 | margin-right: 5px;
13 | padding-bottom: 10px;
14 | }
15 | .search-text {
16 | // This should be the width of the search-bars container, minus the size of the icon
17 | width: calc(100% - 25px);
18 | font-size: $size-m;
19 | color: $state;
20 | }
21 | }
22 |
23 |
24 |
--------------------------------------------------------------------------------
/src/elements/Select.js:
--------------------------------------------------------------------------------
1 | import { withStyles } from 'material-ui/styles';
2 | import Select from 'material-ui/Select';
3 |
4 | const styles = {
5 | root: {
6 | border: 0,
7 | fontFamily: '"Open Sans", Arial, sans-serif',
8 | fontSize: "0.9em",
9 | color: "#555",
10 | }
11 |
12 | };
13 |
14 | export default withStyles(styles)(Select);
15 |
--------------------------------------------------------------------------------
/src/forms/ClinicalTrialEnrollmentForm.css:
--------------------------------------------------------------------------------
1 | .tooltip-clinical-trial {
2 | position: relative;
3 | display: inline-block;
4 | }
5 |
6 | .tooltip-clinical-trial .tooltiptext-clinical-trial {
7 | visibility: hidden;
8 | width: 150px;
9 | background-color: #555;
10 | color: #fff;
11 | text-align: center;
12 | border-radius: 6px;
13 | padding: 10px 10px;
14 | position: absolute;
15 | z-index: 1;
16 | bottom: 125%;
17 | margin-left: 18px !important;
18 | opacity: 0;
19 | transition: opacity 1s;
20 | font-size: .8rem;
21 | }
22 |
23 | .tooltip-clinical-trial .large-clinical-trial {
24 | width: 220px;
25 | margin-left: -95px;
26 | }
27 |
28 | .tooltip-clinical-trial .tooltiptext-clinical-trial::after {
29 | content: "";
30 | position: absolute;
31 | top: 100%;
32 | left: 50%;
33 | margin-left: -5px;
34 | border-width: 5px;
35 | border-style: solid;
36 | border-color: #555 transparent transparent transparent;
37 | }
38 |
39 | .tooltip-clinical-trial:hover .tooltiptext-clinical-trial {
40 | visibility: visible;
41 | opacity: 1;
42 | transition-delay: 0.5s;
43 | }
44 |
45 | .helper-text {
46 | color: #b1b1b1;
47 | }
48 |
49 | .MuiInput-inkbar-113:after{
50 | background-color: #297DA2 !important;
51 | }
52 |
53 | .DayPickerInput-Overlay {
54 | z-index: 3;
55 | }
--------------------------------------------------------------------------------
/src/forms/ClinicalTrialUnenrolledForm.css:
--------------------------------------------------------------------------------
1 | .tooltip-clinical-trial {
2 | position: relative;
3 | display: inline-block;
4 | }
5 |
6 | .tooltip-clinical-trial .tooltiptext-clinical-trial {
7 | visibility: hidden;
8 | width: 150px;
9 | background-color: #555;
10 | color: #fff;
11 | text-align: center;
12 | border-radius: 6px;
13 | padding: 10px 10px;
14 | position: absolute;
15 | z-index: 1;
16 | bottom: 125%;
17 | margin-left: 18px !important;
18 | opacity: 0;
19 | transition: opacity 1s;
20 | font-size: .8rem;
21 | }
22 |
23 | .tooltip-clinical-trial .large-clinical-trial {
24 | width: 220px;
25 | margin-left: -95px;
26 | }
27 |
28 | .tooltip-clinical-trial .tooltiptext-clinical-trial::after {
29 | content: "";
30 | position: absolute;
31 | top: 100%;
32 | left: 50%;
33 | margin-left: -5px;
34 | border-width: 5px;
35 | border-style: solid;
36 | border-color: #555 transparent transparent transparent;
37 | }
38 |
39 | .tooltip-clinical-trial:hover .tooltiptext-clinical-trial {
40 | visibility: visible;
41 | opacity: 1;
42 | transition-delay: 0.5s;
43 | }
44 |
45 | .helper-text {
46 | color: #b1b1b1;
47 | }
48 |
49 | .MuiInput-inkbar-113:after{
50 | background-color: #297DA2 !important;
51 | }
52 |
53 | .DayPickerInput-Overlay {
54 | z-index: 3;
55 | }
--------------------------------------------------------------------------------
/src/forms/DataCaptureForm.css:
--------------------------------------------------------------------------------
1 | .btn_template {
2 | float: left;
3 | clear: left;
4 | margin-bottom: 20px;
5 | }
6 |
--------------------------------------------------------------------------------
/src/forms/DatePicker.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FluxNotes/flux/dcfa6d78442cb9ca51ec627eb5cd193bd76a38db/src/forms/DatePicker.css
--------------------------------------------------------------------------------
/src/forms/DeceasedForm.css:
--------------------------------------------------------------------------------
1 | .helper-text {
2 | color: #b1b1b1;
3 | }
4 |
5 | .MuiInput-inkbar-113:after{
6 | background-color: #297DA2 !important;
7 | }
--------------------------------------------------------------------------------
/src/forms/FormList.css:
--------------------------------------------------------------------------------
1 | #list-panel {
2 | background-color: #F3F3F3;
3 | height: calc(100vh - 64px);
4 | text-align: left;
5 | overflow-y: auto;
6 | overflow: overlay;
7 | }
8 |
9 | #list-panel .list-element.unselected{
10 | border-bottom: 1px solid #d9d9d9 !important;
11 | padding: 16px;
12 | line-height: 16px;
13 | }
14 | #list-panel .list-element.unselected.overview{
15 | color: steelblue !important;
16 | padding: 16px;
17 | line-height: 16px;
18 | }
19 |
20 | #list-panel .list-element.selected{
21 | background-color: white !important;
22 | font-weight: bold!important;
23 | -webkit-box-shadow: 0px 4px 5px -4px rgba(125,125,125,0.7);
24 | -moz-box-shadow: 0px 4px 5px -4px rgba(125,125,125,0.7);
25 | box-shadow: 0px 4px 5px -4px rgba(125,125,125,0.7);
26 | padding: 16px;
27 | line-height: 16px;
28 | }
29 | #list-panel .list-element.selected.overview{
30 | color: steelblue !important;
31 | padding: 16px;
32 | line-height: 16px;
33 | }
34 |
--------------------------------------------------------------------------------
/src/forms/FormSearch.css:
--------------------------------------------------------------------------------
1 |
2 | #form-search {
3 | padding: 15px 0;
4 | background-color: #fbfbfb;
5 | text-align: left;
6 | height: 50px;
7 | border-bottom: 1px solid #d9d9d9 !important;
8 | }
--------------------------------------------------------------------------------
/src/forms/FormSearch.jsx:
--------------------------------------------------------------------------------
1 | // React imports
2 | import React, {Component} from 'react';
3 | // material-ui
4 | import TextField from 'material-ui/TextField';
5 | import FontIcon from 'material-ui/FontIcon';
6 | // Styling
7 | import './FormSearch.css';
8 |
9 | class FormSearch extends Component {
10 | constructor(props) {
11 | super(props);
12 |
13 | this.underlineStyle = {
14 | borderColor: "#17263f",
15 | };
16 | }
17 |
18 | handleSearch(searchValue) {
19 | console.log();
20 | }
21 |
22 | render() {
23 | return (
24 |
38 | );
39 | }
40 | }
41 |
42 | export default FormSearch;
43 |
--------------------------------------------------------------------------------
/src/forms/LandingPageForm.css:
--------------------------------------------------------------------------------
1 | .landing-page-title {
2 | color: steelblue;
3 | }
4 |
5 | ol, ol li {
6 | margin-left: 0;
7 | padding-left: 0;
8 | }
9 |
10 | ol {
11 | margin-left: 1.3em;
12 | }
13 |
14 | .landing-page-about {
15 | margin-bottom: 40px;
16 | }
17 |
18 | .landing-page-using li {
19 | margin: 10px 0;
20 | }
--------------------------------------------------------------------------------
/src/forms/MultiChoiceButton.jsx:
--------------------------------------------------------------------------------
1 | import React, {Component} from 'react';
2 | import PropTypes from 'prop-types';
3 | import ChoiceButton from '../elements/ChoiceButton';
4 |
5 | import "./MultiChoiceButton.css";
6 |
7 | class MultiChoiceButton extends Component {
8 | render() {
9 | let className = "multi-choice-button ";
10 | className += (this.props.className) ? `${this.props.className} ` : "";
11 | className += (this.props.isSelected) ? "selected " : "";
12 |
13 | return (
14 |
21 | {this.props.buttonText}
22 |
23 | );
24 | }
25 | }
26 |
27 | MultiChoiceButton.propTypes= {
28 | buttonKey: PropTypes.number.isRequired,
29 | buttonText: PropTypes.string.isRequired,
30 | onClick: PropTypes.func.isRequired,
31 | className: PropTypes.string,
32 | marginSize: PropTypes.string.isRequired,
33 | isDisabled: PropTypes.bool,
34 | };
35 |
36 | export default MultiChoiceButton;
37 |
--------------------------------------------------------------------------------
/src/forms/MultiChoiceButton.scss:
--------------------------------------------------------------------------------
1 | @import '../styles/variables';
2 |
3 | .multi-choice-button {
4 | border-radius: 5px !important;
5 | border-color: $background;
6 | line-height: 0.9rem !important;
7 | margin: 2px !important;
8 |
9 | &.placeholder-button {
10 | width: 115px !important;
11 | height: 47px !important;
12 | border-radius: 4px !important;
13 | color: $body-black !important;
14 | box-shadow: 0px 0px 0px 0px #DDDDDD, 0px 0px 0px 0px #DDDDDD, 0px 0px 0px 1px #DDDDDD !important;
15 | }
16 |
17 | &.selected {
18 | background-color: $interface-blue !important;
19 | color: $background !important;
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/forms/ProgressionForm.css:
--------------------------------------------------------------------------------
1 | .tooltip-progression-form {
2 | position: relative;
3 | display: inline-block;
4 | }
5 |
6 | .tooltip-progression-form .tooltiptext {
7 | visibility: hidden;
8 | width: 150px;
9 | background-color: #555;
10 | color: #fff;
11 | text-align: center;
12 | border-radius: 5px;
13 | padding: 10px 10px;
14 | position: absolute;
15 | z-index: 1;
16 | bottom: 125%;
17 | margin-left: 18px !important;
18 | opacity: 0;
19 | transition: opacity 1s;
20 | font-size: .8rem;
21 | }
22 |
23 | .tooltip-progression-form .large {
24 | width: 220px;
25 | margin-left: -95px;
26 | }
27 |
28 | .tooltip-progression-form .tooltiptext::after {
29 | content: "";
30 | position: absolute;
31 | top: 100%;
32 | left: 50%;
33 | margin-left: -5px;
34 | border-width: 5px;
35 | border-style: solid;
36 | border-color: #555 transparent transparent transparent;
37 | }
38 |
39 | .tooltip-progression-form:hover .tooltiptext {
40 | visibility: visible;
41 | opacity: 1;
42 | transition-delay: 0.5s;
43 | }
44 |
45 | .helper-text {
46 | color: #b1b1b1;
47 | }
48 |
49 | .MuiInput-inkbar-113:after{
50 | background-color: #297DA2 !important;
51 | }
52 |
53 | .btn-group-reason-progression {
54 | margin: 0 10px;
55 | }
56 |
57 | h4 span.helper-text {
58 | font-size: .9em;
59 | font-style: italic;
60 | }
--------------------------------------------------------------------------------
/src/forms/SingleChoiceButton.jsx:
--------------------------------------------------------------------------------
1 | import React, {Component} from 'react';
2 | import PropTypes from 'prop-types';
3 | import ChoiceButton from '../elements/ChoiceButton';
4 |
5 | import "./SingleChoiceButton.css";
6 |
7 | class SingleChoiceButton extends Component {
8 | render() {
9 | let className = "single-choice-button ";
10 | className += (this.props.className) ? `${this.props.className} ` : "";
11 | className += (this.props.isSelected) ? "selected " : "";
12 |
13 | return (
14 |
25 | {this.props.buttonText}
26 |
27 | );
28 | }
29 | }
30 |
31 | SingleChoiceButton.propTypes= {
32 | buttonKey: PropTypes.number.isRequired,
33 | buttonText: PropTypes.string.isRequired,
34 | onClick: PropTypes.func.isRequired,
35 | className: PropTypes.string,
36 | marginSize: PropTypes.string,
37 | isDisabled: PropTypes.bool,
38 | };
39 |
40 | export default SingleChoiceButton;
41 |
--------------------------------------------------------------------------------
/src/forms/SingleChoiceButton.scss:
--------------------------------------------------------------------------------
1 | @import '../styles/variables';
2 |
3 | .single-choice-button {
4 | border-radius: 5px !important;
5 | border: 2px solid;
6 | border-color: $background;
7 | line-height: 0.9rem !important;
8 | margin: .5px !important;
9 |
10 | &.placeholder-button {
11 | width: 115px !important;
12 | height: 47px !important;
13 | border-radius: 0px !important;
14 | color: $body-black !important;
15 | box-shadow: 0px 0px 0px 0px #DDDDDD, 0px 0px 0px 0px #DDDDDD, 0px 0px 0px 1px #DDDDDD !important;
16 | }
17 |
18 | &.selected {
19 | background-color: $interface-blue !important;
20 | color: $background !important;
21 | }
22 | }
--------------------------------------------------------------------------------
/src/forms/index.js:
--------------------------------------------------------------------------------
1 | export {default as StagingForm} from './StagingForm';
2 | export {default as ProgressionForm} from './ProgressionForm';
3 | export {default as ToxicityForm} from './ToxicityForm';
4 | export {default as DeceasedForm} from './DeceasedForm';
5 | export {default as ClinicalTrialEnrollmentForm} from './ClinicalTrialEnrollmentForm';
6 | export {default as ClinicalTrialUnenrolledForm} from './ClinicalTrialUnenrolledForm';
--------------------------------------------------------------------------------
/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | padding: 0;
4 | height: 100%;
5 | font-family: "Open Sans", Arial, sans-serif;
6 | color: #232323;
7 | }
8 |
9 | html {
10 | font-size: 16px;
11 | }
12 |
13 | ::-webkit-scrollbar {
14 | width: 10px;
15 | height: 12px;
16 | }
17 |
18 | ::-webkit-scrollbar-track {
19 | /*-webkit-box-shadow: inset 0 0 1px rgba(0,0,0,0);
20 | */
21 | background-color: #F0F0F0;
22 | border-radius: 5px;
23 | }
24 |
25 | ::-webkit-scrollbar-thumb {
26 | border-radius: 10px;
27 | background-color: #F0F0F0;
28 | /* -webkit-box-shadow: inset 0 0 5px rgba(0,0,0,0.5);
29 | */
30 | }
31 | /* Hide scrollbar for IE until a specific height or width is reached (This is for the case in full app, when a note is open)*/
32 | /* Commenting out this line for now because it causes hthe landing page to not be scrollable in IE*/
33 | /* @media screen and (-ms-high-contrast: active), (-ms-high-contrast: none) {
34 | body {
35 | overflow: hidden;
36 | }
37 | } */
38 |
39 | /* This line is needed so that users are able to scroll in IE on the landing page */
40 | @media screen and (-ms-high-contrast: active), (-ms-high-contrast: none) and (max-height: 525px), (max-width: 1160px) {
41 | body {
42 | overflow: auto; } }
43 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import 'babel-polyfill';
2 | import 'es6-shim';
3 | import React from 'react';
4 | import { render } from 'react-dom';
5 | import { Provider } from 'react-redux';
6 | import { ConnectedRouter } from 'react-router-redux';
7 | import injectTapEventPlugin from 'react-tap-event-plugin';
8 |
9 | import store, { history } from './store/configureStore';
10 | import App from './containers/App';
11 | import './index.css';
12 |
13 | // Needed for onTouchTap
14 | // http://stackoverflow.com/a/34015469/988941
15 | injectTapEventPlugin();
16 |
17 | const target = document.querySelector('#root');
18 | const base = (global.CONFIG && global.CONFIG.basename) ? global.CONFIG.basename : '/';
19 | render(
20 |
21 |
22 |
25 |
26 | ,
27 | target
28 | );
29 |
--------------------------------------------------------------------------------
/src/lib/FHIRMapper.js:
--------------------------------------------------------------------------------
1 | import Lang from 'lodash';
2 |
3 | // map FHIR resourceType to SHR entryType
4 | const mapOptions = {
5 | "Patient": "http://standardhealthrecord.org/demographics/PersonOfRecord",
6 | "Condition": "http://standardhealthrecord.org/condition/Condition"
7 | }
8 |
9 |
10 | function mapToEntryTypes(entry){
11 | // TODO: Support returning multiple entry types from a single FHIR entry
12 | const entryType = mapOptions[entry.resource.resourceType];
13 | return Lang.isUndefined(entryType) ? [null] : [entryType];
14 | };
15 |
16 | export {
17 | mapToEntryTypes
18 | }
19 |
--------------------------------------------------------------------------------
/src/lib/cancer_lookup.jsx:
--------------------------------------------------------------------------------
1 | import * as codeableConceptUtils from '../model/CodeableConceptUtils';
2 |
3 | const cancerOptions = [
4 | {
5 | name: 'Invasive ductal carcinoma of breast',
6 | description: "Invasive ductal carcinoma of breast",
7 | code: "408643008",
8 | codeSystem: "http://snomed.info/sct"
9 | },
10 | {
11 | name: 'Gastrointestinal stromal tumor',
12 | description: "Gastrointestinal stromal tumor",
13 | code: "420120006",
14 | codeSystem: "http://snomed.info/sct"
15 | }];
16 |
17 | /*
18 | * Searches for value in cancerOptions list
19 | * Will return CodeableConcept object with empty strings if not found
20 | * If value found in list, function will return CodeableConcept with value, codeSystem, and displayText
21 | */
22 | export function getCancerCodeableConcept(possibleSpecificType) {
23 | return codeableConceptUtils.getCodeableConceptFromOptions(possibleSpecificType, cancerOptions);
24 | }
25 |
--------------------------------------------------------------------------------
/src/lib/cql-execution/CQLExecutionEngine.js:
--------------------------------------------------------------------------------
1 | import cql from 'cql-execution';
2 | import cqlfhir from 'cql-exec-fhir';
3 | import CodeService from './codeservice/CodeService';
4 | import valueset_db from './codeservice/vsac_cache/valueset-db.json';
5 |
6 |
7 | /*
8 | * returns CQL execution results when passed in a CQL file(JSON ELM) and set of patients
9 | * cqlLogic is a JSON ELM file, which was converted from a CQL file defining logic
10 | * psource is an array of patients each represented as a FHIR bundle
11 | */
12 | export function getCQLResults(cqlLogic, psource){
13 | // Set up library
14 | const lib = new cql.Library(cqlLogic);
15 |
16 | // Create Patient Source
17 | const patientSource = cqlfhir.PatientSource.FHIRv102();
18 |
19 | // Load patientsource with patients
20 | patientSource.loadBundles(psource);
21 |
22 | // Set up code service and load valuesets
23 | const codeService = new CodeService(valueset_db);
24 |
25 | const executor = new cql.Executor(lib, codeService);
26 | return executor.exec(patientSource);
27 | }
28 |
--------------------------------------------------------------------------------
/src/lib/cql-execution/codeservice/README.md:
--------------------------------------------------------------------------------
1 | valueSetDownloader will download all value sets specified in provided JSON ELM(generated from CQL) file and save it in `vsac_cache/valueset-db.json` to be used by CQLExecutionEngine.
2 | ```
3 | node valueSetDownloader.js [vsacUserName] [vsacPassword]
4 | ```
5 |
6 | Downloading value set definitions from VSAC requires a valid UMLS account. Alternately, the UMLS username and password can be provided via UMLS_USER_NAME and UMLS_PASSWORD environment variables.
7 |
8 |
--------------------------------------------------------------------------------
/src/lib/cql-execution/codeservice/valueSetDownloader.js:
--------------------------------------------------------------------------------
1 | const fs = require('fs');
2 | const path = require('path');
3 | const cql = require('cql-execution');
4 | const cqlfhir = require('cql-exec-fhir');
5 | const cqlvsac = require('cql-exec-vsac');
6 |
7 | if (process.argv.length < 3) {
8 | console.error('JSON ELM file not provided.');
9 | process.exit(1);
10 | }
11 |
12 | let vsacUser, vsacPass;
13 | if (process.argv.length===5) {
14 | [vsacUser, vsacPass] = process.argv.slice(3);
15 | }
16 |
17 | // Set up the library
18 | const elmFile = JSON.parse(fs.readFileSync(process.argv[2], 'utf8'));
19 |
20 | const library = new cql.Library(elmFile);
21 |
22 | // Extract the value sets from the ELM
23 | let valueSets = [];
24 | if (elmFile.library && elmFile.library.valueSets && elmFile.library.valueSets.def) {
25 | valueSets = elmFile.library.valueSets.def;
26 | }
27 |
28 | // Set up the code service, loading from the cache if it exists
29 | const codeService = new cqlvsac.CodeService(path.join(__dirname, 'vsac_cache'), true);
30 | // Ensure value sets, downloading any missing value sets
31 | codeService.ensureValueSets(valueSets, vsacUser, vsacPass)
32 | .then(() => {
33 | // Value sets are loaded
34 | console.log('Value sets downloaded!');
35 | })
36 | .catch((err) => {
37 | // There was an error downloading the value sets!
38 | console.error('Error downloading value sets', err);
39 | });
--------------------------------------------------------------------------------
/src/lib/cql-execution/example/cql/BreastCancer.cql:
--------------------------------------------------------------------------------
1 | // NOTE: This is a simplified example, designed only for the purpose of demonstrating how to
2 | // use the cql-execution, cql-exec-fhir, and cql-exec-vsac javascript modules. This CQL
3 | // is NOT clinically validated and should NOT be used in a clinical setting.
4 |
5 | library BreastCancer version '1.0.0'
6 | using FHIR version '1.0.2'
7 | include FHIRHelpers version '1.0.2' called FHIRHelpers
8 |
9 | // Value set and codes loosely borrowed from CMS 123v7
10 | codesystem "SNOMEDCT": 'http://snomed.info/sct'
11 | valueset "Breast Cancer": '2.16.840.1.113883.3.526.2.98'
12 |
13 | context Patient
14 |
15 | define InDemographic:
16 | AgeInYears() between 18 and 75
17 |
18 | define HasBreastCancer:
19 | exists(
20 | [Condition: "Breast Cancer"] C
21 | where C.verificationStatus.value = 'confirmed'
22 | )
23 |
24 | define MeetsInclusionCriteria:
25 | InDemographic
26 | and HasBreastCancer
27 |
--------------------------------------------------------------------------------
/src/lib/cql-execution/example/cql/age.cql:
--------------------------------------------------------------------------------
1 | library AgeAtMP version '1'
2 |
3 | using QUICK
4 |
5 | parameter MeasurementPeriod default Interval[DateTime(2013, 1, 1, 0, 0, 0, 0), DateTime(2014, 1, 1, 0, 0, 0, 0))
6 |
7 | context Patient
8 |
9 | define InDemographic:
10 | AgeInYearsAt(start of MeasurementPeriod) >= 2 and AgeInYearsAt(start of MeasurementPeriod) < 18
--------------------------------------------------------------------------------
/src/lib/cql-execution/example/cql/gender.cql:
--------------------------------------------------------------------------------
1 | library gender version '1'
2 |
3 | using FHIR version '1.0.2'
4 |
5 | include FHIRHelpers version '1.0.2' called FHIRHelpers
6 |
7 | context Patient
8 |
9 | define "Is Female":
10 | Patient.gender.value = 'female'
11 |
--------------------------------------------------------------------------------
/src/lib/cql-execution/example/patients/No_Foot_Exam.json:
--------------------------------------------------------------------------------
1 | {
2 | "resourceType": "Bundle",
3 | "id": "No_Foot_Exam_Bundle",
4 | "type": "collection",
5 | "entry": [
6 | {
7 | "resource": {
8 | "resourceType": "Patient",
9 | "id": "No_Foot_Exam",
10 | "gender": "female",
11 | "birthDate": "1973-04-28"
12 | }
13 | },
14 | {
15 | "resource": {
16 | "resourceType": "Condition",
17 | "id": "1-1",
18 | "clinicalStatus": "active",
19 | "verificationStatus": "confirmed",
20 | "code": {
21 | "coding": [
22 | {
23 | "system": "http://snomed.info/sct",
24 | "code": "44054006",
25 | "display": "Diabetes mellitus type 2 (disorder)"
26 | }
27 | ]
28 | },
29 | "subject": {
30 | "reference": "Patient/No_Foot_Exam"
31 | },
32 | "onsetDateTime": "2012-10-05"
33 | }
34 | }
35 | ]
36 | }
--------------------------------------------------------------------------------
/src/lib/react-minimap/index.js:
--------------------------------------------------------------------------------
1 | export default Minimap from './react-minimap'
2 | export {default as Child} from './components/Child'
--------------------------------------------------------------------------------
/src/lib/react-minimap/react-minimap.scss:
--------------------------------------------------------------------------------
1 | @import "../../styles/variables";
2 |
3 | .minimap-viewport {
4 | position: absolute;
5 | box-sizing: border-box;
6 | background-color: rgba(0, 0, 0, 0.4);
7 | z-index: 1;
8 | cursor: move;
9 | -webkit-transition: width .5s, height .5s; /* Safari */
10 | transition: width .5s, height .5s;
11 | }
12 |
13 | .minimap {
14 | float: right;
15 | position: fixed;
16 | right: 0;
17 | z-index: 1;
18 | margin: 10px;
19 | background-color: rgba(0, 0, 0, 0.29);
20 | border: 1px solid rgba(0, 0, 0, 0.17);
21 | }
22 |
23 | .minimap-container {
24 | overflow: scroll;
25 | width: 100%;
26 | height: 100%;
27 | }
28 |
29 | .minimap-children-wrapper {
30 | position: absolute;
31 | left: 0;
32 | }
33 |
34 | .minimap-children {
35 | background: #CCC;
36 | border: 1px solid black;
37 | box-sizing: border-box;
38 | }
39 |
40 | .edit-button {
41 | border: 1px solid $state !important;
42 | color: $interface-blue-text;
43 | margin-left: 4px;
44 | }
45 |
46 | .edit_visible {
47 | border: 1px solid rgba(2, 141, 234, .4) !important;
48 | color: $body-black !important;
49 | }
50 |
51 | .edit_invisible {
52 | border: none !important;
53 | background-color: $contrast-gray !important;
54 | color: $state !important;
55 | }
56 |
--------------------------------------------------------------------------------
/src/lib/slate-suggestions-dist/caret-position.js:
--------------------------------------------------------------------------------
1 | // Acquire from http://jsfiddle.net/gliheng/vbucs/12/
2 | function position($node, offsetx, offsety) {
3 | offsetx = offsetx || 0;
4 | offsety = offsety || 0;
5 |
6 | let nodeLeft = 0;
7 | let nodeTop = 0;
8 | if ($node) {
9 | nodeLeft = $node.offsetLeft;
10 | nodeTop = $node.offsetTop;
11 | }
12 |
13 | const pos = { left: 0, top: 0 };
14 |
15 | if (document.selection) {
16 | const range = document.selection.createRange();
17 | pos.left = range.offsetLeft + offsetx - nodeLeft;
18 | pos.top = range.offsetTop + offsety - nodeTop;
19 | } else if (window.getSelection) {
20 | const native = window.getSelection();
21 | const range = native.getRangeAt(0);
22 | const rect = range.getBoundingClientRect();
23 | pos.top = rect.top
24 | + offsety
25 | + nodeTop;
26 |
27 | pos.left = rect.left +
28 | offsetx +
29 | nodeLeft +
30 | rect.width / 2;
31 | }
32 | return pos;
33 | };
34 |
35 | export default position
36 |
--------------------------------------------------------------------------------
/src/lib/slate-suggestions-dist/constants.js:
--------------------------------------------------------------------------------
1 | export const UP_ARROW_KEY = 38
2 | export const DOWN_ARROW_KEY = 40
3 | export const ENTER_KEY = 13
4 | export const RESULT_SIZE = 5
5 |
--------------------------------------------------------------------------------
/src/lib/slate-suggestions-dist/current-word.js:
--------------------------------------------------------------------------------
1 | function getCurrentWord(text, index, trigger) {
2 | const startIndex = text.lastIndexOf(trigger, index + 1)
3 | return text.substring(startIndex, index + 1)
4 | }
5 |
6 | export default getCurrentWord
7 |
--------------------------------------------------------------------------------
/src/lib/slate-suggestions-dist/suggestion-item.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | class SuggestionItem extends React.Component {
4 |
5 | onClick = (e) => {
6 | this.props.closePortal()
7 |
8 | const { editor, suggestion, appendSuggestion } = this.props
9 |
10 | const state = appendSuggestion(suggestion)
11 |
12 | editor.onChange(state)
13 | }
14 |
15 | onMouseEnter = () => {
16 | this.props.setSelectedIndex(this.props.index)
17 | }
18 |
19 | render = () => {
20 | return (
21 |
26 | {this.props.suggestion.suggestion}
27 |
28 | );
29 | }
30 | }
31 |
32 | export default SuggestionItem
33 |
--------------------------------------------------------------------------------
/src/lib/slate/Readme.md:
--------------------------------------------------------------------------------
1 |
2 | This directory contains the core logic of Slate. It's separated further into a series of directories:
3 |
4 | - [**Components**](./components) — containing the React components Slate renders.
5 | - [**Constants**](./constants) — containing constants that are used in Slate's codebase.
6 | - [**Models**](./models) — containing the models that define Slate's internal data structure.
7 | - [**Plugins**](./plugins) — containing the plugins that ship with Slate by default.
8 | - [**Schemas**](./schemas) - containing the schemas that ship with Slate by default.
9 | - [**Serializers**](./serializers) — containing the serializers that ship with Slate by default.
10 | - [**Transforms**](./transforms) — containing the transforms that are used to alter a Slate document.
11 | - [**Utils**](./utils) — containing a few private convenience modules.
12 |
13 | Feel free to poke around in each of them to learn more!
14 |
--------------------------------------------------------------------------------
/src/lib/slate/constants/Readme.md:
--------------------------------------------------------------------------------
1 |
2 | This directory contains constants that are referenced elsewhere in Slate's codebase. They are kept here for consistency.
3 |
--------------------------------------------------------------------------------
/src/lib/slate/constants/is-dev.js:
--------------------------------------------------------------------------------
1 |
2 | /**
3 | * Is in development?
4 | *
5 | * @type {Boolean}
6 | */
7 |
8 | const IS_DEV = (
9 | typeof process !== 'undefined' &&
10 | process.env &&
11 | process.env.NODE_ENV !== 'production'
12 | )
13 |
14 | /**
15 | * Export.
16 | *
17 | * @type {Boolean}
18 | */
19 |
20 | export default IS_DEV
21 |
--------------------------------------------------------------------------------
/src/lib/slate/constants/types.js:
--------------------------------------------------------------------------------
1 |
2 | /**
3 | * Slate-specific data transfer types.
4 | *
5 | * @type {Object}
6 | */
7 |
8 | const TYPES = {
9 | FRAGMENT: 'application/x-slate-fragment',
10 | NODE: 'application/x-slate-node',
11 | }
12 |
13 | /**
14 | * Export.
15 | *
16 | * @type {Object}
17 | */
18 |
19 | export default TYPES
20 |
--------------------------------------------------------------------------------
/src/lib/slate/models/data.js:
--------------------------------------------------------------------------------
1 |
2 | import { Map } from 'immutable'
3 |
4 | /**
5 | * Data.
6 | *
7 | * This isn't an immutable record, it's just a thin wrapper around `Map` so that
8 | * we can allow for more convenient creation.
9 | *
10 | * @type {Object}
11 | */
12 |
13 | const Data = {
14 |
15 | /**
16 | * Create a new `Data` with `properties`.
17 | *
18 | * @param {Object} properties
19 | * @return {Data} data
20 | */
21 |
22 | create(properties = {}) {
23 | return Map.isMap(properties)
24 | ? properties
25 | : new Map(properties)
26 | }
27 |
28 | }
29 |
30 | /**
31 | * Export.
32 | *
33 | * @type {Object}
34 | */
35 |
36 | export default Data
37 |
--------------------------------------------------------------------------------
/src/lib/slate/models/range.js:
--------------------------------------------------------------------------------
1 |
2 | import Character from './character'
3 | import Mark from './mark'
4 | import { Record, Set } from 'immutable'
5 |
6 | /**
7 | * Default properties.
8 | *
9 | * @type {Object}
10 | */
11 |
12 | const DEFAULTS = {
13 | marks: new Set(),
14 | text: '',
15 | }
16 |
17 | /**
18 | * Range.
19 | *
20 | * @type {Range}
21 | */
22 |
23 | class Range extends new Record(DEFAULTS) {
24 |
25 | /**
26 | * Create a new `Range` with `properties`.
27 | *
28 | * @param {Object|Range} properties
29 | * @return {Range}
30 | */
31 |
32 | static create(properties = {}) {
33 | if (properties instanceof Range) return properties
34 | properties.text = properties.text
35 | properties.marks = Mark.createSet(properties.marks)
36 | return new Range(properties)
37 | }
38 |
39 | /**
40 | * Get the node's kind.
41 | *
42 | * @return {String}
43 | */
44 |
45 | get kind() {
46 | return 'range'
47 | }
48 |
49 | /**
50 | * Return range as a list of characters
51 | *
52 | * @return {List}
53 | */
54 |
55 | getCharacters() {
56 | const { marks } = this
57 |
58 | return Character.createList(this.text
59 | .split('')
60 | .map((char) => {
61 | return Character.create({
62 | text: char,
63 | marks
64 | })
65 | }))
66 | }
67 |
68 | }
69 |
70 | /**
71 | * Export.
72 | *
73 | * @type {Range}
74 | */
75 |
76 | export default Range
77 |
--------------------------------------------------------------------------------
/src/lib/slate/plugins/Readme.md:
--------------------------------------------------------------------------------
1 |
2 | This directory contains the only plugin that ships with Slate by default, which controls all of the "core" logic. For example, it handles splitting apart paragraphs when `enter` is pressed, or inserting plain text content from the clipboard on paste.
3 |
--------------------------------------------------------------------------------
/src/lib/slate/schemas/Readme.md:
--------------------------------------------------------------------------------
1 |
2 | This directory contains the core schema that ships with Slate by default, which controls all of the "core" document and selection validation logic. For example, it ensures that two adjacent text nodes are always joined, or that the top-level document only ever contains block nodes. It is not exposed by default, since it is only needed internally.
3 |
--------------------------------------------------------------------------------
/src/lib/slate/serializers/plain.js:
--------------------------------------------------------------------------------
1 |
2 | import Raw from '../serializers/raw'
3 |
4 | /**
5 | * Deserialize a plain text `string` to a state.
6 | *
7 | * @param {String} string
8 | * @param {Object} options
9 | * @property {Boolean} toRaw
10 | * @return {State}
11 | */
12 |
13 | function deserialize(string, options = {}) {
14 | const raw = {
15 | kind: 'state',
16 | document: {
17 | kind: 'document',
18 | nodes: string.split('\n').map((line) => {
19 | return {
20 | kind: 'block',
21 | type: 'line',
22 | nodes: [
23 | {
24 | kind: 'text',
25 | ranges: [
26 | {
27 | text: line,
28 | marks: [],
29 | }
30 | ]
31 | }
32 | ]
33 | }
34 | }),
35 | }
36 | }
37 |
38 | return options.toRaw ? raw : Raw.deserialize(raw)
39 | }
40 |
41 | /**
42 | * Serialize a `state` to plain text.
43 | *
44 | * @param {State} state
45 | * @return {String}
46 | */
47 |
48 | function serialize(state) {
49 | return state.document.nodes
50 | .map(block => block.text)
51 | .join('\n')
52 | }
53 |
54 | /**
55 | * Export.
56 | *
57 | * @type {Object}
58 | */
59 |
60 | export default {
61 | deserialize,
62 | serialize
63 | }
64 |
--------------------------------------------------------------------------------
/src/lib/slate/transforms/Readme.md:
--------------------------------------------------------------------------------
1 |
2 | This directory contains all of the transforms that ship with Slate by default. For example, transforms like `insertText` or `addMarkAtRange`.
3 |
--------------------------------------------------------------------------------
/src/lib/slate/transforms/call.js:
--------------------------------------------------------------------------------
1 |
2 | /**
3 | * Transforms.
4 | *
5 | * @type {Object}
6 | */
7 |
8 | const Transforms = {}
9 |
10 | /**
11 | * Call a `fn` as if it was a core transform. This is a convenience method to
12 | * make using non-core transforms easier to read and chain.
13 | *
14 | * @param {Transform} transform
15 | * @param {Function} fn
16 | * @param {Mixed} ...args
17 | */
18 |
19 | Transforms.call = (transform, fn, ...args) => {
20 | fn(transform, ...args)
21 | return
22 | }
23 |
24 | /**
25 | * Export.
26 | *
27 | * @type {Object}
28 | */
29 |
30 | export default Transforms
31 |
--------------------------------------------------------------------------------
/src/lib/slate/transforms/index.js:
--------------------------------------------------------------------------------
1 |
2 | import ApplyOperation from './apply-operation'
3 | import AtCurrentRange from './at-current-range'
4 | import AtRange from './at-range'
5 | import ByKey from './by-key'
6 | import Call from './call'
7 | import Normalize from './normalize'
8 | import OnHistory from './on-history'
9 | import OnSelection from './on-selection'
10 | import Operations from './operations'
11 |
12 | /**
13 | * Export.
14 | *
15 | * @type {Object}
16 | */
17 |
18 | export default {
19 | ...ApplyOperation,
20 | ...AtCurrentRange,
21 | ...AtRange,
22 | ...ByKey,
23 | ...Call,
24 | ...Normalize,
25 | ...OnHistory,
26 | ...OnSelection,
27 | ...Operations,
28 | }
29 |
--------------------------------------------------------------------------------
/src/lib/slate/utils/Readme.md:
--------------------------------------------------------------------------------
1 |
2 | This directory contains a series of utilities that Slate uses internally. They're pulled out here to re-use code and to enforce consistency. You'll have to read the source to see what they do, but it's all commented so don't worry!
3 |
--------------------------------------------------------------------------------
/src/lib/slate/utils/extend-selection.js:
--------------------------------------------------------------------------------
1 |
2 | /**
3 | * Extends the given selection to a given node and offset
4 | *
5 | * @param {Selection} selection Selection instance
6 | * @param {Element} el Node to extend to
7 | * @param {Number} offset Text offset to extend to
8 | * @returns {Selection} Mutated Selection instance
9 | */
10 |
11 | function extendSelection(selection, el, offset) {
12 | // Use native method when possible
13 | if (typeof selection.extend === 'function') return selection.extend(el, offset)
14 |
15 | // See https://gist.github.com/tyler-johnson/0a3e8818de3f115b2a2dc47468ac0099
16 | const range = document.createRange()
17 | const anchor = document.createRange()
18 | anchor.setStart(selection.anchorNode, selection.anchorOffset)
19 |
20 | const focus = document.createRange()
21 | focus.setStart(el, offset)
22 |
23 | const v = focus.compareBoundaryPoints(Range.START_TO_START, anchor)
24 | if (v >= 0) { // Focus is after anchor
25 | range.setStart(selection.anchorNode, selection.anchorOffset)
26 | range.setEnd(el, offset)
27 | } else { // Anchor is after focus
28 | range.setStart(el, offset)
29 | range.setEnd(selection.anchorNode, selection.anchorOffset)
30 | }
31 |
32 | selection.removeAllRanges()
33 | selection.addRange(range)
34 |
35 | return selection
36 | }
37 |
38 |
39 | /**
40 | * Export.
41 | *
42 | * @type {Function}
43 | */
44 |
45 | export default extendSelection
46 |
--------------------------------------------------------------------------------
/src/lib/slate/utils/find-closest-node.js:
--------------------------------------------------------------------------------
1 |
2 | /**
3 | * Find the closest ancestor of a DOM `element` that matches a given selector.
4 | *
5 | * @param {Element} node
6 | * @param {String} selector
7 | * @return {Element}
8 | */
9 |
10 | function findClosestNode(node, selector) {
11 | if (typeof node.closest === 'function') return node.closest(selector)
12 |
13 | // See https://developer.mozilla.org/en-US/docs/Web/API/Element/closest#Polyfill
14 | const matches = (node.document || node.ownerDocument).querySelectorAll(selector)
15 | let i
16 | let parentNode = node
17 | do {
18 | i = matches.length
19 | while (--i >= 0 && matches.item(i) !== parentNode);
20 | }
21 | while ((i < 0) && (parentNode = parentNode.parentElement))
22 |
23 | return parentNode
24 | }
25 |
26 | /**
27 | * Export.
28 | *
29 | * @type {Function}
30 | */
31 |
32 | export default findClosestNode
33 |
--------------------------------------------------------------------------------
/src/lib/slate/utils/find-deepest-node.js:
--------------------------------------------------------------------------------
1 |
2 | /**
3 | * Find the deepest descendant of a DOM `element`.
4 | *
5 | * @param {Element} node
6 | * @return {Element}
7 | */
8 |
9 | function findDeepestNode(element) {
10 | return element.firstChild
11 | ? findDeepestNode(element.firstChild)
12 | : element
13 | }
14 |
15 | /**
16 | * Export.
17 | *
18 | * @type {Function}
19 | */
20 |
21 | export default findDeepestNode
22 |
--------------------------------------------------------------------------------
/src/lib/slate/utils/find-dom-node.js:
--------------------------------------------------------------------------------
1 |
2 | /**
3 | * Find the DOM node for a `node`.
4 | *
5 | * @param {Node} node
6 | * @return {Element}
7 | */
8 |
9 | function findDOMNode(node) {
10 | const el = window.document.querySelector(`[data-key="${node.key}"]`)
11 |
12 | if (!el) {
13 | throw new Error(`Unable to find a DOM node for "${node.key}". This is
14 | often because of forgetting to add \`props.attributes\` to a component
15 | returned from \`renderNode\`.`)
16 | }
17 |
18 | return el
19 | }
20 |
21 | /**
22 | * Export.
23 | *
24 | * @type {Function}
25 | */
26 |
27 | export default findDOMNode
28 |
--------------------------------------------------------------------------------
/src/lib/slate/utils/generate-key.js:
--------------------------------------------------------------------------------
1 |
2 | /**
3 | * An auto-incrementing index for generating keys.
4 | *
5 | * @type {Number}
6 | */
7 |
8 | let n
9 |
10 | /**
11 | * The global key generating function.
12 | *
13 | * @type {Function}
14 | */
15 |
16 | let generate
17 |
18 | /**
19 | * Generate a key.
20 | *
21 | * @return {String}
22 | */
23 |
24 | function generateKey() {
25 | return generate()
26 | }
27 |
28 | /**
29 | * Set a different unique ID generating `function`.
30 | *
31 | * @param {Function} func
32 | */
33 |
34 | function setKeyGenerator(func) {
35 | generate = func
36 | }
37 |
38 | /**
39 | * Reset the key generating function to its initial state.
40 | */
41 |
42 | function resetKeyGenerator() {
43 | n = 0
44 | generate = () => `${n++}`
45 | }
46 |
47 | /**
48 | * Set the initial state.
49 | */
50 |
51 | resetKeyGenerator()
52 |
53 | /**
54 | * Export.
55 | *
56 | * @type {Object}
57 | */
58 |
59 | export {
60 | generateKey as default,
61 | setKeyGenerator,
62 | resetKeyGenerator
63 | }
64 |
--------------------------------------------------------------------------------
/src/lib/slate/utils/get-point.js:
--------------------------------------------------------------------------------
1 |
2 | import OffsetKey from './offset-key'
3 |
4 | /**
5 | * Get a point from a native selection's DOM `element` and `offset`.
6 | *
7 | * @param {Element} element
8 | * @param {Number} offset
9 | * @param {State} state
10 | * @param {Editor} editor
11 | * @return {Object}
12 | */
13 |
14 | function getPoint(element, offset, state, editor) {
15 | const { document } = state
16 | const schema = editor.getSchema()
17 |
18 | // If we can't find an offset key, we can't get a point.
19 | const offsetKey = OffsetKey.findKey(element, offset)
20 | if (!offsetKey) return null
21 |
22 | // COMPAT: If someone is clicking from one Slate editor into another, the
23 | // select event fires two, once for the old editor's `element` first, and
24 | // then afterwards for the correct `element`. (2017/03/03)
25 | const { key } = offsetKey
26 | const node = document.getDescendant(key)
27 | if (!node) return null
28 |
29 | const decorators = document.getDescendantDecorators(key, schema)
30 | const ranges = node.getRanges(decorators)
31 | const point = OffsetKey.findPoint(offsetKey, ranges)
32 | return point
33 | }
34 |
35 | /**
36 | * Export.
37 | *
38 | * @type {Function}
39 | */
40 |
41 | export default getPoint
42 |
--------------------------------------------------------------------------------
/src/lib/slate/utils/is-in-range.js:
--------------------------------------------------------------------------------
1 |
2 | /**
3 | * Check if an `index` of a `text` node is in a `range`.
4 | *
5 | * @param {Number} index
6 | * @param {Text} text
7 | * @param {Selection} range
8 | * @return {Boolean}
9 | */
10 |
11 | function isInRange(index, text, range) {
12 | const { startKey, startOffset, endKey, endOffset } = range
13 |
14 | if (text.key == startKey && text.key == endKey) {
15 | return startOffset <= index && index < endOffset
16 | } else if (text.key == startKey) {
17 | return startOffset <= index
18 | } else if (text.key == endKey) {
19 | return index < endOffset
20 | } else {
21 | return true
22 | }
23 | }
24 |
25 | /**
26 | * Export.
27 | *
28 | * @type {Function}
29 | */
30 |
31 | export default isInRange
32 |
--------------------------------------------------------------------------------
/src/lib/slate/utils/is-react-component.js:
--------------------------------------------------------------------------------
1 |
2 | /**
3 | * Check if an `object` is a React component.
4 | *
5 | * @param {Object} object
6 | * @return {Boolean}
7 | */
8 |
9 | function isReactComponent(object) {
10 | return (
11 | object &&
12 | object.prototype &&
13 | object.prototype.isReactComponent
14 | )
15 | }
16 |
17 | /**
18 | * Export.
19 | *
20 | * @type {Function}
21 | */
22 |
23 | export default isReactComponent
24 |
--------------------------------------------------------------------------------
/src/lib/slate/utils/noop.js:
--------------------------------------------------------------------------------
1 |
2 | /**
3 | * Noop.
4 | *
5 | * @return {Void}
6 | */
7 |
8 | function noop() {}
9 |
10 | /**
11 | * Export.
12 | *
13 | * @type {Function}
14 | */
15 |
16 | export default noop
17 |
--------------------------------------------------------------------------------
/src/lib/slate/utils/warn.js:
--------------------------------------------------------------------------------
1 |
2 | import IS_DEV from '../constants/is-dev'
3 |
4 | /**
5 | * Log a development warning.
6 | *
7 | * @param {String} message
8 | * @param {Any} ...args
9 | */
10 |
11 | function warn(message, ...args) {
12 | if (!IS_DEV) {
13 | return
14 | }
15 |
16 | if (typeof console !== 'undefined') {
17 | console.warn(`Warning: ${message}`, ...args) // eslint-disable-line no-console
18 | }
19 | }
20 |
21 | /**
22 | * Export.
23 | *
24 | * @type {Function}
25 | */
26 |
27 | export default warn
28 |
--------------------------------------------------------------------------------
/src/mcode-pilot/components/SimilarPatientsSelector/SimilarPatientsSelector.scss:
--------------------------------------------------------------------------------
1 | @import '../../../styles/variables';
2 |
3 | .similar-patients-selector {
4 | &__select-buttons {
5 | button {
6 | background-color: $background;
7 | border: 0;
8 | cursor: pointer;
9 | color: $interface-blue;
10 | font-size: 0.9em;
11 | font-weight: 600;
12 |
13 | &:hover {
14 | color: darken($interface-blue, 10%);
15 | }
16 |
17 | &:focus {
18 | outline: none;
19 | background-color: $interface-blue;
20 | color: #fff;
21 | border-radius: 5px;
22 | }
23 | }
24 | }
25 |
26 | .selection-option {
27 | display: flex;
28 | flex-direction: column;
29 | margin: 20px 0;
30 | }
31 |
32 | &__options {
33 | display: flex;
34 | justify-content: flex-start;
35 | flex-wrap: wrap;
36 |
37 | .options-checkbox-list {
38 | flex: 0 1 calc(33% - 1em);
39 | }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/mcode-pilot/components/TreatmentOptionsOutcomesTable/CompareSelectedIcon.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 |
4 | const CompareSelectedIcon = ({ onClick }) => {
5 | return (
6 |
7 |
20 |
21 | );
22 | };
23 |
24 | CompareSelectedIcon.propTypes = {
25 | onClick: PropTypes.func
26 | };
27 |
28 | export default CompareSelectedIcon;
29 |
--------------------------------------------------------------------------------
/src/mcode-pilot/components/TreatmentOptionsOutcomesTable/PersonIcon.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 |
4 | const PersonIcon = (props) => {
5 | return (
6 |
12 | );
13 | };
14 |
15 | PersonIcon.propTypes = {
16 | onClick: PropTypes.func
17 | };
18 |
19 | export default PersonIcon;
20 |
--------------------------------------------------------------------------------
/src/mcode-pilot/components/TreatmentOptionsSelector/TreatmentOptionsSelector.scss:
--------------------------------------------------------------------------------
1 | @import '../../../styles/variables';
2 |
3 | div.treatment-options-selector {
4 | box-shadow: none;
5 | margin: 10px 0;
6 |
7 | &::before {
8 | background-color: transparent;
9 | }
10 |
11 | &__header {
12 | cursor: pointer;
13 |
14 | &-icon,
15 | &-title,
16 | &-subtitle {
17 | display: inline-block;
18 | }
19 |
20 | &-icon {
21 | font-size: 1.2em;
22 | color: $state;
23 | }
24 |
25 | &-title {
26 | font-weight: 600;
27 | font-size: 0.9em;
28 | }
29 |
30 | &-subtitle {
31 | font-size: 0.8em;
32 | margin-left: 15px;
33 | }
34 |
35 | &-subheader {
36 | font-size: 0.8em;
37 | margin-left: 35px;
38 | }
39 |
40 | .bold { font-weight: bold; }
41 | .italic { font-style: italic; }
42 |
43 | .muted {
44 | color: #888;
45 | margin-left: 10px;
46 | }
47 | }
48 |
49 | &__content {
50 | margin: 10px 25px;
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/src/mcode-pilot/components/TreatmentsPopover/TreatmentsPopover.scss:
--------------------------------------------------------------------------------
1 | @import '../../../styles/variables';
2 |
3 | .treatments-popper {
4 | position: absolute;
5 | top: 0;
6 | left: 0;
7 | min-width: 250px;
8 | z-index: 1;
9 | margin-bottom: 1rem;
10 |
11 | .form-control {
12 | display: flex;
13 | }
14 |
15 | .popover {
16 | padding: 10px 15px;
17 | font-size: 0.9em;
18 | }
19 |
20 | .popover-title {
21 | font-weight: bold;
22 | margin-bottom: 0.5rem;
23 | color: inherit;
24 | font-size: 0.9em;
25 | }
26 |
27 | .popover-checklist {
28 | margin-left: 20px;
29 |
30 | .form-control {
31 | white-space: nowrap;
32 |
33 | .checkbox {
34 | height: 22px;
35 | color: $shr-context-dark;
36 | margin-right: -5px;
37 | }
38 | }
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/mcode-pilot/containers/TreatmentOptionsVisualizer/TreatmentOptionsVisualizer.scss:
--------------------------------------------------------------------------------
1 | div.treatment-options-visualizer {
2 | max-width: 1200px;
3 |
4 | &__info {
5 | font-size: 0.8em;
6 | margin: 5px 25px;
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/src/mcode-pilot/services/outcomes/IOutcomesService.js:
--------------------------------------------------------------------------------
1 | /*
2 | Interface spec for OutcomesService implementations.
3 | Initial version of the spec is dervived from the functionality currently in
4 | use by the TreatmentOptionsOutcomes container and supporting views.
5 | */
6 | export default class IOutcomesService {
7 |
8 | /*
9 | Function to process similar patient outcomes.
10 | @param {Object} fOptions -- An object containing all information about the filters.
11 | @return {Object} returns the calculated outcome data
12 | similarPatientTreatments -- treatments that matched the similar patients [{key: String, name: String}]
13 | similarPatientTreatmentsData -- the outcomes for the similar patient treatments
14 | totalPatients -- total number of patients in the
15 | totalSimilarPatients -- total number of patients that match the cohort filtering criteria
16 | */
17 | processSimilarPatientOutcomes(fOptions) {
18 | throw new Error("processSimilarPatientOutcomes not implemented by " + this.constructor.name);
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/mcode-pilot/services/outcomes/StaticOutcomesService.js:
--------------------------------------------------------------------------------
1 | import { filterTreatmentData } from '../../utils/filterTreatmentData';
2 | import IOutcomesService from './IOutcomesService';
3 |
4 | export default class StaticOutcomesService extends IOutcomesService {
5 | constructor(config) {
6 | super();
7 | this.timescale = config.timescale;
8 | this.filters = config.filters;
9 | this.showSideEffects = config.showSideEffects;
10 | }
11 |
12 | async processSimilarPatientOutcomes(fOptions) {
13 | return filterTreatmentData(fOptions, this.timescale);
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/mcode-pilot/utils/numberWithCommas.js:
--------------------------------------------------------------------------------
1 | export default function numberWithCommas(x) {
2 | return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
3 | }
4 |
--------------------------------------------------------------------------------
/src/mcode-pilot/utils/sideEffects.js:
--------------------------------------------------------------------------------
1 | export default function getSideEffects(similarPatientTreatmentsData) {
2 | const allTreatmentData = [...similarPatientTreatmentsData];
3 | const allEffects = allTreatmentData.map(effect => Object.keys(effect.sideEffects.effects));
4 |
5 | return allEffects.reduce((p, c) => {
6 | // concat the arrays, filter out duplicate entries
7 | return p.concat(c.filter(cx => p.indexOf(cx) < 0));
8 | }, []).sort(function (a, b) {
9 | return a.toLowerCase().localeCompare(b.toLowerCase());
10 | });
11 | };
12 |
--------------------------------------------------------------------------------
/src/model/FluxObjectFactory.js:
--------------------------------------------------------------------------------
1 | import { getNamespaceAndName, uuid } from './json-helper';
2 | import ObjectFactory from './ObjectFactory';
3 | import FluxOncocoreObjectFactory from './fluxWrappers/onco/core/FluxOncocoreObjectFactory';
4 | import FluxCoreObjectFactory from './fluxWrappers/core/FluxCoreObjectFactory';
5 |
6 | /*
7 | * FluxObjectFactory class returns instances of Flux model classes
8 | * Default case will return SHR model classes if no Flux wrapper class is found
9 | */
10 | export default class FluxObjectFactory {
11 | static createInstance(json, type, patientRecord) {
12 | const { namespace } = getNamespaceAndName(json, type);
13 | switch (namespace) {
14 | case 'shr.core': return FluxCoreObjectFactory.createInstance(json, type, patientRecord);
15 | case 'onco.core': return FluxOncocoreObjectFactory.createInstance(json, type, patientRecord);
16 | default: return ObjectFactory.createInstance(json, type, patientRecord);
17 | }
18 | }
19 |
20 | static createInstanceFromFHIR(shrType, fhir, fhirType, shrId=uuid(), allEntries=[], mappedResources={}, referencesOut=[], asExtension=false) {
21 | return ObjectFactory.createInstanceFromFHIR(shrType, fhir, fhirType, shrId, allEntries, mappedResources, referencesOut, asExtension);
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/model/fluxExtensions/EntryFix.js:
--------------------------------------------------------------------------------
1 | import Entry from '../shr/base/Entry';
2 |
3 | /**
4 | * This fix class adds SourceClinicalNote fields to the shr.base.Entry classes.
5 | */
6 | export default class EntryFix extends Entry {
7 | /**
8 | * Get the SourceClinicalNote.
9 | * @returns {SourceClinicalNote} The shr.base.SourceClinicalNote
10 | */
11 | get sourceClinicalNote() {
12 | return this._sourceClinicalNote;
13 | }
14 |
15 | /**
16 | * Set the SourceClinicalNote.
17 | * @param {SourceClinicalNote} sourceClinicalNote - The shr.base.SourceClinicalNote
18 | */
19 | set sourceClinicalNote(sourceClinicalNote) {
20 | this._sourceClinicalNote = sourceClinicalNote;
21 | }
22 |
23 | /**
24 | * Serializes an instance of the Entry class to a JSON object.
25 | * The JSON is expected to be valid against the Entry JSON schema, but no validation checks are performed.
26 | * @returns {object} a JSON object populated with the data from the element
27 | */
28 | toJSON() {
29 | const inst = super.toJSON()
30 | if (this.sourceClinicalNote != null) {
31 | inst['SourceClinicalNote'] = typeof this.sourceClinicalNote.toJSON === 'function' ? this.sourceClinicalNote.toJSON() : this.sourceClinicalNote;
32 | }
33 | return inst;
34 | }
35 | }
--------------------------------------------------------------------------------
/src/model/fluxExtensions/ExpectedPerformanceTimeFix.js:
--------------------------------------------------------------------------------
1 | import ExpectedPerformanceTime from "../shr/core/ExpectedPerformanceTime";
2 | import { FHIRHelper, uuid } from '../json-helper';
3 |
4 | export default class ExpectedPerformanceTimeFix extends ExpectedPerformanceTime {
5 | static fromFHIR(fhir, fhirType, shrId=uuid(), allEntries=[], mappedResources={}, referencesOut=[], asExtension=false) {
6 | const inst = new ExpectedPerformanceTimeFix();
7 | if (!asExtension && fhir != null) {
8 | // reminder: ExpectedPerformanceTime.value can be: (dateTime|TimePeriod|Timing)
9 |
10 | switch(fhirType) {
11 | case 'dateTime':
12 | inst.value = fhir;
13 | break;
14 |
15 | case 'Timing':
16 | inst.value = FHIRHelper.createInstanceFromFHIR('shr.core.Timing', fhir, 'Timing', shrId, allEntries, mappedResources, referencesOut);
17 | break;
18 |
19 | // the one instance here where the FHIR type != the SHR type name....
20 | case 'Period':
21 | inst.value = FHIRHelper.createInstanceFromFHIR('shr.core.TimePeriod', fhir, 'Period', shrId, allEntries, mappedResources, referencesOut);
22 | break;
23 |
24 | default:
25 | // do nothing
26 | }
27 | }
28 | return inst;
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/model/fluxExtensions/MedicationRequestFix.js:
--------------------------------------------------------------------------------
1 | import MedicationRequest from '../shr/core/MedicationRequest';
2 | import { FHIRHelper, uuid } from '../json-helper';
3 |
4 | /**
5 | * This fix class adds a reasonReference mapping to the shr.core.MedicationRequest class fromFHIR method.
6 | */
7 | export default class MedicationRequestFix extends MedicationRequest {
8 |
9 | static fromFHIR(fhir, fhirType, shrId=uuid(), allEntries=[], mappedResources={}, referencesOut=[], asExtension=false) {
10 | const inst = super.fromFHIR(fhir, fhirType, shrId, allEntries, mappedResources, referencesOut, asExtension);
11 |
12 | // reasonReference is in the spec and ES6 class but not mapped in fromFHIR for some reason. need to review
13 | if (fhir['reasonReference'] != null) {
14 | inst.reasonReference = inst.reasonReference || [];
15 | const inst_reason = FHIRHelper.createInstanceFromFHIR('shr.core.ReasonReference', fhir['reasonReference'], 'Reference', shrId, allEntries, mappedResources, referencesOut, false);
16 | inst.reasonReference.push(inst_reason);
17 | }
18 |
19 | return inst;
20 | }
21 | }
--------------------------------------------------------------------------------
/src/model/fluxExtensions/PrimaryCancerConditionFix.js:
--------------------------------------------------------------------------------
1 | import PrimaryCancerCondition from '../onco/core/PrimaryCancerCondition';
2 | import { FHIRHelper, uuid } from '../json-helper';
3 |
4 | /**
5 | * This fix class replaces the original onco.core.PrimaryCancerCondition.fromFHIR function
6 | * with a version that handles the extension.valueReference correctly.
7 | *
8 | * See also: https://github.com/standardhealth/shr-es6-export/issues/57
9 | */
10 | export default class PrimaryCancerConditionFix extends PrimaryCancerCondition {
11 |
12 | static fromFHIR(fhir, fhirType, shrId=uuid(), allEntries=[], mappedResources={}, referencesOut=[], asExtension=false) {
13 | if (asExtension && fhir['valueReference']) {
14 |
15 | const entryId = fhir['valueReference']['reference'];
16 | if (!mappedResources[entryId]) {
17 | const referencedEntry = allEntries.find(e => e.fullUrl === entryId);
18 | if (referencedEntry) {
19 | mappedResources[entryId] = FHIRHelper.createInstanceFromFHIR('onco.core.PrimaryCancerCondition', referencedEntry['resource'], 'undefined', shrId, allEntries, mappedResources, referencesOut);
20 | }
21 | }
22 | return mappedResources[entryId];
23 |
24 | } else {
25 | return super.fromFHIR(fhir, fhirType, shrId, allEntries, mappedResources, referencesOut, asExtension);
26 | }
27 | }
28 | }
--------------------------------------------------------------------------------
/src/model/fluxExtensions/ReasonReferenceFix.js:
--------------------------------------------------------------------------------
1 | import ReasonReference from '../shr/core/ReasonReference';
2 | import { FHIRHelper, uuid } from '../json-helper';
3 |
4 | /**
5 | * This fix class replaces the original shr.core.ReasonReference.fromFHIR function
6 | * with a version that sets the value correctly as a reference instead of a full object.
7 | */
8 | export default class ReasonReferenceFix extends ReasonReference {
9 |
10 | static fromFHIR(fhir, fhirType, shrId=uuid(), allEntries=[], mappedResources={}, referencesOut=[], asExtension=false) {
11 | if (!asExtension && fhir['reference']) {
12 | const inst = new ReasonReferenceFix();
13 |
14 | const entryId = fhir['reference'];
15 | if (!mappedResources[entryId]) {
16 | const referencedEntry = allEntries.find(e => e.fullUrl === entryId);
17 | if (referencedEntry) {
18 | mappedResources[entryId] = FHIRHelper.createInstanceFromFHIR(null, referencedEntry['resource'], 'undefined', shrId, allEntries, mappedResources, referencesOut);
19 | }
20 | }
21 | if (mappedResources[entryId]) {
22 | inst.value = FHIRHelper.createReference(mappedResources[entryId], referencesOut);
23 | }
24 | // no else in this case since we don't know which of the 2 possible types it is
25 |
26 | return inst;
27 | } else {
28 | return super.fromFHIR(fhir, fhirType, shrId, allEntries, mappedResources, referencesOut, asExtension);
29 | }
30 | }
31 | }
--------------------------------------------------------------------------------
/src/model/fluxWrappers/base/FluxEntry.js:
--------------------------------------------------------------------------------
1 | import ClassRegistry from '../../ClassRegistry';
2 |
3 | class FluxEntry {
4 | get sourceClinicalNoteReference() {
5 | return this._entry.entryInfo.sourceClinicalNote;
6 | }
7 |
8 | get entryInfo() {
9 | return this._entry.entryInfo;
10 | }
11 |
12 | set entryInfo(entryInfo) {
13 | this._entry.entryInfo = entryInfo;
14 | }
15 |
16 | toJSON() {
17 | return this._entry.toJSON();
18 | }
19 |
20 | /**
21 | * Extract a human-readable string from a code.
22 | *
23 | * @param {Coding} coding
24 | * @returns {string} the display text if available, otherwise the code.
25 | * @private
26 | */
27 | _displayTextOrCode(coding) {
28 | if (!coding) return null;
29 | if (coding.displayText) return coding.displayText.value;
30 | if (coding.codeValue) return coding.codeValue.value;
31 | return null;
32 | }
33 |
34 | /**
35 | * Helper function to construct an entry with the given URI as the entry type value.
36 | */
37 | _constructEntry(uri) {
38 | const Entry = ClassRegistry.get('shr.base', 'Entry');
39 | const EntryType = ClassRegistry.get('shr.base', 'EntryType');
40 |
41 | let entry = new Entry();
42 | entry.entryType = new EntryType();
43 | entry.entryType.uri = uri;
44 | return entry;
45 | }
46 | }
47 |
48 | export default FluxEntry;
49 |
--------------------------------------------------------------------------------
/src/model/fluxWrappers/core/FluxBloodPressure.js:
--------------------------------------------------------------------------------
1 | import BloodPressure from "../../shr/core/BloodPressure";
2 |
3 | class FluxBloodPressure {
4 | constructor(json) {
5 | this._bloodPressure = BloodPressure.fromJSON(json);
6 | }
7 |
8 | get code() {
9 | return this._bloodPressure.code.value.coding[0].codeValue.code;
10 | }
11 |
12 | get dataValue() {
13 | return this._bloodPressure.dataValue;
14 | }
15 |
16 | get entryInfo() {
17 | return this._bloodPressure.entryInfo;
18 | }
19 |
20 | get relevantTime() {
21 | return this._bloodPressure.relevantTime.value;
22 | }
23 |
24 | get value() {
25 | return this._bloodPressure.components.map(r => r.dataValue.value.number.decimal).join('/');
26 | }
27 |
28 | toJSON() {
29 | return this._bloodPressure.toJSON();
30 | }
31 | }
32 |
33 | export default FluxBloodPressure;
34 |
--------------------------------------------------------------------------------
/src/model/fluxWrappers/core/FluxBodyTemperature.js:
--------------------------------------------------------------------------------
1 | import BodyTemperature from '../../shr/core/BodyTemperature';
2 |
3 | class FluxBodyTemperature {
4 | constructor(json) {
5 | this._bodyTemperature = BodyTemperature.fromJSON(json);
6 | }
7 |
8 | get code() {
9 | return this._bodyTemperature.code.value.coding[0].codeValue.code;
10 | }
11 |
12 | get entryInfo() {
13 | return this._bodyTemperature.entryInfo;
14 | }
15 |
16 | get relevantTime() {
17 | return this._bodyTemperature.relevantTime.value;
18 | }
19 |
20 | get units() {
21 | return this._bodyTemperature.dataValue.value.units.coding.codeValue.value;
22 | }
23 |
24 | get value() {
25 | return this._bodyTemperature.dataValue.value.number.decimal;
26 | }
27 |
28 | toJSON() {
29 | return this._bodyTemperature.toJSON();
30 | }
31 | }
32 |
33 | export default FluxBodyTemperature;
34 |
--------------------------------------------------------------------------------
/src/model/fluxWrappers/core/FluxBodyWeight.js:
--------------------------------------------------------------------------------
1 | import BodyWeight from '../../shr/core/BodyWeight';
2 |
3 | class FluxBodyWeight {
4 | constructor(json) {
5 | this._bodyWeight = BodyWeight.fromJSON(json);
6 | }
7 |
8 | get code() {
9 | return this._bodyWeight.code.value.coding[0].codeValue.code;
10 | }
11 |
12 | get entryInfo() {
13 | return this._bodyWeight.entryInfo;
14 | }
15 |
16 | get relevantTime() {
17 | return this._bodyWeight.relevantTime.value;
18 | }
19 |
20 | get units() {
21 | return this._bodyWeight.dataValue.value.units.coding.codeValue.value;
22 | }
23 |
24 | get value() {
25 | return this._bodyWeight.dataValue.value.number.decimal;
26 | }
27 |
28 | toJSON() {
29 | return this._bodyWeight.toJSON();
30 | }
31 | }
32 |
33 | export default FluxBodyWeight;
34 |
--------------------------------------------------------------------------------
/src/model/fluxWrappers/core/FluxDiagnosticReport.js:
--------------------------------------------------------------------------------
1 | import DiagnosticReport from '../../shr/core/DiagnosticReport';
2 | import FluxEntry from '../base/FluxEntry';
3 |
4 | class FluxDiagnosticReport extends FluxEntry {
5 | constructor(json, patientRecord) {
6 | super();
7 |
8 | this._diagnosticReport = this._entry = DiagnosticReport.fromJSON(json);
9 | this._patientRecord = patientRecord;
10 | }
11 |
12 | get relevantTime() {
13 | return this._diagnosticReport.relevantTime.value;
14 | }
15 |
16 | get value() {
17 | return this._patientRecord.getEntryFromReference(this._diagnosticReport.media);
18 | }
19 |
20 | get author() {
21 | if (this._diagnosticReport.participation && this._diagnosticReport.participation.participant && this._diagnosticReport.participation.participant.value) {
22 | const author = this._patientRecord.getEntryFromReference(this._diagnosticReport.participation.participant.value);
23 |
24 | if (author
25 | && author.person
26 | && author.person.humanName
27 | && author.person.humanName[0]
28 | && author.person.humanName[0].nameAsText) {
29 | return author.person.humanName[0].nameAsText.value;
30 | }
31 | }
32 |
33 | return null;
34 | }
35 | }
36 | export default FluxDiagnosticReport;
37 |
--------------------------------------------------------------------------------
/src/model/fluxWrappers/core/FluxECOGPerformanceStatus.js:
--------------------------------------------------------------------------------
1 | import FluxEntry from '../base/FluxEntry';
2 | import ECOGPerformanceStatus from '../../shr/core/ECOGPerformanceStatus';
3 |
4 | class FluxECOGPerformanceStatus extends FluxEntry {
5 | constructor(json, type, patientRecord) {
6 | super();
7 | this._patientRecord = patientRecord;
8 | this._entry = ECOGPerformanceStatus.fromJSON(json);
9 | }
10 |
11 | get entryInfo() {
12 | return this._entry.entryInfo;
13 | }
14 |
15 | }
16 |
17 | export default FluxECOGPerformanceStatus;
18 |
--------------------------------------------------------------------------------
/src/model/fluxWrappers/core/FluxEncounter.js:
--------------------------------------------------------------------------------
1 | import Encounter from '../../shr/core/Encounter';
2 |
3 | class FluxEncounter {
4 | constructor(json) {
5 | this._encounter = Encounter.fromJSON(json);
6 | }
7 |
8 | get entryInfo() {
9 | return this._encounter.entryInfo;
10 | }
11 |
12 | get timePeriod() {
13 | return this._encounter.timePeriod;
14 | }
15 |
16 | toJSON() {
17 | return this._encounter.toJSON();
18 | }
19 | }
20 |
21 | export default FluxEncounter;
--------------------------------------------------------------------------------
/src/model/fluxWrappers/core/FluxHeartRate.js:
--------------------------------------------------------------------------------
1 | import HeartRate from '../../shr/core/HeartRate';
2 |
3 | class FluxHeartRate {
4 | constructor(json) {
5 | this._heartRate = HeartRate.fromJSON(json);
6 | }
7 |
8 | get code() {
9 | return this._heartRate.code.value.coding[0].codeValue.code;
10 | }
11 |
12 | get entryInfo() {
13 | return this._heartRate.entryInfo;
14 | }
15 |
16 | get relevantTime() {
17 | return this._heartRate.relevantTime.value;
18 | }
19 |
20 | get units() {
21 | return this._heartRate.dataValue.value.units.coding.codeValue.value;
22 | }
23 |
24 | get value() {
25 | return this._heartRate.dataValue.value.number.decimal;
26 | }
27 |
28 | toJSON() {
29 | return this._heartRate.toJSON();
30 | }
31 | }
32 |
33 | export default FluxHeartRate;
34 |
--------------------------------------------------------------------------------
/src/model/fluxWrappers/core/FluxKarnofskyPerformanceStatus.js:
--------------------------------------------------------------------------------
1 | import FluxEntry from '../base/FluxEntry';
2 | import KarnofskyPerformanceStatus from '../../shr/core/KarnofskyPerformanceStatus';
3 |
4 | class FluxKarnofskyPerformanceStatus extends FluxEntry {
5 | constructor(json, type, patientRecord) {
6 | super();
7 | this._patientRecord = patientRecord;
8 | this._entry = KarnofskyPerformanceStatus.fromJSON(json);
9 | }
10 |
11 | get entryInfo() {
12 | return this._entry.entryInfo;
13 | }
14 |
15 | }
16 |
17 | export default FluxKarnofskyPerformanceStatus;
18 |
--------------------------------------------------------------------------------
/src/model/fluxWrappers/core/FluxQuestionnaireResponse.js:
--------------------------------------------------------------------------------
1 | import QuestionnaireResponse from "../../shr/core/QuestionnaireResponse";
2 | import FluxQuestionnaireResponseItem from "./FluxQuestionnaireResponseItem";
3 |
4 | class FluxQuestionnaireResponse {
5 | constructor(json) {
6 | this._questionnaireResponse = QuestionnaireResponse.fromJSON(json);
7 | this._questionnaireResponseItem = this._questionnaireResponse.questionnaireResponseItem.map(q => new FluxQuestionnaireResponseItem(q));
8 | }
9 |
10 | get entryInfo() {
11 | return this._questionnaireResponse.entryInfo;
12 | }
13 |
14 | get members() {
15 | return this._questionnaireResponseItem;
16 | }
17 |
18 | get statementDateTime() {
19 | return this._questionnaireResponse.statementDateTime.value;
20 | }
21 | }
22 |
23 | export default FluxQuestionnaireResponse;
24 |
--------------------------------------------------------------------------------
/src/model/fluxWrappers/core/FluxQuestionnaireResponseItem.js:
--------------------------------------------------------------------------------
1 | class FluxQuestionnaireResponseItem {
2 | constructor(questionnaireResponseItem) {
3 | this._questionnaireResponseItem = questionnaireResponseItem;
4 | }
5 |
6 | get questionText() {
7 | return this._questionnaireResponseItem.question.value;
8 | }
9 |
10 | get value() {
11 | // TODO: We are assuming Answer array only has one element
12 | return this._questionnaireResponseItem.answer[0].answerValue.value;
13 | }
14 | }
15 |
16 | export default FluxQuestionnaireResponseItem;
17 |
--------------------------------------------------------------------------------
/src/model/fluxWrappers/onco/core/FluxEvidenceType.js:
--------------------------------------------------------------------------------
1 | import EvidenceType from '../../../onco/core/EvidenceType';
2 |
3 | export default class FluxEvidenceType {
4 | constructor(json) {
5 | this._evidenceType = EvidenceType.fromJSON(json);
6 | }
7 |
8 | get value() {
9 | return this._evidenceType.value.coding[0].displayText.value
10 | }
11 |
12 | set value(value) {
13 | this._evidenceType.value = value;
14 | }
15 |
16 | toJSON() {
17 | return this._evidenceType.toJSON();
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/model/fluxWrappers/onco/core/FluxGenomicsReport.js:
--------------------------------------------------------------------------------
1 | import GenomicsReport from "../../../onco/core/GenomicsReport";
2 | import FluxEntry from "../../base/FluxEntry";
3 |
4 | class FluxGenomicsReport extends FluxEntry {
5 | constructor(json, patientRecord) {
6 | super();
7 |
8 | this._genomicsReport = this._entry = GenomicsReport.fromJSON(json);
9 | this._patientRecord = patientRecord;
10 | }
11 |
12 | get relevantTime() {
13 | return this._genomicsReport.relevantTime.value;
14 | }
15 |
16 | get members() {
17 | return this._genomicsReport.observation.map(o => this._patientRecord.getEntryFromReference(o));
18 | }
19 | }
20 |
21 | export default FluxGenomicsReport;
22 |
--------------------------------------------------------------------------------
/src/model/fluxWrappers/onco/core/FluxTNMClinicalDistantMetastasesCategory.js:
--------------------------------------------------------------------------------
1 | import TNMClinicalDistantMetastasesCategory from '../../../onco/core/TNMClinicalDistantMetastasesCategory';
2 | import FluxCancerStageCategory from './FluxCancerStageCategory';
3 |
4 | class FluxTNMClinicalDistantMetastasesCategory extends FluxCancerStageCategory {
5 | constructor(json) {
6 | super(json);
7 | this._cancerStageCategory = TNMClinicalDistantMetastasesCategory.fromJSON(json);
8 | if (!this._cancerStageCategory.entryInfo) {
9 | this._cancerStageCategory.entryInfo = this._constructEntry('http://standardhealthrecord.org/spec/onco/core/TNMClinicalDistantMetastasesCategory');
10 | }
11 | }
12 | }
13 |
14 | export default FluxTNMClinicalDistantMetastasesCategory;
15 |
--------------------------------------------------------------------------------
/src/model/fluxWrappers/onco/core/FluxTNMClinicalPrimaryTumorCategory.js:
--------------------------------------------------------------------------------
1 | import FluxCancerStageCategory from './FluxCancerStageCategory';
2 | import TNMClinicalPrimaryTumorCategory from '../../../onco/core/TNMClinicalPrimaryTumorCategory';
3 |
4 | class FluxTNMClinicalPrimaryTumorCategory extends FluxCancerStageCategory {
5 | constructor(json) {
6 | super(json);
7 | this._cancerStageCategory = TNMClinicalPrimaryTumorCategory.fromJSON(json);
8 | if (!this._cancerStageCategory.entryInfo) {
9 | this._cancerStageCategory.entryInfo = this._constructEntry('http://standardhealthrecord.org/spec/onco/core/TNMClinicalPrimaryTumorCategory');
10 | }
11 | }
12 | }
13 |
14 | export default FluxTNMClinicalPrimaryTumorCategory;
15 |
--------------------------------------------------------------------------------
/src/model/fluxWrappers/onco/core/FluxTNMClinicalRegionalNodesCategory.js:
--------------------------------------------------------------------------------
1 | import FluxCancerStageCategory from './FluxCancerStageCategory';
2 | import TNMClinicalRegionalNodesCategory from '../../../onco/core/TNMClinicalRegionalNodesCategory';
3 |
4 | class FluxTNMClinicalRegionalNodesCategory extends FluxCancerStageCategory {
5 | constructor(json) {
6 | super(json);
7 | this._cancerStageCategory = TNMClinicalRegionalNodesCategory.fromJSON(json);
8 | if (!this._cancerStageCategory.entryInfo) {
9 | this._cancerStageCategory.entryInfo = this._constructEntry('http://standardhealthrecord.org/spec/onco/core/TNMClinicalRegionalNodesCategory');
10 | }
11 | }
12 | }
13 |
14 | export default FluxTNMClinicalRegionalNodesCategory;
15 |
--------------------------------------------------------------------------------
/src/model/fluxWrappers/onco/core/FluxTNMClinicalStageGroup.js:
--------------------------------------------------------------------------------
1 | import TNMClinicalStageGroup from '../../../onco/core/TNMClinicalStageGroup';
2 | import PanelMembers from '../../../shr/core/PanelMembers';
3 | import FluxTNMStageGroup from './FluxTNMStageGroup';
4 | import moment from 'moment';
5 |
6 | class FluxTNMClinicalStageGroup extends FluxTNMStageGroup {
7 | constructor(json, patientRecord) {
8 | super();
9 | this._entry = this._tnmStageGroup = TNMClinicalStageGroup.fromJSON(json);
10 | if (!this._tnmStageGroup.entryInfo) {
11 | this._tnmStageGroup.entryInfo = this._constructEntry('http://standardhealthrecord.org/spec/onco/core/TNMClinicalStageGroup');
12 | this._tnmStageGroup.panelMembers = new PanelMembers();
13 | this._tnmStageGroup.panelMembers.observation = [];
14 | }
15 | if (!this._tnmStageGroup.relevantTime) {
16 | const today = new moment().format('D MMM YYYY');
17 | this.relevantTime = today;
18 | }
19 | this._patientRecord = patientRecord;
20 | }
21 | }
22 |
23 | export default FluxTNMClinicalStageGroup;
24 |
--------------------------------------------------------------------------------
/src/model/fluxWrappers/onco/core/FluxTNMPathologicStageGroup.js:
--------------------------------------------------------------------------------
1 | import TNMPathologicStageGroup from '../../../onco/core/TNMPathologicStageGroup';
2 | import PanelMembers from '../../../shr/core/PanelMembers';
3 | import FluxTNMStageGroup from './FluxTNMStageGroup';
4 |
5 | class FluxTNMPathologicStageGroup extends FluxTNMStageGroup {
6 | constructor(json, patientRecord) {
7 | super();
8 | this._entry = this._tnmStageGroup = TNMPathologicStageGroup.fromJSON(json);
9 | if (!this._tnmStageGroup.entryInfo) {
10 | this._tnmStageGroup.entryInfo = this._constructEntry('http://standardhealthrecord.org/spec/onco/core/TNMPathologicStageGroup');
11 | this._tnmStageGroup.panelMembers = new PanelMembers();
12 | this._tnmStageGroup.panelMembers.observation = [];
13 | }
14 | this._patientRecord = patientRecord;
15 | }
16 | }
17 |
18 | export default FluxTNMPathologicStageGroup;
19 |
--------------------------------------------------------------------------------
/src/model/fluxWrappers/oncocore/FluxCancerHistologicType.js:
--------------------------------------------------------------------------------
1 | // import CancerHistologicType from '../oncocore/CancerHistologicType';
2 | import FluxObservation from '../core/FluxObservation';
3 |
4 | class FluxCancerHistologicType extends FluxObservation {
5 | constructor(json) {
6 | super();
7 | // this._histologicType = this._observation = this._entry = CancerHistologicType.fromJSON(json);
8 | }
9 |
10 | get entryInfo() {
11 | return this._histologicType.entryInfo;
12 | }
13 |
14 | /**
15 | * Getter for type
16 | * This will return the displayText string from CodeableConcept Value
17 | */
18 | get type() {
19 | return this._displayTextOrCode(this._histologicType.value.coding[0]);
20 | }
21 |
22 | toJSON() {
23 | return this._histologicType.toJSON();
24 | }
25 | }
26 |
27 | export default FluxCancerHistologicType;
--------------------------------------------------------------------------------
/src/model/fluxWrappers/tumor/FluxTumorDimensions.js:
--------------------------------------------------------------------------------
1 | import TumorDimensions from '../../onco/core/TumorDimensions';
2 | import FluxObservation from '../core/FluxObservation';
3 |
4 | class FluxTumorDimensions extends FluxObservation {
5 | constructor(json) {
6 | super();
7 | this._tumorDimensions = this._observation = this._entry = TumorDimensions.fromJSON(json);
8 | }
9 |
10 | get entryInfo() {
11 | return this._tumorDimensions.entryInfo;
12 | }
13 |
14 | toJSON() {
15 | return this._tumorDimensions.toJSON();
16 | }
17 | }
18 |
19 | export default FluxTumorDimensions;
20 |
--------------------------------------------------------------------------------
/src/model/fluxWrappers/tumor/FluxTumorMargins.js:
--------------------------------------------------------------------------------
1 | // import TumorMargins from './TumorMargins';
2 | import FluxObservation from '../core/FluxObservation';
3 |
4 | class FluxTumorMargins extends FluxObservation {
5 | constructor(json, patientRecord) {
6 | super();
7 | this._patientRecord = patientRecord;
8 | // this._tumorMargins = this._observation = this._entry = TumorMargins.fromJSON(json);
9 | }
10 |
11 | get entryInfo() {
12 | return this._tumorMargins.entryInfo;
13 | }
14 |
15 | get value() {
16 | return this._tumorMargins.findingResult.value.coding[0].displayText.value;
17 | }
18 | }
19 |
20 | export default FluxTumorMargins;
21 |
--------------------------------------------------------------------------------
/src/model/fluxWrappers/tumor/FluxTumorObjectFactory.js:
--------------------------------------------------------------------------------
1 | import { getNamespaceAndName } from '../../json-helper';
2 | import FluxTumorDimensions from './FluxTumorDimensions';
3 | // import TumorObjectFactory from './TumorObjectFactory';
4 | import FluxTumorMargins from './FluxTumorMargins';
5 |
6 | export default class FluxTumorObjectFactory {
7 | static createInstance(json, type, patientRecord) {
8 | const { namespace, elementName } = getNamespaceAndName(json, type);
9 | if (namespace !== 'tumor') {
10 | throw new Error(`Unsupported type in TumorObjectFactory: ${type}`);
11 | }
12 |
13 | // returns Flux wrapper class if found, otherwise use ShrTumorObjectFactory
14 | switch (elementName) {
15 | case 'TumorDimensions': return new FluxTumorDimensions(json, patientRecord);
16 | case 'TumorMargins': return new FluxTumorMargins(json, patientRecord);
17 | // default: return TumorObjectFactory.createInstance(json, type);
18 | }
19 | }
20 | }
--------------------------------------------------------------------------------
/src/nav/NavBar.css:
--------------------------------------------------------------------------------
1 | .navbar-custom {
2 | background-color: #FFFFFF !important;
3 | }
4 |
--------------------------------------------------------------------------------
/src/noteparser/samples/note1.txt:
--------------------------------------------------------------------------------
1 | Debra Hernandez672 is presenting with carcinoma of the breast. #staging assessed as tumor size T2 and N0 + M0.
--------------------------------------------------------------------------------
/src/noteparser/samples/note10.txt:
--------------------------------------------------------------------------------
1 | Debra Hernandez672 is a 51 year old female is part of #enrollment #PATINA
--------------------------------------------------------------------------------
/src/noteparser/samples/note11.txt:
--------------------------------------------------------------------------------
1 | Debra Hernandez672 is #deceased on #10/01/2017
--------------------------------------------------------------------------------
/src/noteparser/samples/note12.txt:
--------------------------------------------------------------------------------
1 | Debra Hernandez672 is presenting with carcinoma of the breast.
2 |
3 | #ER #Positive #PR #Negative #HER2 #Positive
--------------------------------------------------------------------------------
/src/noteparser/samples/note13.txt:
--------------------------------------------------------------------------------
1 | Debra Hernandez672 is a 51 year old female who #unenrolled from #PATINA on #09/04/2017
--------------------------------------------------------------------------------
/src/noteparser/samples/note14.txt:
--------------------------------------------------------------------------------
1 | #stop medication @active medication[[ibuprofen 600mg tablet]]
--------------------------------------------------------------------------------
/src/noteparser/samples/note2.txt:
--------------------------------------------------------------------------------
1 | Debra Hernandez672 is presenting with carcinoma of the breast.
2 |
3 | #toxicity #nausea #grade 2 #treatment
--------------------------------------------------------------------------------
/src/noteparser/samples/note3.txt:
--------------------------------------------------------------------------------
1 | Debra Hernandez672 is presenting with carcinoma of the breast.
2 |
3 | #disease status #stable based on #imaging and #physical exam
--------------------------------------------------------------------------------
/src/noteparser/samples/note4.txt:
--------------------------------------------------------------------------------
1 | Invasive ductal carcinoma of breast
2 |
3 | #staging #T2 #N0 #M0
4 |
5 | #disease status #Stable #Pathology and #Symptoms
6 |
7 | #toxicity #Thrombotic thrombocytopenic purpura #Grade 3 attributed to #Disease
--------------------------------------------------------------------------------
/src/noteparser/samples/note5.txt:
--------------------------------------------------------------------------------
1 | testing. unknown patient.
2 |
3 | #disease status is #Complete Response based on #Physical exam, #Markers, #Pathology
4 |
5 | more text. more stuff. no extra hash tags!
--------------------------------------------------------------------------------
/src/noteparser/samples/note6.txt:
--------------------------------------------------------------------------------
1 | #toxicity of #Grade 3 #Blood and lymphatic system disorders - Other, specify related to #Unrelated and due to @active medication[[ibuprofen 600mg tablet]]
--------------------------------------------------------------------------------
/src/noteparser/samples/note7.txt:
--------------------------------------------------------------------------------
1 | #toxicity of #not a valid phrase #Grade 3 #Blood and lymphatic system disorders - Other, specify related to #Unrelated
--------------------------------------------------------------------------------
/src/noteparser/samples/note8.txt:
--------------------------------------------------------------------------------
1 | testing. unknown patient.
2 |
3 | #disease status is #Complete Response based on #Physical exam, #Markers, #Pathology #as of #10/5/2017 #reference date #5/2/2017
4 |
5 | more text. more stuff. no extra hash tags!
--------------------------------------------------------------------------------
/src/noteparser/samples/note9.txt:
--------------------------------------------------------------------------------
1 | Debra Hernandez672 is a 51 year old female who consented to #enrollment #PATINA on #09/04/2017
--------------------------------------------------------------------------------
/src/notes/ActiveContextsBreadcrumbs.scss:
--------------------------------------------------------------------------------
1 | @import '../styles/variables';
2 |
3 | .toolbar-breadcrumbs-container {
4 | color: $state;
5 | font-size: $size-m;
6 | font-style: italic;
7 | display: inline-block;
8 | vertical-align: bottom;
9 | max-width: calc(100% - 315px);
10 | }
11 |
12 | .breadcrumbs-container:after {
13 | content:"...";
14 | background-color: white;
15 | color: transparent;
16 | position: relative;
17 | z-index: 2;
18 | }
19 |
20 | .breadcrumbs-container {
21 | margin-right: 1px;
22 | vertical-align: bottom;
23 | direction: rtl;
24 | display: inline-block;
25 | width: 100%;
26 | white-space: nowrap;
27 | overflow: hidden;
28 | position: relative;
29 | z-index: 3;
30 | }
31 |
32 | .breadcrumbs-container:before {
33 | content:"...";
34 | background-color: white;
35 | position: absolute;
36 | left: 0;
37 | z-index: 1;
38 | }
39 |
40 | .breadcrumbs {
41 | display: inline-block;
42 | }
43 |
44 | .breadcrumb {
45 | display: inline;
46 | }
47 |
48 | .breadcrumb-separator {
49 | display: inline;
50 | padding: 0px 10px;
51 | }
52 |
--------------------------------------------------------------------------------
/src/notes/CompletionComponentFactory.js:
--------------------------------------------------------------------------------
1 | import ContextListOptions from '../context/ContextListOptions';
2 | import ContextGetHelp from '../context/ContextGetHelp';
3 | import ContextCalendar from '../context/ContextCalendar';
4 |
5 | export default class CompletionComponentFactory {
6 | static createInstance(completionComponentName) {
7 | // Can't do an instance of with a switch
8 | switch (completionComponentName) {
9 | case "number":
10 | console.error(`We don't currently support a completion component for ${completionComponentName}-subtypes; trying to get a completionComponent for ${completionComponentName}`);
11 | return null;
12 | case "date":
13 | return ContextCalendar;
14 | case "multi-choice":
15 | case "choice":
16 | return ContextListOptions;
17 | case "menu":
18 | return ContextGetHelp;
19 | default:
20 | console.error(`We don't currently support a completion component for ${completionComponentName}-subtypes; trying to get a completionComponent for ${completionComponentName}`);
21 | return null;
22 | }
23 | }
24 | }
--------------------------------------------------------------------------------
/src/notes/KeyboardShortcutsPlugin.js:
--------------------------------------------------------------------------------
1 | export default function KeyboardShortcutsPlugin() {
2 | const onKeyDown = (e, data, state, editor) => {
3 | if (data.isCmd || data.isCtrl) {
4 | let style = "";
5 | if (data.key === "b") {
6 | style = "bold";
7 | } else if (data.key === "i") {
8 | style = "italic";
9 | } else if (data.key === "u") {
10 | style = "underlined";
11 | } else {
12 | return state;
13 | }
14 | return state
15 | .transform()
16 | .toggleMark(style)
17 | .apply();
18 | }
19 | };
20 |
21 | return {
22 | onKeyDown
23 | };
24 | }
25 |
--------------------------------------------------------------------------------
/src/notes/PointOfCare.css:
--------------------------------------------------------------------------------
1 | #poc-panel {
2 | width: 100%;
3 | margin-top: 15px;
4 | overflow-x: hidden;
5 | overflow-y: scroll;
6 | /* 96px is the height of the Patient Control Panel, 20px is the height of the top margin of post encounter view
7 | content and a little extra for potential scroll bars, 82px accounts for the editor header */
8 | height: calc(100vh - 96px - 20px - 82px);
9 | }
10 |
11 |
--------------------------------------------------------------------------------
/src/panels/NotesPanel.scss:
--------------------------------------------------------------------------------
1 | @import '../styles/variables';
2 |
3 | #finish-sign-component {
4 | position: fixed;
5 | bottom: 0px;
6 | width: calc(35vw);
7 | background-color: #ffffff;
8 | text-align: left;
9 | z-index: 5;
10 | display: flex;
11 | justify-content: left;
12 | .btn-finish {
13 | background-color: #FFFFFF;
14 | text-transform: none;
15 | display: inline-block;
16 | min-width: 90%;
17 | margin: 10px 30px 10px 30px;
18 | border: 1px solid $line-gray;
19 | border-radius: 3px;
20 | }
21 | }
22 | .panel-content.note-assistant-panel {
23 | padding: 0px !important;
24 | }
25 |
--------------------------------------------------------------------------------
/src/panels/PatientControlPanel.scss:
--------------------------------------------------------------------------------
1 | @import '../styles/variables';
2 |
3 | .patient-control-panel {
4 | width: 100vw;
5 | position: relative;
6 | text-align: left;
7 | left: 50%;
8 | right: 50%;
9 | margin-left: -50vw;
10 | margin-right: -50vw;
11 | &, .FullApp-content {
12 | background-color: $background;
13 | }
14 | .clickable {
15 | cursor: pointer;
16 | }
17 | .logo-title-column {
18 | display: flex;
19 | align-items: center;
20 |
21 | .logo-accompaniment {
22 | display: inline-block;
23 |
24 | .title {
25 | display: block;
26 | color: $shr-context-dark;
27 | font-size: 1.1rem;
28 | font-weight: 600;
29 | padding-left: 5px;
30 | }
31 |
32 | .login {
33 | display: block;
34 | font-size: 0.8rem;
35 | margin-left: 0.4rem;
36 | }
37 | }
38 | }
39 | .summary-header-column {
40 | padding-left:0;
41 | }
42 | #condition-selection-container {
43 | padding: 5px;
44 | }
45 | }
46 |
47 | .vertical-divider {
48 | border-left: 1px solid $line-gray;
49 | padding: 0 .5rem;
50 | }
51 |
52 | .search-icon {
53 | padding-right: 5px;
54 | }
55 |
56 |
57 |
--------------------------------------------------------------------------------
/src/panels/TargetedDataPanel.scss:
--------------------------------------------------------------------------------
1 | @import '../styles/variables';
2 |
3 | .panel-heading {
4 | text-align: left;
5 | }
6 |
7 | .fitted-panel.minimap-container {
8 | width: auto;
9 | }
10 |
11 | .fitted-panel .minimap {
12 | position: absolute;
13 | left: 0;
14 | margin: 0;
15 | background-color: #ffffff;
16 | border: none;
17 | float: none;
18 | backface-visibility: hidden;
19 | -webkit-backface-visibility: hidden;
20 | }
21 |
22 | .minimap-viewport {
23 | background-color: #555;
24 | opacity: 0.15;
25 | width: 100px !important;
26 | }
27 |
28 | .minimap-children {
29 | display: flex;
30 | margin: 3px 10px;
31 | align-items: center;
32 | justify-content: center;
33 | background-color: #fff;
34 | border-radius: 4px;
35 | border: 1px solid $line-gray;
36 | cursor: pointer;
37 | }
38 |
39 | .minimap-children .minimap-title {
40 | text-align: center;
41 | color: $body-gray;
42 | font-size: $size-xs;
43 | }
44 |
45 | .minimap-title-hidden {
46 | position: absolute;
47 | top: 0;
48 | left: 0;
49 | width: 78px;
50 | font-size: $size-xs;
51 | display: block;
52 | visibility: hidden;
53 | }
54 |
55 | .edit-button {
56 | border-radius: 3px;
57 | border: 1px solid $state !important;
58 | color: $interface-blue-text;
59 | margin-bottom: 5px;
60 | }
61 |
62 | .targeted-data-subpanel-no-minimap {
63 | margin-left: 20px;
64 | margin-right: 0px;
65 | }
66 |
--------------------------------------------------------------------------------
/src/patientControl/BaseIndexer.js:
--------------------------------------------------------------------------------
1 | import { Component } from 'react';
2 |
3 | class BaseIndexer extends Component {
4 | indexData(section, subsection, data, searchIndex, onHighlight) {
5 | if (subsection) {
6 | const sectionId = this.getStringForId(section);
7 | const subsectionId = this.getStringForId(subsection);
8 | searchIndex.addSearchableData({
9 | id: `${sectionId}_${subsectionId}_subsection`,
10 | section,
11 | subsection,
12 | valueTitle: "Subsection",
13 | value: subsection,
14 | onHighlight
15 | });
16 | }
17 | }
18 |
19 | getStringForId(s) {
20 | try {
21 | return s.toLowerCase().replace(/[.,#!$%&;:{}=\-_`~()]/g,"").replace(/ /g, '_');
22 | } catch (e) {
23 | console.error(e);
24 | return '';
25 | }
26 | }
27 | }
28 |
29 | export default BaseIndexer;
--------------------------------------------------------------------------------
/src/patientControl/ClusterPointsIndexer.js:
--------------------------------------------------------------------------------
1 | import BaseIndexer from './BaseIndexer';
2 |
3 | class ClusterPointsIndexer extends BaseIndexer {
4 | indexData(section, subsection, data, searchIndex, onHighlight) {
5 | super.indexData(section, subsection, data, searchIndex, onHighlight);
6 | }
7 | }
8 |
9 | export default ClusterPointsIndexer;
--------------------------------------------------------------------------------
/src/patientControl/DiseaseStatusValuesIndexer.js:
--------------------------------------------------------------------------------
1 | import BaseIndexer from './BaseIndexer';
2 |
3 | class DiseaseStatusValuesIndexer extends BaseIndexer {
4 | indexData(section, subsection, data, searchIndex, onHighlight) {
5 | super.indexData(section, subsection, data, searchIndex, onHighlight);
6 | const sectionId = super.getStringForId(section);
7 | data.potentialDiagnosisDates.forEach(item => {
8 | const valueTitleId = super.getStringForId(item.label);
9 | searchIndex.addSearchableData({
10 | id: `${sectionId}_${valueTitleId}`,
11 | section,
12 | subsection: "",
13 | valueTitle: item.label,
14 | value: item.date,
15 | onHighlight
16 | });
17 | });
18 |
19 | data.progressions.forEach(progression => {
20 | const valueTitleId = super.getStringForId(progression.start_time);
21 | searchIndex.addSearchableData({
22 | id: `${sectionId}_${valueTitleId}`,
23 | section,
24 | subsection: "",
25 | valueTitle: progression.start_time,
26 | value: progression.disease_status_string,
27 | onHighlight
28 | });
29 | });
30 | }
31 | }
32 |
33 | export default DiseaseStatusValuesIndexer;
--------------------------------------------------------------------------------
/src/patientControl/EventsIndexer.js:
--------------------------------------------------------------------------------
1 | import BaseIndexer from './BaseIndexer';
2 |
3 | class EventsIndexer extends BaseIndexer {
4 | indexData(section, subsection, data, searchIndex, onHighlight) {
5 | super.indexData(section, subsection, data, searchIndex, onHighlight);
6 | const sectionId = super.getStringForId(section);
7 | const subsectionId = super.getStringForId(sectionId);
8 | data.forEach(item => {
9 | const value = subsection === "Procedures" ? item.hoverText : `${item.hoverTitle}: ${item.hoverText}`;
10 | searchIndex.addSearchableData({
11 | id: `${sectionId}_${subsectionId}_${super.getStringForId(value)}`,
12 | section,
13 | subsection,
14 | valueTitle: "",
15 | value,
16 | onHighlight
17 | });
18 | });
19 | }
20 | }
21 |
22 | export default EventsIndexer;
--------------------------------------------------------------------------------
/src/patientControl/NameValuePairsIndexer.js:
--------------------------------------------------------------------------------
1 | import Lang from 'lodash';
2 | import BaseIndexer from './BaseIndexer';
3 |
4 | class NameValuePairsIndexer extends BaseIndexer {
5 | indexData(section, subsection, data, searchIndex, onHighlight) {
6 | super.indexData(section, subsection, data, searchIndex, onHighlight);
7 | const sectionId = super.getStringForId(section);
8 | let value;
9 | data.forEach(obj => {
10 | if (Lang.isObject(obj.value)) {
11 | value = obj.value.value || "Missing Data";
12 | } else {
13 | value = obj.value || "Missing Data";
14 | }
15 | searchIndex.addSearchableData({
16 | id: `${sectionId}_${super.getStringForId(obj.name)}`,
17 | section,
18 | subsection: "",
19 | valueTitle: obj.name,
20 | value,
21 | onHighlight
22 | });
23 | });
24 | }
25 | }
26 |
27 | export default NameValuePairsIndexer;
--------------------------------------------------------------------------------
/src/patientControl/NotesIndexer.js:
--------------------------------------------------------------------------------
1 | import NoteContentIndexer from './NoteContentIndexer';
2 |
3 | class NotesIndexer extends NoteContentIndexer {
4 | indexData(section, subsection, data, searchIndex, onHighlight, onClick) {
5 | const noteSectionId = super.getStringForId(section);
6 | searchIndex.addSearchableData({
7 | id: noteSectionId,
8 | section,
9 | subsection: '',
10 | valueTitle: 'Section',
11 | value: section,
12 | });
13 |
14 | searchIndex.addSearchableData({
15 | id: `${noteSectionId}_signed_notes`,
16 | section,
17 | subsection: 'Signed Notes',
18 | valueTitle: 'Subsection',
19 | value: 'Signed Notes',
20 | });
21 |
22 | searchIndex.addSearchableData({
23 | id: `${noteSectionId}_in_progress_notes`,
24 | section,
25 | subsection: 'In Progress Notes',
26 | valueTitle: 'Subsection',
27 | value: 'In Progress Notes',
28 | });
29 |
30 | data.forEach(note => {
31 | const subsectionId = note.signed ? 'signed_notes' : 'in_progress_notes';
32 | if (searchIndex.hasDocument(`open_note_${subsectionId}_content_${note.entryInfo.entryId.id}`)) return;
33 | super.indexData(section, subsection, note, searchIndex, onHighlight, onClick);
34 | });
35 | }
36 | }
37 |
38 | export default NotesIndexer;
39 |
--------------------------------------------------------------------------------
/src/patientControl/ReviewOfSystemsValuesIndexer.js:
--------------------------------------------------------------------------------
1 | import BaseIndexer from './BaseIndexer';
2 |
3 | class ReviewOfSystemsValuesIndexer extends BaseIndexer {
4 | indexData(section, subsection, data, searchIndex, onHighlight) {
5 | super.indexData(section, subsection, data, searchIndex, onHighlight);
6 | const sectionId = super.getStringForId(section);
7 |
8 | data.forEach((item) => {
9 | const dateId = super.getStringForId(item.date);
10 | searchIndex.addSearchableData({
11 | id: `${sectionId}_${dateId}`,
12 | section,
13 | subsection: "",
14 | valueTitle: 'Date',
15 | value: item.date,
16 | date: item.date,
17 | onHighlight
18 | });
19 |
20 | item.questions.forEach((question) => {
21 | const questionId = super.getStringForId(question.name);
22 | searchIndex.addSearchableData({
23 | id: `${sectionId}_${dateId}_${questionId}`,
24 | section,
25 | subsection: "",
26 | valueTitle: question.name,
27 | value: question.value,
28 | date: item.date,
29 | onHighlight
30 | });
31 | });
32 | });
33 | }
34 | }
35 |
36 | export default ReviewOfSystemsValuesIndexer;
--------------------------------------------------------------------------------
/src/patientControl/SearchSuggestion.scss:
--------------------------------------------------------------------------------
1 | @import '../styles/variables';
2 |
3 | .suggestion {
4 | &-item {
5 | display: block;
6 | align-items: center;
7 | padding: 10px;
8 | }
9 |
10 | &-label {
11 | min-width: 80px;
12 | display: block;
13 | font-size: 10px;
14 | width: 80px;
15 | padding: 5px auto;
16 |
17 | & .label-content {
18 | margin: 0;
19 | display: inline-block;
20 | white-space: nowrap;
21 | line-height: 1.2rem;
22 | text-overflow: ellipsis;
23 | }
24 | }
25 |
26 | &-text {
27 | font-size: 14px;
28 | display: block;
29 | white-space: nowrap;
30 | overflow: hidden;
31 | text-overflow: ellipsis;
32 | }
33 | }
34 |
35 | .highlighted-input-value {
36 | font-weight: 600;
37 | }
38 |
39 | .dividing-line:after {
40 | background: #b1b1b1;
41 | width: 1px;
42 | content: "";
43 | display: inline-block;
44 | top: 0;
45 | bottom: 0;
46 | right: 0;
47 | min-height: 25px;
48 | margin: -5px 10px -5px 10px;
49 | }
--------------------------------------------------------------------------------
/src/patientControl/ValueOverTimeIndexer.js:
--------------------------------------------------------------------------------
1 | import BaseIndexer from './BaseIndexer';
2 |
3 | class ValueOverTimeIndexer extends BaseIndexer {
4 | indexData(section, subsection, data, searchIndex, onHighlight) {
5 | super.indexData(section, subsection, data, searchIndex, onHighlight);
6 | const sectionId = super.getStringForId(section);
7 | const subsectionId = super.getStringForId(subsection);
8 | data.forEach(item => {
9 | const value = item.displayValue || `${item[subsection]} ${item.unit}`;
10 | searchIndex.addSearchableData({
11 | id: `${sectionId}_${subsectionId}_${super.getStringForId(value)}`,
12 | section,
13 | subsection,
14 | valueTitle: subsection,
15 | value: `${item.start_time}: ${value}`
16 | });
17 | });
18 | }
19 | }
20 |
21 | export default ValueOverTimeIndexer;
--------------------------------------------------------------------------------
/src/preferences/IPreferenceStore.jsx:
--------------------------------------------------------------------------------
1 | class IPreferenceStore {
2 | setPreference(name, value) {
3 | }
4 |
5 | getPreference(name) {
6 | return null;
7 | }
8 |
9 | removePreference(name) {
10 | }
11 | }
12 |
13 | export default IPreferenceStore;
--------------------------------------------------------------------------------
/src/preferences/LocalStoragePreferenceStore.jsx:
--------------------------------------------------------------------------------
1 | import IPreferenceStore from './IPreferenceStore';
2 |
3 | class LocalStoragePreferenceStore extends IPreferenceStore {
4 | setPreference(name, value) {
5 | try {
6 | localStorage.setItem(name, JSON.stringify(value));
7 | } catch (e) {
8 | }
9 | }
10 |
11 | getPreference(name) {
12 | try {
13 | return JSON.parse(localStorage.getItem(name));
14 | } catch (e) {
15 | return null;
16 | }
17 | }
18 |
19 | removePreference(name) {
20 | try {
21 | localStorage.removeItem(name);
22 | } catch (e) {
23 | }
24 | }
25 | }
26 |
27 | export default LocalStoragePreferenceStore;
--------------------------------------------------------------------------------
/src/preferences/PreferenceManager.jsx:
--------------------------------------------------------------------------------
1 | import LocalStoragePreferenceStore from './LocalStoragePreferenceStore';
2 |
3 | class PreferenceManager {
4 | constructor(user) {
5 | this._user = user;
6 | this._preferenceStore = this._getPreferenceStore();
7 | }
8 |
9 | _getPreferenceStore() {
10 | return new LocalStoragePreferenceStore();
11 | }
12 |
13 | /*
14 | * name = name of preference to store
15 | * value = value for the named preference item
16 | */
17 | setPreference(name, value) {
18 | this._preferenceStore.setPreference(name, value);
19 | }
20 |
21 | removePreference(name) {
22 | this._preferenceStore.removePreference(name);
23 | }
24 |
25 | getPreference(name) {
26 | return this._preferenceStore.getPreference(name);
27 | }
28 | }
29 |
30 | export default PreferenceManager;
--------------------------------------------------------------------------------
/src/reducers/index.js:
--------------------------------------------------------------------------------
1 | import { combineReducers } from 'redux';
2 |
3 | import mcodeReducer from './mcode';
4 |
5 | export default combineReducers({
6 | mcode: mcodeReducer
7 | });
8 |
--------------------------------------------------------------------------------
/src/shortcuts/NLPHashtag.jsx:
--------------------------------------------------------------------------------
1 | import EntryShortcut from './EntryShortcut';
2 |
3 | export default class NLPHashtag extends EntryShortcut {
4 | constructor(onUpdate, metadata, patient, shortcutData) {
5 | super(metadata);
6 | this.nlpTemplate = this.metadata.nlpTemplate;
7 | this.isSetByLabel = {};
8 | this.onUpdate = onUpdate;
9 | this.patient = patient;
10 | this._initializeValueObject(metadata, patient, shortcutData);
11 | this._initializeValueObjectAttributes(metadata);
12 | this.setAttributeValue = this.setAttributeValue.bind(this);
13 | }
14 |
15 | getAttributeIsSetByLabel(name) {
16 | return this.isSetByLabel[name];
17 | }
18 |
19 | setAttributeIsSetByLabel(name, val) {
20 | this.isSetByLabel[name] = val;
21 | }
22 |
23 | get isComplete() {
24 | return this.hasParentContext() && this.hasChildren();
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/store/configureStore.js:
--------------------------------------------------------------------------------
1 | import { createStore, applyMiddleware, compose } from 'redux';
2 | import { routerMiddleware } from 'react-router-redux';
3 | import thunk from 'redux-thunk';
4 | import { createHashHistory as createHistory } from 'history';
5 | import rootReducer from '../reducers';
6 |
7 | export const history = createHistory();
8 |
9 | const initialState = {};
10 | const enhancers = [];
11 | const middleware = [
12 | thunk,
13 | routerMiddleware(history)
14 | ];
15 |
16 | if (process.env.NODE_ENV === 'development') {
17 | const devToolsExtension = window.__REDUX_DEVTOOLS_EXTENSION__;
18 |
19 | if (typeof devToolsExtension === 'function') {
20 | enhancers.push(devToolsExtension());
21 | }
22 | }
23 |
24 | const composedEnhancers = compose(
25 | applyMiddleware(...middleware),
26 | ...enhancers
27 | );
28 |
29 | const store = createStore(
30 | rootReducer,
31 | initialState,
32 | composedEnhancers
33 | );
34 |
35 | export default store;
36 |
--------------------------------------------------------------------------------
/src/styles/SlimApp.css:
--------------------------------------------------------------------------------
1 | /* Restricts app to max fixed width for very wide screens. */
2 | .SlimApp-content {
3 | background-color: white;
4 | font-size:0.93rem;
5 | /*64 px is the height of the nav bar*/
6 | height: calc(100vh - 64px);
7 | padding: 0 0;
8 | }
9 |
10 | .SlimApp-content .row{
11 | margin: 0!important;
12 | }
13 |
14 | .SlimApp-content .divider {
15 | margin: 10px 0 20px 0px !important;
16 | clear: both;
17 | }
18 |
19 | .SlimApp-content h1 {
20 | margin: 10px 0;
21 | font-size: 1.25rem;
22 | font-family: "Open Sans", Arial, sans-serif;
23 | }
24 |
25 | .SlimApp-content h2 {
26 | margin: 0px;
27 | font-size: 0.9rem;
28 | font-weight: lighter;
29 | font-family: "Open Sans", Arial, sans-serif;
30 | }
31 |
32 | .SlimApp-content h3 {
33 | margin: 0px;
34 | font-size: 0.8rem;
35 | font-weight: lighter;
36 | }
37 |
38 | .SlimApp-content h4 {
39 | margin: 10px 0;
40 | font-size: 0.9rem;
41 | font-weight: 600;
42 | }
43 |
44 | .SlimApp-content ::-webkit-scrollbar-track {
45 | background-color: #FFFFFF;
46 | }
47 |
48 | .SlimApp-content .no-padding {
49 | padding: 0!important;
50 | }
51 |
52 | .SlimApp-content .header-spacing {
53 | margin-top: 25px;
54 | }
55 |
56 | .SlimApp-content a {
57 | color: #297DA2;
58 | }
59 |
60 |
61 | .SlimApp-content .data-element-description {
62 | margin-top: 15px;
63 | font-style: italic;
64 | font-size: 0.9em;
65 | }
--------------------------------------------------------------------------------
/src/styles/mixins/_colors.scss:
--------------------------------------------------------------------------------
1 | @import '../variables';
2 |
3 | $colorMap: (
4 | color-1: $icons-purple,
5 | color-2: $icons-green,
6 | color-3: $icons-blue,
7 | color-4: $icons-red,
8 | color-5: $icons-teal
9 | );
10 |
11 | @mixin index-colors($attribute: 'color', $prefix: '-', $opacity: 1) {
12 | @each $color-index, $color in $colorMap {
13 | {$prefix}#{$color-index} {
14 | #{$attribute}: rgba($color, $opacity);
15 | }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/styles/mixins/_media-queries.scss:
--------------------------------------------------------------------------------
1 | // Breakpoints
2 | $breakpoint-tablet: 576px;
3 | $breakpoint-desktop: 768px;
4 |
5 | // Media queries
6 | @mixin respond-to($media) {
7 | @if $media==mobile {
8 | @media only screen and (max-width: $breakpoint-tablet) { @content; }
9 | }
10 | @else if $media==tablet {
11 | @media only screen and (min-width: $breakpoint-tablet + 1) and (max-width: $breakpoint-desktop) { @content; }
12 | }
13 | @else if $media==desktop {
14 | @media only screen and (min-width: $breakpoint-desktop + 1) { @content; }
15 | }
16 | @else {
17 | @media only screen and (max-width: $media) { @content; }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/summary/.gitignore:
--------------------------------------------------------------------------------
1 |
2 | /MedicationRangeChartVisualizer.css
3 | /ExpandedTableVisualizer.css
4 | /BandedLineChartVisualizer.css
5 | /SummaryHeader.css
6 |
--------------------------------------------------------------------------------
/src/summary/BandedLineChartVisualizer.scss:
--------------------------------------------------------------------------------
1 | @import '../styles/variables';
2 |
3 | .line-chart-subsection {
4 | .subsection-heading {
5 | h2 {
6 | margin: 10px 0;
7 |
8 | .subsection-name {
9 | font-weight: $weight-regular;
10 | font-size: $size-m;
11 | }
12 | .subsection-icons {
13 | margin-left: 5px;
14 |
15 | .small-btn {
16 | min-width: 0 !important;
17 | min-height: 0 !important;
18 | }
19 | }
20 | }
21 | }
22 |
23 | .no-entries {
24 | padding: 20px 0px 10px 0px;
25 | font-size: $size-l;
26 | font-weight: $weight-regular;
27 | color: $state;
28 | }
29 |
30 | .recharts-responsive-container {
31 | .recharts-tooltip-wrapper {
32 | font-size: $size-m;
33 | }
34 |
35 | .recharts-text {
36 | font-size: $size-s;
37 | }
38 |
39 | .hide-line {
40 | .recharts-curve {
41 | stroke: none;
42 |
43 | &.recharts-tooltip-cursor {
44 | stroke: #CCCCCC;
45 | }
46 | }
47 | }
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/summary/ClinicalEventSelection.css:
--------------------------------------------------------------------------------
1 | .clinical-event-selection .clinical-event-select {
2 | width: 90%;
3 | height: 30px;
4 | font-size: 0.8em;
5 | background-color: #fafafa;
6 | border-radius: 2px;
7 | padding: 5px 2px 2px 20px;
8 | border: none;
9 | -webkit-box-shadow: 0px 1px 5px 0px rgba(0, 0, 0, 0.2), 0px 2px 2px 0px rgba(0, 0, 0, 0.14), 0px 3px 1px -2px rgba(0, 0, 0, 0.12);
10 | -moz-box-shadow: 0px 1px 5px 0px rgba(0, 0, 0, 0.2), 0px 2px 2px 0px rgba(0, 0, 0, 0.14), 0px 3px 1px -2px rgba(0, 0, 0, 0.12);
11 | box-shadow: 0px 1px 5px 0px rgba(0, 0, 0, 0.2), 0px 2px 2px 0px rgba(0, 0, 0, 0.14), 0px 3px 1px -2px rgba(0, 0, 0, 0.12);
12 | }
13 |
14 | .clinical-event-select .MuiSelect-select-111:focus {
15 | background: inherit;
16 | }
17 |
18 |
19 | li.clinical-event-item {
20 | font-family: "Open Sans", Roboto, Arial, sans-serif;
21 | color: #444;
22 | height: 10px;
23 | margin: 5px 0;
24 | font-size: 0.9em;
25 | }
26 |
27 | li.clinical-event-item:hover {
28 | background-color: #1384b5;
29 | color: #fff;
30 | }
--------------------------------------------------------------------------------
/src/summary/CompassAppSummaryMetadata.jsx:
--------------------------------------------------------------------------------
1 | import SummaryMetadata from './SummaryMetadata';
2 | import DefaultCompassAppMetadata from './metadata/DefaultCompassAppMetadata';
3 | import McodeMetadata from './metadata/McodeMetadata';
4 | import FluxCancerCondition from '../model/fluxWrappers/onco/core/FluxCancerCondition';
5 | import FunctionMatcher from './matchers/FunctionMatcher';
6 | import AlwaysMatcher from './matchers/AlwaysMatcher';
7 |
8 | export default class CompassAppSummaryMetadata extends SummaryMetadata {
9 | constructor(setForceRefresh) {
10 | super();
11 | this.setForceRefresh = setForceRefresh;
12 |
13 | this.hardCodedMetadata = [
14 | { "enabled": true, "type": FunctionMatcher, "matchFunction": (condition) => condition instanceof FluxCancerCondition, "metadata": McodeMetadata },
15 | { "enabled": true, "type": AlwaysMatcher, "metadata": DefaultCompassAppMetadata },
16 | ];
17 | }
18 | }
19 |
20 |
--------------------------------------------------------------------------------
/src/summary/ConditionSelection.scss:
--------------------------------------------------------------------------------
1 | @import '../styles/variables';
2 |
3 | #condition-selection {
4 | .condition-select {
5 | width: 95%;
6 | height: 30px;
7 | padding-top: 2px;
8 | opacity: 0.9;
9 | font-size: $size-s;
10 | //background-color: $contrast-gray;
11 | border: none;
12 | //-webkit-box-shadow: 0px 1px 5px 0px rgba(0, 0, 0, 0.2), 0px 2px 2px 0px rgba(0, 0, 0, 0.14), 0px 3px 1px -2px rgba(0, 0, 0, 0.12);
13 | //-moz-box-shadow: 0px 1px 5px 0px rgba(0, 0, 0, 0.2), 0px 2px 2px 0px rgba(0, 0, 0, 0.14), 0px 3px 1px -2px rgba(0, 0, 0, 0.12);
14 | //box-shadow: 0px 1px 5px 0px rgba(0, 0, 0, 0.2), 0px 2px 2px 0px rgba(0, 0, 0, 0.14), 0px 3px 1px -2px rgba(0, 0, 0, 0.12);
15 | &:after {
16 | background-color: $shr-context-dark;
17 | }
18 | }
19 | li.condition-item {
20 | font-family: "Open Sans", Roboto, Arial, sans-serif;
21 | color: #444;
22 | height: 10px;
23 | margin: 5px 0;
24 | font-size: 0.9em;
25 | }
26 | .condition-select-menu {
27 | padding-left: 0px;
28 | color: $body-black;
29 | size: $size-s;
30 | }
31 | .label {
32 | font-size: $size-s;
33 | color: $body-gray;
34 | margin: 0px;
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/summary/FormatTabularListVisualizer.css:
--------------------------------------------------------------------------------
1 | stopped-cell {
2 | padding: 8px;
3 | border: 0;
4 | color: #bd4e3a;
5 | font-family: "Open Sans", Arial, sans-serif;
6 | }
--------------------------------------------------------------------------------
/src/summary/Pilot2MvpAppSummaryMetadata.jsx:
--------------------------------------------------------------------------------
1 | import SummaryMetadata from './SummaryMetadata';
2 | import DefaultPilot2MvpAppMetadata from './metadata/DefaultPilot2MvpAppMetadata';
3 | import Pilot2MvpMetadata from './metadata/Pilot2MvpMetadata';
4 | import FluxCancerCondition from '../model/fluxWrappers/onco/core/FluxCancerCondition';
5 | import FunctionMatcher from './matchers/FunctionMatcher';
6 | import AlwaysMatcher from './matchers/AlwaysMatcher';
7 |
8 | export default class Pilot2MvpAppSummaryMetadata extends SummaryMetadata {
9 | constructor(setForceRefresh) {
10 | super();
11 | this.setForceRefresh = setForceRefresh;
12 |
13 | this.hardCodedMetadata = [
14 | { "enabled": true, "type": FunctionMatcher, "matchFunction": (condition) => condition instanceof FluxCancerCondition, "metadata": Pilot2MvpMetadata },
15 | { "enabled": true, "type": AlwaysMatcher, "metadata": DefaultPilot2MvpAppMetadata },
16 | ];
17 | }
18 | }
19 |
20 |
--------------------------------------------------------------------------------
/src/summary/ProgressionLineChartVisualizer.scss:
--------------------------------------------------------------------------------
1 | @import '../styles/variables';
2 |
3 | .progression-line-chart-subsection {
4 | padding: 10px 0;
5 |
6 | .sub-section-heading h2.sub-section-name {
7 | margin: 10px 0;
8 | font-weight: $weight-regular;
9 | }
10 |
11 | .recharts-tooltip-wrapper {
12 | font-size: $size-m;
13 | }
14 |
15 | .recharts-text {
16 | font-size: $size-s;
17 | }
18 |
19 | .disease-status-tooltip {
20 | padding: 10px;
21 | background-color: rgb(255, 255, 255);
22 | border: 1px solid rgb(204, 204, 204);
23 | max-width: 200px;
24 | }
25 |
26 | }
27 |
--------------------------------------------------------------------------------
/src/summary/RangeChart.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FluxNotes/flux/dcfa6d78442cb9ca51ec627eb5cd193bd76a38db/src/summary/RangeChart.css
--------------------------------------------------------------------------------
/src/summary/ScatterPlotVisualizer.css:
--------------------------------------------------------------------------------
1 | @import 'https://code.highcharts.com/css/highcharts.css';
2 |
3 | .highcharts-title *{
4 | color: #0067B0;
5 | fill: #0067b0;
6 | font-weight: bold;
7 | }
8 |
9 | #table-loading-animation-container {
10 | display:flex;
11 | justify-content: center;
12 | width: 100%;
13 | overflow: hidden;
14 | padding: 20px 0px;
15 | }
16 |
17 | .highcharts-axis-title *{
18 | left: 0px;
19 | }
20 |
21 |
--------------------------------------------------------------------------------
/src/summary/TargetedDataSubpanel.css:
--------------------------------------------------------------------------------
1 | #condition-summary-section {
2 | text-align: left;
3 | overflow-x: hidden;
4 | }
5 |
6 | .tabs-container div .tab{
7 | color: black !important;
8 | }
9 |
10 | .table-list h2 {
11 | color: #333;
12 | }
13 |
14 | .table-list {
15 | margin-top: 20px;
16 | }
17 |
18 | /*table.existing-notes td {*/
19 | /*padding: 20px 10px;*/
20 | /*}*/
21 |
22 | /*td.existing-note-metadata {*/
23 | /*color: #333333;*/
24 | /*}*/
25 |
26 | /*td.existing-note-date {*/
27 | /*color: #999;*/
28 | /*}*/
29 |
30 | /*td span#existing-note-subject {*/
31 | /*font-weight: bold;*/
32 | /*font-size: 1rem;*/
33 | /*}*/
34 |
35 | /*Explicitly add in top and bottom border for last cell in row because it is removed in the Data Summary Table css*/
36 | tr.existing-note-entry td:last-child {
37 | border-top: 1px solid #ccc;
38 | border-bottom: 1px solid #ccc;
39 | }
40 |
41 | #condition-summary-section h2.section-header{
42 | /*font-weight: bold;*/
43 | /*color: #333;*/
44 | }
45 |
46 | .icons {
47 | float: right;
48 | padding: 10px;
49 | }
50 |
--------------------------------------------------------------------------------
/src/summary/activeTreatmentSummary/ActiveTreatmentSummaryObjectFactory.js:
--------------------------------------------------------------------------------
1 |
2 | import CancerDisorderPresentActiveTreatmentSummary from './CancerDisorderPresentActiveTreatmentSummary';
3 | import FluxCancerCondition from '../../model/fluxWrappers/onco/core/FluxCancerCondition';
4 | /*
5 | * ActiveTreatmentSummaryFactory class returns instances of Flux model classes
6 | * Default case will return SHR model classes if no Flux wrapper class is found
7 | */
8 | export default class ActiveTreatmentSummaryObjectFactory {
9 | static createInstance(patient, currentConditionEntry) {
10 | // Can't do an instance of with a switch
11 | if (currentConditionEntry instanceof FluxCancerCondition) return new CancerDisorderPresentActiveTreatmentSummary();
12 | else return null;
13 | }
14 | }
--------------------------------------------------------------------------------
/src/summary/activeTreatmentSummary/IActiveTreatmentSummary.js:
--------------------------------------------------------------------------------
1 | class IActiveTreatmentSummary {
2 | getActiveTreatmentSummary(patient, currentConditionEntry) {
3 | return null;
4 | }
5 | }
6 |
7 | export default IActiveTreatmentSummary;
--------------------------------------------------------------------------------
/src/summary/matchers/AlwaysMatcher.js:
--------------------------------------------------------------------------------
1 | import Matcher from './Matcher';
2 |
3 | class AlwaysMatcher extends Matcher {
4 | match = (condition, roleType, role, specialty) => {
5 | return true;
6 | }
7 | }
8 |
9 | export default AlwaysMatcher;
--------------------------------------------------------------------------------
/src/summary/matchers/FunctionMatcher.js:
--------------------------------------------------------------------------------
1 | import Matcher from './Matcher';
2 |
3 | class FunctionMatcher extends Matcher {
4 | match = (condition, roleType, role, specialty) => {
5 | return this._metadata.matchFunction(condition, roleType, role, specialty);
6 | }
7 | }
8 |
9 | export default FunctionMatcher;
--------------------------------------------------------------------------------
/src/summary/matchers/Matcher.js:
--------------------------------------------------------------------------------
1 | class Matcher {
2 | constructor(metadata) {
3 | this._metadata = metadata;
4 | }
5 |
6 | match = (condition, roleType, role, specialty) => {
7 | return false;
8 | }
9 | }
10 |
11 | export default Matcher;
--------------------------------------------------------------------------------
/src/summary/matchers/StringMatcher.js:
--------------------------------------------------------------------------------
1 | import Matcher from './Matcher';
2 | import Lang from 'lodash';
3 |
4 | class StringMatcher extends Matcher {
5 | // returns an array of strings which are keys to find the metadata for summary in priority order (1st one should be used first). List should always end with DefautMetadata
6 | buildPrioritizedMetadataKeyList = (condition, roleType, role, specialty) => {
7 | if (Lang.isNull(condition)) return [ "default" ];
8 | const codeSystem = condition.codeSystem;
9 | const code = condition.code;
10 | const conditionType = `${codeSystem}/${code}`;
11 | const userType = `${roleType}/${role}/${specialty}`;
12 | return [ userType + "/" + conditionType, conditionType, "default" ];
13 | }
14 |
15 | match = (condition, roleType, role, specialty) => {
16 | const prioritizedKeyList = this.buildPrioritizedMetadataKeyList(condition, roleType, role, specialty);
17 | const numKeys = prioritizedKeyList.length;
18 | let keyIndex = 0;
19 | while (keyIndex < numKeys) {
20 | if (prioritizedKeyList[keyIndex] === this._metadata.matchString) return true;
21 | keyIndex++;
22 | }
23 | return false;
24 | }
25 | }
26 |
27 | export default StringMatcher;
--------------------------------------------------------------------------------
/src/summary/metadata/DetailedTreatmentOptionsSection.jsx:
--------------------------------------------------------------------------------
1 | import MetadataSection from "./MetadataSection";
2 |
3 | export default class DetailedTreatmentOptionsSection extends MetadataSection {
4 | getMetadata(preferencesManager, patient, condition, roleType, role, specialty) {
5 | return {
6 | name: "Treatment Options",
7 | shortName: "Treatments",
8 | type: "TreatmentOptions",
9 | data: []
10 | };
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/src/summary/metadata/HeartRateSubsection.jsx:
--------------------------------------------------------------------------------
1 | import VitalsSubsection from './VitalsSubsection';
2 |
3 | export default class HeartRateSubsection extends VitalsSubsection {
4 | getMetadata(preferencesManager, patient, condition, roleType, role, specialty) {
5 | return {
6 | name: "Heart Rate",
7 | code: "8867-4",
8 | itemsFunction: this.getVitalsForSubsection,
9 | displayChartLine: false,
10 |
11 | // Source: https://www.medicalnewstoday.com/articles/235710.php
12 | bands: [
13 | {
14 | low: 40,
15 | high: 50,
16 | assessment: 'bad'
17 | },
18 |
19 | {
20 | low: 50,
21 | high: 100,
22 | assessment: 'good'
23 | },
24 | {
25 | low: 100,
26 | high: 200,
27 | assessment: 'bad'
28 | }
29 | ]
30 | };
31 | }
32 | }
--------------------------------------------------------------------------------
/src/summary/metadata/HemoglobinSubsection.jsx:
--------------------------------------------------------------------------------
1 | import LabTestSubsection from "./LabTestSubsection";
2 |
3 | export default class HemoglobinSubsection extends LabTestSubsection {
4 | getMetadata(preferencesManager, patient, condition, roleType, role, specialty) {
5 | return {
6 | name: "Hemoglobin",
7 | code: "C0019046",
8 | itemsFunction: this.getTestsForSubSection,
9 | displayChartLine: false,
10 |
11 | // Source: https://www.emedicinehealth.com/hemoglobin_levels/page2_em.htm
12 | // Source: https://www.quora.com/What-is-the-percentage-of-haemoglobin-in-blood
13 | bands: [
14 | {
15 | low: 0,
16 | high: 12,
17 | assessment: 'bad'
18 | },
19 |
20 | {
21 | low: 12,
22 | high: 16,
23 | assessment: 'good'
24 | },
25 | {
26 | low: 16,
27 | high: 20,
28 | assessment: 'bad'
29 | }
30 | ]
31 | };
32 | }
33 | }
--------------------------------------------------------------------------------
/src/summary/metadata/LabTestSubsection.jsx:
--------------------------------------------------------------------------------
1 | import MetadataSection from "./MetadataSection";
2 | import _ from 'lodash';
3 |
4 | export default class LabTestSubsection extends MetadataSection {
5 | getTestsForSubSection = (patient, currentConditionEntry, subsection) => {
6 | if (_.isNull(patient) || _.isNull(currentConditionEntry)) return [];
7 | const labResults = currentConditionEntry.getLabResultsChronologicalOrder();
8 |
9 | return labResults.filter(lab => lab.codeableConceptCode === subsection.code).map((lab) => {
10 | const processedLab = {
11 | start_time: lab.relevantTime,
12 | unit: lab.quantity.unit
13 | };
14 |
15 | processedLab[subsection.name] = lab.quantity.number;
16 |
17 | return processedLab;
18 | });
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/summary/metadata/McodeMetadata.jsx:
--------------------------------------------------------------------------------
1 | import MetadataSection from "./MetadataSection";
2 | import GeneralCancerSummarySection from './GeneralCancerSummarySection';
3 | import DetailedTreatmentOptionsSection from './DetailedTreatmentOptionsSection';
4 | import DiseaseStatusSection from './DiseaseStatusSection';
5 | import ProceduresSection from './ProceduresSection';
6 | import MedicationsSection from './MedicationsSection';
7 | import ActiveConditionsSection from "./ActiveConditionsSection";
8 |
9 | export default class McodeMetadata extends MetadataSection {
10 | getMetadata(preferencesManager, patient, condition, roleType, role, specialty) {
11 | return { // sarcoma
12 | sections: this.buildMetadataSections(preferencesManager, patient, condition, roleType, role, specialty,
13 | GeneralCancerSummarySection,
14 | ActiveConditionsSection,
15 | MedicationsSection,
16 | ProceduresSection,
17 | DiseaseStatusSection,
18 | DetailedTreatmentOptionsSection
19 | )
20 | };
21 | }
22 | }
--------------------------------------------------------------------------------
/src/summary/metadata/NeutrophilCountSubsection.jsx:
--------------------------------------------------------------------------------
1 | import LabTestSubsection from "./LabTestSubsection";
2 |
3 | export default class NeutrophilCountSubsection extends LabTestSubsection {
4 | getMetadata(preferencesManager, patient, condition, roleType, role, specialty) {
5 | return {
6 | name: "Neutrophil count",
7 | code: "C0027950",
8 | itemsFunction: this.getTestsForSubSection,
9 | displayChartLine: false,
10 |
11 | // Source: https://www.healthline.com/health/neutrophils#anc
12 | // Source: https://evs.nci.nih.gov/ftp1/CTCAE/CTCAE_4.03_2010-06-14_QuickReference_8.5x11.pdf page 42
13 | bands: [
14 | {
15 | low: 0,
16 | high: 1,
17 | assessment: 'bad'
18 | },
19 | {
20 | low: 1,
21 | high: 8,
22 | assessment: 'good'
23 | },
24 | {
25 | low: 8,
26 | // Only draws if an element is captured in this range
27 | high: 'max',
28 | assessment: 'bad'
29 | }
30 | ]
31 | };
32 | }
33 | }
--------------------------------------------------------------------------------
/src/summary/metadata/Pilot2MvpMetadata.jsx:
--------------------------------------------------------------------------------
1 | import MetadataSection from './MetadataSection';
2 | import SarcomaSummarySection from './SarcomaSummarySection';
3 | import TimelineSection from './TimelineSection';
4 |
5 | export default class Pilot2MvpMetadata extends MetadataSection {
6 | getMetadata(preferencesManager, patient, condition, roleType, role, specialty) {
7 | return {
8 | sections: this.buildMetadataSections(preferencesManager, patient, condition, roleType, role, specialty,
9 | SarcomaSummarySection,
10 | TimelineSection
11 | )
12 | };
13 | }
14 | }
--------------------------------------------------------------------------------
/src/summary/metadata/PlateletSubsection.jsx:
--------------------------------------------------------------------------------
1 | import LabTestSubsection from "./LabTestSubsection";
2 |
3 | export default class PlateletSubsection extends LabTestSubsection {
4 | getMetadata(preferencesManager, patient, condition, roleType, role, specialty) {
5 | return {
6 | name: "Platelet count",
7 | code: "C0005821",
8 | itemsFunction: this.getTestsForSubSection,
9 | displayChartLine: false,
10 |
11 | bands: [
12 | {
13 | low: 0,
14 | high: 150,
15 | assessment: 'bad'
16 | },
17 |
18 | {
19 | low: 150,
20 | high: 450,
21 | assessment: 'good'
22 | },
23 | {
24 | low: 450,
25 | high: 'max',
26 | assessment: 'bad'
27 | }
28 | ]
29 | };
30 | }
31 | }
--------------------------------------------------------------------------------
/src/summary/metadata/RecentLabResultsSubsection.jsx:
--------------------------------------------------------------------------------
1 | import MetadataSection from './MetadataSection';
2 | import _ from 'lodash';
3 | import moment from 'moment';
4 |
5 | export default class RecentLabResultsSubsection extends MetadataSection {
6 | getMetadata(preferencesManager, patient, condition, roleType, role, specialty) {
7 | return {
8 | name: "Recent Labs (last 6 Months)",
9 | itemsFunction: this.getItemListForLabResults
10 | };
11 | }
12 |
13 | getItemListForLabResults = (patient, currentConditionEntry) => {
14 | if (_.isNull(patient) || _.isNull(currentConditionEntry)) return [];
15 |
16 | // set a const for the number of months that dictates most recent lab results
17 | const numberOfMonths = 6;
18 | const labResultsInOrder = currentConditionEntry.getLabResultsChronologicalOrder(moment().subtract(numberOfMonths, 'months'));
19 |
20 | return labResultsInOrder.map((l, i) => {
21 | const value = `${l.quantity.number} ${l.quantity.unit} (${l.relevantTime})`;
22 | const name = `${l.name}`;
23 | return { name: name,
24 | value: {value},
25 | shortcut: null
26 | };
27 | });
28 | }
29 | }
--------------------------------------------------------------------------------
/src/summary/metadata/SarcomaCompassAppMetadata.jsx:
--------------------------------------------------------------------------------
1 | import MetadataSection from "./MetadataSection";
2 | import SarcomaSummarySection from './SarcomaSummarySection';
3 | import DetailedTreatmentOptionsSection from './DetailedTreatmentOptionsSection';
4 |
5 | export default class SarcomaCompassAppMetadata extends MetadataSection {
6 | getMetadata(preferencesManager, patient, condition, roleType, role, specialty) {
7 | return { // sarcoma
8 | sections: this.buildMetadataSections(preferencesManager, patient, condition, roleType, role, specialty,
9 | SarcomaSummarySection,
10 | DetailedTreatmentOptionsSection
11 | )
12 | };
13 | }
14 | }
--------------------------------------------------------------------------------
/src/summary/metadata/SarcomaLabsSection.jsx:
--------------------------------------------------------------------------------
1 | import MetadataSection from "./MetadataSection";
2 | import WhiteBloodCellCountSubsection from './WhiteBloodCellCountSubsection';
3 | import NeutrophilCountSubsection from "./NeutrophilCountSubsection";
4 | import HemoglobinSubsection from "./HemoglobinSubsection";
5 | import PlateletSubsection from "./PlateletSubsection";
6 |
7 | export default class SarcomaLabsSection extends MetadataSection {
8 | getMetadata(preferencesManager, patient, condition, roleType, role, specialty) {
9 | return {
10 | name: "Labs",
11 | shortName: "Labs",
12 | subsectionLabel: "Lab Name",
13 | clinicalEvents: ["pre-encounter"],
14 | type: "ValueOverTime",
15 | data: [
16 | WhiteBloodCellCountSubsection,
17 | NeutrophilCountSubsection,
18 | HemoglobinSubsection,
19 | PlateletSubsection,
20 | ]
21 | };
22 | }
23 | }
--------------------------------------------------------------------------------
/src/summary/metadata/TemperatureSubsection.jsx:
--------------------------------------------------------------------------------
1 | import VitalsSubsection from './VitalsSubsection';
2 |
3 | export default class TemperatureSubsection extends VitalsSubsection {
4 | getMetadata(preferencesManager, patient, condition, roleType, role, specialty) {
5 | return {
6 | name: "Temperature",
7 | code: "8310-5",
8 | itemsFunction: this.getVitalsForSubsection,
9 | displayChartLine: false,
10 |
11 | // Source: https://medlineplus.gov/ency/article/001982.htm#start
12 | bands: [
13 | {
14 | low: 85,
15 | high: 97,
16 | assessment: 'bad'
17 | },
18 |
19 | {
20 | low: 97,
21 | high: 99,
22 | assessment: 'good'
23 | },
24 | {
25 | low: 99,
26 | high: 105,
27 | assessment: 'bad'
28 | }
29 | ]
30 | };
31 | }
32 | }
--------------------------------------------------------------------------------
/src/summary/metadata/VitalsSection.jsx:
--------------------------------------------------------------------------------
1 | import MetadataSection from "./MetadataSection";
2 | import BloodPressureSubsection from './BloodPressureSubsection';
3 | import TemperatureSubsection from './TemperatureSubsection';
4 | import WeightSubsection from './WeightSubsection';
5 | import HeartRateSubsection from './HeartRateSubsection';
6 |
7 | export default class VitalsSection extends MetadataSection {
8 | getMetadata(preferencesManager, patient, condition, roleType, role, specialty) {
9 | return {
10 | name: "Vitals",
11 | shortName: "Vitals",
12 | subsectionLabel: "Vital Name",
13 | clinicalEvents: ["pre-encounter"],
14 | type: "ValueOverTime",
15 | data: [
16 | BloodPressureSubsection,
17 | TemperatureSubsection,
18 | WeightSubsection,
19 | HeartRateSubsection
20 | ],
21 | };
22 | }
23 | }
--------------------------------------------------------------------------------
/src/summary/metadata/VitalsSubsection.jsx:
--------------------------------------------------------------------------------
1 | import MetadataSection from "./MetadataSection";
2 | import Lang from 'lodash';
3 |
4 | export default class VitalsSubsection extends MetadataSection {
5 | getVitalsForSubsection = (patient, currentConditionEntry, subsection) => {
6 | if (Lang.isNull(patient) || Lang.isNull(currentConditionEntry)) return [];
7 | return patient.getVitalByCode(subsection.code)
8 | .map(v => {
9 | const processedVital = {};
10 |
11 | processedVital["start_time"] = v.relevantTime;
12 | processedVital[subsection.name] = v.value;
13 | processedVital["unit"] = v.units;
14 |
15 | return processedVital;
16 | });
17 | }
18 | }
--------------------------------------------------------------------------------
/src/summary/metadata/WeightSubsection.jsx:
--------------------------------------------------------------------------------
1 | import VitalsSubsection from './VitalsSubsection';
2 |
3 | export default class WeightSubsection extends VitalsSubsection {
4 | getMetadata(preferencesManager, patient, condition, roleType, role, specialty) {
5 | return {
6 | name: "Weight",
7 | code: "29463-7",
8 | itemsFunction: this.getVitalsForSubsection,
9 | displayChartLine: false,
10 |
11 | // Source: https://www.healthline.com/health/mens-health/average-weight-for-men
12 | bands: [
13 | {
14 | low: 120,
15 | high: 135,
16 | assessment: 'bad'
17 | },
18 |
19 | {
20 | low: 135,
21 | high: 180,
22 | assessment: 'good'
23 | },
24 | {
25 | low: 180,
26 | high: 250,
27 | assessment: 'bad'
28 | }
29 | ]
30 | };
31 | }
32 | }
--------------------------------------------------------------------------------
/src/summary/metadata/WhiteBloodCellCountSubsection.jsx:
--------------------------------------------------------------------------------
1 | import LabTestSubsection from "./LabTestSubsection";
2 |
3 | export default class WhiteBloodCellCountSubsection extends LabTestSubsection {
4 | getMetadata(preferencesManager, patient, condition, roleType, role, specialty) {
5 | return {
6 | name: "White blood cell count",
7 | code: "C0023508",
8 | itemsFunction: this.getTestsForSubSection,
9 | displayChartLine: false,
10 |
11 | // Source: https://www.cancer.org/treatment/understanding-your-diagnosis/tests/understanding-your-lab-test-results.html
12 | // Source: https://www.mayoclinic.org/symptoms/low-white-blood-cell-count/basics/definition/sym-20050615
13 | bands: [
14 | { low: 0, high: 3, assessment: 'bad' },
15 | { low: 3, high: 10, assessment: 'good' },
16 | { low: 10, high: 'max', assessment: 'bad' }
17 | ]
18 | };
19 |
20 | }
21 | }
--------------------------------------------------------------------------------
/src/templates/TemplateOptionPreviewButton.jsx:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import RemoveRedEye from 'material-ui-icons/RemoveRedEye';
3 | import "./TemplateOptionPreviewButton.css";
4 |
5 | export default class TemplateOptionPreviewButton extends Component {
6 | handleClick = (e) => {
7 | // stops note from opening and instead only shows note preview popover
8 | e.stopPropagation();
9 | this.props.onClick();
10 | }
11 |
12 | render() {
13 | return (
14 |
15 |
16 |
17 | );
18 | }
19 | }
--------------------------------------------------------------------------------
/src/templates/TemplateOptionPreviewButton.scss:
--------------------------------------------------------------------------------
1 | @import '../styles/variables';
2 |
3 | .template-preview-button {
4 | position: absolute;
5 | bottom: 0;
6 | right: 0;
7 | display: flex;
8 | padding: 2px 5px;
9 | border: 1px $line-gray solid;
10 | border-top-left-radius: 5px;
11 | border-bottom: 0px;
12 | border-right: 0px;
13 | svg > * {
14 | fill: $icons-gray;
15 | }
16 | &:hover {
17 | cursor: pointer;
18 | background-color: $interface-blue;
19 | svg > * {
20 | fill: $background;
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/timeline/HoverItem.css:
--------------------------------------------------------------------------------
1 | .hover-item {
2 | position: fixed;
3 | background-color: #fff;
4 | border: 1px solid #aaa;
5 | padding: 10px;
6 | min-width: 150px;
7 | z-index: 100;
8 | }
9 |
10 | .hover-item p {
11 | margin: 0;
12 | margin-top: 5px;
13 | padding: 0;
14 | font-size: 14px;
15 | }
16 |
--------------------------------------------------------------------------------
/src/timeline/HoverItem.jsx:
--------------------------------------------------------------------------------
1 | import React, {Component} from 'react';
2 | import PropTypes from 'prop-types';
3 | import Paper from 'material-ui/Paper';
4 | import './HoverItem.css';
5 |
6 | class HoverItem extends Component {
7 | render() {
8 | const style = this.props.style;
9 | return (
10 |
11 | {this.props.title}
12 | {this.props.text}
13 |
14 | );
15 | }
16 | }
17 |
18 | HoverItem.propTypes = {
19 | title: PropTypes.string,
20 | text: PropTypes.string
21 | };
22 |
23 | export default HoverItem;
24 |
--------------------------------------------------------------------------------
/src/timeline/Item.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 |
4 | // Item provides custom rendering of the the content of a timeline item.
5 | // Items may have any combination of:
6 | // icon - a font-awesome icon to display before the title
7 | // title - a title to display
8 | // details - additional information to display next to the title
9 | function Item({ item }) {
10 | let icon = null;
11 | let details = null;
12 |
13 | if (item.icon) {
14 | icon = (
15 |
16 |
17 |
18 | );
19 | }
20 |
21 | if (item.details) {
22 | details = (
23 |
24 | | {item.details}
25 |
26 | );
27 | }
28 |
29 | const itemId = `timeline-item-${item.id}`;
30 |
31 | return (
32 |
33 | {icon}
34 | {item.title}
35 | {details}
36 |
37 | );
38 | };
39 |
40 | Item.propTypes = {
41 | item: PropTypes.object.isRequired
42 | };
43 |
44 | export default Item;
--------------------------------------------------------------------------------
/src/timeline/TimelineLegend.css:
--------------------------------------------------------------------------------
1 | .legend {
2 | margin-top: 10px;
3 | font-size: 14px;
4 | }
5 |
6 | .legend-icon {
7 | text-align: center;
8 | min-width: 30px;
9 | }
10 |
--------------------------------------------------------------------------------
/src/timeline/TimelineLegend.jsx:
--------------------------------------------------------------------------------
1 | import React, {Component} from 'react';
2 | import PropTypes from 'prop-types';
3 | import './TimelineLegend.css';
4 |
5 | class Legend extends Component {
6 | render() {
7 | return (
8 |
9 | {this.props.items.map((item, i) => {
10 | return (
11 |
: {item.description}
12 | );
13 | })}
14 |
15 | );
16 | }
17 | }
18 |
19 | Legend.propTypes = {
20 | items: PropTypes.arrayOf(PropTypes.shape({
21 | icon: PropTypes.string,
22 | description: PropTypes.string
23 | })),
24 | };
25 |
26 | export default Legend;
--------------------------------------------------------------------------------
/src/timeline/util.js:
--------------------------------------------------------------------------------
1 | // utils/supportsSticky
2 | const supportsSticky = (() => {
3 | const node = document.createElement('div');
4 | node.style.position = 'sticky';
5 | return node.style.position === 'sticky';
6 | })();
7 |
8 | export default supportsSticky;
--------------------------------------------------------------------------------