diff --git a/src/pages/studyView/StudyViewPage.tsx b/src/pages/studyView/StudyViewPage.tsx index f485d25d8e3..3fae2de9aa1 100644 --- a/src/pages/studyView/StudyViewPage.tsx +++ b/src/pages/studyView/StudyViewPage.tsx @@ -189,13 +189,18 @@ export default class StudyViewPage extends React.Component< newStudyViewFilter.sharedCustomData = params.sharedCustomData; } } + + let updateStoreFromURLPromise = remoteData(() => Promise.resolve([])); if (!_.isEqual(newStudyViewFilter, this.store.studyViewQueryFilter)) { - this.store.updateStoreFromURL(newStudyViewFilter); this.store.studyViewQueryFilter = newStudyViewFilter; + updateStoreFromURLPromise = remoteData(async () => { + await this.store.updateStoreFromURL(newStudyViewFilter); + return []; + }); } onMobxPromise( - this.store.queriedPhysicalStudyIds, + [this.store.queriedPhysicalStudyIds, updateStoreFromURLPromise], (strArr: string[]) => { this.store.initializeReaction(); trackEvent({ diff --git a/src/pages/studyView/StudyViewPageStore.ts b/src/pages/studyView/StudyViewPageStore.ts index e008c43da76..e516edf6103 100644 --- a/src/pages/studyView/StudyViewPageStore.ts +++ b/src/pages/studyView/StudyViewPageStore.ts @@ -57,6 +57,7 @@ import { PatientTreatmentRow, ResourceData, Sample, + SampleFilter, SampleIdentifier, SampleMolecularIdentifier, SampleTreatmentRow, @@ -267,6 +268,10 @@ import { PageType } from 'shared/userSession/PageType'; import { FeatureFlagEnum } from 'shared/featureFlags'; import intersect from 'fast_array_intersect'; import { PillStore } from 'shared/components/PillTag/PillTag'; +import { + PatientIdentifier, + PatientIdentifierFilter, +} from 'shared/model/PatientIdentifierFilter'; export const STUDY_VIEW_FILTER_AUTOSUBMIT = 'study_view_filter_autosubmit'; @@ -2165,14 +2170,20 @@ export class StudyViewPageStore // We do not support studyIds in the query filters let filters: Partial = {}; if (query.filterJson) { - try { - filters = JSON.parse( - decodeURIComponent(query.filterJson) - ) as Partial; - this.updateStoreByFilters(filters); - } catch (e) { - // TODO: add some logging here? + const parsedFilterJson = this.parseRawFilterJson(query.filterJson); + if (query.filterJson.includes('patientIdentifiers')) { + const sampleListIds = studyIds.map(s => s.concat('', '_all')); + const samples = await this.fetchSamplesWithSampleListIds( + sampleListIds + ); + filters = this.getStudyViewFilterFromPatientIdentifierFilter( + parsedFilterJson as PatientIdentifierFilter, + samples + ); + } else { + filters = parsedFilterJson as Partial; } + this.updateStoreByFilters(filters); } else if (query.filterAttributeId && query.filterValues) { const clinicalAttributes = _.uniqBy( await defaultClient.fetchClinicalAttributesUsingPOST({ @@ -2224,6 +2235,57 @@ export class StudyViewPageStore } } + parseRawFilterJson(filterJson: string): any { + let rawJson; + try { + rawJson = JSON.parse(decodeURIComponent(filterJson)); + } catch (e) { + console.error('FilterJson invalid Json: error: ', e); + } + return rawJson; + } + + fetchSamplesWithSampleListIds(sampleListIds: string[]) { + return defaultClient.fetchSamplesUsingPOST({ + sampleFilter: { + sampleListIds: sampleListIds, + } as SampleFilter, + projection: 'SUMMARY', + }); + } + + getStudyViewFilterFromPatientIdentifierFilter( + patientIdentifierFilter: PatientIdentifierFilter, + samples: Sample[] + ): Partial { + const filters: Partial = {}; + const sampleIdentifiers = this.convertPatientIdentifiersToSampleIdentifiers( + patientIdentifierFilter.patientIdentifiers, + samples + ); + if (sampleIdentifiers.length > 0) { + filters.sampleIdentifiers = sampleIdentifiers; + } + return filters; + } + + convertPatientIdentifiersToSampleIdentifiers( + patientIdentifiers: Array, + samples: Sample[] + ): SampleIdentifier[] { + const patientIdentifiersMap = new Map( + patientIdentifiers.map(p => [p.studyId.concat('_', p.patientId), p]) + ); + return samples + .filter(s => + patientIdentifiersMap.has(s.studyId.concat('_', s.patientId)) + ) + .map(s => ({ + sampleId: s.sampleId, + studyId: s.studyId, + })); + } + @computed get initialFilters(): StudyViewFilter { let initialFilter = {} as StudyViewFilter; diff --git a/src/shared/model/PatientIdentifierFilter.ts b/src/shared/model/PatientIdentifierFilter.ts new file mode 100644 index 00000000000..5758f3ddb0c --- /dev/null +++ b/src/shared/model/PatientIdentifierFilter.ts @@ -0,0 +1,8 @@ +export interface PatientIdentifierFilter { + patientIdentifiers: PatientIdentifier[]; +} + +export interface PatientIdentifier { + patientId: string; + studyId: string; +}