@@ -74,6 +74,7 @@ export class DataUtil {
7474
7575 this . bolusToWizardIdMap = this . bolusToWizardIdMap || { } ;
7676 this . bolusDatumsByIdMap = this . bolusDatumsByIdMap || { } ;
77+ this . deviceUploadMap = this . deviceUploadMap || { } ;
7778 this . wizardDatumsByIdMap = this . wizardDatumsByIdMap || { } ;
7879 this . latestDatumByType = this . latestDatumByType || { } ;
7980
@@ -186,6 +187,23 @@ export class DataUtil {
186187 if ( d . type === 'bolus' ) {
187188 this . bolusDatumsByIdMap [ d . id ] = d ;
188189 }
190+
191+ // Generate a map of devices by deviceId
192+ if ( ! d . deviceId && _ . get ( d , 'origin.name' ) === 'com.apple.HealthKit' ) {
193+ const HKdeviceId = [ 'HealthKit' ] ;
194+ if ( _ . get ( d , 'origin.payload.sourceRevision.source.name' ) ) {
195+ HKdeviceId . push ( _ . get ( d , 'origin.payload.sourceRevision.source.name' ) ) ;
196+ }
197+ HKdeviceId . push ( d . uploadId . slice ( 0 , 6 ) ) ;
198+ d . deviceId = HKdeviceId . join ( ' ' ) ;
199+ }
200+ if ( ! d . deviceId && _ . get ( d , 'payload.transmitterId' , false ) ) {
201+ const dexDeviceId = [ 'Dexcom' , d . uploadId . slice ( 0 , 6 ) ] ;
202+ d . deviceId = dexDeviceId . join ( ' ' ) ;
203+ }
204+ if ( d . deviceId && ! this . deviceUploadMap [ d . deviceId ] ) {
205+ this . deviceUploadMap [ d . deviceId ] = d . uploadId ;
206+ }
189207 } ;
190208
191209 joinWizardAndBolus = d => {
@@ -476,10 +494,12 @@ export class DataUtil {
476494 this . bolusDatumsByIdMap = { } ;
477495 this . wizardDatumsByIdMap = { } ;
478496 this . latestDatumByType = { } ;
497+ this . deviceUploadMap = { } ;
479498 delete this . bgSources ;
480499 delete this . bgPrefs ;
481500 delete this . timePrefs ;
482501 delete this . latestPumpUpload ;
502+ delete this . devices ;
483503 this . init ( ) ;
484504 }
485505 } ;
@@ -538,6 +558,10 @@ export class DataUtil {
538558 this . dimension . byType = this . data . dimension ( d => d . type ) ;
539559 } ;
540560
561+ buildByDeviceIdDimension = ( ) => {
562+ this . dimension . byDeviceId = this . data . dimension ( d => d . deviceId || '' ) ;
563+ } ;
564+
541565 // N.B. May need to become smarter about creating and removing dimensions if we get above 8,
542566 // which would introduce additional performance overhead as per crossfilter docs.
543567 buildDimensions = ( ) => {
@@ -549,6 +573,7 @@ export class DataUtil {
549573 this . buildBySubTypeDimension ( ) ;
550574 this . buildByTimeDimension ( ) ;
551575 this . buildByTypeDimension ( ) ;
576+ this . buildByDeviceIdDimension ( ) ;
552577 this . endTimer ( 'buildDimensions' ) ;
553578 } ;
554579
@@ -576,6 +601,8 @@ export class DataUtil {
576601 return this . dimension . bySubType . filterExact ( subType ) ;
577602 } ;
578603
604+ this . filter . byDeviceIds = ( excludedDeviceIds = [ ] ) => this . dimension . byDeviceId . filterFunction ( deviceId => ! _ . includes ( excludedDeviceIds , deviceId ) ) ;
605+
579606 this . filter . byId = id => this . dimension . byId . filterExact ( id ) ;
580607 this . endTimer ( 'buildFilters' ) ;
581608 } ;
@@ -597,6 +624,7 @@ export class DataUtil {
597624 this . dimension . bySubType . filterAll ( ) ;
598625 this . dimension . byId . filterAll ( ) ;
599626 this . dimension . byDayOfWeek . filterAll ( ) ;
627+ this . dimension . byDeviceId . filterAll ( ) ;
600628 this . endTimer ( 'clearFilters' ) ;
601629 } ;
602630
@@ -707,6 +735,43 @@ export class DataUtil {
707735 this . endTimer ( 'setSize' ) ;
708736 } ;
709737
738+ /* eslint-disable no-param-reassign */
739+ setDevices = ( ) => {
740+ this . startTimer ( 'setDevices' ) ;
741+ const uploadsById = _ . keyBy ( this . sort . byTime ( this . filter . byType ( 'upload' ) . top ( Infinity ) ) , 'uploadId' ) ;
742+ this . devices = _ . reduce ( this . deviceUploadMap , ( result , value , key ) => {
743+ const upload = uploadsById [ value ] ;
744+ let device = { id : key } ;
745+
746+ if ( upload ) {
747+ const isContinuous = _ . get ( upload , 'dataSetType' ) === 'continuous' ;
748+ const deviceManufacturer = _ . get ( upload , 'deviceManufacturers.0' , '' ) ;
749+ const deviceModel = _ . get ( upload , 'deviceModel' , '' ) ;
750+ let label = key ;
751+ if ( deviceManufacturer || deviceModel ) {
752+ if ( deviceManufacturer === 'Dexcom' && isContinuous ) {
753+ label = 'Dexcom API' ;
754+ } else {
755+ label = [ deviceManufacturer , deviceModel ] . join ( ' ' ) ;
756+ }
757+ }
758+ device = {
759+ bgm : _ . includes ( upload . deviceTags , 'bgm' ) ,
760+ cgm : _ . includes ( upload . deviceTags , 'cgm' ) ,
761+ id : key ,
762+ label,
763+ pump : _ . includes ( upload . deviceTags , 'insulin-pump' ) ,
764+ serialNumber : upload . deviceSerialNumber ,
765+ } ;
766+ }
767+
768+ result . push ( device ) ;
769+ return result ;
770+ } , [ ] ) ;
771+ this . endTimer ( 'setDevices' ) ;
772+ }
773+ /* eslint-enable no-param-reassign */
774+
710775 setMetaData = ( ) => {
711776 this . startTimer ( 'setMetaData' ) ;
712777 this . setSize ( ) ;
@@ -717,6 +782,7 @@ export class DataUtil {
717782 this . setActiveDays ( ) ;
718783 this . setTypes ( ) ;
719784 this . setUploadMap ( ) ;
785+ this . setDevices ( ) ;
720786 this . setLatestPumpUpload ( ) ;
721787 this . setIncompleteSuspends ( ) ;
722788 this . endTimer ( 'setMetaData' ) ;
@@ -910,6 +976,12 @@ export class DataUtil {
910976 this . returnRawData = returnRaw ;
911977 } ;
912978
979+ setExcludedDevices = ( deviceIds = [ ] ) => {
980+ this . startTimer ( 'setExcludedDevices' ) ;
981+ this . excludedDevices = deviceIds ;
982+ this . endTimer ( 'setExcludedDevices' ) ;
983+ }
984+
913985 query = ( query = { } ) => {
914986 this . log ( 'Query' , query ) ;
915987
@@ -928,6 +1000,7 @@ export class DataUtil {
9281000 timePrefs,
9291001 types,
9301002 raw,
1003+ excludedDevices,
9311004 } = query ;
9321005
9331006 // N.B. Must ensure that we get the desired endpoints in UTC time so that when we display in
@@ -944,6 +1017,7 @@ export class DataUtil {
9441017 if ( timePrefs ) this . setTimePrefs ( timePrefs ) ;
9451018 this . setEndpoints ( endpoints , nextDays , prevDays ) ;
9461019 this . setActiveDays ( activeDays ) ;
1020+ this . setExcludedDevices ( excludedDevices ) ;
9471021
9481022 const data = { } ;
9491023
@@ -958,6 +1032,9 @@ export class DataUtil {
9581032 // Filter out any inactive days of the week
9591033 this . filter . byActiveDays ( this . activeDays ) ;
9601034
1035+ // Filter out any excluded devices
1036+ this . filter . byDeviceIds ( this . excludedDevices ) ;
1037+
9611038 // Generate the stats for current range
9621039 if ( this . stats . length && rangeKey === 'current' ) {
9631040 data [ rangeKey ] . stats = this . getStats ( this . stats ) ;
@@ -1111,6 +1188,7 @@ export class DataUtil {
11111188 'latestPumpUpload' ,
11121189 'patientId' ,
11131190 'size' ,
1191+ 'devices' ,
11141192 ] ;
11151193
11161194 const requestedMetaData = _ . isString ( metaData ) ? _ . map ( metaData . split ( ',' ) , _ . trim ) : metaData ;
0 commit comments