From ae7a42ba6770185b448dc2d778cd4b4238847fab Mon Sep 17 00:00:00 2001 From: Alek Perron Date: Tue, 6 Feb 2024 08:52:49 -0500 Subject: [PATCH] feat: SKFP-894 add posibility to search by external ids --- src/graphql/biospecimens/queries.ts | 2 ++ src/graphql/participants/queries.ts | 1 + src/locales/en.ts | 32 +++++++++++++++++++ .../components/BiospecimenSearch.tsx | 16 ++++++---- .../DataExploration/components/FileSearch.tsx | 7 ++-- .../components/ParticipantSearch.tsx | 10 ++++-- .../UploadIds/BiospecimenUploadIds.tsx | 10 +++--- .../components/UploadIds/FileUploadIds.tsx | 4 +-- .../UploadIds/ParticipantUploadIds.tsx | 10 +++--- 9 files changed, 70 insertions(+), 22 deletions(-) diff --git a/src/graphql/biospecimens/queries.ts b/src/graphql/biospecimens/queries.ts index 788323025..8cbe18c1a 100644 --- a/src/graphql/biospecimens/queries.ts +++ b/src/graphql/biospecimens/queries.ts @@ -149,6 +149,7 @@ export const CHECK_BIOSPECIMEN_MATCH = gql` edges { node { fhir_id + external_sample_id sample_id study { study_id @@ -169,6 +170,7 @@ export const BIOSPECIMEN_SEARCH_BY_ID_QUERY = gql` edges { node { sample_id + external_sample_id collection_sample_id } } diff --git a/src/graphql/participants/queries.ts b/src/graphql/participants/queries.ts index 192fb3ec0..57a316b30 100644 --- a/src/graphql/participants/queries.ts +++ b/src/graphql/participants/queries.ts @@ -307,6 +307,7 @@ export const PARTICIPANT_SEARCH_BY_ID_QUERY = gql` edges { node { participant_id + external_id } } } diff --git a/src/locales/en.ts b/src/locales/en.ts index 62f61af4b..22f2afe09 100644 --- a/src/locales/en.ts +++ b/src/locales/en.ts @@ -52,6 +52,28 @@ const en = { title: 'Search by study', tooltip: 'Search by Study Code, Study Name, dbGaP Accession Number', }, + participant: { + emptyText: 'No participants found', + placeholder: 'e.g. PT_1BCRHQVF, HTP0001', + title: 'Search by Participant ID', + tooltip: 'Search by Participant ID or External Participant ID', + }, + biospecimen: { + emptyText: 'No samples found', + placeholder: 'e.g. BS_011DYZ2J, HTP0001B2_Plasma, SSH3953290', + title: 'Search by Sample ID', + tooltip: 'Search by Sample ID or External Sample ID', + collection: { + emptyText: 'No collection ID found', + placeholder: 'e.g. HTP0001B2_Whole blood, BS_1YEZ2XR4_Saliva', + title: 'Search by Collection ID', + }, + }, + file: { + emptyText: 'No files found', + placeholder: 'e.g. GF_001CSF26', + title: 'Search by File ID', + }, }, filters: { actions: { @@ -364,6 +386,16 @@ const en = { inputLabel: 'Copy-paste a list of identifiers or upload a file', match: 'Matched ({count})', unmatch: 'Unmatched ({count})', + identifiers: { + participant: 'Participant ID, External Participant ID', + biospecimen: 'Sample ID, External Sample ID', + file: 'File ID', + }, + placeholders: { + participant: 'e.g. PT_03Y3K025, HTP0001, 10214, HTP0001', + biospecimen: 'e.g. HTP0001B2_Whole blood, BS_011DYZ2J_DNA, 238981007, SSH3953290', + file: 'e.g. GF_2JAYWYDX, GF_TP6PG8Z0', + }, tableMessage: '{submittedCount} submitted identifiers mapped to {mappedCount} unique system identifiers', matchTable: { diff --git a/src/views/DataExploration/components/BiospecimenSearch.tsx b/src/views/DataExploration/components/BiospecimenSearch.tsx index dadb3e9d9..e7a6629ac 100644 --- a/src/views/DataExploration/components/BiospecimenSearch.tsx +++ b/src/views/DataExploration/components/BiospecimenSearch.tsx @@ -1,3 +1,4 @@ +import intl from 'react-intl-universal'; import { ExperimentOutlined } from '@ant-design/icons'; import useQueryBuilderState from '@ferlab/ui/core/components/QueryBuilder/utils/useQueryBuilderState'; import { ISqonGroupFilter } from '@ferlab/ui/core/data/sqon/types'; @@ -18,9 +19,10 @@ const BiospecimenSearch = ({ queryBuilderId }: ICustomSearchProps) => { queryBuilderId={queryBuilderId} field="sample_id" // @todo: search_text, see when implemented + searchFields={['sample_id', 'external_sample_id']} index={INDEXES.BIOSPECIMEN} - placeholder="e.g. BS_011DYZ2J, HTP0001B2_Plasma" - emptyDescription="No samples found" + placeholder={intl.get('global.search.biospecimen.placeholder')} + emptyDescription={intl.get('global.search.biospecimen.emptyText')} query={BIOSPECIMEN_SEARCH_BY_ID_QUERY} sqon={activeQuery as ISqonGroupFilter} optionsFormatter={(options, matchRegex, search) => @@ -29,12 +31,14 @@ const BiospecimenSearch = ({ queryBuilderId }: ICustomSearchProps) => { } title={highlightSearchMatch(option.sample_id, matchRegex, search)} + caption={highlightSearchMatch(option.external_sample_id, matchRegex, search)} /> ), value: option.sample_id, })) } - title="Search by sample ID" + title={intl.get('global.search.biospecimen.title')} + tooltipText={intl.get('global.search.biospecimen.tooltip')} /> ); }; @@ -47,8 +51,8 @@ const BiospecimenCollectionSearch = ({ queryBuilderId }: ICustomSearchProps) => queryBuilderId={queryBuilderId} field="collection_sample_id" // @todo: search_text, see when implemented index={INDEXES.BIOSPECIMEN} - placeholder="e.g. HTP0001B2_Whole blood, BS_1YEZ2XR4_Saliva" - emptyDescription="No collection ID found" + placeholder={intl.get('global.search.biospecimen.collection.placeholder')} + emptyDescription={intl.get('global.search.biospecimen.collection.emptyText')} query={BIOSPECIMEN_SEARCH_BY_ID_QUERY} sqon={sqon} optionsFormatter={(options, matchRegex, search) => @@ -62,7 +66,7 @@ const BiospecimenCollectionSearch = ({ queryBuilderId }: ICustomSearchProps) => value: option.collection_sample_id, })) } - title="Search by collection ID" + title={intl.get('global.search.biospecimen.collection.title')} /> ); }; diff --git a/src/views/DataExploration/components/FileSearch.tsx b/src/views/DataExploration/components/FileSearch.tsx index 6333dff61..9ec51230d 100644 --- a/src/views/DataExploration/components/FileSearch.tsx +++ b/src/views/DataExploration/components/FileSearch.tsx @@ -1,3 +1,4 @@ +import intl from 'react-intl-universal'; import { FileTextOutlined } from '@ant-design/icons'; import useQueryBuilderState from '@ferlab/ui/core/components/QueryBuilder/utils/useQueryBuilderState'; import { ISqonGroupFilter } from '@ferlab/ui/core/data/sqon/types'; @@ -17,8 +18,8 @@ const FileSearch = ({ queryBuilderId }: ICustomSearchProps) => { queryBuilderId={queryBuilderId} field="file_id" index={INDEXES.FILE} - placeholder="e.g. GF_001CSF26" - emptyDescription="No files found" + placeholder={intl.get('global.search.file.placeholder')} + emptyDescription={intl.get('global.search.file.emptyText')} query={FILE_SEARCH_BY_ID_QUERY} sqon={activeQuery as ISqonGroupFilter} optionsFormatter={(options, matchRegex, search) => @@ -32,7 +33,7 @@ const FileSearch = ({ queryBuilderId }: ICustomSearchProps) => { value: option.file_id, })) } - title="Search by file ID" + title={intl.get('global.search.file.title')} /> ); }; diff --git a/src/views/DataExploration/components/ParticipantSearch.tsx b/src/views/DataExploration/components/ParticipantSearch.tsx index 2dddd27c7..955280dcf 100644 --- a/src/views/DataExploration/components/ParticipantSearch.tsx +++ b/src/views/DataExploration/components/ParticipantSearch.tsx @@ -1,3 +1,4 @@ +import intl from 'react-intl-universal'; import { UserOutlined } from '@ant-design/icons'; import useQueryBuilderState from '@ferlab/ui/core/components/QueryBuilder/utils/useQueryBuilderState'; import { ISqonGroupFilter } from '@ferlab/ui/core/data/sqon/types'; @@ -16,9 +17,10 @@ const ParticipantSearch = ({ queryBuilderId }: ICustomSearchProps) => { queryBuilderId={queryBuilderId} field="participant_id" + searchFields={['participant_id', 'external_id']} index={INDEXES.PARTICIPANT} - placeholder="e.g. PT_1BCRHQVF" - emptyDescription="No participants found" + placeholder={intl.get('global.search.participant.placeholder')} + emptyDescription={intl.get('global.search.participant.emptyText')} query={PARTICIPANT_SEARCH_BY_ID_QUERY} sqon={activeQuery as ISqonGroupFilter} optionsFormatter={(options, matchRegex, search) => @@ -27,12 +29,14 @@ const ParticipantSearch = ({ queryBuilderId }: ICustomSearchProps) => { } title={highlightSearchMatch(option.participant_id, matchRegex, search)} + caption={highlightSearchMatch(option.external_id, matchRegex, search)} /> ), value: option.participant_id, })) } - title="Search by participant ID" + title={intl.get('global.search.participant.title')} + tooltipText={intl.get('global.search.participant.tooltip')} /> ); }; diff --git a/src/views/DataExploration/components/UploadIds/BiospecimenUploadIds.tsx b/src/views/DataExploration/components/UploadIds/BiospecimenUploadIds.tsx index 6e3776c63..e64b06e96 100644 --- a/src/views/DataExploration/components/UploadIds/BiospecimenUploadIds.tsx +++ b/src/views/DataExploration/components/UploadIds/BiospecimenUploadIds.tsx @@ -22,8 +22,8 @@ const BiospecimenUploadIds = ({ queryBuilderId }: OwnProps) => ( { const response = await ArrangerApi.graphqlRequest({ query: CHECK_BIOSPECIMEN_MATCH.loc?.source.body, @@ -32,7 +32,7 @@ const BiospecimenUploadIds = ({ queryBuilderId }: OwnProps) => ( offset: 0, sqon: generateQuery({ operator: BooleanOperators.or, - newFilters: ['sample_id'].map((field) => + newFilters: ['sample_id', 'external_sample_id'].map((field) => generateValueFilter({ field, value: ids, @@ -49,7 +49,9 @@ const BiospecimenUploadIds = ({ queryBuilderId }: OwnProps) => ( return biospecimens?.flatMap((biospecimen) => { const matchedIds: string[] = ids.filter( - (id: string) => biospecimen.sample_id.toLocaleLowerCase() === id.toLocaleLowerCase(), + (id: string) => + biospecimen.sample_id.toLocaleLowerCase() === id.toLocaleLowerCase() || + biospecimen.external_sample_id.toLocaleLowerCase() === id.toLocaleLowerCase(), ); return matchedIds.map((id, index) => ({ diff --git a/src/views/DataExploration/components/UploadIds/FileUploadIds.tsx b/src/views/DataExploration/components/UploadIds/FileUploadIds.tsx index 8cacfad01..35d6064ad 100644 --- a/src/views/DataExploration/components/UploadIds/FileUploadIds.tsx +++ b/src/views/DataExploration/components/UploadIds/FileUploadIds.tsx @@ -22,8 +22,8 @@ const FileUploadIds = ({ queryBuilderId }: OwnProps) => ( { const response = await ArrangerApi.graphqlRequest({ query: CHECK_FILE_MATCH.loc?.source.body, diff --git a/src/views/DataExploration/components/UploadIds/ParticipantUploadIds.tsx b/src/views/DataExploration/components/UploadIds/ParticipantUploadIds.tsx index fdcca7618..a231e791b 100644 --- a/src/views/DataExploration/components/UploadIds/ParticipantUploadIds.tsx +++ b/src/views/DataExploration/components/UploadIds/ParticipantUploadIds.tsx @@ -22,8 +22,8 @@ const ParticipantUploadIds = ({ queryBuilderId }: OwnProps) => ( { const response = await ArrangerApi.graphqlRequest({ query: CHECK_PARTICIPANT_MATCH.loc?.source.body, @@ -32,7 +32,7 @@ const ParticipantUploadIds = ({ queryBuilderId }: OwnProps) => ( offset: 0, sqon: generateQuery({ operator: BooleanOperators.or, - newFilters: ['participant_id'].map((field) => + newFilters: ['participant_id', 'external_id'].map((field) => generateValueFilter({ field, value: ids, @@ -49,7 +49,9 @@ const ParticipantUploadIds = ({ queryBuilderId }: OwnProps) => ( return participants?.flatMap((participant) => { const matchedIds: string[] = ids.filter( - (id: string) => participant.participant_id.toLocaleLowerCase() === id.toLocaleLowerCase(), + (id: string) => + participant.participant_id.toLocaleLowerCase() === id.toLocaleLowerCase() || + participant.external_id.toLocaleLowerCase() === id.toLocaleLowerCase(), ); return matchedIds.map((id, index) => ({