moved connected sources list to its own component.

adding medical sources filter component for left menu with pipe for code => category name.
filter component can exand and shrink wiht animations

TODO: clear checkbox list when query changes.
This commit is contained in:
Jason Kulatunga 2023-05-08 22:11:21 -07:00
parent 551c7cbd42
commit 4c680a6c42
16 changed files with 1821 additions and 1313 deletions

View File

@ -0,0 +1,57 @@
<h2 class="az-content-title">Connected Sources</h2>
<div *ngIf="!loading else isLoadingTemplate" class="row">
<div *ngFor="let sourceInfo of connectedSourceList" class="col-sm-3 mg-b-20 px-3">
<div class="card h-100 d-flex align-items-center justify-content-center mt-3 mt-3 rounded-0 cursor-pointer">
<div (click)="openModal(contentModalRef, sourceInfo)" class="card-body">
<div class="h-100 d-flex align-items-center">
<img [src]="'assets/sources/'+(sourceInfo.metadata.brand_logo ? sourceInfo.metadata.brand_logo : sourceInfo.metadata.source_type+'.png')" [alt]="sourceInfo?.metadata.display" class="img-fluid">
</div>
<div *ngIf="status[sourceInfo.metadata?.source_type]" class="progress">
<div [style.width]="status[sourceInfo?.metadata?.source_type] == 'authorize' ? '33%' : '66%'" class="bg-indigo progress-bar progress-bar-striped progress-bar-animated" role="progressbar"></div>
</div>
</div>
<div class="card-footer text-center p-1" style="width:100%">
<small class="tx-gray-700">
{{sourceInfo?.metadata.display}}
</small>
</div>
</div>
</div>
</div>
<ng-template #contentModalRef let-modal>
<div class="modal-header">
<h4 class="modal-title" id="modal-basic-title">{{modalSelectedSourceListItem?.metadata["display"]}}</h4>
<button type="button" class="btn btn-close" aria-label="Close" (click)="modal.dismiss('Cross click')">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<h6>Manage Source</h6>
<p>Existing connections can be "Synced", "Reconnected" or "Deleted"</p>
<ul>
<li><p><strong>Sync</strong> - Download all resources from this healthcare provider, storing them securely in Fasten</p></li>
<li><p><strong>Reconnect</strong> - If your healthcare connection has expired, you can use this button to reconnect</p></li>
<li><p><strong>Delete</strong> - Delete all resources for this healthcare provider. This will ONLY effect data stored in Fasten</p></li>
</ul>
</div>
<div class="modal-footer">
<button (click)="sourceSyncHandler(modalSelectedSourceListItem.source)" type="button" class="btn btn-indigo">Sync</button>
<!-- <button (click)="connectHandler($event, modalSelectedSourceListItem.source['source_type'])" type="button" class="btn btn-outline-light">Reconnect</button>-->
<button type="button" class="btn btn-outline-danger">Delete</button>
<button (click)="modal.dismiss('Close click')" type="button" class="btn btn-outline-light">Close</button>
</div>
</ng-template>
<ng-template #isLoadingTemplate>
<div class="row">
<div class="col-12">
<app-loading-spinner [loadingTitle]="'Please wait, loading sources...'"></app-loading-spinner>
</div>
</div>
</ng-template>

View File

@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { MedicalSourcesConnectedComponent } from './medical-sources-connected.component';
describe('MedicalSourcesConnectedComponent', () => {
let component: MedicalSourcesConnectedComponent;
let fixture: ComponentFixture<MedicalSourcesConnectedComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ MedicalSourcesConnectedComponent ]
})
.compileComponents();
fixture = TestBed.createComponent(MedicalSourcesConnectedComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,89 @@
import {Component, Input, OnInit} from '@angular/core';
import {Source} from '../../models/fasten/source';
import {SourceListItem} from '../../pages/medical-sources/medical-sources.component';
import {ModalDismissReasons, NgbModal} from '@ng-bootstrap/ng-bootstrap';
import {FastenApiService} from '../../services/fasten-api.service';
import {forkJoin} from 'rxjs';
import {LighthouseService} from '../../services/lighthouse.service';
@Component({
selector: 'app-medical-sources-connected',
templateUrl: './medical-sources-connected.component.html',
styleUrls: ['./medical-sources-connected.component.scss']
})
export class MedicalSourcesConnectedComponent implements OnInit {
loading: boolean = false
status: { [name: string]: string } = {}
modalSelectedSourceListItem:SourceListItem = null;
modalCloseResult = '';
connectedSourceList: SourceListItem[] = [] //source's are populated for this list
constructor(
private lighthouseApi: LighthouseService,
private fastenApi: FastenApiService,
private modalService: NgbModal,
) { }
ngOnInit(): void {
this.loading = true
this.fastenApi.getSources().subscribe(results => {
this.loading = false
//handle connected sources sources
const connectedSources = results as Source[]
forkJoin(connectedSources.map((source) => this.lighthouseApi.getLighthouseSource(source.source_type))).subscribe((connectedMetadata) => {
for(const ndx in connectedSources){
this.connectedSourceList.push({source: connectedSources[ndx], metadata: connectedMetadata[ndx]})
}
})
})
}
public openModal(contentModalRef, sourceListItem: SourceListItem) {
if(this.status[sourceListItem.metadata.source_type] || !sourceListItem.source){
//if this source is currently "loading" dont open the modal window
return
}
this.modalSelectedSourceListItem = sourceListItem
this.modalService.open(contentModalRef, {ariaLabelledBy: 'modal-basic-title'}).result.then((result) => {
this.modalSelectedSourceListItem = null
this.modalCloseResult = `Closed with: ${result}`;
}, (reason) => {
this.modalSelectedSourceListItem = null
this.modalCloseResult = `Dismissed ${this.getDismissReason(reason)}`;
});
}
public sourceSyncHandler(source: Source){
this.status[source.source_type] = "authorize"
this.modalService.dismissAll()
this.fastenApi.syncSource(source.id).subscribe(
(respData) => {
delete this.status[source.source_type]
console.log("source sync response:", respData)
},
(err) => {
delete this.status[source.source_type]
console.log(err)
}
)
}
private getDismissReason(reason: any): string {
if (reason === ModalDismissReasons.ESC) {
return 'by pressing ESC';
} else if (reason === ModalDismissReasons.BACKDROP_CLICK) {
return 'by clicking on a backdrop';
} else {
return `with: ${reason}`;
}
}
}

View File

@ -0,0 +1,8 @@
import { MedicalSourcesCategoryLookupPipe } from './medical-sources-category-lookup.pipe';
describe('MedicalSourcesCategoryLookupPipe', () => {
it('create an instance', () => {
const pipe = new MedicalSourcesCategoryLookupPipe();
expect(pipe).toBeTruthy();
});
});

View File

@ -0,0 +1,892 @@
import { Pipe, PipeTransform } from '@angular/core';
@Pipe({
name: 'medicalSourcesCategoryLookup'
})
export class MedicalSourcesCategoryLookupPipe implements PipeTransform {
transform(categoryCode: string, ...args: unknown[]): string {
if (!categoryCode){
return null;
}
let lookupDescription = SOURCE_CATEGORY_CODE_LOOKUP[categoryCode];
if (!lookupDescription){
console.log("COULD NOT FIND CATEGORY CODE", categoryCode, "IN LOOKUP")
return categoryCode;
} else {
return lookupDescription;
}
}
}
const SOURCE_CATEGORY_CODE_LOOKUP = {
"101200000X": "Drama Therapist",
"101Y00000X": "Counselor",
"101YA0400X": "Addiction (Substance Use Disorder) Counselor",
"101YM0800X": "Mental Health Counselor",
"101YP1600X": "Pastoral Counselor",
"101YP2500X": "Professional Counselor",
"101YS0200X": "School Counselor",
"102L00000X": "Psychoanalyst",
"102X00000X": "Poetry Therapist",
"103G00000X": "Clinical Neuropsychologist",
"103GC0700X": "Deactivated - Clinical Neuropsychologist",
"103K00000X": "Behavioral Analyst",
"103T00000X": "Psychologist",
"103TA0400X": "Addiction (Substance Use Disorder) Psychologist",
"103TA0700X": "Adult Development & Aging Psychologist",
"103TB0200X": "Cognitive & Behavioral Psychologist",
"103TC0700X": "Clinical Psychologist",
"103TC1900X": "Counseling Psychologist",
"103TC2200X": "Clinical Child & Adolescent Psychologist",
"103TE1000X": "Deactivated - Psychologist",
"103TE1100X": "Exercise & Sports Psychologist",
"103TF0000X": "Family Psychologist",
"103TF0200X": "Forensic Psychologist",
"103TH0004X": "Health Psychologist",
"103TH0100X": "Health Service Psychologist",
"103TM1700X": "Deactivated - Psychologist Men & Masculinity",
"103TM1800X": "Intellectual & Developmental Disabilities Psychologist",
"103TP0016X": "Prescribing (Medical) Psychologist",
"103TP0814X": "Psychoanalysis Psychologist",
"103TP2700X": "Deactivated - Psychologist Psychotherapy",
"103TP2701X": "Group Psychotherapy Psychologist",
"103TR0400X": "Rehabilitation Psychologist",
"103TS0200X": "School Psychologist",
"103TW0100X": "Deactivated - Psychotherapy Women",
"104100000X": "Social Worker",
"1041C0700X": "Clinical Social Worker",
"1041S0200X": "School Social Worker",
"106E00000X": "Assistant Behavior Analyst",
"106H00000X": "Marriage & Family Therapist",
"106S00000X": "Behavior Technician",
"111N00000X": "Chiropractor",
"111NI0013X": "Independent Medical Examiner Chiropractor",
"111NI0900X": "Internist Chiropractor",
"111NN0400X": "Neurology Chiropractor",
"111NN1001X": "Nutrition Chiropractor",
"111NP0017X": "Pediatric Chiropractor",
"111NR0200X": "Radiology Chiropractor",
"111NR0400X": "Rehabilitation Chiropractor",
"111NS0005X": "Sports Physician Chiropractor",
"111NT0100X": "Thermography Chiropractor",
"111NX0100X": "Occupational Health Chiropractor",
"111NX0800X": "Orthopedic Chiropractor",
"122300000X": "Dentist",
"1223D0001X": "Public Health Dentist",
"1223D0004X": "Dentist Anesthesiologist",
"1223E0200X": "Endodontist",
"1223G0001X": "General Practice Dentistry",
"1223P0106X": "Oral and Maxillofacial Pathology Dentist",
"1223P0221X": "Pediatric Dentist",
"1223P0300X": "Periodontist",
"1223P0700X": "Prosthodontist",
"1223S0112X": "Oral and Maxillofacial Surgery (Dentist)",
"1223X0008X": "Oral and Maxillofacial Radiology Dentist",
"1223X0400X": "Orthodontics and Dentofacial Orthopedic Dentist",
"1223X2210X": "Orofacial Pain Dentist",
"122400000X": "Denturist",
"124Q00000X": "Dental Hygienist",
"125J00000X": "Dental Therapist",
"125K00000X": "Advanced Practice Dental Therapist",
"125Q00000X": "Oral Medicinist",
"126800000X": "Dental Assistant",
"126900000X": "Dental Laboratory Technician",
"132700000X": "Dietary Manager",
"133N00000X": "Nutritionist",
"133NN1002X": "Nutrition Education Nutritionist",
"133V00000X": "Registered Dietitian",
"133VN1004X": "Pediatric Nutrition Registered Dietitian",
"133VN1005X": "Renal Nutrition Registered Dietitian",
"133VN1006X": "Metabolic Nutrition Registered Dietitian",
"133VN1101X": "Gerontological Nutrition Registered Dietitian",
"133VN1201X": "Obesity and Weight Management Nutrition Registered Dietitian",
"133VN1301X": "Oncology Nutrition Registered Dietitian",
"133VN1401X": "Pediatric Critical Care Nutrition Registered Dietitian",
"133VN1501X": "Sports Dietetics Nutrition Registered Dietitian",
"136A00000X": "Registered Dietetic Technician",
"146D00000X": "Personal Emergency Response Attendant",
"146L00000X": "Paramedic",
"146M00000X": "Intermediate Emergency Medical Technician",
"146N00000X": "Basic Emergency Medical Technician",
"152W00000X": "Optometrist",
"152WC0802X": "Corneal and Contact Management Optometrist",
"152WL0500X": "Low Vision Rehabilitation Optometrist",
"152WP0200X": "Pediatric Optometrist",
"152WS0006X": "Sports Vision Optometrist",
"152WV0400X": "Vision Therapy Optometrist",
"152WX0102X": "Occupational Vision Optometrist",
"156F00000X": "Technician/Technologist",
"156FC0800X": "Contact Lens Technician/Technologist",
"156FC0801X": "Contact Lens Fitter",
"156FX1100X": "Ophthalmic Technician/Technologist",
"156FX1101X": "Ophthalmic Assistant",
"156FX1201X": "Optometric Assistant Technician",
"156FX1202X": "Optometric Technician",
"156FX1700X": "Ocularist",
"156FX1800X": "Optician",
"156FX1900X": "Orthoptist",
"163W00000X": "Registered Nurse",
"163WA0400X": "Addiction (Substance Use Disorder) Registered Nurse",
"163WA2000X": "Administrator Registered Nurse",
"163WC0200X": "Critical Care Medicine Registered Nurse",
"163WC0400X": "Case Management Registered Nurse",
"163WC1400X": "College Health Registered Nurse",
"163WC1500X": "Community Health Registered Nurse",
"163WC1600X": "Continuing Education/Staff Development Registered Nurse",
"163WC2100X": "Continence Care Registered Nurse",
"163WC3500X": "Cardiac Rehabilitation Registered Nurse",
"163WD0400X": "Diabetes Educator Registered Nurse",
"163WD1100X": "Peritoneal Dialysis Registered Nurse",
"163WE0003X": "Emergency Registered Nurse",
"163WE0900X": "Enterostomal Therapy Registered Nurse",
"163WF0300X": "Flight Registered Nurse",
"163WG0000X": "General Practice Registered Nurse",
"163WG0100X": "Gastroenterology Registered Nurse",
"163WG0600X": "Gerontology Registered Nurse",
"163WH0200X": "Home Health Registered Nurse",
"163WH0500X": "Hemodialysis Registered Nurse",
"163WH1000X": "Hospice Registered Nurse",
"163WI0500X": "Infusion Therapy Registered Nurse",
"163WI0600X": "Infection Control Registered Nurse",
"163WL0100X": "Lactation Consultant (Registered Nurse)",
"163WM0102X": "Maternal Newborn Registered Nurse",
"163WM0705X": "Medical-Surgical Registered Nurse",
"163WM1400X": "Nurse Massage Therapist (NMT)",
"163WN0002X": "Neonatal Intensive Care Registered Nurse",
"163WN0003X": "Low-Risk Neonatal Registered Nurse",
"163WN0300X": "Nephrology Registered Nurse",
"163WN0800X": "Neuroscience Registered Nurse",
"163WN1003X": "Nutrition Support Registered Nurse",
"163WP0000X": "Pain Management Registered Nurse",
"163WP0200X": "Pediatric Registered Nurse",
"163WP0218X": "Pediatric Oncology Registered Nurse",
"163WP0807X": "Child & Adolescent Psychiatric/Mental Health Registered Nurse",
"163WP0808X": "Psychiatric/Mental Health Registered Nurse",
"163WP0809X": "Adult Psychiatric/Mental Health Registered Nurse",
"163WP1700X": "Perinatal Registered Nurse",
"163WP2201X": "Ambulatory Care Registered Nurse",
"163WR0006X": "Registered Nurse First Assistant",
"163WR0400X": "Rehabilitation Registered Nurse",
"163WR1000X": "Reproductive Endocrinology/Infertility Registered Nurse",
"163WS0121X": "Plastic Surgery Registered Nurse",
"163WS0200X": "School Registered Nurse",
"163WU0100X": "Urology Registered Nurse",
"163WW0000X": "Wound Care Registered Nurse",
"163WW0101X": "Ambulatory Women's Health Care Registered Nurse",
"163WX0002X": "High-Risk Obstetric Registered Nurse",
"163WX0003X": "Inpatient Obstetric Registered Nurse",
"163WX0106X": "Occupational Health Registered Nurse",
"163WX0200X": "Oncology Registered Nurse",
"163WX0601X": "Otorhinolaryngology & Head-Neck Registered Nurse",
"163WX0800X": "Orthopedic Registered Nurse",
"163WX1100X": "Ophthalmic Registered Nurse",
"163WX1500X": "Ostomy Care Registered Nurse",
"164W00000X": "Licensed Practical Nurse",
"164X00000X": "Licensed Vocational Nurse",
"167G00000X": "Licensed Psychiatric Technician",
"170100000X": "Ph.D. Medical Genetics",
"170300000X": "Genetic Counselor (M.S.)",
"171000000X": "Military Health Care Provider",
"1710I1002X": "Independent Duty Corpsman",
"1710I1003X": "Independent Duty Medical Technicians",
"171100000X": "Acupuncturist",
"171400000X": "Health & Wellness Coach",
"171M00000X": "Case Manager/Care Coordinator",
"171R00000X": "Interpreter",
"171W00000X": "Contractor",
"171WH0202X": "Home Modifications Contractor",
"171WV0202X": "Vehicle Modifications Contractor",
"172A00000X": "Driver",
"172M00000X": "Mechanotherapist",
"172P00000X": "Naprapath",
"172V00000X": "Community Health Worker",
"173000000X": "Legal Medicine",
"173C00000X": "Reflexologist",
"173F00000X": "Sleep Specialist (PhD)",
"174200000X": "Meals Provider",
"174400000X": "Specialist",
"1744G0900X": "Graphics Designer",
"1744P3200X": "Prosthetics Case Management",
"1744R1102X": "Research Study Specialist",
"1744R1103X": "Research Study Abstracter/Coder",
"174H00000X": "Health Educator",
"174M00000X": "Veterinarian",
"174MM1900X": "Medical Research Veterinarian",
"174N00000X": "Lactation Consultant (Non-RN)",
"174V00000X": "Clinical Ethicist",
"175F00000X": "Naturopath",
"175L00000X": "Homeopath",
"175M00000X": "Lay Midwife",
"175T00000X": "Peer Specialist",
"176B00000X": "Midwife",
"176P00000X": "Funeral Director",
"177F00000X": "Lodging Provider",
"183500000X": "Pharmacist",
"1835C0205X": "Critical Care Pharmacist",
"1835G0000X": "Deactivated - Pharmacist",
"1835G0303X": "Geriatric Pharmacist",
"1835N0905X": "Nuclear Pharmacist",
"1835N1003X": "Nutrition Support Pharmacist",
"1835P0018X": "Pharmacist Clinician (PhC)/ Clinical Pharmacy Specialist",
"1835P0200X": "Pediatric Pharmacist",
"1835P1200X": "Pharmacotherapy Pharmacist",
"1835P1300X": "Psychiatric Pharmacist",
"1835P2201X": "Ambulatory Care Pharmacist",
"1835X0200X": "Oncology Pharmacist",
"183700000X": "Pharmacy Technician",
"193200000X": "Multi-Specialty Group",
"193400000X": "Single Specialty Group",
"202C00000X": "Independent Medical Examiner Physician",
"202D00000X": "Integrative Medicine",
"202K00000X": "Phlebology Physician",
"204C00000X": "Sports Medicine (Neuromusculoskeletal Medicine) Physician",
"204D00000X": "Neuromusculoskeletal Medicine & OMM Physician",
"204E00000X": "Oral & Maxillofacial Surgery (D.M.D.)",
"204F00000X": "Transplant Surgery Physician",
"204R00000X": "Electrodiagnostic Medicine Physician",
"207K00000X": "Allergy & Immunology Physician",
"207KA0200X": "Allergy Physician",
"207KI0005X": "Clinical & Laboratory Immunology (Allergy & Immunology) Physician",
"207L00000X": "Anesthesiology Physician",
"207LA0401X": "Addiction Medicine (Anesthesiology) Physician",
"207LC0200X": "Critical Care Medicine (Anesthesiology) Physician",
"207LH0002X": "Hospice and Palliative Medicine (Anesthesiology) Physician",
"207LP2900X": "Pain Medicine (Anesthesiology) Physician",
"207LP3000X": "Pediatric Anesthesiology Physician",
"207N00000X": "Dermatology Physician",
"207ND0101X": "MOHS-Micrographic Surgery Physician",
"207ND0900X": "Dermatopathology Physician",
"207NI0002X": "Clinical & Laboratory Dermatological Immunology Physician",
"207NP0225X": "Pediatric Dermatology Physician",
"207NS0135X": "Procedural Dermatology Physician",
"207P00000X": "Emergency Medicine Physician",
"207PE0004X": "Emergency Medical Services (Emergency Medicine) Physician",
"207PE0005X": "Undersea and Hyperbaric Medicine (Emergency Medicine) Physician",
"207PH0002X": "Hospice and Palliative Medicine (Emergency Medicine) Physician",
"207PP0204X": "Pediatric Emergency Medicine (Emergency Medicine) Physician",
"207PS0010X": "Sports Medicine (Emergency Medicine) Physician",
"207PT0002X": "Medical Toxicology (Emergency Medicine) Physician",
"207Q00000X": "Family Medicine Physician",
"207QA0000X": "Adolescent Medicine (Family Medicine) Physician",
"207QA0401X": "Addiction Medicine (Family Medicine) Physician",
"207QA0505X": "Adult Medicine Physician",
"207QB0002X": "Obesity Medicine (Family Medicine) Physician",
"207QG0300X": "Geriatric Medicine (Family Medicine) Physician",
"207QH0002X": "Hospice and Palliative Medicine (Family Medicine) Physician",
"207QS0010X": "Sports Medicine (Family Medicine) Physician",
"207QS1201X": "Sleep Medicine (Family Medicine) Physician",
"207R00000X": "Internal Medicine Physician",
"207RA0000X": "Adolescent Medicine (Internal Medicine) Physician",
"207RA0001X": "Advanced Heart Failure and Transplant Cardiology Physician",
"207RA0002X": "Adult Congenital Heart Disease Physician",
"207RA0201X": "Allergy & Immunology (Internal Medicine) Physician",
"207RA0401X": "Addiction Medicine (Internal Medicine) Physician",
"207RB0002X": "Obesity Medicine (Internal Medicine) Physician",
"207RC0000X": "Cardiovascular Disease Physician",
"207RC0001X": "Clinical Cardiac Electrophysiology Physician",
"207RC0200X": "Critical Care Medicine (Internal Medicine) Physician",
"207RE0101X": "Endocrinology, Diabetes & Metabolism Physician",
"207RG0100X": "Gastroenterology Physician",
"207RG0300X": "Geriatric Medicine (Internal Medicine) Physician",
"207RH0000X": "Hematology (Internal Medicine) Physician",
"207RH0002X": "Hospice and Palliative Medicine (Internal Medicine) Physician",
"207RH0003X": "Hematology & Oncology Physician",
"207RH0005X": "Hypertension Specialist Physician",
"207RI0001X": "Clinical & Laboratory Immunology (Internal Medicine) Physician",
"207RI0008X": "Hepatology Physician",
"207RI0011X": "Interventional Cardiology Physician",
"207RI0200X": "Infectious Disease Physician",
"207RM1200X": "Magnetic Resonance Imaging (MRI) Internal Medicine Physician",
"207RN0300X": "Nephrology Physician",
"207RP1001X": "Pulmonary Disease Physician",
"207RR0500X": "Rheumatology Physician",
"207RS0010X": "Sports Medicine (Internal Medicine) Physician",
"207RS0012X": "Sleep Medicine (Internal Medicine) Physician",
"207RT0003X": "Transplant Hepatology Physician",
"207RX0202X": "Medical Oncology Physician",
"207SC0300X": "Clinical Cytogenetics Physician",
"207SG0201X": "Clinical Genetics (M.D.) Physician",
"207SG0202X": "Clinical Biochemical Genetics Physician",
"207SG0203X": "Clinical Molecular Genetics Physician",
"207SG0205X": "Ph.D. Medical Genetics Physician",
"207SM0001X": "Molecular Genetic Pathology (Medical Genetics) Physician",
"207T00000X": "Neurological Surgery Physician",
"207U00000X": "Nuclear Medicine Physician",
"207UN0901X": "Nuclear Cardiology Physician",
"207UN0902X": "Nuclear Imaging & Therapy Physician",
"207UN0903X": "In Vivo & In Vitro Nuclear Medicine Physician",
"207V00000X": "Obstetrics & Gynecology Physician",
"207VB0002X": "Obesity Medicine (Obstetrics & Gynecology) Physician",
"207VC0200X": "Critical Care Medicine (Obstetrics & Gynecology) Physician",
"207VC0300X": "Complex Family Planning",
"207VE0102X": "Reproductive Endocrinology Physician",
"207VF0040X": "Female Pelvic Medicine and Reconstructive Surgery (Obstetrics & Gynecology) Physician",
"207VG0400X": "Gynecology Physician",
"207VH0002X": "Hospice and Palliative Medicine (Obstetrics & Gynecology) Physician",
"207VM0101X": "Maternal & Fetal Medicine Physician",
"207VX0000X": "Obstetrics Physician",
"207VX0201X": "Gynecologic Oncology Physician",
"207W00000X": "Ophthalmology Physician",
"207WX0009X": "Glaucoma Specialist (Ophthalmology) Physician",
"207WX0107X": "Retina Specialist (Ophthalmology) Physician",
"207WX0108X": "Uveitis and Ocular Inflammatory Disease (Ophthalmology) Physician",
"207WX0109X": "Neuro-ophthalmology Physician",
"207WX0110X": "Pediatric Ophthalmology and Strabismus Specialist Physician Physician",
"207WX0120X": "Cornea and External Diseases Specialist Physician",
"207WX0200X": "Ophthalmic Plastic and Reconstructive Surgery Physician",
"207X00000X": "Orthopaedic Surgery Physician",
"207XP3100X": "Pediatric Orthopaedic Surgery Physician",
"207XS0106X": "Orthopaedic Hand Surgery Physician",
"207XS0114X": "Adult Reconstructive Orthopaedic Surgery Physician",
"207XS0117X": "Orthopaedic Surgery of the Spine Physician",
"207XX0004X": "Orthopaedic Foot and Ankle Surgery Physician",
"207XX0005X": "Sports Medicine (Orthopaedic Surgery) Physician",
"207XX0801X": "Orthopaedic Trauma Physician",
"207Y00000X": "Otolaryngology Physician",
"207YP0228X": "Pediatric Otolaryngology Physician",
"207YS0012X": "Sleep Medicine (Otolaryngology) Physician",
"207YS0123X": "Facial Plastic Surgery Physician",
"207YX0007X": "Plastic Surgery within the Head & Neck (Otolaryngology) Physician",
"207YX0602X": "Otolaryngic Allergy Physician",
"207YX0901X": "Otology & Neurotology Physician",
"207YX0905X": "Otolaryngology/Facial Plastic Surgery Physician",
"207ZB0001X": "Blood Banking & Transfusion Medicine Physician",
"207ZC0006X": "Clinical Pathology Physician",
"207ZC0008X": "Clinical Informatics (Pathology) Physician",
"207ZC0500X": "Cytopathology Physician",
"207ZD0900X": "Dermatopathology (Pathology) Physician",
"207ZF0201X": "Forensic Pathology Physician",
"207ZH0000X": "Hematology (Pathology) Physician",
"207ZI0100X": "Immunopathology Physician",
"207ZM0300X": "Medical Microbiology Physician",
"207ZN0500X": "Neuropathology Physician",
"207ZP0007X": "Molecular Genetic Pathology (Pathology) Physician",
"207ZP0101X": "Anatomic Pathology Physician",
"207ZP0102X": "Anatomic Pathology & Clinical Pathology Physician",
"207ZP0104X": "Chemical Pathology Physician",
"207ZP0105X": "Clinical Pathology/Laboratory Medicine Physician",
"207ZP0213X": "Pediatric Pathology Physician",
"208000000X": "Pediatrics Physician",
"2080A0000X": "Pediatric Adolescent Medicine Physician",
"2080B0002X": "Pediatric Obesity Medicine Physician",
"2080C0008X": "Child Abuse Pediatrics Physician",
"2080H0002X": "Pediatric Hospice and Palliative Medicine Physician",
"2080I0007X": "Pediatric Clinical & Laboratory Immunology Physician",
"2080N0001X": "Neonatal-Perinatal Medicine Physician",
"2080P0006X": "Developmental - Behavioral Pediatrics Physician",
"2080P0008X": "Pediatric Neurodevelopmental Disabilities Physician",
"2080P0201X": "Pediatric Allergy/Immunology Physician",
"2080P0202X": "Pediatric Cardiology Physician",
"2080P0203X": "Pediatric Critical Care Medicine Physician",
"2080P0204X": "Pediatric Emergency Medicine (Pediatrics) Physician",
"2080P0205X": "Pediatric Endocrinology Physician",
"2080P0206X": "Pediatric Gastroenterology Physician",
"2080P0207X": "Pediatric Hematology & Oncology Physician",
"2080P0208X": "Pediatric Infectious Diseases Physician",
"2080P0210X": "Pediatric Nephrology Physician",
"2080P0214X": "Pediatric Pulmonology Physician",
"2080P0216X": "Pediatric Rheumatology Physician",
"2080S0010X": "Pediatric Sports Medicine Physician",
"2080S0012X": "Pediatric Sleep Medicine Physician",
"2080T0002X": "Pediatric Medical Toxicology Physician",
"2080T0004X": "Pediatric Transplant Hepatology Physician",
"208100000X": "Physical Medicine & Rehabilitation Physician",
"2081H0002X": "Hospice and Palliative Medicine (Physical Medicine & Rehabilitation) Physician",
"2081N0008X": "Neuromuscular Medicine (Physical Medicine & Rehabilitation) Physician",
"2081P0004X": "Spinal Cord Injury Medicine Physician",
"2081P0010X": "Pediatric Rehabilitation Medicine Physician",
"2081P0301X": "Brain Injury Medicine (Physical Medicine & Rehabilitation) Physician",
"2081P2900X": "Pain Medicine (Physical Medicine & Rehabilitation) Physician",
"2081S0010X": "Sports Medicine (Physical Medicine & Rehabilitation) Physician",
"208200000X": "Plastic Surgery Physician",
"2082S0099X": "Plastic Surgery Within the Head and Neck (Plastic Surgery) Physician",
"2082S0105X": "Surgery of the Hand (Plastic Surgery) Physician",
"2083A0100X": "Aerospace Medicine Physician",
"2083A0300X": "Addiction Medicine (Preventive Medicine) Physician",
"2083B0002X": "Obesity Medicine (Preventive Medicine) Physician",
"2083C0008X": "Clinical Informatics Physician",
"2083P0011X": "Undersea and Hyperbaric Medicine (Preventive Medicine) Physician",
"2083P0500X": "Preventive Medicine/Occupational Environmental Medicine Physician",
"2083P0901X": "Public Health & General Preventive Medicine Physician",
"2083S0010X": "Sports Medicine (Preventive Medicine) Physician",
"2083T0002X": "Medical Toxicology (Preventive Medicine) Physician",
"2083X0100X": "Occupational Medicine Physician",
"2084A0401X": "Addiction Medicine (Psychiatry & Neurology) Physician",
"2084A2900X": "Neurocritical Care Physician",
"2084B0002X": "Obesity Medicine (Psychiatry & Neurology) Physician",
"2084B0040X": "Behavioral Neurology & Neuropsychiatry Physician",
"2084D0003X": "Diagnostic Neuroimaging (Psychiatry & Neurology) Physician",
"2084E0001X": "Epilepsy Physician",
"2084F0202X": "Forensic Psychiatry Physician",
"2084H0002X": "Hospice and Palliative Medicine (Psychiatry & Neurology) Physician",
"2084N0008X": "Neuromuscular Medicine (Psychiatry & Neurology) Physician",
"2084N0400X": "Neurology Physician",
"2084N0402X": "Neurology with Special Qualifications in Child Neurology Physician",
"2084N0600X": "Clinical Neurophysiology Physician",
"2084P0005X": "Neurodevelopmental Disabilities Physician Physician",
"2084P0015X": "Psychosomatic Medicine Physician",
"2084P0301X": "Brain Injury Medicine (Psychiatry & Neurology) Physician",
"2084P0800X": "Psychiatry Physician",
"2084P0802X": "Addiction Psychiatry Physician",
"2084P0804X": "Child & Adolescent Psychiatry Physician",
"2084P0805X": "Geriatric Psychiatry Physician",
"2084P2900X": "Pain Medicine (Psychiatry & Neurology) Physician",
"2084S0010X": "Sports Medicine (Psychiatry & Neurology) Physician",
"2084S0012X": "Sleep Medicine (Psychiatry & Neurology) Physician",
"2084V0102X": "Vascular Neurology Physician",
"2085B0100X": "Body Imaging Physician",
"2085D0003X": "Diagnostic Neuroimaging (Radiology) Physician",
"2085H0002X": "Hospice and Palliative Medicine (Radiology) Physician",
"2085N0700X": "Neuroradiology Physician",
"2085N0904X": "Nuclear Radiology Physician",
"2085P0229X": "Pediatric Radiology Physician",
"2085R0001X": "Radiation Oncology Physician",
"2085R0202X": "Diagnostic Radiology Physician",
"2085R0203X": "Therapeutic Radiology Physician",
"2085R0204X": "Vascular & Interventional Radiology Physician",
"2085R0205X": "Radiological Physics Physician",
"2085U0001X": "Diagnostic Ultrasound Physician",
"208600000X": "Surgery Physician",
"2086H0002X": "Hospice and Palliative Medicine (Surgery) Physician",
"2086S0102X": "Surgical Critical Care Physician",
"2086S0105X": "Surgery of the Hand (Surgery) Physician",
"2086S0120X": "Pediatric Surgery Physician",
"2086S0122X": "Plastic and Reconstructive Surgery Physician",
"2086S0127X": "Trauma Surgery Physician",
"2086S0129X": "Vascular Surgery Physician",
"2086X0206X": "Surgical Oncology Physician",
"208800000X": "Urology Physician",
"2088F0040X": "Female Pelvic Medicine and Reconstructive Surgery (Urology) Physician",
"2088P0231X": "Pediatric Urology Physician",
"208C00000X": "Colon & Rectal Surgery Physician",
"208D00000X": "General Practice Physician",
"208G00000X": "Thoracic Surgery (Cardiothoracic Vascular Surgery) Physician",
"208M00000X": "Hospitalist Physician",
"208U00000X": "Clinical Pharmacology Physician",
"208VP0000X": "Pain Medicine Physician",
"208VP0014X": "Interventional Pain Medicine Physician",
"209800000X": "Legal Medicine (M.D./D.O.) Physician",
"211D00000X": "Podiatric Assistant",
"213E00000X": "Podiatrist",
"213EG0000X": "Deactivated - Podiatrist",
"213EP0504X": "Public Medicine Podiatrist",
"213EP1101X": "Primary Podiatric Medicine Podiatrist",
"213ER0200X": "Radiology Podiatrist",
"213ES0000X": "Sports Medicine Podiatrist",
"213ES0103X": "Foot & Ankle Surgery Podiatrist",
"213ES0131X": "Foot Surgery Podiatrist",
"221700000X": "Art Therapist",
"222Q00000X": "Developmental Therapist",
"222Z00000X": "Orthotist",
"224900000X": "Mastectomy Fitter",
"224L00000X": "Pedorthist",
"224P00000X": "Prosthetist",
"224Y00000X": "Clinical Exercise Physiologist",
"224Z00000X": "Occupational Therapy Assistant",
"224ZE0001X": "Environmental Modification Occupational Therapy Assistant",
"224ZF0002X": "Feeding, Eating & Swallowing Occupational Therapy Assistant",
"224ZL0004X": "Low Vision Occupational Therapy Assistant",
"224ZR0403X": "Driving and Community Mobility Occupational Therapy Assistant",
"225000000X": "Orthotic Fitter",
"225100000X": "Physical Therapist",
"2251C2600X": "Cardiopulmonary Physical Therapist",
"2251E1200X": "Ergonomics Physical Therapist",
"2251E1300X": "Clinical Electrophysiology Physical Therapist",
"2251G0304X": "Geriatric Physical Therapist",
"2251H1200X": "Hand Physical Therapist",
"2251H1300X": "Human Factors Physical Therapist",
"2251N0400X": "Neurology Physical Therapist",
"2251P0200X": "Pediatric Physical Therapist",
"2251S0007X": "Sports Physical Therapist",
"2251X0800X": "Orthopedic Physical Therapist",
"225200000X": "Physical Therapy Assistant",
"225400000X": "Rehabilitation Practitioner",
"225500000X": "Respiratory/Developmental/Rehabilitative Specialist/Technologist",
"2255A2300X": "Athletic Trainer",
"2255R0406X": "Blind Rehabilitation Specialist/Technologist",
"225600000X": "Dance Therapist",
"225700000X": "Massage Therapist",
"225800000X": "Recreation Therapist",
"225A00000X": "Music Therapist",
"225B00000X": "Pulmonary Function Technologist",
"225C00000X": "Rehabilitation Counselor",
"225CA2400X": "Assistive Technology Practitioner Rehabilitation Counselor",
"225CA2500X": "Assistive Technology Supplier Rehabilitation Counselor",
"225CX0006X": "Orientation and Mobility Training Rehabilitation Counselor",
"225X00000X": "Occupational Therapist",
"225XE0001X": "Environmental Modification Occupational Therapist",
"225XE1200X": "Ergonomics Occupational Therapist",
"225XF0002X": "Feeding, Eating & Swallowing Occupational Therapist",
"225XG0600X": "Gerontology Occupational Therapist",
"225XH1200X": "Hand Occupational Therapist",
"225XH1300X": "Human Factors Occupational Therapist",
"225XL0004X": "Low Vision Occupational Therapist",
"225XM0800X": "Mental Health Occupational Therapist",
"225XN1300X": "Neurorehabilitation Occupational Therapist",
"225XP0019X": "Physical Rehabilitation Occupational Therapist",
"225XP0200X": "Pediatric Occupational Therapist",
"225XR0403X": "Driving and Community Mobility Occupational Therapist",
"226000000X": "Recreational Therapist Assistant",
"226300000X": "Kinesiotherapist",
"227800000X": "Certified Respiratory Therapist",
"2278C0205X": "Critical Care Certified Respiratory Therapist",
"2278E0002X": "Emergency Care Certified Respiratory Therapist",
"2278E1000X": "Educational Certified Respiratory Therapist",
"2278G0305X": "Geriatric Care Certified Respiratory Therapist",
"2278G1100X": "General Care Certified Respiratory Therapist",
"2278H0200X": "Home Health Certified Respiratory Therapist",
"2278P1004X": "Pulmonary Diagnostics Certified Respiratory Therapist",
"2278P1005X": "Pulmonary Rehabilitation Certified Respiratory Therapist",
"2278P1006X": "Pulmonary Function Technologist Certified Respiratory Therapist",
"2278P3800X": "Palliative/Hospice Certified Respiratory Therapist",
"2278P3900X": "Neonatal/Pediatric Certified Respiratory Therapist",
"2278P4000X": "Patient Transport Certified Respiratory Therapist",
"2278S1500X": "SNF/Subacute Care Certified Respiratory Therapist",
"227900000X": "Registered Respiratory Therapist",
"2279C0205X": "Critical Care Registered Respiratory Therapist",
"2279E0002X": "Emergency Care Registered Respiratory Therapist",
"2279E1000X": "Educational Registered Respiratory Therapist",
"2279G0305X": "Geriatric Care Registered Respiratory Therapist",
"2279G1100X": "General Care Registered Respiratory Therapist",
"2279H0200X": "Home Health Registered Respiratory Therapist",
"2279P1004X": "Pulmonary Diagnostics Registered Respiratory Therapist",
"2279P1005X": "Pulmonary Rehabilitation Registered Respiratory Therapist",
"2279P1006X": "Pulmonary Function Technologist Registered Respiratory Therapist",
"2279P3800X": "Palliative/Hospice Registered Respiratory Therapist",
"2279P3900X": "Neonatal/Pediatric Registered Respiratory Therapist",
"2279P4000X": "Patient Transport Registered Respiratory Therapist",
"2279S1500X": "SNF/Subacute Care Registered Respiratory Therapist",
"229N00000X": "Anaplastologist",
"231H00000X": "Audiologist",
"231HA2400X": "Assistive Technology Practitioner Audiologist",
"231HA2500X": "Assistive Technology Supplier Audiologist",
"235500000X": "Speech/Language/Hearing Specialist/Technologist",
"2355A2700X": "Audiology Assistant",
"2355S0801X": "Speech-Language Assistant",
"235Z00000X": "Speech-Language Pathologist",
"237600000X": "Audiologist-Hearing Aid Fitter",
"237700000X": "Hearing Instrument Specialist",
"242T00000X": "Perfusionist",
"243U00000X": "Radiology Practitioner Assistant",
"246Q00000X": "Pathology Specialist/Technologist",
"246QB0000X": "Blood Banking Specialist/Technologist",
"246QC1000X": "Chemistry Pathology Specialist/Technologist",
"246QC2700X": "Cytotechnology Specialist/Technologist",
"246QH0000X": "Hematology Specialist/Technologist",
"246QH0401X": "Hemapheresis Practitioner",
"246QH0600X": "Histology Specialist/Technologist",
"246QI0000X": "Immunology Pathology Specialist/Technologist",
"246QL0900X": "Laboratory Management Specialist/Technologist",
"246QL0901X": "Diplomate Laboratory Management Specialist/Technologist",
"246QM0706X": "Medical Technologist",
"246QM0900X": "Microbiology Specialist/Technologist",
"246R00000X": "Pathology Technician",
"246RH0600X": "Histology Technician",
"246RM2200X": "Medical Laboratory Technician",
"246RP1900X": "Phlebotomy Technician",
"246W00000X": "Cardiology Technician",
"246X00000X": "Cardiovascular Specialist/Technologist",
"246XC2901X": "Cardiovascular Invasive Specialist/Technologist",
"246XC2903X": "Vascular Specialist/Technologist",
"246XS1301X": "Sonography Specialist/Technologist",
"246Y00000X": "Health Information Specialist/Technologist",
"246YC3301X": "Hospital Based Coding Specialist",
"246YC3302X": "Physician Office Based Coding Specialist",
"246YR1600X": "Registered Record Administrator",
"246Z00000X": "Other Specialist/Technologist",
"246ZA2600X": "Medical Art Specialist/Technologist",
"246ZB0301X": "Biomedical Engineer",
"246ZB0302X": "Biomedical Photographer",
"246ZB0500X": "Biochemist",
"246ZB0600X": "Biostatiscian",
"246ZC0007X": "Surgical Assistant",
"246ZE0500X": "EEG Specialist/Technologist",
"246ZE0600X": "Electroneurodiagnostic Specialist/Technologist",
"246ZG0701X": "Graphics Methods Specialist/Technologist",
"246ZG1000X": "Medical Geneticist (PhD) Specialist/Technologist",
"246ZI1000X": "Medical Illustrator",
"246ZN0300X": "Nephrology Specialist/Technologist",
"246ZS0410X": "Surgical Technologist",
"246ZX2200X": "Orthopedic Assistant",
"247000000X": "Health Information Technician",
"2470A2800X": "Assistant Health Information Record Technician",
"247100000X": "Radiologic Technologist",
"2471B0102X": "Bone Densitometry Radiologic Technologist",
"2471C1101X": "Cardiovascular-Interventional Technology Radiologic Technologist",
"2471C1106X": "Cardiac-Interventional Technology Radiologic Technologist",
"2471C3401X": "Computed Tomography Radiologic Technologist",
"2471C3402X": "Radiography Radiologic Technologist",
"2471M1202X": "Magnetic Resonance Imaging Radiologic Technologist",
"2471M2300X": "Mammography Radiologic Technologist",
"2471N0900X": "Nuclear Medicine Technology Radiologic Technologist",
"2471Q0001X": "Quality Management Radiologic Technologist",
"2471R0002X": "Radiation Therapy Radiologic Technologist",
"2471S1302X": "Sonography Radiologic Technologist",
"2471V0105X": "Vascular Sonography Radiologic Technologist",
"2471V0106X": "Vascular-Interventional Technology Radiologic Technologist",
"247200000X": "Other Technician",
"2472B0301X": "Biomedical Engineering Technician",
"2472D0500X": "Darkroom Technician",
"2472E0500X": "EEG Technician",
"2472R0900X": "Renal Dialysis Technician",
"2472V0600X": "Veterinary Technician",
"247ZC0005X": "Clinical Laboratory Director (Non-physician)",
"251300000X": "Local Education Agency (LEA)",
"251B00000X": "Case Management Agency",
"251C00000X": "Developmentally Disabled Services Day Training Agency",
"251E00000X": "Home Health Agency",
"251F00000X": "Home Infusion Agency",
"251G00000X": "Community Based Hospice Care Agency",
"251J00000X": "Nursing Care Agency",
"251K00000X": "Public Health or Welfare Agency",
"251S00000X": "Community/Behavioral Health Agency",
"251T00000X": "PACE Provider Organization",
"251V00000X": "Voluntary or Charitable Agency",
"251X00000X": "Supports Brokerage Agency",
"252Y00000X": "Early Intervention Provider Agency",
"253J00000X": "Foster Care Agency",
"253Z00000X": "In Home Supportive Care Agency",
"261Q00000X": "Clinic/Center",
"261QA0005X": "Ambulatory Family Planning Facility",
"261QA0006X": "Ambulatory Fertility Facility",
"261QA0600X": "Adult Day Care Clinic/Center",
"261QA0900X": "Amputee Clinic/Center",
"261QA1903X": "Ambulatory Surgical Clinic/Center",
"261QA3000X": "Augmentative Communication Clinic/Center",
"261QB0400X": "Birthing Clinic/Center",
"261QC0050X": "Critical Access Hospital Clinic/Center",
"261QC1500X": "Community Health Clinic/Center",
"261QC1800X": "Corporate Health Clinic/Center",
"261QD0000X": "Dental Clinic/Center",
"261QD1600X": "Developmental Disabilities Clinic/Center",
"261QE0002X": "Emergency Care Clinic/Center",
"261QE0700X": "End-Stage Renal Disease (ESRD) Treatment Clinic/Center",
"261QE0800X": "Endoscopy Clinic/Center",
"261QF0050X": "Non-Surgical Family Planning Clinic/Center",
"261QF0400X": "Federally Qualified Health Center (FQHC)",
"261QG0250X": "Genetics Clinic/Center",
"261QH0100X": "Health Service Clinic/Center",
"261QH0700X": "Hearing and Speech Clinic/Center",
"261QI0500X": "Infusion Therapy Clinic/Center",
"261QL0400X": "Lithotripsy Clinic/Center",
"261QM0801X": "Mental Health Clinic/Center (Including Community Mental Health Center)",
"261QM0850X": "Adult Mental Health Clinic/Center",
"261QM0855X": "Adolescent and Children Mental Health Clinic/Center",
"261QM1000X": "Migrant Health Clinic/Center",
"261QM1100X": "Military/U.S. Coast Guard Outpatient Clinic/Center",
"261QM1101X": "Military and U.S. Coast Guard Ambulatory Procedure Clinic/Center",
"261QM1102X": "Military Outpatient Operational (Transportable) Component Clinic/Center",
"261QM1103X": "Military Ambulatory Procedure Visits Operational (Transportable) Clinic/Center",
"261QM1200X": "Magnetic Resonance Imaging (MRI) Clinic/Center",
"261QM1300X": "Multi-Specialty Clinic/Center",
"261QM2500X": "Medical Specialty Clinic/Center",
"261QM2800X": "Methadone Clinic",
"261QM3000X": "Medically Fragile Infants and Children Day Care",
"261QP0904X": "Federal Public Health Clinic/Center",
"261QP0905X": "State or Local Public Health Clinic/Center",
"261QP1100X": "Podiatric Clinic/Center",
"261QP2000X": "Physical Therapy Clinic/Center",
"261QP2300X": "Primary Care Clinic/Center",
"261QP2400X": "Prison Health Clinic/Center",
"261QP3300X": "Pain Clinic/Center",
"261QR0200X": "Radiology Clinic/Center",
"261QR0206X": "Mammography Clinic/Center",
"261QR0207X": "Mobile Mammography Clinic/Center",
"261QR0208X": "Mobile Radiology Clinic/Center",
"261QR0400X": "Rehabilitation Clinic/Center",
"261QR0401X": "Comprehensive Outpatient Rehabilitation Facility (CORF)",
"261QR0404X": "Cardiac Rehabilitation Clinic/Center",
"261QR0405X": "Substance Use Disorder Rehabilitation Clinic/Center",
"261QR0800X": "Recovery Care Clinic/Center",
"261QR1100X": "Research Clinic/Center",
"261QR1300X": "Rural Health Clinic/Center",
"261QS0112X": "Oral and Maxillofacial Surgery Clinic/Center",
"261QS0132X": "Ophthalmologic Surgery Clinic/Center",
"261QS1000X": "Student Health Clinic/Center",
"261QS1200X": "Sleep Disorder Diagnostic Clinic/Center",
"261QU0200X": "Urgent Care Clinic/Center",
"261QV0200X": "VA Clinic/Center",
"261QX0100X": "Occupational Medicine Clinic/Center",
"261QX0200X": "Oncology Clinic/Center",
"261QX0203X": "Radiation Oncology Clinic/Center",
"273100000X": "Epilepsy Hospital Unit",
"273R00000X": "Psychiatric Hospital Unit",
"273Y00000X": "Rehabilitation Hospital Unit",
"275N00000X": "Medicare Defined Swing Bed Hospital Unit",
"276400000X": "Substance Use Disorder Rehabilitation Hospital Unit",
"281P00000X": "Chronic Disease Hospital",
"281PC2000X": "Children' s Chronic Disease Hospital",
"282E00000X": "Long Term Care Hospital",
"282J00000X": "Religious Nonmedical Health Care Institution",
"282N00000X": "General Acute Care Hospital",
"282NC0060X": "Critical Access Hospital",
"282NC2000X": "Children's Hospital",
"282NR1301X": "Rural Acute Care Hospital",
"282NW0100X": "Women's Hospital",
"283Q00000X": "Psychiatric Hospital",
"283X00000X": "Rehabilitation Hospital",
"283XC2000X": "Children's Rehabilitation Hospital",
"284300000X": "Special Hospital",
"286500000X": "Military Hospital",
"2865C1500X": "Deactivated - Military Hospital",
"2865M2000X": "Military General Acute Care Hospital",
"2865X1600X": "Operational (Transportable) Military General Acute Care Hospital",
"287300000X": "Deactivated - Christian Science Sanitorium",
"291900000X": "Military Clinical Medical Laboratory",
"291U00000X": "Clinical Medical Laboratory",
"292200000X": "Dental Laboratory",
"293D00000X": "Physiological Laboratory",
"302F00000X": "Exclusive Provider Organization",
"302R00000X": "Health Maintenance Organization",
"305R00000X": "Preferred Provider Organization",
"305S00000X": "Point of Service",
"310400000X": "Assisted Living Facility",
"3104A0625X": "Assisted Living Facility (Mental Illness)",
"3104A0630X": "Assisted Living Facility (Behavioral Disturbances)",
"310500000X": "Mental Illness Intermediate Care Facility",
"311500000X": "Alzheimer Center (Dementia Center)",
"311Z00000X": "Custodial Care Facility",
"311ZA0620X": "Adult Care Home Facility",
"313M00000X": "Nursing Facility/Intermediate Care Facility",
"314000000X": "Skilled Nursing Facility",
"3140N1450X": "Pediatric Skilled Nursing Facility",
"315D00000X": "Inpatient Hospice",
"315P00000X": "Intellectual Disabilities Intermediate Care Facility",
"317400000X": "Deactivated - Christian Science Facility",
"320600000X": "Intellectual and/or Developmental Disabilities Residential Treatment Facility",
"320700000X": "Physical Disabilities Residential Treatment Facility",
"320800000X": "Mental Illness Community Based Residential Treatment Facility",
"320900000X": "Intellectual and/or Developmental Disabilities Community Based Residential Treatment Facility",
"322D00000X": "Emotionally Disturbed Childrens' Residential Treatment Facility",
"323P00000X": "Psychiatric Residential Treatment Facility",
"324500000X": "Substance Abuse Rehabilitation Facility",
"3245S0500X": "Children's Substance Abuse Rehabilitation Facility",
"331L00000X": "Blood Bank",
"332000000X": "Military/U.S. Coast Guard Pharmacy",
"332100000X": "Department of Veterans Affairs (VA) Pharmacy",
"332800000X": "Indian Health Service/Tribal/Urban Indian Health (I/T/U) Pharmacy",
"332900000X": "Non-Pharmacy Dispensing Site",
"332B00000X": "Durable Medical Equipment & Medical Supplies",
"332BC3200X": "Customized Equipment (DME)",
"332BD1200X": "Dialysis Equipment & Supplies (DME)",
"332BN1400X": "Nursing Facility Supplies (DME)",
"332BP3500X": "Parenteral & Enteral Nutrition Supplies (DME)",
"332BX2000X": "Oxygen Equipment & Supplies (DME)",
"332G00000X": "Eye Bank",
"332H00000X": "Eyewear Supplier",
"332S00000X": "Hearing Aid Equipment",
"332U00000X": "Home Delivered Meals",
"333300000X": "Emergency Response System Companies",
"333600000X": "Pharmacy",
"3336C0002X": "Clinic Pharmacy",
"3336C0003X": "Community/Retail Pharmacy",
"3336C0004X": "Compounding Pharmacy",
"3336H0001X": "Home Infusion Therapy Pharmacy",
"3336I0012X": "Institutional Pharmacy",
"3336L0003X": "Long Term Care Pharmacy",
"3336M0002X": "Mail Order Pharmacy",
"3336M0003X": "Managed Care Organization Pharmacy",
"3336N0007X": "Nuclear Pharmacy",
"3336S0011X": "Specialty Pharmacy",
"335E00000X": "Prosthetic/Orthotic Supplier",
"335G00000X": "Medical Foods Supplier",
"335U00000X": "Organ Procurement Organization",
"335V00000X": "Portable X-ray and/or Other Portable Diagnostic Imaging Supplier",
"341600000X": "Ambulance",
"3416A0800X": "Air Ambulance",
"3416L0300X": "Land Ambulance",
"3416S0300X": "Water Ambulance",
"341800000X": "Military/U.S. Coast Guard Transport,",
"3418M1110X": "Military or U.S. Coast Guard Ground Transport Ambulance",
"3418M1120X": "Military or U.S. Coast Guard Air Transport Ambulance",
"3418M1130X": "Military or U.S. Coast Guard Water Transport Ambulance",
"342000000X": "Transportation Network Company",
"343800000X": "Secured Medical Transport (VAN)",
"343900000X": "Non-emergency Medical Transport (VAN)",
"344600000X": "Taxi",
"344800000X": "Air Carrier",
"347B00000X": "Bus",
"347C00000X": "Private Vehicle",
"347D00000X": "Train",
"347E00000X": "Transportation Broker",
"363A00000X": "Physician Assistant",
"363AM0700X": "Medical Physician Assistant",
"363AS0400X": "Surgical Physician Assistant",
"363L00000X": "Nurse Practitioner",
"363LA2100X": "Acute Care Nurse Practitioner",
"363LA2200X": "Adult Health Nurse Practitioner",
"363LC0200X": "Critical Care Medicine Nurse Practitioner",
"363LC1500X": "Community Health Nurse Practitioner",
"363LF0000X": "Family Nurse Practitioner",
"363LG0600X": "Gerontology Nurse Practitioner",
"363LN0000X": "Neonatal Nurse Practitioner",
"363LN0005X": "Critical Care Neonatal Nurse Practitioner",
"363LP0200X": "Pediatric Nurse Practitioner",
"363LP0222X": "Critical Care Pediatric Nurse Practitioner",
"363LP0808X": "Psychiatric/Mental Health Nurse Practitioner",
"363LP1700X": "Perinatal Nurse Practitioner",
"363LP2300X": "Primary Care Nurse Practitioner",
"363LS0200X": "School Nurse Practitioner",
"363LW0102X": "Women's Health Nurse Practitioner",
"363LX0001X": "Obstetrics & Gynecology Nurse Practitioner",
"363LX0106X": "Occupational Health Nurse Practitioner",
"364S00000X": "Clinical Nurse Specialist",
"364SA2100X": "Acute Care Clinical Nurse Specialist",
"364SA2200X": "Adult Health Clinical Nurse Specialist",
"364SC0200X": "Critical Care Medicine Clinical Nurse Specialist",
"364SC1501X": "Community Health/Public Health Clinical Nurse Specialist",
"364SC2300X": "Chronic Care Clinical Nurse Specialist",
"364SE0003X": "Emergency Clinical Nurse Specialist",
"364SE1400X": "Ethics Clinical Nurse Specialist",
"364SF0001X": "Family Health Clinical Nurse Specialist",
"364SG0600X": "Gerontology Clinical Nurse Specialist",
"364SH0200X": "Home Health Clinical Nurse Specialist",
"364SH1100X": "Holistic Clinical Nurse Specialist",
"364SI0800X": "Informatics Clinical Nurse Specialist",
"364SL0600X": "Long-Term Care Clinical Nurse Specialist",
"364SM0705X": "Medical-Surgical Clinical Nurse Specialist",
"364SN0000X": "Neonatal Clinical Nurse Specialist",
"364SN0800X": "Neuroscience Clinical Nurse Specialist",
"364SP0200X": "Pediatric Clinical Nurse Specialist",
"364SP0807X": "Child & Adolescent Psychiatric/Mental Health Clinical Nurse Specialist",
"364SP0808X": "Psychiatric/Mental Health Clinical Nurse Specialist",
"364SP0809X": "Adult Psychiatric/Mental Health Clinical Nurse Specialist",
"364SP0810X": "Child & Family Psychiatric/Mental Health Clinical Nurse Specialist",
"364SP0811X": "Chronically Ill Psychiatric/Mental Health Clinical Nurse Specialist",
"364SP0812X": "Community Psychiatric/Mental Health Clinical Nurse Specialist",
"364SP0813X": "Geropsychiatric Psychiatric/Mental Health Clinical Nurse Specialist",
"364SP1700X": "Perinatal Clinical Nurse Specialist",
"364SP2800X": "Perioperative Clinical Nurse Specialist",
"364SR0400X": "Rehabilitation Clinical Nurse Specialist",
"364SS0200X": "School Clinical Nurse Specialist",
"364ST0500X": "Transplantation Clinical Nurse Specialist",
"364SW0102X": "Women's Health Clinical Nurse Specialist",
"364SX0106X": "Occupational Health Clinical Nurse Specialist",
"364SX0200X": "Oncology Clinical Nurse Specialist",
"364SX0204X": "Pediatric Oncology Clinical Nurse Specialist",
"367500000X": "Certified Registered Nurse Anesthetist",
"367A00000X": "Advanced Practice Midwife",
"367H00000X": "Anesthesiologist Assistant",
"372500000X": "Chore Provider",
"372600000X": "Adult Companion",
"373H00000X": "Day Training/Habilitation Specialist",
"374700000X": "Technician",
"3747A0650X": "Attendant Care Provider",
"3747P1801X": "Personal Care Attendant",
"374J00000X": "Doula",
"374K00000X": "Religious Nonmedical Practitioner",
"374T00000X": "Religious Nonmedical Nursing Personnel",
"374U00000X": "Home Health Aide",
"376G00000X": "Nursing Home Administrator",
"376J00000X": "Homemaker",
"376K00000X": "Nurse's Aide",
"385H00000X": "Respite Care",
"385HR2050X": "Respite Care Camp",
"385HR2055X": "Child Mental Illness Respite Care",
"385HR2060X": "Child Intellectual and/or Developmental Disabilities Respite Care",
"385HR2065X": "Child Physical Disabilities Respite Care",
"390200000X": "Student in an Organized Health Care Education/Training Program",
"405300000X": "Prevention Professional"
}

View File

@ -1,4 +1,4 @@
<div class="az-content-left az-content-left-components sticky-top" style="position:sticky;"> <div [formGroup]="filterService.filterForm" class="az-content-left az-content-left-components sticky-top" style="position:sticky;">
<div class="component-item"> <div class="component-item">
<label>Connected</label> <label>Connected</label>
<nav class="nav flex-column"> <nav class="nav flex-column">
@ -6,12 +6,16 @@
<a ngbTooltip="not yet implemented" routerLinkActive="active" class="nav-link">Manual</a> <a ngbTooltip="not yet implemented" routerLinkActive="active" class="nav-link">Manual</a>
</nav> </nav>
<label>Categories</label> <label>Categories</label>
<nav class="nav flex-column"> <nav formGroupName="categories" class="nav flex-column">
<a ngbTooltip="not yet implemented" routerLinkActive="active" class="nav-link">Hospital Networks/Clinics</a>
<a ngbTooltip="not yet implemented" routerLinkActive="active" class="nav-link">Pharmacies</a> <div *ngFor="let category of filterService.filterForm.get('categories').value | keyvalue " class="switch-container">
<a ngbTooltip="not yet implemented" routerLinkActive="active" class="nav-link">Insurers</a> <label class="switch text-nowrap">
<a ngbTooltip="not yet implemented" routerLinkActive="active" class="nav-link">Laboratories</a> <input type="checkbox" [formControlName]="category.key" [value]="category.value">
<a ngbTooltip="not yet implemented" routerLinkActive="active" class="nav-link">Wearables</a> <span class="switch-button"></span><span class="category-label truncate pl-1 pr-1">{{category.key | medicalSourcesCategoryLookup}}</span>
<span *ngIf="!filterService.filterForm.get('categories').get(category.key).value" class="badge badge-primary mr-1">{{bucketDocCount(categories, category.key)}}</span>
</label>
</div>
</nav> </nav>
<label>Industry</label> <label>Industry</label>

View File

@ -1,4 +1,8 @@
import { Component, OnInit } from '@angular/core'; import {Component, Input, OnInit} from '@angular/core';
import {
LighthouseSourceSearchAggregation,
} from '../../models/lighthouse/lighthouse-source-search';
import {MedicalSourcesFilterService} from '../../services/medical-sources-filter.service';
@Component({ @Component({
selector: 'app-medical-sources-filter', selector: 'app-medical-sources-filter',
@ -7,9 +11,24 @@ import { Component, OnInit } from '@angular/core';
}) })
export class MedicalSourcesFilterComponent implements OnInit { export class MedicalSourcesFilterComponent implements OnInit {
constructor() { } @Input() categories: LighthouseSourceSearchAggregation = {buckets: [], sum_other_doc_count: 0}
@Input() platformTypes: LighthouseSourceSearchAggregation = {buckets: [], sum_other_doc_count: 0}
constructor(
public filterService: MedicalSourcesFilterService,
) { }
ngOnInit(): void { ngOnInit(): void {
}
categorySelected(category: string){
console.log("SELECTED CATEGORY", category)
this.filterService.filterForm.patchValue({'categories': {[category]: true}})
}
bucketDocCount(aggregationData: LighthouseSourceSearchAggregation, key): number {
return aggregationData?.buckets?.find(bucket => bucket.key === key)?.doc_count
} }
} }

View File

@ -72,6 +72,8 @@ import { ReportMedicalHistoryExplanationOfBenefitComponent } from './report-medi
import {GridstackComponent} from './gridstack/gridstack.component'; import {GridstackComponent} from './gridstack/gridstack.component';
import {GridstackItemComponent} from './gridstack/gridstack-item.component'; import {GridstackItemComponent} from './gridstack/gridstack-item.component';
import { MedicalSourcesFilterComponent } from './medical-sources-filter/medical-sources-filter.component'; import { MedicalSourcesFilterComponent } from './medical-sources-filter/medical-sources-filter.component';
import { MedicalSourcesConnectedComponent } from './medical-sources-connected/medical-sources-connected.component';
import { MedicalSourcesCategoryLookupPipe } from './medical-sources-filter/medical-sources-category-lookup.pipe';
@NgModule({ @NgModule({
imports: [ imports: [
@ -156,72 +158,75 @@ import { MedicalSourcesFilterComponent } from './medical-sources-filter/medical-
MediaComponent, MediaComponent,
ReportMedicalHistoryExplanationOfBenefitComponent, ReportMedicalHistoryExplanationOfBenefitComponent,
MedicalSourcesFilterComponent, MedicalSourcesFilterComponent,
MedicalSourcesConnectedComponent,
MedicalSourcesCategoryLookupPipe,
], ],
exports: [ exports: [
BinaryComponent, BinaryComponent,
ComponentsSidebarComponent, ComponentsSidebarComponent,
DiagnosticReportComponent, DiagnosticReportComponent,
DocumentReferenceComponent, DocumentReferenceComponent,
FallbackComponent, FallbackComponent,
FhirResourceComponent, FhirResourceComponent,
FhirResourceOutletDirective, FhirResourceOutletDirective,
ImmunizationComponent, ImmunizationComponent,
ListAdverseEventComponent, ListAdverseEventComponent,
ListAllergyIntoleranceComponent, ListAllergyIntoleranceComponent,
ListAppointmentComponent, ListAppointmentComponent,
ListCarePlanComponent, ListCarePlanComponent,
ListCommunicationComponent, ListCommunicationComponent,
ListConditionComponent, ListConditionComponent,
ListCoverageComponent, ListCoverageComponent,
ListDeviceComponent, ListDeviceComponent,
ListDeviceRequestComponent, ListDeviceRequestComponent,
ListDiagnosticReportComponent, ListDiagnosticReportComponent,
ListDocumentReferenceComponent, ListDocumentReferenceComponent,
ListEncounterComponent, ListEncounterComponent,
ListGenericResourceComponent, ListGenericResourceComponent,
ListGoalComponent, ListGoalComponent,
ListImmunizationComponent, ListImmunizationComponent,
ListMedicationAdministrationComponent, ListMedicationAdministrationComponent,
ListMedicationComponent, ListMedicationComponent,
ListMedicationDispenseComponent, ListMedicationDispenseComponent,
ListMedicationRequestComponent, ListMedicationRequestComponent,
ListNutritionOrderComponent, ListNutritionOrderComponent,
ListObservationComponent, ListObservationComponent,
ListPatientComponent, ListPatientComponent,
ListProcedureComponent, ListProcedureComponent,
ListServiceRequestComponent, ListServiceRequestComponent,
MedicalSourcesFilterComponent, MedicalSourcesFilterComponent,
MedicationRequestComponent, MedicationRequestComponent,
NlmTypeaheadComponent, NlmTypeaheadComponent,
PractitionerComponent, PractitionerComponent,
ProcedureComponent, ProcedureComponent,
ReportHeaderComponent, ReportHeaderComponent,
ReportLabsObservationComponent, ReportLabsObservationComponent,
ReportMedicalHistoryConditionComponent, ReportMedicalHistoryConditionComponent,
ReportMedicalHistoryEditorComponent, ReportMedicalHistoryEditorComponent,
ReportMedicalHistoryExplanationOfBenefitComponent, ReportMedicalHistoryExplanationOfBenefitComponent,
ResourceListComponent, ResourceListComponent,
ResourceListOutletDirective, ResourceListOutletDirective,
ToastComponent, ToastComponent,
UtilitiesSidebarComponent, UtilitiesSidebarComponent,
//standalone components //standalone components
BadgeComponent, BadgeComponent,
TableComponent, TableComponent,
CodingComponent, CodingComponent,
LoadingSpinnerComponent, LoadingSpinnerComponent,
GlossaryLookupComponent, GlossaryLookupComponent,
AllergyIntoleranceComponent, AllergyIntoleranceComponent,
MedicationComponent, MedicationComponent,
MedicationRequestComponent, MedicationRequestComponent,
PractitionerComponent, PractitionerComponent,
ProcedureComponent, ProcedureComponent,
ImmunizationComponent, ImmunizationComponent,
BinaryComponent, BinaryComponent,
GridstackComponent, GridstackComponent,
GridstackItemComponent, GridstackItemComponent,
MedicalSourcesConnectedComponent,
] ]
}) })
export class SharedModule { } export class SharedModule { }

View File

@ -1,5 +1,22 @@
import {MetadataSource} from '../fasten/metadata-source'; import {MetadataSource} from '../fasten/metadata-source';
export class LighthouseSourceSearchResult {
_index: string;
_type: string;
_id: string;
_score: number;
_source: MetadataSource;
sort: string[];
}
export class LighthouseSourceSearchAggregation {
sum_other_doc_count: number;
buckets: {
key: string;
doc_count: number;
}[]
}
export class LighthouseSourceSearch { export class LighthouseSourceSearch {
_scroll_id: string; _scroll_id: string;
took: number; took: number;
@ -10,28 +27,10 @@ export class LighthouseSourceSearch {
relation: string; relation: string;
}; };
max_score: number; max_score: number;
hits: { hits: LighthouseSourceSearchResult[];
_index: string;
_type: string;
_id: string;
_score: number;
_source: MetadataSource;
}[];
}; };
aggregations: { aggregations: {
by_platform_type: { by_platform_type: LighthouseSourceSearchAggregation
sum_other_doc_count: number; by_category: LighthouseSourceSearchAggregation
buckets: { };
key: string;
doc_count: number;
}[]
},
by_category: {
sum_other_doc_count: number;
buckets: {
key: string;
doc_count: number;
}[]
}
}
} }

View File

@ -1,6 +1,6 @@
<div class="az-content"> <div class="az-content">
<div class="container"> <div class="container">
<app-medical-sources-filter></app-medical-sources-filter> <app-medical-sources-filter [categories]="resultLimits.categoryBuckets" [platformTypes]="resultLimits.platformTypesBuckets"></app-medical-sources-filter>
<div class="az-content-body pd-lg-l-40 d-flex flex-column"> <div class="az-content-body pd-lg-l-40 d-flex flex-column">
<div class="az-content-breadcrumb"> <div class="az-content-breadcrumb">
<span>Medical Sources</span> <span>Medical Sources</span>
@ -23,29 +23,8 @@
</span> </span>
</div> </div>
<app-medical-sources-connected></app-medical-sources-connected>
<h2 class="az-content-title">Connected Sources</h2>
<div *ngIf="!loading else isLoadingTemplate" class="row">
<div *ngFor="let sourceInfo of connectedSourceList" class="col-sm-3 mg-b-20 px-3">
<div class="card h-100 d-flex align-items-center justify-content-center mt-3 mt-3 rounded-0 cursor-pointer">
<div (click)="openModal(contentModalRef, sourceInfo)" class="card-body">
<div class="h-100 d-flex align-items-center">
<img [src]="'assets/sources/'+(sourceInfo.metadata.brand_logo ? sourceInfo.metadata.brand_logo : sourceInfo.metadata.source_type+'.png')" [alt]="sourceInfo?.metadata.display" class="img-fluid">
</div>
<div *ngIf="status[sourceInfo.metadata?.source_type]" class="progress">
<div [style.width]="status[sourceInfo?.metadata?.source_type] == 'authorize' ? '33%' : '66%'" class="bg-indigo progress-bar progress-bar-striped progress-bar-animated" role="progressbar"></div>
</div>
</div>
<div class="card-footer text-center p-1" style="width:100%">
<small class="tx-gray-700">
{{sourceInfo?.metadata.display}}
</small>
</div>
</div>
</div>
</div>
<h2 class="az-content-title mg-t-40">Medical Record Sources</h2> <h2 class="az-content-title mg-t-40">Medical Record Sources</h2>
@ -76,9 +55,9 @@
<div class="input-group-prepend"> <div class="input-group-prepend">
<span class="input-group-text" id="search-prefix">Search</span> <span class="input-group-text" id="search-prefix">Search</span>
</div> </div>
<input (keyup)="searchTermUpdate.next($event.target.value)" type="text" class="form-control" placeholder="Search Term"> <input [ngModel]="searchTermUpdate | async" (keyup)="searchTermUpdate.next($event.target.value)" type="text" class="form-control" placeholder="Search Term">
<div class="input-group-append"> <div class="input-group-append">
<span class="input-group-text">{{this.availableSourceList.length}} of {{this.totalAvailableSourceList}} results</span> <span class="input-group-text">{{this.availableSourceList.length}} of {{this.resultLimits.totalItems}} results</span>
</div> </div>
</div><!-- input-group --> </div><!-- input-group -->
@ -86,7 +65,7 @@
</div> </div>
<div *ngIf="!loading else isLoadingTemplate" class="row row-sm" <div *ngIf="!loading || availableSourceList.length > 0 else isLoadingTemplate" class="row row-sm"
infiniteScroll infiniteScroll
[infiniteScrollDistance]="2" [infiniteScrollDistance]="2"
[infiniteScrollThrottle]="50" [infiniteScrollThrottle]="50"
@ -116,32 +95,6 @@
</div><!-- container --> </div><!-- container -->
</div><!-- az-content --> </div><!-- az-content -->
<ng-template #contentModalRef let-modal>
<div class="modal-header">
<h4 class="modal-title" id="modal-basic-title">{{modalSelectedSourceListItem?.metadata["display"]}}</h4>
<button type="button" class="btn btn-close" aria-label="Close" (click)="modal.dismiss('Cross click')">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<h6>Manage Source</h6>
<p>Existing connections can be "Synced", "Reconnected" or "Deleted"</p>
<ul>
<li><p><strong>Sync</strong> - Download all resources from this healthcare provider, storing them securely in Fasten</p></li>
<li><p><strong>Reconnect</strong> - If your healthcare connection has expired, you can use this button to reconnect</p></li>
<li><p><strong>Delete</strong> - Delete all resources for this healthcare provider. This will ONLY effect data stored in Fasten</p></li>
</ul>
</div>
<div class="modal-footer">
<button (click)="sourceSyncHandler(modalSelectedSourceListItem.source)" type="button" class="btn btn-indigo">Sync</button>
<button (click)="connectHandler($event, modalSelectedSourceListItem.source['source_type'])" type="button" class="btn btn-outline-light">Reconnect</button>
<button type="button" class="btn btn-outline-danger">Delete</button>
<button (click)="modal.dismiss('Close click')" type="button" class="btn btn-outline-light">Close</button>
</div>
</ng-template>
<ng-template #isLoadingTemplate> <ng-template #isLoadingTemplate>
<div class="row"> <div class="row">
<div class="col-12"> <div class="col-12">

View File

@ -1,4 +1,4 @@
import {Component, OnInit} from '@angular/core'; import {Component, EventEmitter, OnInit, Optional, Output} from '@angular/core';
import {LighthouseService} from '../../services/lighthouse.service'; import {LighthouseService} from '../../services/lighthouse.service';
import {FastenApiService} from '../../services/fasten-api.service'; import {FastenApiService} from '../../services/fasten-api.service';
import {LighthouseSourceMetadata} from '../../models/lighthouse/lighthouse-source-metadata'; import {LighthouseSourceMetadata} from '../../models/lighthouse/lighthouse-source-metadata';
@ -10,9 +10,15 @@ import {Location} from '@angular/common';
import {ToastService} from '../../services/toast.service'; import {ToastService} from '../../services/toast.service';
import {ToastNotification, ToastType} from '../../models/fasten/toast'; import {ToastNotification, ToastType} from '../../models/fasten/toast';
import {environment} from '../../../environments/environment'; import {environment} from '../../../environments/environment';
import {BehaviorSubject, forkJoin, Subject} from 'rxjs'; import {BehaviorSubject, forkJoin, Observable, Subject} from 'rxjs';
import {LighthouseSourceSearch} from '../../models/lighthouse/lighthouse-source-search'; import {
LighthouseSourceSearch,
LighthouseSourceSearchAggregation,
LighthouseSourceSearchResult
} from '../../models/lighthouse/lighthouse-source-search';
import {debounceTime, distinctUntilChanged} from 'rxjs/operators'; import {debounceTime, distinctUntilChanged} from 'rxjs/operators';
import {MedicalSourcesFilter, MedicalSourcesFilterService} from '../../services/medical-sources-filter.service';
import {FormControl, FormGroup} from '@angular/forms';
// If you dont import this angular will import the wrong "Location" // If you dont import this angular will import the wrong "Location"
export const sourceConnectWindowTimeout = 24*5000 //wait 2 minutes (5 * 24 = 120) export const sourceConnectWindowTimeout = 24*5000 //wait 2 minutes (5 * 24 = 120)
@ -31,78 +37,145 @@ export class MedicalSourcesComponent implements OnInit {
loading: boolean = false loading: boolean = false
environment_name = environment.environment_name environment_name = environment.environment_name
status: { [name: string]: string } = {}
connectedSourceList: SourceListItem[] = [] //source's are populated for this list
availableSourceList: SourceListItem[] = []
totalAvailableSourceList: number = 0
uploadedFile: File[] = [] uploadedFile: File[] = []
closeResult = '';
modalSelectedSourceListItem:SourceListItem = null;
scrollId: string = "" availableSourceList: SourceListItem[] = []
scrollComplete: boolean = false
searchTermUpdate = new BehaviorSubject<string>(""); searchTermUpdate = new BehaviorSubject<string>("");
showHidden: boolean = false status: { [name: string]: string } = {}
//aggregation/filter data & limits
globalLimits: {
// aggregations: LighthouseSourceSearchAggregations | undefined,
} = {
// categories: [],
// aggregations: undefined,
}
//limits that are tied to the current result set.
resultLimits: {
totalItems: number,
scrollComplete: boolean,
platformTypesBuckets: LighthouseSourceSearchAggregation,
categoryBuckets: LighthouseSourceSearchAggregation,
} = {
totalItems: 0,
scrollComplete: false,
platformTypesBuckets: undefined,
categoryBuckets: undefined
}
//source of truth for current state
filterForm = this.filterService.filterForm;
constructor( constructor(
private lighthouseApi: LighthouseService, private lighthouseApi: LighthouseService,
private fastenApi: FastenApiService, private fastenApi: FastenApiService,
private modalService: NgbModal, private activatedRoute: ActivatedRoute,
private route: ActivatedRoute,
private router: Router, private router: Router,
private location: Location, private location: Location,
private toastService: ToastService private toastService: ToastService,
private filterService: MedicalSourcesFilterService,
) { } ) { }
ngOnInit(): void { ngOnInit(): void {
this.loading = true
forkJoin([this.lighthouseApi.findLighthouseSources("", "", this.showHidden), this.fastenApi.getSources()]).subscribe(results => {
this.loading = false
//handle connected sources sources //changing the form, should change the URL, BUT NOT do a query
const connectedSources = results[1] as Source[] this.filterForm.valueChanges.pipe(debounceTime(100)).subscribe(val => {
forkJoin(connectedSources.map((source) => this.lighthouseApi.getLighthouseSource(source.source_type))).subscribe((connectedMetadata) => { console.log("FILTER FORM CHANGED:", val, this.filterService.toQueryParams())
for(const ndx in connectedSources){
this.connectedSourceList.push({source: connectedSources[ndx], metadata: connectedMetadata[ndx]})
}
})
// change the browser url whenever the filter is updated.
//handle source metadata map response this.updateBrowserUrl(this.filterService.toQueryParams())
this.populateAvailableSourceList(results[0] as LighthouseSourceSearch)
//check if we've just started connecting a "source_type"
const callbackSourceType = this.route.snapshot.paramMap.get('source_type')
if(callbackSourceType){
this.status[callbackSourceType] = "token"
//move this source from available to connected (with a progress bar)
//remove item from available sources list, add to connected sources.
let inProgressAvailableIndex = this.availableSourceList.findIndex((item) => item.metadata.source_type == callbackSourceType)
if(inProgressAvailableIndex > -1){
let sourcesInProgress = this.availableSourceList.splice(inProgressAvailableIndex, 1);
}
//the structure of "availableSourceList" vs "connectedSourceList" sources is slightly different,
//connectedSourceList contains a "source" field. The this.fastenApi.createSource() call in the callback function will set it.
this.lighthouseApi.getLighthouseSource(callbackSourceType)
.then((metadata) => {
this.connectedSourceList.push({metadata: metadata})
return this.callback(callbackSourceType)
})
.then(console.log)
}
}, err => {
this.loading = false
}) })
//TODO: handle Callbacks from the source connect window
const callbackSourceType = this.activatedRoute.snapshot.paramMap.get('source_type')
if(callbackSourceType){
console.error("TODO! handle callback redirect from source")
} else {
//we're not in a callback redirect, lets load the sources
if(this.activatedRoute.snapshot.queryParams['query']){
this.searchTermUpdate.next(this.activatedRoute.snapshot.queryParams['query'])
}
//register a callback for when the search term changes
//changing the route should trigger a query
this.activatedRoute.queryParams
.subscribe(params => {
console.log("QUERY PARAMS CHANGED ON ROUTE", params); // {order: "popular"}
var updatedForm = this.filterService.parseQueryParams(params);
//this is a "breaking change" to the filter values, causing a reset and a new query
this.availableSourceList = []
this.resultLimits.totalItems = 0
this.resultLimits.scrollComplete = false
// this.filterService.filterForm.setControl("categories", this.{: {}}, { emitEvent: false})
//update the form with data from route (don't emit a new patch event), then submit query
var searchObservable = this.querySources(this.filterService.toMedicalSourcesFilter(updatedForm));
searchObservable.subscribe(null, null, () => {
this.filterForm.patchValue(updatedForm, { emitEvent: false});
})
});
}
/// OLD CODE - Should be refactored
// this.loading = true
// forkJoin([this.lighthouseApi.findLighthouseSources("", "", this.showHidden), this.fastenApi.getSources()]).subscribe(results => {
// this.loading = false
//
// //handle connected sources sources
// const connectedSources = results[1] as Source[]
// forkJoin(connectedSources.map((source) => this.lighthouseApi.getLighthouseSource(source.source_type))).subscribe((connectedMetadata) => {
// for(const ndx in connectedSources){
// this.connectedSourceList.push({source: connectedSources[ndx], metadata: connectedMetadata[ndx]})
// }
// })
//
//
// //handle source metadata map response
// this.populateAvailableSourceList(results[0] as LighthouseSourceSearch)
//
//
// //check if we've just started connecting a "source_type"
// const callbackSourceType = this.route.snapshot.paramMap.get('source_type')
// if(callbackSourceType){
// this.status[callbackSourceType] = "token"
//
// //move this source from available to connected (with a progress bar)
// //remove item from available sources list, add to connected sources.
// let inProgressAvailableIndex = this.availableSourceList.findIndex((item) => item.metadata.source_type == callbackSourceType)
// if(inProgressAvailableIndex > -1){
// let sourcesInProgress = this.availableSourceList.splice(inProgressAvailableIndex, 1);
//
// }
//
// //the structure of "availableSourceList" vs "connectedSourceList" sources is slightly different,
// //connectedSourceList contains a "source" field. The this.fastenApi.createSource() call in the callback function will set it.
// this.lighthouseApi.getLighthouseSource(callbackSourceType)
// .then((metadata) => {
// this.connectedSourceList.push({metadata: metadata})
// return this.callback(callbackSourceType)
// })
// .then(console.log)
// }
//
// }, err => {
// this.loading = false
// })
//
//
//register a callback for when the search box content changes
this.searchTermUpdate this.searchTermUpdate
.pipe( .pipe(
debounceTime(200), debounceTime(200),
@ -110,215 +183,293 @@ export class MedicalSourcesComponent implements OnInit {
) )
.subscribe(value => { .subscribe(value => {
console.log("search term changed:", value) console.log("search term changed:", value)
let currentQuery = this.filterService.filterForm.value.query || ""
//reset available sources if(value != null && currentQuery != value){
this.availableSourceList = [] this.filterService.filterForm.patchValue({query: value})
this.scrollId = "" }
this.scrollComplete = false
this.totalAvailableSourceList = 0
this.lighthouseApi.findLighthouseSources(value, this.scrollId, this.showHidden)
.subscribe((results) => {
this.populateAvailableSourceList(results)
})
}); });
} }
private populateAvailableSourceList(results: LighthouseSourceSearch): void { updateBrowserUrl(queryParams: {[name: string]: string}){
this.totalAvailableSourceList = results.hits.total.value console.log("update the browser url with query params data", queryParams)
if(results.hits.hits.length == 0){ this.router.navigate(['/sources'], { queryParams: queryParams })
this.scrollComplete = true }
console.log("scroll complete")
private querySources(filter?: MedicalSourcesFilter): Observable<LighthouseSourceSearch> {
if(this.loading){
return return
} }
this.scrollId = results._scroll_id //TODO: pass filter to function.
this.availableSourceList = this.availableSourceList.concat(results.hits.hits.map((result) => { // this.location.replaceState('/dashboard','', this.filter)
return {metadata: result._source}
}).filter((item) => {
return !this.connectedSourceList.find((connectedItem) => connectedItem.metadata.source_type == item.metadata.source_type)
}))
}
public onScroll(): void { if(!filter){
if(this.scrollComplete){ filter = this.filterService.toMedicalSourcesFilter(this.filterForm.value)
return console.log("querySources() - no filter provided, using current form value", filter)
} }
this.lighthouseApi.findLighthouseSources(this.searchTermUpdate.getValue(), this.scrollId, this.showHidden)
.subscribe((results) => {
this.populateAvailableSourceList(results)
})
}
/** filter.fields = ["*"];
* after pressing the logo (connectHandler button), this function will generate an authorize url for this source, and redirec the user. this.loading = true
* @param $event var searchObservable = this.lighthouseApi.searchLighthouseSources(filter);
* @param sourceType searchObservable.subscribe(wrapper => {
*/ console.log("search sources", wrapper);
public connectHandler($event: MouseEvent, sourceType: string):void { // this.searchResults = wrapper.hits.hits;
($event.currentTarget as HTMLButtonElement).disabled = true; this.resultLimits.totalItems = wrapper.hits.total.value;
this.status[sourceType] = "authorize"
this.lighthouseApi.getLighthouseSource(sourceType) this.availableSourceList = this.availableSourceList.concat(wrapper.hits.hits.map((result) => {
.then(async (sourceMetadata: LighthouseSourceMetadata) => { return {metadata: result._source}
console.log(sourceMetadata); }))
let authorizationUrl = await this.lighthouseApi.generateSourceAuthorizeUrl(sourceType, sourceMetadata)
console.log('authorize url:', authorizationUrl.toString()); //change the current Page (but don't cause a new query)
// redirect to lighthouse with uri's if(wrapper.hits.hits.length == 0){
this.lighthouseApi.redirectWithOriginAndDestination(authorizationUrl.toString(), sourceType, sourceMetadata.redirect_uri) console.log("SCROLL_COMPLETE!@@@@@@@@")
this.resultLimits.scrollComplete = true;
} else {
console.log("SETTING NEXT SORT KEY:", wrapper.hits.hits[wrapper.hits.hits.length - 1].sort.join(','))
this.filterService.filterForm.patchValue({searchAfter: wrapper.hits.hits[wrapper.hits.hits.length - 1].sort.join(",")}, {emitEvent: false})
}
}); // .filter((item) => {
} // return !this.connectedSourceList.find((connectedItem) => connectedItem.metadata.source_type == item.metadata.source_type)
// }))
/**
* if the user is redirected to this page from the lighthouse, we'll need to process the "code" to retrieve the access token & refresh token.
* @param sourceType
*/
public async callback(sourceType: string) {
//get the source metadata again
await this.lighthouseApi.getLighthouseSource(sourceType)
.then(async (sourceMetadata: LighthouseSourceMetadata) => {
//get required parameters from the URI and local storage this.resultLimits.platformTypesBuckets = wrapper.aggregations.by_platform_type;
const callbackUrlParts = new URL(window.location.href) this.resultLimits.categoryBuckets = wrapper.aggregations.by_category;
const fragmentParams = new URLSearchParams(callbackUrlParts.hash.substring(1))
const callbackCode = callbackUrlParts.searchParams.get("code") || fragmentParams.get("code")
const callbackState = callbackUrlParts.searchParams.get("state") || fragmentParams.get("state")
const callbackError = callbackUrlParts.searchParams.get("error") || fragmentParams.get("error")
const callbackErrorDescription = callbackUrlParts.searchParams.get("error_description") || fragmentParams.get("error_description")
//reset the url, removing the params and fragment from the current url.
const urlTree = this.router.createUrlTree(["/sources"],{
relativeTo: this.route,
});
this.location.replaceState(urlTree.toString());
const expectedSourceStateInfo = JSON.parse(localStorage.getItem(callbackState))
localStorage.removeItem(callbackState)
if(callbackError && !callbackCode){ var currentCategories = this.filterForm.get('categories').value;
//TOOD: print this message in the UI this.resultLimits.categoryBuckets.buckets.forEach((bucketData) => {
let errMsg = "an error occurred while authenticating to this source. Please try again later" if(!currentCategories.hasOwnProperty(bucketData.key)){
console.error(errMsg, callbackErrorDescription) (this.filterForm.get('categories') as FormGroup).addControl(bucketData.key, new FormControl(false))
throw new Error(errMsg)
}
console.log("callback code:", callbackCode)
this.status[sourceType] = "token"
let payload: any
payload = await this.lighthouseApi.swapOauthToken(sourceType, sourceMetadata,expectedSourceStateInfo, callbackCode)
if(!payload.access_token || payload.error){
//if the access token is not set, then something is wrong,
let errMsg = payload.error || "unable to retrieve access_token"
console.error(errMsg)
throw new Error(errMsg)
}
//If payload.patient is not set, make sure we extract the patient ID from the id_token or make an introspection req
if(!payload.patient && payload.id_token){
//
console.log("NO PATIENT ID present, decoding jwt to extract patient")
//const introspectionResp = await Oauth.introspectionRequest(as, client, payload.access_token)
//console.log(introspectionResp)
let decodedIdToken = this.jwtDecode(payload.id_token)
//nextGen uses fhirUser instead of profile.
payload.patient = decodedIdToken["profile"] || decodedIdToken["fhirUser"]
if(payload.patient){
payload.patient = payload.patient.replace(/^(Patient\/)/,'')
} }
}
//Create FHIR Client
const dbSourceCredential = new Source({
source_type: sourceType,
authorization_endpoint: sourceMetadata.authorization_endpoint,
token_endpoint: sourceMetadata.token_endpoint,
introspection_endpoint: sourceMetadata.introspection_endpoint,
userinfo_endpoint: sourceMetadata.userinfo_endpoint,
api_endpoint_base_url: sourceMetadata.api_endpoint_base_url,
client_id: sourceMetadata.client_id,
redirect_uri: sourceMetadata.redirect_uri,
scopes_supported: sourceMetadata.scopes_supported,
issuer: sourceMetadata.issuer,
grant_types_supported: sourceMetadata.grant_types_supported,
response_types_supported: sourceMetadata.response_types_supported,
aud: sourceMetadata.aud,
code_challenge_methods_supported: sourceMetadata.code_challenge_methods_supported,
confidential: sourceMetadata.confidential,
cors_relay_required: sourceMetadata.cors_relay_required,
patient: payload.patient,
access_token: payload.access_token,
refresh_token: payload.refresh_token,
id_token: payload.id_token,
// @ts-ignore - in some cases the getAccessTokenExpiration is a string, which cases failures to store Source in db.
expires_at: parseInt(this.getAccessTokenExpiration(payload)),
}) })
//
// this.resultLimits.categoryBuckets.forEach((bucketData) => {
// if(!this.globalLimits.categories.some((category) => { return category.id === bucketData.key})){
// this.globalLimits.categories.push({
// id: bucketData.key,
// name: bucketData.key,
// group: 'custom'
// })
// }
// })
this.fastenApi.createSource(dbSourceCredential) // const fileTypes = <FormGroup>this.filterForm.get('fileTypes');
.subscribe((resp) => { // fileTypes.forEach((option: any) => {
// const sourceSyncMessage = JSON.parse(msg) as SourceSyncMessage // checkboxes.addControl(option.title, new FormControl(true));
delete this.status[sourceType] // });
// window.location.reload(); this.loading = false
// this.connectedSourceList. },
error => {
//find the index of the "inprogress" source in the connected List, and then add this source to its source metadata. this.loading = false
let foundSource = this.connectedSourceList.findIndex((item) => item.metadata.source_type == sourceType) console.error("sources FAILED", error)
this.connectedSourceList[foundSource].source = resp.source },
() => {
console.log("source sync-all response:", resp.summary) this.loading = false
console.log("sources finished")
const toastNotification = new ToastNotification() }
toastNotification.type = ToastType.Success );
toastNotification.message = `Successfully connected ${sourceType}` return searchObservable;
// const upsertSummary = sourceSyncMessage.response as UpsertSummary
// if(upsertSummary && upsertSummary.totalResources != upsertSummary.updatedResources.length){
// toastNotification.message += `\n (total: ${upsertSummary.totalResources}, updated: ${upsertSummary.updatedResources.length})`
// } else if(upsertSummary){
// toastNotification.message += `\n (total: ${upsertSummary.totalResources})`
// }
this.toastService.show(toastNotification)
},
(err) => {
delete this.status[sourceType]
// window.location.reload();
const toastNotification = new ToastNotification()
toastNotification.type = ToastType.Error
toastNotification.message = `An error occurred while accessing ${sourceType}: ${err}`
toastNotification.autohide = false
this.toastService.show(toastNotification)
console.error(err)
});
})
.catch((err) => {
delete this.status[sourceType]
// window.location.reload();
const toastNotification = new ToastNotification()
toastNotification.type = ToastType.Error
toastNotification.message = `An error occurred while accessing ${sourceType}: ${err}`
toastNotification.autohide = false
this.toastService.show(toastNotification)
console.error(err)
})
} }
//OLD FUNCTIONS
//
//
// private populateAvailableSourceList(results: LighthouseSourceSearch): void {
// console.log("AGGREGATIONS!!!!!", results.aggregations)
// this.totalAvailableSourceList = results.hits.total.value
// if(results.hits.hits.length == 0){
// this.scrollComplete = true
// console.log("scroll complete")
// return
// }
// this.scrollId = results._scroll_id
// this.availableSourceList = this.availableSourceList.concat(results.hits.hits.map((result) => {
// return {metadata: result._source}
// }).filter((item) => {
// return !this.connectedSourceList.find((connectedItem) => connectedItem.metadata.source_type == item.metadata.source_type)
// }))
// }
//
public onScroll(): void {
console.log("TODO: SCROLL, TRIGGER update")
this.querySources()
}
// /**
// * after pressing the logo (connectHandler button), this function will generate an authorize url for this source, and redirec the user.
// * @param $event
// * @param sourceType
// */
public connectHandler($event: MouseEvent, sourceType: string):void {
console.log("TODO: connect Handler")
// ($event.currentTarget as HTMLButtonElement).disabled = true;
// this.status[sourceType] = "authorize"
//
// this.lighthouseApi.getLighthouseSource(sourceType)
// .then(async (sourceMetadata: LighthouseSourceMetadata) => {
// console.log(sourceMetadata);
// let authorizationUrl = await this.lighthouseApi.generateSourceAuthorizeUrl(sourceType, sourceMetadata)
//
// console.log('authorize url:', authorizationUrl.toString());
// // redirect to lighthouse with uri's
// this.lighthouseApi.redirectWithOriginAndDestination(authorizationUrl.toString(), sourceType, sourceMetadata.redirect_uri)
//
// });
}
//
// /**
// * if the user is redirected to this page from the lighthouse, we'll need to process the "code" to retrieve the access token & refresh token.
// * @param sourceType
// */
// public async callback(sourceType: string) {
//
// //get the source metadata again
// await this.lighthouseApi.getLighthouseSource(sourceType)
// .then(async (sourceMetadata: LighthouseSourceMetadata) => {
//
// //get required parameters from the URI and local storage
// const callbackUrlParts = new URL(window.location.href)
// const fragmentParams = new URLSearchParams(callbackUrlParts.hash.substring(1))
// const callbackCode = callbackUrlParts.searchParams.get("code") || fragmentParams.get("code")
// const callbackState = callbackUrlParts.searchParams.get("state") || fragmentParams.get("state")
// const callbackError = callbackUrlParts.searchParams.get("error") || fragmentParams.get("error")
// const callbackErrorDescription = callbackUrlParts.searchParams.get("error_description") || fragmentParams.get("error_description")
//
// //reset the url, removing the params and fragment from the current url.
// const urlTree = this.router.createUrlTree(["/sources"],{
// relativeTo: this.route,
// });
// this.location.replaceState(urlTree.toString());
//
// const expectedSourceStateInfo = JSON.parse(localStorage.getItem(callbackState))
// localStorage.removeItem(callbackState)
//
// if(callbackError && !callbackCode){
// //TOOD: print this message in the UI
// let errMsg = "an error occurred while authenticating to this source. Please try again later"
// console.error(errMsg, callbackErrorDescription)
// throw new Error(errMsg)
// }
//
// console.log("callback code:", callbackCode)
// this.status[sourceType] = "token"
//
// let payload: any
// payload = await this.lighthouseApi.swapOauthToken(sourceType, sourceMetadata,expectedSourceStateInfo, callbackCode)
//
// if(!payload.access_token || payload.error){
// //if the access token is not set, then something is wrong,
// let errMsg = payload.error || "unable to retrieve access_token"
// console.error(errMsg)
// throw new Error(errMsg)
// }
//
// //If payload.patient is not set, make sure we extract the patient ID from the id_token or make an introspection req
// if(!payload.patient && payload.id_token){
// //
// console.log("NO PATIENT ID present, decoding jwt to extract patient")
// //const introspectionResp = await Oauth.introspectionRequest(as, client, payload.access_token)
// //console.log(introspectionResp)
// let decodedIdToken = this.jwtDecode(payload.id_token)
// //nextGen uses fhirUser instead of profile.
// payload.patient = decodedIdToken["profile"] || decodedIdToken["fhirUser"]
//
// if(payload.patient){
// payload.patient = payload.patient.replace(/^(Patient\/)/,'')
// }
//
// }
//
//
//
// //Create FHIR Client
//
// const dbSourceCredential = new Source({
// source_type: sourceType,
//
// authorization_endpoint: sourceMetadata.authorization_endpoint,
// token_endpoint: sourceMetadata.token_endpoint,
// introspection_endpoint: sourceMetadata.introspection_endpoint,
// userinfo_endpoint: sourceMetadata.userinfo_endpoint,
// api_endpoint_base_url: sourceMetadata.api_endpoint_base_url,
// client_id: sourceMetadata.client_id,
// redirect_uri: sourceMetadata.redirect_uri,
// scopes_supported: sourceMetadata.scopes_supported,
// issuer: sourceMetadata.issuer,
// grant_types_supported: sourceMetadata.grant_types_supported,
// response_types_supported: sourceMetadata.response_types_supported,
// aud: sourceMetadata.aud,
// code_challenge_methods_supported: sourceMetadata.code_challenge_methods_supported,
// confidential: sourceMetadata.confidential,
// cors_relay_required: sourceMetadata.cors_relay_required,
//
// patient: payload.patient,
// access_token: payload.access_token,
// refresh_token: payload.refresh_token,
// id_token: payload.id_token,
//
// // @ts-ignore - in some cases the getAccessTokenExpiration is a string, which cases failures to store Source in db.
// expires_at: parseInt(this.getAccessTokenExpiration(payload)),
// })
//
// this.fastenApi.createSource(dbSourceCredential)
// .subscribe((resp) => {
// // const sourceSyncMessage = JSON.parse(msg) as SourceSyncMessage
// delete this.status[sourceType]
// // window.location.reload();
// // this.connectedSourceList.
//
// //find the index of the "inprogress" source in the connected List, and then add this source to its source metadata.
// let foundSource = this.connectedSourceList.findIndex((item) => item.metadata.source_type == sourceType)
// this.connectedSourceList[foundSource].source = resp.source
//
// console.log("source sync-all response:", resp.summary)
//
// const toastNotification = new ToastNotification()
// toastNotification.type = ToastType.Success
// toastNotification.message = `Successfully connected ${sourceType}`
//
// // const upsertSummary = sourceSyncMessage.response as UpsertSummary
// // if(upsertSummary && upsertSummary.totalResources != upsertSummary.updatedResources.length){
// // toastNotification.message += `\n (total: ${upsertSummary.totalResources}, updated: ${upsertSummary.updatedResources.length})`
// // } else if(upsertSummary){
// // toastNotification.message += `\n (total: ${upsertSummary.totalResources})`
// // }
//
// this.toastService.show(toastNotification)
// },
// (err) => {
// delete this.status[sourceType]
// // window.location.reload();
//
// const toastNotification = new ToastNotification()
// toastNotification.type = ToastType.Error
// toastNotification.message = `An error occurred while accessing ${sourceType}: ${err}`
// toastNotification.autohide = false
// this.toastService.show(toastNotification)
// console.error(err)
// });
// })
// .catch((err) => {
// delete this.status[sourceType]
// // window.location.reload();
//
// const toastNotification = new ToastNotification()
// toastNotification.type = ToastType.Error
// toastNotification.message = `An error occurred while accessing ${sourceType}: ${err}`
// toastNotification.autohide = false
// this.toastService.show(toastNotification)
// console.error(err)
// })
// }
/** /**
* this function is used to process manually "uploaded" FHIR bundle files, adding them to the database. * this function is used to process manually "uploaded" FHIR bundle files, adding them to the database.
* @param event * @param event
@ -337,52 +488,14 @@ export class MedicalSourcesComponent implements OnInit {
) )
} }
public openModal(contentModalRef, sourceListItem: SourceListItem) {
if(this.status[sourceListItem.metadata.source_type] || !sourceListItem.source){
//if this source is currently "loading" dont open the modal window
return
}
this.modalSelectedSourceListItem = sourceListItem
this.modalService.open(contentModalRef, {ariaLabelledBy: 'modal-basic-title'}).result.then((result) => {
this.modalSelectedSourceListItem = null
this.closeResult = `Closed with: ${result}`;
}, (reason) => {
this.modalSelectedSourceListItem = null
this.closeResult = `Dismissed ${this.getDismissReason(reason)}`;
});
}
public sourceSyncHandler(source: Source){
this.status[source.source_type] = "authorize"
this.modalService.dismissAll()
this.fastenApi.syncSource(source.id).subscribe(
(respData) => {
delete this.status[source.source_type]
console.log("source sync response:", respData)
},
(err) => {
delete this.status[source.source_type]
console.log(err)
}
)
}
/////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////
// Private // Private
/////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////
private getDismissReason(reason: any): string {
if (reason === ModalDismissReasons.ESC) {
return 'by pressing ESC';
} else if (reason === ModalDismissReasons.BACKDROP_CLICK) {
return 'by clicking on a backdrop';
} else {
return `with: ${reason}`;
}
}
/** /**

View File

@ -11,6 +11,7 @@ import {MetadataSource} from '../models/fasten/metadata-source';
import {uuidV4} from '../../lib/utils/uuid'; import {uuidV4} from '../../lib/utils/uuid';
import {LighthouseSourceSearch} from '../models/lighthouse/lighthouse-source-search'; import {LighthouseSourceSearch} from '../models/lighthouse/lighthouse-source-search';
import {HTTP_CLIENT_TOKEN} from "../dependency-injection"; import {HTTP_CLIENT_TOKEN} from "../dependency-injection";
import {MedicalSourcesFilter} from './medical-sources-filter.service';
@Injectable({ @Injectable({
providedIn: 'root' providedIn: 'root'
@ -20,19 +21,14 @@ export class LighthouseService {
constructor(@Inject(HTTP_CLIENT_TOKEN) private _httpClient: HttpClient) { constructor(@Inject(HTTP_CLIENT_TOKEN) private _httpClient: HttpClient) {
} }
public findLighthouseSources(searchTerm: string, scrollId= "", showHidden = false): Observable<LighthouseSourceSearch> { public searchLighthouseSources(filter: MedicalSourcesFilter): Observable<LighthouseSourceSearch> {
const endpointUrl = new URL(`${environment.lighthouse_api_endpoint_base}/list/search`); if(filter.searchAfter){
if(showHidden){ filter.searchAfter = (filter.searchAfter as string).split(',')
endpointUrl.searchParams.set('show_hidden', 'true'); } else {
filter.searchAfter = []
} }
if(scrollId){ const endpointUrl = new URL(`${environment.lighthouse_api_endpoint_base}/search`);
endpointUrl.searchParams.set('scroll_id', scrollId); return this._httpClient.post<ResponseWrapper>(endpointUrl.toString(), filter)
}
if(searchTerm){
endpointUrl.searchParams.set('query', searchTerm);
}
return this._httpClient.get<ResponseWrapper>(endpointUrl.toString())
.pipe( .pipe(
map((response: ResponseWrapper) => { map((response: ResponseWrapper) => {
console.log("Metadata RESPONSE", response) console.log("Metadata RESPONSE", response)
@ -41,6 +37,28 @@ export class LighthouseService {
); );
} }
//deprecated
// public findLighthouseSources(searchTerm: string, scrollId= "", showHidden = false): Observable<LighthouseSourceSearch> {
// const endpointUrl = new URL(`${environment.lighthouse_api_endpoint_base}/list/search`);
// if(showHidden){
// endpointUrl.searchParams.set('show_hidden', 'true');
// }
// if(scrollId){
// endpointUrl.searchParams.set('scroll_id', scrollId);
// }
// if(searchTerm){
// endpointUrl.searchParams.set('query', searchTerm);
// }
//
// return this._httpClient.get<ResponseWrapper>(endpointUrl.toString())
// .pipe(
// map((response: ResponseWrapper) => {
// console.log("Metadata RESPONSE", response)
// return response.data as LighthouseSourceSearch
// })
// );
// }
public getLighthouseSourceMetadataMap(showHidden = false): Observable<{[name: string]: MetadataSource}> { public getLighthouseSourceMetadataMap(showHidden = false): Observable<{[name: string]: MetadataSource}> {
const endpointUrl = new URL(`${environment.lighthouse_api_endpoint_base}/list`); const endpointUrl = new URL(`${environment.lighthouse_api_endpoint_base}/list`);
if(showHidden){ if(showHidden){
@ -209,881 +227,5 @@ export class LighthouseService {
}) })
return parts.join(separator); return parts.join(separator);
} }
public categoryCodeLookup(code: string): string {
return SOURCE_CATEGORY_CODE_LOOKUP[code];
}
} }
const SOURCE_CATEGORY_CODE_LOOKUP = {
"101200000X": "Drama Therapist",
"101Y00000X": "Counselor",
"101YA0400X": "Addiction (Substance Use Disorder) Counselor",
"101YM0800X": "Mental Health Counselor",
"101YP1600X": "Pastoral Counselor",
"101YP2500X": "Professional Counselor",
"101YS0200X": "School Counselor",
"102L00000X": "Psychoanalyst",
"102X00000X": "Poetry Therapist",
"103G00000X": "Clinical Neuropsychologist",
"103GC0700X": "Deactivated - Clinical Neuropsychologist",
"103K00000X": "Behavioral Analyst",
"103T00000X": "Psychologist",
"103TA0400X": "Addiction (Substance Use Disorder) Psychologist",
"103TA0700X": "Adult Development & Aging Psychologist",
"103TB0200X": "Cognitive & Behavioral Psychologist",
"103TC0700X": "Clinical Psychologist",
"103TC1900X": "Counseling Psychologist",
"103TC2200X": "Clinical Child & Adolescent Psychologist",
"103TE1000X": "Deactivated - Psychologist",
"103TE1100X": "Exercise & Sports Psychologist",
"103TF0000X": "Family Psychologist",
"103TF0200X": "Forensic Psychologist",
"103TH0004X": "Health Psychologist",
"103TH0100X": "Health Service Psychologist",
"103TM1700X": "Deactivated - Psychologist Men & Masculinity",
"103TM1800X": "Intellectual & Developmental Disabilities Psychologist",
"103TP0016X": "Prescribing (Medical) Psychologist",
"103TP0814X": "Psychoanalysis Psychologist",
"103TP2700X": "Deactivated - Psychologist Psychotherapy",
"103TP2701X": "Group Psychotherapy Psychologist",
"103TR0400X": "Rehabilitation Psychologist",
"103TS0200X": "School Psychologist",
"103TW0100X": "Deactivated - Psychotherapy Women",
"104100000X": "Social Worker",
"1041C0700X": "Clinical Social Worker",
"1041S0200X": "School Social Worker",
"106E00000X": "Assistant Behavior Analyst",
"106H00000X": "Marriage & Family Therapist",
"106S00000X": "Behavior Technician",
"111N00000X": "Chiropractor",
"111NI0013X": "Independent Medical Examiner Chiropractor",
"111NI0900X": "Internist Chiropractor",
"111NN0400X": "Neurology Chiropractor",
"111NN1001X": "Nutrition Chiropractor",
"111NP0017X": "Pediatric Chiropractor",
"111NR0200X": "Radiology Chiropractor",
"111NR0400X": "Rehabilitation Chiropractor",
"111NS0005X": "Sports Physician Chiropractor",
"111NT0100X": "Thermography Chiropractor",
"111NX0100X": "Occupational Health Chiropractor",
"111NX0800X": "Orthopedic Chiropractor",
"122300000X": "Dentist",
"1223D0001X": "Public Health Dentist",
"1223D0004X": "Dentist Anesthesiologist",
"1223E0200X": "Endodontist",
"1223G0001X": "General Practice Dentistry",
"1223P0106X": "Oral and Maxillofacial Pathology Dentist",
"1223P0221X": "Pediatric Dentist",
"1223P0300X": "Periodontist",
"1223P0700X": "Prosthodontist",
"1223S0112X": "Oral and Maxillofacial Surgery (Dentist)",
"1223X0008X": "Oral and Maxillofacial Radiology Dentist",
"1223X0400X": "Orthodontics and Dentofacial Orthopedic Dentist",
"1223X2210X": "Orofacial Pain Dentist",
"122400000X": "Denturist",
"124Q00000X": "Dental Hygienist",
"125J00000X": "Dental Therapist",
"125K00000X": "Advanced Practice Dental Therapist",
"125Q00000X": "Oral Medicinist",
"126800000X": "Dental Assistant",
"126900000X": "Dental Laboratory Technician",
"132700000X": "Dietary Manager",
"133N00000X": "Nutritionist",
"133NN1002X": "Nutrition Education Nutritionist",
"133V00000X": "Registered Dietitian",
"133VN1004X": "Pediatric Nutrition Registered Dietitian",
"133VN1005X": "Renal Nutrition Registered Dietitian",
"133VN1006X": "Metabolic Nutrition Registered Dietitian",
"133VN1101X": "Gerontological Nutrition Registered Dietitian",
"133VN1201X": "Obesity and Weight Management Nutrition Registered Dietitian",
"133VN1301X": "Oncology Nutrition Registered Dietitian",
"133VN1401X": "Pediatric Critical Care Nutrition Registered Dietitian",
"133VN1501X": "Sports Dietetics Nutrition Registered Dietitian",
"136A00000X": "Registered Dietetic Technician",
"146D00000X": "Personal Emergency Response Attendant",
"146L00000X": "Paramedic",
"146M00000X": "Intermediate Emergency Medical Technician",
"146N00000X": "Basic Emergency Medical Technician",
"152W00000X": "Optometrist",
"152WC0802X": "Corneal and Contact Management Optometrist",
"152WL0500X": "Low Vision Rehabilitation Optometrist",
"152WP0200X": "Pediatric Optometrist",
"152WS0006X": "Sports Vision Optometrist",
"152WV0400X": "Vision Therapy Optometrist",
"152WX0102X": "Occupational Vision Optometrist",
"156F00000X": "Technician/Technologist",
"156FC0800X": "Contact Lens Technician/Technologist",
"156FC0801X": "Contact Lens Fitter",
"156FX1100X": "Ophthalmic Technician/Technologist",
"156FX1101X": "Ophthalmic Assistant",
"156FX1201X": "Optometric Assistant Technician",
"156FX1202X": "Optometric Technician",
"156FX1700X": "Ocularist",
"156FX1800X": "Optician",
"156FX1900X": "Orthoptist",
"163W00000X": "Registered Nurse",
"163WA0400X": "Addiction (Substance Use Disorder) Registered Nurse",
"163WA2000X": "Administrator Registered Nurse",
"163WC0200X": "Critical Care Medicine Registered Nurse",
"163WC0400X": "Case Management Registered Nurse",
"163WC1400X": "College Health Registered Nurse",
"163WC1500X": "Community Health Registered Nurse",
"163WC1600X": "Continuing Education/Staff Development Registered Nurse",
"163WC2100X": "Continence Care Registered Nurse",
"163WC3500X": "Cardiac Rehabilitation Registered Nurse",
"163WD0400X": "Diabetes Educator Registered Nurse",
"163WD1100X": "Peritoneal Dialysis Registered Nurse",
"163WE0003X": "Emergency Registered Nurse",
"163WE0900X": "Enterostomal Therapy Registered Nurse",
"163WF0300X": "Flight Registered Nurse",
"163WG0000X": "General Practice Registered Nurse",
"163WG0100X": "Gastroenterology Registered Nurse",
"163WG0600X": "Gerontology Registered Nurse",
"163WH0200X": "Home Health Registered Nurse",
"163WH0500X": "Hemodialysis Registered Nurse",
"163WH1000X": "Hospice Registered Nurse",
"163WI0500X": "Infusion Therapy Registered Nurse",
"163WI0600X": "Infection Control Registered Nurse",
"163WL0100X": "Lactation Consultant (Registered Nurse)",
"163WM0102X": "Maternal Newborn Registered Nurse",
"163WM0705X": "Medical-Surgical Registered Nurse",
"163WM1400X": "Nurse Massage Therapist (NMT)",
"163WN0002X": "Neonatal Intensive Care Registered Nurse",
"163WN0003X": "Low-Risk Neonatal Registered Nurse",
"163WN0300X": "Nephrology Registered Nurse",
"163WN0800X": "Neuroscience Registered Nurse",
"163WN1003X": "Nutrition Support Registered Nurse",
"163WP0000X": "Pain Management Registered Nurse",
"163WP0200X": "Pediatric Registered Nurse",
"163WP0218X": "Pediatric Oncology Registered Nurse",
"163WP0807X": "Child & Adolescent Psychiatric/Mental Health Registered Nurse",
"163WP0808X": "Psychiatric/Mental Health Registered Nurse",
"163WP0809X": "Adult Psychiatric/Mental Health Registered Nurse",
"163WP1700X": "Perinatal Registered Nurse",
"163WP2201X": "Ambulatory Care Registered Nurse",
"163WR0006X": "Registered Nurse First Assistant",
"163WR0400X": "Rehabilitation Registered Nurse",
"163WR1000X": "Reproductive Endocrinology/Infertility Registered Nurse",
"163WS0121X": "Plastic Surgery Registered Nurse",
"163WS0200X": "School Registered Nurse",
"163WU0100X": "Urology Registered Nurse",
"163WW0000X": "Wound Care Registered Nurse",
"163WW0101X": "Ambulatory Women's Health Care Registered Nurse",
"163WX0002X": "High-Risk Obstetric Registered Nurse",
"163WX0003X": "Inpatient Obstetric Registered Nurse",
"163WX0106X": "Occupational Health Registered Nurse",
"163WX0200X": "Oncology Registered Nurse",
"163WX0601X": "Otorhinolaryngology & Head-Neck Registered Nurse",
"163WX0800X": "Orthopedic Registered Nurse",
"163WX1100X": "Ophthalmic Registered Nurse",
"163WX1500X": "Ostomy Care Registered Nurse",
"164W00000X": "Licensed Practical Nurse",
"164X00000X": "Licensed Vocational Nurse",
"167G00000X": "Licensed Psychiatric Technician",
"170100000X": "Ph.D. Medical Genetics",
"170300000X": "Genetic Counselor (M.S.)",
"171000000X": "Military Health Care Provider",
"1710I1002X": "Independent Duty Corpsman",
"1710I1003X": "Independent Duty Medical Technicians",
"171100000X": "Acupuncturist",
"171400000X": "Health & Wellness Coach",
"171M00000X": "Case Manager/Care Coordinator",
"171R00000X": "Interpreter",
"171W00000X": "Contractor",
"171WH0202X": "Home Modifications Contractor",
"171WV0202X": "Vehicle Modifications Contractor",
"172A00000X": "Driver",
"172M00000X": "Mechanotherapist",
"172P00000X": "Naprapath",
"172V00000X": "Community Health Worker",
"173000000X": "Legal Medicine",
"173C00000X": "Reflexologist",
"173F00000X": "Sleep Specialist (PhD)",
"174200000X": "Meals Provider",
"174400000X": "Specialist",
"1744G0900X": "Graphics Designer",
"1744P3200X": "Prosthetics Case Management",
"1744R1102X": "Research Study Specialist",
"1744R1103X": "Research Study Abstracter/Coder",
"174H00000X": "Health Educator",
"174M00000X": "Veterinarian",
"174MM1900X": "Medical Research Veterinarian",
"174N00000X": "Lactation Consultant (Non-RN)",
"174V00000X": "Clinical Ethicist",
"175F00000X": "Naturopath",
"175L00000X": "Homeopath",
"175M00000X": "Lay Midwife",
"175T00000X": "Peer Specialist",
"176B00000X": "Midwife",
"176P00000X": "Funeral Director",
"177F00000X": "Lodging Provider",
"183500000X": "Pharmacist",
"1835C0205X": "Critical Care Pharmacist",
"1835G0000X": "Deactivated - Pharmacist",
"1835G0303X": "Geriatric Pharmacist",
"1835N0905X": "Nuclear Pharmacist",
"1835N1003X": "Nutrition Support Pharmacist",
"1835P0018X": "Pharmacist Clinician (PhC)/ Clinical Pharmacy Specialist",
"1835P0200X": "Pediatric Pharmacist",
"1835P1200X": "Pharmacotherapy Pharmacist",
"1835P1300X": "Psychiatric Pharmacist",
"1835P2201X": "Ambulatory Care Pharmacist",
"1835X0200X": "Oncology Pharmacist",
"183700000X": "Pharmacy Technician",
"193200000X": "Multi-Specialty Group",
"193400000X": "Single Specialty Group",
"202C00000X": "Independent Medical Examiner Physician",
"202D00000X": "Integrative Medicine",
"202K00000X": "Phlebology Physician",
"204C00000X": "Sports Medicine (Neuromusculoskeletal Medicine) Physician",
"204D00000X": "Neuromusculoskeletal Medicine & OMM Physician",
"204E00000X": "Oral & Maxillofacial Surgery (D.M.D.)",
"204F00000X": "Transplant Surgery Physician",
"204R00000X": "Electrodiagnostic Medicine Physician",
"207K00000X": "Allergy & Immunology Physician",
"207KA0200X": "Allergy Physician",
"207KI0005X": "Clinical & Laboratory Immunology (Allergy & Immunology) Physician",
"207L00000X": "Anesthesiology Physician",
"207LA0401X": "Addiction Medicine (Anesthesiology) Physician",
"207LC0200X": "Critical Care Medicine (Anesthesiology) Physician",
"207LH0002X": "Hospice and Palliative Medicine (Anesthesiology) Physician",
"207LP2900X": "Pain Medicine (Anesthesiology) Physician",
"207LP3000X": "Pediatric Anesthesiology Physician",
"207N00000X": "Dermatology Physician",
"207ND0101X": "MOHS-Micrographic Surgery Physician",
"207ND0900X": "Dermatopathology Physician",
"207NI0002X": "Clinical & Laboratory Dermatological Immunology Physician",
"207NP0225X": "Pediatric Dermatology Physician",
"207NS0135X": "Procedural Dermatology Physician",
"207P00000X": "Emergency Medicine Physician",
"207PE0004X": "Emergency Medical Services (Emergency Medicine) Physician",
"207PE0005X": "Undersea and Hyperbaric Medicine (Emergency Medicine) Physician",
"207PH0002X": "Hospice and Palliative Medicine (Emergency Medicine) Physician",
"207PP0204X": "Pediatric Emergency Medicine (Emergency Medicine) Physician",
"207PS0010X": "Sports Medicine (Emergency Medicine) Physician",
"207PT0002X": "Medical Toxicology (Emergency Medicine) Physician",
"207Q00000X": "Family Medicine Physician",
"207QA0000X": "Adolescent Medicine (Family Medicine) Physician",
"207QA0401X": "Addiction Medicine (Family Medicine) Physician",
"207QA0505X": "Adult Medicine Physician",
"207QB0002X": "Obesity Medicine (Family Medicine) Physician",
"207QG0300X": "Geriatric Medicine (Family Medicine) Physician",
"207QH0002X": "Hospice and Palliative Medicine (Family Medicine) Physician",
"207QS0010X": "Sports Medicine (Family Medicine) Physician",
"207QS1201X": "Sleep Medicine (Family Medicine) Physician",
"207R00000X": "Internal Medicine Physician",
"207RA0000X": "Adolescent Medicine (Internal Medicine) Physician",
"207RA0001X": "Advanced Heart Failure and Transplant Cardiology Physician",
"207RA0002X": "Adult Congenital Heart Disease Physician",
"207RA0201X": "Allergy & Immunology (Internal Medicine) Physician",
"207RA0401X": "Addiction Medicine (Internal Medicine) Physician",
"207RB0002X": "Obesity Medicine (Internal Medicine) Physician",
"207RC0000X": "Cardiovascular Disease Physician",
"207RC0001X": "Clinical Cardiac Electrophysiology Physician",
"207RC0200X": "Critical Care Medicine (Internal Medicine) Physician",
"207RE0101X": "Endocrinology, Diabetes & Metabolism Physician",
"207RG0100X": "Gastroenterology Physician",
"207RG0300X": "Geriatric Medicine (Internal Medicine) Physician",
"207RH0000X": "Hematology (Internal Medicine) Physician",
"207RH0002X": "Hospice and Palliative Medicine (Internal Medicine) Physician",
"207RH0003X": "Hematology & Oncology Physician",
"207RH0005X": "Hypertension Specialist Physician",
"207RI0001X": "Clinical & Laboratory Immunology (Internal Medicine) Physician",
"207RI0008X": "Hepatology Physician",
"207RI0011X": "Interventional Cardiology Physician",
"207RI0200X": "Infectious Disease Physician",
"207RM1200X": "Magnetic Resonance Imaging (MRI) Internal Medicine Physician",
"207RN0300X": "Nephrology Physician",
"207RP1001X": "Pulmonary Disease Physician",
"207RR0500X": "Rheumatology Physician",
"207RS0010X": "Sports Medicine (Internal Medicine) Physician",
"207RS0012X": "Sleep Medicine (Internal Medicine) Physician",
"207RT0003X": "Transplant Hepatology Physician",
"207RX0202X": "Medical Oncology Physician",
"207SC0300X": "Clinical Cytogenetics Physician",
"207SG0201X": "Clinical Genetics (M.D.) Physician",
"207SG0202X": "Clinical Biochemical Genetics Physician",
"207SG0203X": "Clinical Molecular Genetics Physician",
"207SG0205X": "Ph.D. Medical Genetics Physician",
"207SM0001X": "Molecular Genetic Pathology (Medical Genetics) Physician",
"207T00000X": "Neurological Surgery Physician",
"207U00000X": "Nuclear Medicine Physician",
"207UN0901X": "Nuclear Cardiology Physician",
"207UN0902X": "Nuclear Imaging & Therapy Physician",
"207UN0903X": "In Vivo & In Vitro Nuclear Medicine Physician",
"207V00000X": "Obstetrics & Gynecology Physician",
"207VB0002X": "Obesity Medicine (Obstetrics & Gynecology) Physician",
"207VC0200X": "Critical Care Medicine (Obstetrics & Gynecology) Physician",
"207VC0300X": "Complex Family Planning",
"207VE0102X": "Reproductive Endocrinology Physician",
"207VF0040X": "Female Pelvic Medicine and Reconstructive Surgery (Obstetrics & Gynecology) Physician",
"207VG0400X": "Gynecology Physician",
"207VH0002X": "Hospice and Palliative Medicine (Obstetrics & Gynecology) Physician",
"207VM0101X": "Maternal & Fetal Medicine Physician",
"207VX0000X": "Obstetrics Physician",
"207VX0201X": "Gynecologic Oncology Physician",
"207W00000X": "Ophthalmology Physician",
"207WX0009X": "Glaucoma Specialist (Ophthalmology) Physician",
"207WX0107X": "Retina Specialist (Ophthalmology) Physician",
"207WX0108X": "Uveitis and Ocular Inflammatory Disease (Ophthalmology) Physician",
"207WX0109X": "Neuro-ophthalmology Physician",
"207WX0110X": "Pediatric Ophthalmology and Strabismus Specialist Physician Physician",
"207WX0120X": "Cornea and External Diseases Specialist Physician",
"207WX0200X": "Ophthalmic Plastic and Reconstructive Surgery Physician",
"207X00000X": "Orthopaedic Surgery Physician",
"207XP3100X": "Pediatric Orthopaedic Surgery Physician",
"207XS0106X": "Orthopaedic Hand Surgery Physician",
"207XS0114X": "Adult Reconstructive Orthopaedic Surgery Physician",
"207XS0117X": "Orthopaedic Surgery of the Spine Physician",
"207XX0004X": "Orthopaedic Foot and Ankle Surgery Physician",
"207XX0005X": "Sports Medicine (Orthopaedic Surgery) Physician",
"207XX0801X": "Orthopaedic Trauma Physician",
"207Y00000X": "Otolaryngology Physician",
"207YP0228X": "Pediatric Otolaryngology Physician",
"207YS0012X": "Sleep Medicine (Otolaryngology) Physician",
"207YS0123X": "Facial Plastic Surgery Physician",
"207YX0007X": "Plastic Surgery within the Head & Neck (Otolaryngology) Physician",
"207YX0602X": "Otolaryngic Allergy Physician",
"207YX0901X": "Otology & Neurotology Physician",
"207YX0905X": "Otolaryngology/Facial Plastic Surgery Physician",
"207ZB0001X": "Blood Banking & Transfusion Medicine Physician",
"207ZC0006X": "Clinical Pathology Physician",
"207ZC0008X": "Clinical Informatics (Pathology) Physician",
"207ZC0500X": "Cytopathology Physician",
"207ZD0900X": "Dermatopathology (Pathology) Physician",
"207ZF0201X": "Forensic Pathology Physician",
"207ZH0000X": "Hematology (Pathology) Physician",
"207ZI0100X": "Immunopathology Physician",
"207ZM0300X": "Medical Microbiology Physician",
"207ZN0500X": "Neuropathology Physician",
"207ZP0007X": "Molecular Genetic Pathology (Pathology) Physician",
"207ZP0101X": "Anatomic Pathology Physician",
"207ZP0102X": "Anatomic Pathology & Clinical Pathology Physician",
"207ZP0104X": "Chemical Pathology Physician",
"207ZP0105X": "Clinical Pathology/Laboratory Medicine Physician",
"207ZP0213X": "Pediatric Pathology Physician",
"208000000X": "Pediatrics Physician",
"2080A0000X": "Pediatric Adolescent Medicine Physician",
"2080B0002X": "Pediatric Obesity Medicine Physician",
"2080C0008X": "Child Abuse Pediatrics Physician",
"2080H0002X": "Pediatric Hospice and Palliative Medicine Physician",
"2080I0007X": "Pediatric Clinical & Laboratory Immunology Physician",
"2080N0001X": "Neonatal-Perinatal Medicine Physician",
"2080P0006X": "Developmental - Behavioral Pediatrics Physician",
"2080P0008X": "Pediatric Neurodevelopmental Disabilities Physician",
"2080P0201X": "Pediatric Allergy/Immunology Physician",
"2080P0202X": "Pediatric Cardiology Physician",
"2080P0203X": "Pediatric Critical Care Medicine Physician",
"2080P0204X": "Pediatric Emergency Medicine (Pediatrics) Physician",
"2080P0205X": "Pediatric Endocrinology Physician",
"2080P0206X": "Pediatric Gastroenterology Physician",
"2080P0207X": "Pediatric Hematology & Oncology Physician",
"2080P0208X": "Pediatric Infectious Diseases Physician",
"2080P0210X": "Pediatric Nephrology Physician",
"2080P0214X": "Pediatric Pulmonology Physician",
"2080P0216X": "Pediatric Rheumatology Physician",
"2080S0010X": "Pediatric Sports Medicine Physician",
"2080S0012X": "Pediatric Sleep Medicine Physician",
"2080T0002X": "Pediatric Medical Toxicology Physician",
"2080T0004X": "Pediatric Transplant Hepatology Physician",
"208100000X": "Physical Medicine & Rehabilitation Physician",
"2081H0002X": "Hospice and Palliative Medicine (Physical Medicine & Rehabilitation) Physician",
"2081N0008X": "Neuromuscular Medicine (Physical Medicine & Rehabilitation) Physician",
"2081P0004X": "Spinal Cord Injury Medicine Physician",
"2081P0010X": "Pediatric Rehabilitation Medicine Physician",
"2081P0301X": "Brain Injury Medicine (Physical Medicine & Rehabilitation) Physician",
"2081P2900X": "Pain Medicine (Physical Medicine & Rehabilitation) Physician",
"2081S0010X": "Sports Medicine (Physical Medicine & Rehabilitation) Physician",
"208200000X": "Plastic Surgery Physician",
"2082S0099X": "Plastic Surgery Within the Head and Neck (Plastic Surgery) Physician",
"2082S0105X": "Surgery of the Hand (Plastic Surgery) Physician",
"2083A0100X": "Aerospace Medicine Physician",
"2083A0300X": "Addiction Medicine (Preventive Medicine) Physician",
"2083B0002X": "Obesity Medicine (Preventive Medicine) Physician",
"2083C0008X": "Clinical Informatics Physician",
"2083P0011X": "Undersea and Hyperbaric Medicine (Preventive Medicine) Physician",
"2083P0500X": "Preventive Medicine/Occupational Environmental Medicine Physician",
"2083P0901X": "Public Health & General Preventive Medicine Physician",
"2083S0010X": "Sports Medicine (Preventive Medicine) Physician",
"2083T0002X": "Medical Toxicology (Preventive Medicine) Physician",
"2083X0100X": "Occupational Medicine Physician",
"2084A0401X": "Addiction Medicine (Psychiatry & Neurology) Physician",
"2084A2900X": "Neurocritical Care Physician",
"2084B0002X": "Obesity Medicine (Psychiatry & Neurology) Physician",
"2084B0040X": "Behavioral Neurology & Neuropsychiatry Physician",
"2084D0003X": "Diagnostic Neuroimaging (Psychiatry & Neurology) Physician",
"2084E0001X": "Epilepsy Physician",
"2084F0202X": "Forensic Psychiatry Physician",
"2084H0002X": "Hospice and Palliative Medicine (Psychiatry & Neurology) Physician",
"2084N0008X": "Neuromuscular Medicine (Psychiatry & Neurology) Physician",
"2084N0400X": "Neurology Physician",
"2084N0402X": "Neurology with Special Qualifications in Child Neurology Physician",
"2084N0600X": "Clinical Neurophysiology Physician",
"2084P0005X": "Neurodevelopmental Disabilities Physician Physician",
"2084P0015X": "Psychosomatic Medicine Physician",
"2084P0301X": "Brain Injury Medicine (Psychiatry & Neurology) Physician",
"2084P0800X": "Psychiatry Physician",
"2084P0802X": "Addiction Psychiatry Physician",
"2084P0804X": "Child & Adolescent Psychiatry Physician",
"2084P0805X": "Geriatric Psychiatry Physician",
"2084P2900X": "Pain Medicine (Psychiatry & Neurology) Physician",
"2084S0010X": "Sports Medicine (Psychiatry & Neurology) Physician",
"2084S0012X": "Sleep Medicine (Psychiatry & Neurology) Physician",
"2084V0102X": "Vascular Neurology Physician",
"2085B0100X": "Body Imaging Physician",
"2085D0003X": "Diagnostic Neuroimaging (Radiology) Physician",
"2085H0002X": "Hospice and Palliative Medicine (Radiology) Physician",
"2085N0700X": "Neuroradiology Physician",
"2085N0904X": "Nuclear Radiology Physician",
"2085P0229X": "Pediatric Radiology Physician",
"2085R0001X": "Radiation Oncology Physician",
"2085R0202X": "Diagnostic Radiology Physician",
"2085R0203X": "Therapeutic Radiology Physician",
"2085R0204X": "Vascular & Interventional Radiology Physician",
"2085R0205X": "Radiological Physics Physician",
"2085U0001X": "Diagnostic Ultrasound Physician",
"208600000X": "Surgery Physician",
"2086H0002X": "Hospice and Palliative Medicine (Surgery) Physician",
"2086S0102X": "Surgical Critical Care Physician",
"2086S0105X": "Surgery of the Hand (Surgery) Physician",
"2086S0120X": "Pediatric Surgery Physician",
"2086S0122X": "Plastic and Reconstructive Surgery Physician",
"2086S0127X": "Trauma Surgery Physician",
"2086S0129X": "Vascular Surgery Physician",
"2086X0206X": "Surgical Oncology Physician",
"208800000X": "Urology Physician",
"2088F0040X": "Female Pelvic Medicine and Reconstructive Surgery (Urology) Physician",
"2088P0231X": "Pediatric Urology Physician",
"208C00000X": "Colon & Rectal Surgery Physician",
"208D00000X": "General Practice Physician",
"208G00000X": "Thoracic Surgery (Cardiothoracic Vascular Surgery) Physician",
"208M00000X": "Hospitalist Physician",
"208U00000X": "Clinical Pharmacology Physician",
"208VP0000X": "Pain Medicine Physician",
"208VP0014X": "Interventional Pain Medicine Physician",
"209800000X": "Legal Medicine (M.D./D.O.) Physician",
"211D00000X": "Podiatric Assistant",
"213E00000X": "Podiatrist",
"213EG0000X": "Deactivated - Podiatrist",
"213EP0504X": "Public Medicine Podiatrist",
"213EP1101X": "Primary Podiatric Medicine Podiatrist",
"213ER0200X": "Radiology Podiatrist",
"213ES0000X": "Sports Medicine Podiatrist",
"213ES0103X": "Foot & Ankle Surgery Podiatrist",
"213ES0131X": "Foot Surgery Podiatrist",
"221700000X": "Art Therapist",
"222Q00000X": "Developmental Therapist",
"222Z00000X": "Orthotist",
"224900000X": "Mastectomy Fitter",
"224L00000X": "Pedorthist",
"224P00000X": "Prosthetist",
"224Y00000X": "Clinical Exercise Physiologist",
"224Z00000X": "Occupational Therapy Assistant",
"224ZE0001X": "Environmental Modification Occupational Therapy Assistant",
"224ZF0002X": "Feeding, Eating & Swallowing Occupational Therapy Assistant",
"224ZL0004X": "Low Vision Occupational Therapy Assistant",
"224ZR0403X": "Driving and Community Mobility Occupational Therapy Assistant",
"225000000X": "Orthotic Fitter",
"225100000X": "Physical Therapist",
"2251C2600X": "Cardiopulmonary Physical Therapist",
"2251E1200X": "Ergonomics Physical Therapist",
"2251E1300X": "Clinical Electrophysiology Physical Therapist",
"2251G0304X": "Geriatric Physical Therapist",
"2251H1200X": "Hand Physical Therapist",
"2251H1300X": "Human Factors Physical Therapist",
"2251N0400X": "Neurology Physical Therapist",
"2251P0200X": "Pediatric Physical Therapist",
"2251S0007X": "Sports Physical Therapist",
"2251X0800X": "Orthopedic Physical Therapist",
"225200000X": "Physical Therapy Assistant",
"225400000X": "Rehabilitation Practitioner",
"225500000X": "Respiratory/Developmental/Rehabilitative Specialist/Technologist",
"2255A2300X": "Athletic Trainer",
"2255R0406X": "Blind Rehabilitation Specialist/Technologist",
"225600000X": "Dance Therapist",
"225700000X": "Massage Therapist",
"225800000X": "Recreation Therapist",
"225A00000X": "Music Therapist",
"225B00000X": "Pulmonary Function Technologist",
"225C00000X": "Rehabilitation Counselor",
"225CA2400X": "Assistive Technology Practitioner Rehabilitation Counselor",
"225CA2500X": "Assistive Technology Supplier Rehabilitation Counselor",
"225CX0006X": "Orientation and Mobility Training Rehabilitation Counselor",
"225X00000X": "Occupational Therapist",
"225XE0001X": "Environmental Modification Occupational Therapist",
"225XE1200X": "Ergonomics Occupational Therapist",
"225XF0002X": "Feeding, Eating & Swallowing Occupational Therapist",
"225XG0600X": "Gerontology Occupational Therapist",
"225XH1200X": "Hand Occupational Therapist",
"225XH1300X": "Human Factors Occupational Therapist",
"225XL0004X": "Low Vision Occupational Therapist",
"225XM0800X": "Mental Health Occupational Therapist",
"225XN1300X": "Neurorehabilitation Occupational Therapist",
"225XP0019X": "Physical Rehabilitation Occupational Therapist",
"225XP0200X": "Pediatric Occupational Therapist",
"225XR0403X": "Driving and Community Mobility Occupational Therapist",
"226000000X": "Recreational Therapist Assistant",
"226300000X": "Kinesiotherapist",
"227800000X": "Certified Respiratory Therapist",
"2278C0205X": "Critical Care Certified Respiratory Therapist",
"2278E0002X": "Emergency Care Certified Respiratory Therapist",
"2278E1000X": "Educational Certified Respiratory Therapist",
"2278G0305X": "Geriatric Care Certified Respiratory Therapist",
"2278G1100X": "General Care Certified Respiratory Therapist",
"2278H0200X": "Home Health Certified Respiratory Therapist",
"2278P1004X": "Pulmonary Diagnostics Certified Respiratory Therapist",
"2278P1005X": "Pulmonary Rehabilitation Certified Respiratory Therapist",
"2278P1006X": "Pulmonary Function Technologist Certified Respiratory Therapist",
"2278P3800X": "Palliative/Hospice Certified Respiratory Therapist",
"2278P3900X": "Neonatal/Pediatric Certified Respiratory Therapist",
"2278P4000X": "Patient Transport Certified Respiratory Therapist",
"2278S1500X": "SNF/Subacute Care Certified Respiratory Therapist",
"227900000X": "Registered Respiratory Therapist",
"2279C0205X": "Critical Care Registered Respiratory Therapist",
"2279E0002X": "Emergency Care Registered Respiratory Therapist",
"2279E1000X": "Educational Registered Respiratory Therapist",
"2279G0305X": "Geriatric Care Registered Respiratory Therapist",
"2279G1100X": "General Care Registered Respiratory Therapist",
"2279H0200X": "Home Health Registered Respiratory Therapist",
"2279P1004X": "Pulmonary Diagnostics Registered Respiratory Therapist",
"2279P1005X": "Pulmonary Rehabilitation Registered Respiratory Therapist",
"2279P1006X": "Pulmonary Function Technologist Registered Respiratory Therapist",
"2279P3800X": "Palliative/Hospice Registered Respiratory Therapist",
"2279P3900X": "Neonatal/Pediatric Registered Respiratory Therapist",
"2279P4000X": "Patient Transport Registered Respiratory Therapist",
"2279S1500X": "SNF/Subacute Care Registered Respiratory Therapist",
"229N00000X": "Anaplastologist",
"231H00000X": "Audiologist",
"231HA2400X": "Assistive Technology Practitioner Audiologist",
"231HA2500X": "Assistive Technology Supplier Audiologist",
"235500000X": "Speech/Language/Hearing Specialist/Technologist",
"2355A2700X": "Audiology Assistant",
"2355S0801X": "Speech-Language Assistant",
"235Z00000X": "Speech-Language Pathologist",
"237600000X": "Audiologist-Hearing Aid Fitter",
"237700000X": "Hearing Instrument Specialist",
"242T00000X": "Perfusionist",
"243U00000X": "Radiology Practitioner Assistant",
"246Q00000X": "Pathology Specialist/Technologist",
"246QB0000X": "Blood Banking Specialist/Technologist",
"246QC1000X": "Chemistry Pathology Specialist/Technologist",
"246QC2700X": "Cytotechnology Specialist/Technologist",
"246QH0000X": "Hematology Specialist/Technologist",
"246QH0401X": "Hemapheresis Practitioner",
"246QH0600X": "Histology Specialist/Technologist",
"246QI0000X": "Immunology Pathology Specialist/Technologist",
"246QL0900X": "Laboratory Management Specialist/Technologist",
"246QL0901X": "Diplomate Laboratory Management Specialist/Technologist",
"246QM0706X": "Medical Technologist",
"246QM0900X": "Microbiology Specialist/Technologist",
"246R00000X": "Pathology Technician",
"246RH0600X": "Histology Technician",
"246RM2200X": "Medical Laboratory Technician",
"246RP1900X": "Phlebotomy Technician",
"246W00000X": "Cardiology Technician",
"246X00000X": "Cardiovascular Specialist/Technologist",
"246XC2901X": "Cardiovascular Invasive Specialist/Technologist",
"246XC2903X": "Vascular Specialist/Technologist",
"246XS1301X": "Sonography Specialist/Technologist",
"246Y00000X": "Health Information Specialist/Technologist",
"246YC3301X": "Hospital Based Coding Specialist",
"246YC3302X": "Physician Office Based Coding Specialist",
"246YR1600X": "Registered Record Administrator",
"246Z00000X": "Other Specialist/Technologist",
"246ZA2600X": "Medical Art Specialist/Technologist",
"246ZB0301X": "Biomedical Engineer",
"246ZB0302X": "Biomedical Photographer",
"246ZB0500X": "Biochemist",
"246ZB0600X": "Biostatiscian",
"246ZC0007X": "Surgical Assistant",
"246ZE0500X": "EEG Specialist/Technologist",
"246ZE0600X": "Electroneurodiagnostic Specialist/Technologist",
"246ZG0701X": "Graphics Methods Specialist/Technologist",
"246ZG1000X": "Medical Geneticist (PhD) Specialist/Technologist",
"246ZI1000X": "Medical Illustrator",
"246ZN0300X": "Nephrology Specialist/Technologist",
"246ZS0410X": "Surgical Technologist",
"246ZX2200X": "Orthopedic Assistant",
"247000000X": "Health Information Technician",
"2470A2800X": "Assistant Health Information Record Technician",
"247100000X": "Radiologic Technologist",
"2471B0102X": "Bone Densitometry Radiologic Technologist",
"2471C1101X": "Cardiovascular-Interventional Technology Radiologic Technologist",
"2471C1106X": "Cardiac-Interventional Technology Radiologic Technologist",
"2471C3401X": "Computed Tomography Radiologic Technologist",
"2471C3402X": "Radiography Radiologic Technologist",
"2471M1202X": "Magnetic Resonance Imaging Radiologic Technologist",
"2471M2300X": "Mammography Radiologic Technologist",
"2471N0900X": "Nuclear Medicine Technology Radiologic Technologist",
"2471Q0001X": "Quality Management Radiologic Technologist",
"2471R0002X": "Radiation Therapy Radiologic Technologist",
"2471S1302X": "Sonography Radiologic Technologist",
"2471V0105X": "Vascular Sonography Radiologic Technologist",
"2471V0106X": "Vascular-Interventional Technology Radiologic Technologist",
"247200000X": "Other Technician",
"2472B0301X": "Biomedical Engineering Technician",
"2472D0500X": "Darkroom Technician",
"2472E0500X": "EEG Technician",
"2472R0900X": "Renal Dialysis Technician",
"2472V0600X": "Veterinary Technician",
"247ZC0005X": "Clinical Laboratory Director (Non-physician)",
"251300000X": "Local Education Agency (LEA)",
"251B00000X": "Case Management Agency",
"251C00000X": "Developmentally Disabled Services Day Training Agency",
"251E00000X": "Home Health Agency",
"251F00000X": "Home Infusion Agency",
"251G00000X": "Community Based Hospice Care Agency",
"251J00000X": "Nursing Care Agency",
"251K00000X": "Public Health or Welfare Agency",
"251S00000X": "Community/Behavioral Health Agency",
"251T00000X": "PACE Provider Organization",
"251V00000X": "Voluntary or Charitable Agency",
"251X00000X": "Supports Brokerage Agency",
"252Y00000X": "Early Intervention Provider Agency",
"253J00000X": "Foster Care Agency",
"253Z00000X": "In Home Supportive Care Agency",
"261Q00000X": "Clinic/Center",
"261QA0005X": "Ambulatory Family Planning Facility",
"261QA0006X": "Ambulatory Fertility Facility",
"261QA0600X": "Adult Day Care Clinic/Center",
"261QA0900X": "Amputee Clinic/Center",
"261QA1903X": "Ambulatory Surgical Clinic/Center",
"261QA3000X": "Augmentative Communication Clinic/Center",
"261QB0400X": "Birthing Clinic/Center",
"261QC0050X": "Critical Access Hospital Clinic/Center",
"261QC1500X": "Community Health Clinic/Center",
"261QC1800X": "Corporate Health Clinic/Center",
"261QD0000X": "Dental Clinic/Center",
"261QD1600X": "Developmental Disabilities Clinic/Center",
"261QE0002X": "Emergency Care Clinic/Center",
"261QE0700X": "End-Stage Renal Disease (ESRD) Treatment Clinic/Center",
"261QE0800X": "Endoscopy Clinic/Center",
"261QF0050X": "Non-Surgical Family Planning Clinic/Center",
"261QF0400X": "Federally Qualified Health Center (FQHC)",
"261QG0250X": "Genetics Clinic/Center",
"261QH0100X": "Health Service Clinic/Center",
"261QH0700X": "Hearing and Speech Clinic/Center",
"261QI0500X": "Infusion Therapy Clinic/Center",
"261QL0400X": "Lithotripsy Clinic/Center",
"261QM0801X": "Mental Health Clinic/Center (Including Community Mental Health Center)",
"261QM0850X": "Adult Mental Health Clinic/Center",
"261QM0855X": "Adolescent and Children Mental Health Clinic/Center",
"261QM1000X": "Migrant Health Clinic/Center",
"261QM1100X": "Military/U.S. Coast Guard Outpatient Clinic/Center",
"261QM1101X": "Military and U.S. Coast Guard Ambulatory Procedure Clinic/Center",
"261QM1102X": "Military Outpatient Operational (Transportable) Component Clinic/Center",
"261QM1103X": "Military Ambulatory Procedure Visits Operational (Transportable) Clinic/Center",
"261QM1200X": "Magnetic Resonance Imaging (MRI) Clinic/Center",
"261QM1300X": "Multi-Specialty Clinic/Center",
"261QM2500X": "Medical Specialty Clinic/Center",
"261QM2800X": "Methadone Clinic",
"261QM3000X": "Medically Fragile Infants and Children Day Care",
"261QP0904X": "Federal Public Health Clinic/Center",
"261QP0905X": "State or Local Public Health Clinic/Center",
"261QP1100X": "Podiatric Clinic/Center",
"261QP2000X": "Physical Therapy Clinic/Center",
"261QP2300X": "Primary Care Clinic/Center",
"261QP2400X": "Prison Health Clinic/Center",
"261QP3300X": "Pain Clinic/Center",
"261QR0200X": "Radiology Clinic/Center",
"261QR0206X": "Mammography Clinic/Center",
"261QR0207X": "Mobile Mammography Clinic/Center",
"261QR0208X": "Mobile Radiology Clinic/Center",
"261QR0400X": "Rehabilitation Clinic/Center",
"261QR0401X": "Comprehensive Outpatient Rehabilitation Facility (CORF)",
"261QR0404X": "Cardiac Rehabilitation Clinic/Center",
"261QR0405X": "Substance Use Disorder Rehabilitation Clinic/Center",
"261QR0800X": "Recovery Care Clinic/Center",
"261QR1100X": "Research Clinic/Center",
"261QR1300X": "Rural Health Clinic/Center",
"261QS0112X": "Oral and Maxillofacial Surgery Clinic/Center",
"261QS0132X": "Ophthalmologic Surgery Clinic/Center",
"261QS1000X": "Student Health Clinic/Center",
"261QS1200X": "Sleep Disorder Diagnostic Clinic/Center",
"261QU0200X": "Urgent Care Clinic/Center",
"261QV0200X": "VA Clinic/Center",
"261QX0100X": "Occupational Medicine Clinic/Center",
"261QX0200X": "Oncology Clinic/Center",
"261QX0203X": "Radiation Oncology Clinic/Center",
"273100000X": "Epilepsy Hospital Unit",
"273R00000X": "Psychiatric Hospital Unit",
"273Y00000X": "Rehabilitation Hospital Unit",
"275N00000X": "Medicare Defined Swing Bed Hospital Unit",
"276400000X": "Substance Use Disorder Rehabilitation Hospital Unit",
"281P00000X": "Chronic Disease Hospital",
"281PC2000X": "Children' s Chronic Disease Hospital",
"282E00000X": "Long Term Care Hospital",
"282J00000X": "Religious Nonmedical Health Care Institution",
"282N00000X": "General Acute Care Hospital",
"282NC0060X": "Critical Access Hospital",
"282NC2000X": "Children's Hospital",
"282NR1301X": "Rural Acute Care Hospital",
"282NW0100X": "Women's Hospital",
"283Q00000X": "Psychiatric Hospital",
"283X00000X": "Rehabilitation Hospital",
"283XC2000X": "Children's Rehabilitation Hospital",
"284300000X": "Special Hospital",
"286500000X": "Military Hospital",
"2865C1500X": "Deactivated - Military Hospital",
"2865M2000X": "Military General Acute Care Hospital",
"2865X1600X": "Operational (Transportable) Military General Acute Care Hospital",
"287300000X": "Deactivated - Christian Science Sanitorium",
"291900000X": "Military Clinical Medical Laboratory",
"291U00000X": "Clinical Medical Laboratory",
"292200000X": "Dental Laboratory",
"293D00000X": "Physiological Laboratory",
"302F00000X": "Exclusive Provider Organization",
"302R00000X": "Health Maintenance Organization",
"305R00000X": "Preferred Provider Organization",
"305S00000X": "Point of Service",
"310400000X": "Assisted Living Facility",
"3104A0625X": "Assisted Living Facility (Mental Illness)",
"3104A0630X": "Assisted Living Facility (Behavioral Disturbances)",
"310500000X": "Mental Illness Intermediate Care Facility",
"311500000X": "Alzheimer Center (Dementia Center)",
"311Z00000X": "Custodial Care Facility",
"311ZA0620X": "Adult Care Home Facility",
"313M00000X": "Nursing Facility/Intermediate Care Facility",
"314000000X": "Skilled Nursing Facility",
"3140N1450X": "Pediatric Skilled Nursing Facility",
"315D00000X": "Inpatient Hospice",
"315P00000X": "Intellectual Disabilities Intermediate Care Facility",
"317400000X": "Deactivated - Christian Science Facility",
"320600000X": "Intellectual and/or Developmental Disabilities Residential Treatment Facility",
"320700000X": "Physical Disabilities Residential Treatment Facility",
"320800000X": "Mental Illness Community Based Residential Treatment Facility",
"320900000X": "Intellectual and/or Developmental Disabilities Community Based Residential Treatment Facility",
"322D00000X": "Emotionally Disturbed Childrens' Residential Treatment Facility",
"323P00000X": "Psychiatric Residential Treatment Facility",
"324500000X": "Substance Abuse Rehabilitation Facility",
"3245S0500X": "Children's Substance Abuse Rehabilitation Facility",
"331L00000X": "Blood Bank",
"332000000X": "Military/U.S. Coast Guard Pharmacy",
"332100000X": "Department of Veterans Affairs (VA) Pharmacy",
"332800000X": "Indian Health Service/Tribal/Urban Indian Health (I/T/U) Pharmacy",
"332900000X": "Non-Pharmacy Dispensing Site",
"332B00000X": "Durable Medical Equipment & Medical Supplies",
"332BC3200X": "Customized Equipment (DME)",
"332BD1200X": "Dialysis Equipment & Supplies (DME)",
"332BN1400X": "Nursing Facility Supplies (DME)",
"332BP3500X": "Parenteral & Enteral Nutrition Supplies (DME)",
"332BX2000X": "Oxygen Equipment & Supplies (DME)",
"332G00000X": "Eye Bank",
"332H00000X": "Eyewear Supplier",
"332S00000X": "Hearing Aid Equipment",
"332U00000X": "Home Delivered Meals",
"333300000X": "Emergency Response System Companies",
"333600000X": "Pharmacy",
"3336C0002X": "Clinic Pharmacy",
"3336C0003X": "Community/Retail Pharmacy",
"3336C0004X": "Compounding Pharmacy",
"3336H0001X": "Home Infusion Therapy Pharmacy",
"3336I0012X": "Institutional Pharmacy",
"3336L0003X": "Long Term Care Pharmacy",
"3336M0002X": "Mail Order Pharmacy",
"3336M0003X": "Managed Care Organization Pharmacy",
"3336N0007X": "Nuclear Pharmacy",
"3336S0011X": "Specialty Pharmacy",
"335E00000X": "Prosthetic/Orthotic Supplier",
"335G00000X": "Medical Foods Supplier",
"335U00000X": "Organ Procurement Organization",
"335V00000X": "Portable X-ray and/or Other Portable Diagnostic Imaging Supplier",
"341600000X": "Ambulance",
"3416A0800X": "Air Ambulance",
"3416L0300X": "Land Ambulance",
"3416S0300X": "Water Ambulance",
"341800000X": "Military/U.S. Coast Guard Transport,",
"3418M1110X": "Military or U.S. Coast Guard Ground Transport Ambulance",
"3418M1120X": "Military or U.S. Coast Guard Air Transport Ambulance",
"3418M1130X": "Military or U.S. Coast Guard Water Transport Ambulance",
"342000000X": "Transportation Network Company",
"343800000X": "Secured Medical Transport (VAN)",
"343900000X": "Non-emergency Medical Transport (VAN)",
"344600000X": "Taxi",
"344800000X": "Air Carrier",
"347B00000X": "Bus",
"347C00000X": "Private Vehicle",
"347D00000X": "Train",
"347E00000X": "Transportation Broker",
"363A00000X": "Physician Assistant",
"363AM0700X": "Medical Physician Assistant",
"363AS0400X": "Surgical Physician Assistant",
"363L00000X": "Nurse Practitioner",
"363LA2100X": "Acute Care Nurse Practitioner",
"363LA2200X": "Adult Health Nurse Practitioner",
"363LC0200X": "Critical Care Medicine Nurse Practitioner",
"363LC1500X": "Community Health Nurse Practitioner",
"363LF0000X": "Family Nurse Practitioner",
"363LG0600X": "Gerontology Nurse Practitioner",
"363LN0000X": "Neonatal Nurse Practitioner",
"363LN0005X": "Critical Care Neonatal Nurse Practitioner",
"363LP0200X": "Pediatric Nurse Practitioner",
"363LP0222X": "Critical Care Pediatric Nurse Practitioner",
"363LP0808X": "Psychiatric/Mental Health Nurse Practitioner",
"363LP1700X": "Perinatal Nurse Practitioner",
"363LP2300X": "Primary Care Nurse Practitioner",
"363LS0200X": "School Nurse Practitioner",
"363LW0102X": "Women's Health Nurse Practitioner",
"363LX0001X": "Obstetrics & Gynecology Nurse Practitioner",
"363LX0106X": "Occupational Health Nurse Practitioner",
"364S00000X": "Clinical Nurse Specialist",
"364SA2100X": "Acute Care Clinical Nurse Specialist",
"364SA2200X": "Adult Health Clinical Nurse Specialist",
"364SC0200X": "Critical Care Medicine Clinical Nurse Specialist",
"364SC1501X": "Community Health/Public Health Clinical Nurse Specialist",
"364SC2300X": "Chronic Care Clinical Nurse Specialist",
"364SE0003X": "Emergency Clinical Nurse Specialist",
"364SE1400X": "Ethics Clinical Nurse Specialist",
"364SF0001X": "Family Health Clinical Nurse Specialist",
"364SG0600X": "Gerontology Clinical Nurse Specialist",
"364SH0200X": "Home Health Clinical Nurse Specialist",
"364SH1100X": "Holistic Clinical Nurse Specialist",
"364SI0800X": "Informatics Clinical Nurse Specialist",
"364SL0600X": "Long-Term Care Clinical Nurse Specialist",
"364SM0705X": "Medical-Surgical Clinical Nurse Specialist",
"364SN0000X": "Neonatal Clinical Nurse Specialist",
"364SN0800X": "Neuroscience Clinical Nurse Specialist",
"364SP0200X": "Pediatric Clinical Nurse Specialist",
"364SP0807X": "Child & Adolescent Psychiatric/Mental Health Clinical Nurse Specialist",
"364SP0808X": "Psychiatric/Mental Health Clinical Nurse Specialist",
"364SP0809X": "Adult Psychiatric/Mental Health Clinical Nurse Specialist",
"364SP0810X": "Child & Family Psychiatric/Mental Health Clinical Nurse Specialist",
"364SP0811X": "Chronically Ill Psychiatric/Mental Health Clinical Nurse Specialist",
"364SP0812X": "Community Psychiatric/Mental Health Clinical Nurse Specialist",
"364SP0813X": "Geropsychiatric Psychiatric/Mental Health Clinical Nurse Specialist",
"364SP1700X": "Perinatal Clinical Nurse Specialist",
"364SP2800X": "Perioperative Clinical Nurse Specialist",
"364SR0400X": "Rehabilitation Clinical Nurse Specialist",
"364SS0200X": "School Clinical Nurse Specialist",
"364ST0500X": "Transplantation Clinical Nurse Specialist",
"364SW0102X": "Women's Health Clinical Nurse Specialist",
"364SX0106X": "Occupational Health Clinical Nurse Specialist",
"364SX0200X": "Oncology Clinical Nurse Specialist",
"364SX0204X": "Pediatric Oncology Clinical Nurse Specialist",
"367500000X": "Certified Registered Nurse Anesthetist",
"367A00000X": "Advanced Practice Midwife",
"367H00000X": "Anesthesiologist Assistant",
"372500000X": "Chore Provider",
"372600000X": "Adult Companion",
"373H00000X": "Day Training/Habilitation Specialist",
"374700000X": "Technician",
"3747A0650X": "Attendant Care Provider",
"3747P1801X": "Personal Care Attendant",
"374J00000X": "Doula",
"374K00000X": "Religious Nonmedical Practitioner",
"374T00000X": "Religious Nonmedical Nursing Personnel",
"374U00000X": "Home Health Aide",
"376G00000X": "Nursing Home Administrator",
"376J00000X": "Homemaker",
"376K00000X": "Nurse's Aide",
"385H00000X": "Respite Care",
"385HR2050X": "Respite Care Camp",
"385HR2055X": "Child Mental Illness Respite Care",
"385HR2060X": "Child Intellectual and/or Developmental Disabilities Respite Care",
"385HR2065X": "Child Physical Disabilities Respite Care",
"390200000X": "Student in an Organized Health Care Education/Training Program",
"405300000X": "Prevention Professional"
}

View File

@ -0,0 +1,16 @@
import { TestBed } from '@angular/core/testing';
import { MedicalSourcesFilterService } from './medical-sources-filter.service';
describe('MedicalSourcesFilterService', () => {
let service: MedicalSourcesFilterService;
beforeEach(() => {
TestBed.configureTestingModule({});
service = TestBed.inject(MedicalSourcesFilterService);
});
it('should be created', () => {
expect(service).toBeTruthy();
});
});

View File

@ -0,0 +1,168 @@
import { Injectable } from '@angular/core';
import {FormBuilder, FormControl, FormGroup} from '@angular/forms';
export class MedicalSourcesFilter {
searchAfter: string | string[] = '';
query: string;
platformTypes: string[] = [];
categories: string[] = [];
showHidden: boolean = false;
fields: string[] = []; //specify the fields to return. if null or empty list, return all.
}
@Injectable({
providedIn: 'root'
})
export class MedicalSourcesFilterService {
filterForm = this.formBuilder.group({
searchAfter: [''],
query: [''],
platformTypes: this.formBuilder.group({}),
categories: this.formBuilder.group({}),
showHidden: [false],
})
constructor(private formBuilder: FormBuilder) { }
//parse angular query string parameters
parseQueryParams(queryParams: {[name:string]:string}){
var updateData: {
searchAfter?: string,
query?: string,
platformTypes?: {},
categories?: {},
showHidden?: boolean,
} = {};
if(queryParams['searchAfter']){
updateData.searchAfter = queryParams['searchAfter']
}
if(queryParams['query']){
updateData.query = queryParams['query']
}
if(queryParams['platformTypes']){
updateData.platformTypes = updateData.platformTypes ? updateData.platformTypes : {};
for(let platformType of queryParams['platformTypes']?.split(',')){
updateData.platformTypes[platformType] = true;
}
}
if(queryParams['categories']){
updateData.categories = updateData.categories ? updateData.categories : {};
for(let category of queryParams['categories']?.split(',')){
updateData.categories[category] = true;
}
}
if(queryParams['showHidden']){
updateData.showHidden = queryParams['showHidden'] == 'true';
}
//ensure that checkbox list values exist before trying to "patch" them in.
if(updateData.platformTypes){
var currentFileTypes = this.filterForm.get('platformTypes').value;
Object.keys(updateData.platformTypes).forEach((bucketKey) => {
if(!currentFileTypes.hasOwnProperty(bucketKey)){
(this.filterForm.get('platformTypes') as FormGroup).addControl(bucketKey, new FormControl(false))
}
})
}
if(updateData.categories){
Object.keys(updateData.categories).forEach((bucketKey) => {
if(!this.filterForm.get('categories').get(bucketKey)){
(this.filterForm.get('categories') as FormGroup).addControl(bucketKey, new FormControl(false))
}
})
}
return updateData;
}
toQueryParams() : {[name:string]:string} {
var form = this.filterForm.value;
var queryParams = {};
// if(form.searchAfter){
// var searchAfter = [];
// Object.keys(form.searchAfter).forEach((key) => {
// if (form.searchAfter[key]) {
// searchAfter.push(key);
// }
// })
//
// queryParams['searchAfter'] = searchAfter.join(',');
// }
if(form.query){
queryParams['query'] = form.query
}
if(form.platformTypes && Object.keys(form.platformTypes).length){
var platformTypes = [];
Object.keys(form.platformTypes).forEach((key) => {
if (form.platformTypes[key]) {
platformTypes.push(key);
}
})
queryParams['platformTypes'] = platformTypes.join(',');
}
if(form.categories && Object.keys(form.categories).length){
var categories = [];
Object.keys(form.categories).forEach((key) => {
if (form.categories[key]) {
categories.push(key);
}
})
queryParams['categories'] = categories.join(',');
}
if(form.showHidden){
queryParams['showHidden'] = form.showHidden.toString();
}
return queryParams;
}
toMedicalSourcesFilter(form): MedicalSourcesFilter {
var medicalSourcesFilter = new MedicalSourcesFilter();
if(form.searchAfter){
medicalSourcesFilter.searchAfter = form.searchAfter
}
if(form.query){
medicalSourcesFilter.query = form.query;
}
if(form.platformTypes){
medicalSourcesFilter.platformTypes = [];
Object.keys(form.platformTypes).forEach((key) => {
if (form.platformTypes[key]) {
medicalSourcesFilter.platformTypes.push(key);
}
})
}
if(form.categories){
medicalSourcesFilter.categories = [];
Object.keys(form.categories).forEach((key) => {
if (form.categories[key]) {
medicalSourcesFilter.categories.push(key);
}
})
}
if (form.showHidden) {
medicalSourcesFilter.showHidden = form.showHidden;
}
return medicalSourcesFilter
}
}

View File

@ -214,3 +214,23 @@ app-nlm-typeahead {
border-radius: 10px; border-radius: 10px;
} }
} }
//Medical Source Filter
.category-label {
font-weight: 400
}
app-medical-sources-filter > .az-content-left-components {
overflow: hidden;
-webkit-transition: width 0.2s ease-in-out;
-moz-transition: width 0.2s ease-in-out;
-o-transition: width 0.2s ease-in-out;
transition: width 0.2s ease-in-out;
}
app-medical-sources-filter > .az-content-left-components:hover{
width: 100%;
-webkit-transition: width 0.2s ease-in-out;
-moz-transition: width 0.2s ease-in-out;
-o-transition: width 0.2s ease-in-out;
transition: width 0.2s ease-in-out;
}