diff --git a/src/api/utils.ts b/src/api/utils.ts index 199cd2e..ad2a20a 100644 --- a/src/api/utils.ts +++ b/src/api/utils.ts @@ -7,7 +7,3 @@ export type DjangoRestApiResponse = { }; results: unknown[]; }; - -export const getBaseNameFromKey = (key: string) => { - return key.split('/')[key.split('/').length - 1]; -}; diff --git a/src/components/OpenInIgvDialog/index.tsx b/src/components/OpenInIgvDialog/index.tsx index 9015b24..ce4ee19 100644 --- a/src/components/OpenInIgvDialog/index.tsx +++ b/src/components/OpenInIgvDialog/index.tsx @@ -9,6 +9,8 @@ import { constructGDSUrl } from '../../api/gds'; import { useToastContext } from '../../providers/ToastProvider'; import CircularLoaderWithText from '../../components/CircularLoaderWithText'; import { post } from 'aws-amplify/api'; +import { useParams } from 'react-router-dom'; +import { SubjectApiRes, usePortalSubjectDataAPI } from '../../api/subject'; type OpenIGVDesktopDialogType = { handleClose: () => void; @@ -19,15 +21,32 @@ type OpenIGVDesktopDialogType = { type: 's3' | 'gds'; }; export default function OpenIGVDesktopDialog(props: OpenIGVDesktopDialogType) { + const { subjectId } = useParams(); const { toastShow } = useToastContext(); const { id, bucketOrVolume, pathOrKey, type, handleClose, handleNeedRestore } = props; + if (!subjectId) return
No subject Id found!
; + + // Pulling data from usePortalSubjectDataAPI (this hook should cache if it was previously called) + const { + isError: subjectIsError, + error: subjectError, + data: subjectData, + } = usePortalSubjectDataAPI(subjectId); + // Query data const gdsLocalIgvUrl = useQuery( ['gds-local-igv', bucketOrVolume, pathOrKey], - async () => - await constructGDSLocalIgvUrl({ bucketOrVolume: bucketOrVolume, pathOrKey: pathOrKey }), - { enabled: type == 'gds', retry: false } + async () => { + const igvName = constructIgvNameParameter({ pathOrKey, subjectData: subjectData! }); + + return await constructGDSLocalIgvUrl({ + bucketOrVolume: bucketOrVolume, + pathOrKey: pathOrKey, + igvName: igvName, + }); + }, + { enabled: type == 'gds' && !!subjectData, retry: false } ); const s3LocalIgvUrl = useQuery( @@ -39,12 +58,15 @@ export default function OpenIGVDesktopDialog(props: OpenIGVDesktopDialogType) { handleNeedRestore(); } + const igvName = constructIgvNameParameter({ pathOrKey, subjectData: subjectData! }); + return constructS3LocalIgvUrl({ + igvName: igvName, bucketOrVolume: bucketOrVolume, pathOrKey: pathOrKey, }); }, - { enabled: type == 's3', retry: false } + { enabled: type == 's3' && !!subjectData, retry: false } ); // IsError handling @@ -67,7 +89,23 @@ export default function OpenIGVDesktopDialog(props: OpenIGVDesktopDialogType) { }); handleClose(); } - }, [s3LocalIgvUrl.isError, s3LocalIgvUrl.error, gdsLocalIgvUrl.isError, gdsLocalIgvUrl.error]); + if (subjectError && subjectIsError) { + toastShow({ + severity: 'error', + summary: 'Error on retrieving subject data.', + detail: `${subjectError}`, + sticky: true, + }); + handleClose(); + } + }, [ + s3LocalIgvUrl.isError, + s3LocalIgvUrl.error, + gdsLocalIgvUrl.isError, + gdsLocalIgvUrl.error, + subjectError, + subjectIsError, + ]); useEffect(() => { let localIgvUrl: string; @@ -139,8 +177,12 @@ export default function OpenIGVDesktopDialog(props: OpenIGVDesktopDialogType) { ); } -const constructGDSLocalIgvUrl = async (props: { bucketOrVolume: string; pathOrKey: string }) => { - const { bucketOrVolume, pathOrKey } = props; +const constructGDSLocalIgvUrl = async (props: { + igvName: string; + bucketOrVolume: string; + pathOrKey: string; +}) => { + const { bucketOrVolume, pathOrKey, igvName } = props; let idxFilePath: string; if (pathOrKey.endsWith('bam')) { @@ -183,15 +225,79 @@ const constructGDSLocalIgvUrl = async (props: { bucketOrVolume: string; pathOrKe const idx = encodeURIComponent(idxFilePresignUrl); const enf = encodeURIComponent(filePresignUrl); - const name = pathOrKey.split('/').pop() ?? pathOrKey; - return `http://localhost:60151/load?index=${idx}&file=${enf}&name=${name}`; + + return `http://localhost:60151/load?index=${idx}&file=${enf}&name=${igvName}`; }; -const constructS3LocalIgvUrl = async (props: { bucketOrVolume: string; pathOrKey: string }) => { - const { bucketOrVolume, pathOrKey } = props; +const constructS3LocalIgvUrl = (props: { + igvName: string; + bucketOrVolume: string; + pathOrKey: string; +}) => { + const { bucketOrVolume, pathOrKey, igvName } = props; - const name = pathOrKey.split('/').pop() ?? pathOrKey; const file = `s3://${bucketOrVolume + '/' + pathOrKey}`; - return `http://localhost:60151/load?file=${encodeURIComponent(file)}&name=${name}`; + return `http://localhost:60151/load?file=${encodeURIComponent(file)}&name=${igvName}`; +}; + +/** + * + * We wanted to show more info in the name parameter when opening in IGV + * Ref: https://umccr.slack.com/archives/CP356DDCH/p1707116441928299?thread_ts=1706583808.733149&cid=CP356DDCH + * + * For BAM files the desired outcome is to include libraryId, sampleId, type, and filetype + * Desired output: SBJ00000_L0000000_PRJ00000_tumor.bam + * + * Other than BAM + * Desired output: SBJ00000_MDX0000.vcf.gz + * + * To find the match of metadata for the specific key/path will iterate through the lims record + * @param props + */ +export const constructIgvNameParameter = ({ + subjectData, + pathOrKey, +}: { + pathOrKey: string; + subjectData: SubjectApiRes; +}): string => { + const nameArray: string[] = []; + + const filetype = pathOrKey.split('.').pop(); + // Find sampleId from its filename + const filename = pathOrKey.split('/').pop() ?? pathOrKey; + const sampleId = filename.split('.').shift()?.split('_').shift() ?? filename; + + // Append subjectId if filename does not contain subjectId + if (!filename.startsWith(subjectData.id)) { + nameArray.push(subjectData.id); + } + + // If it is a `bam` file it will try to figure out the appropriate libraryId + if (filetype?.toLocaleLowerCase() == 'bam') { + const libraryIdArray = subjectData.lims.reduce((acc, curr) => { + const currLibId = curr.library_id; + const currSampId = curr.sample_id; + + // do not want value to appear twice at the return array + if (acc.includes(currLibId)) { + return acc; + } + + // find the matching value and push to the array + if (currSampId == sampleId) { + acc.push(currLibId); + } + + return acc; + }, [] as Array); + + nameArray.push(...libraryIdArray); + } + + // Append filename at the end + nameArray.push(filename); + + return nameArray.join('_'); }; diff --git a/src/containers/subjects/AnalysisResultTable/index.tsx b/src/containers/subjects/AnalysisResultTable/index.tsx index 4a936bc..f7a6ab1 100644 --- a/src/containers/subjects/AnalysisResultTable/index.tsx +++ b/src/containers/subjects/AnalysisResultTable/index.tsx @@ -314,7 +314,7 @@ function AnalysisResultS3Table(prop: AnalysisResultS3TableProps) { type Props = { subjectId: string }; -function AnalysisResultsPanel({ subjectId }: Props) { +function AnalysisResultsTable({ subjectId }: Props) { const { isFetching, isLoading, data } = usePortalSubjectDataAPI(subjectId); if (isLoading || isFetching) { @@ -396,7 +396,7 @@ function AnalysisResultsPanel({ subjectId }: Props) { return
; } -export default AnalysisResultsPanel; +export default AnalysisResultsTable; function groupResultsData({ results_s3, diff --git a/src/containers/subjects/IGV/genomes.ts b/src/containers/subjects/IGV/genomes.ts index a6913d2..d050ffd 100644 --- a/src/containers/subjects/IGV/genomes.ts +++ b/src/containers/subjects/IGV/genomes.ts @@ -1,57 +1,68 @@ +// More info see https://github.com/igvteam/igv.js/wiki/Reference-Genome + export const genomes = [ { id: 'hg38', name: 'Human (GRCh38/hg38)', - fastaURL: 'https://s3.amazonaws.com/igv.broadinstitute.org/genomes/seq/hg38/hg38.fa', - indexURL: 'https://s3.amazonaws.com/igv.broadinstitute.org/genomes/seq/hg38/hg38.fa.fai', - cytobandURL: 'https://s3.amazonaws.com/igv.org.genomes/hg38/annotations/cytoBandIdeo.txt.gz', + fastaURL: 'https://igv-genepattern-org.s3.amazonaws.com/genomes/seq/hg38/hg38.fa', + indexURL: 'https://igv-genepattern-org.s3.amazonaws.com/genomes/seq/hg38/hg38.fa.fai', + cytobandURL: 'https://igv-genepattern-org.s3.amazonaws.com/genomes/hg38/cytoBandIdeo.txt.gz', + aliasURL: 'https://igv-genepattern-org.s3.amazonaws.com/genomes/hg38/hg38_alias.tab', + chromSizesURL: 'https://hgdownload.soe.ucsc.edu/goldenPath/hg38/bigZips/hg38.chrom.sizes', + twoBitURL: 'https://hgdownload.soe.ucsc.edu/goldenPath/hg38/bigZips/hg38.2bit', tracks: [ { name: 'Refseq Genes', format: 'refgene', - url: 'https://s3.amazonaws.com/igv.org.genomes/hg38/ncbiRefGene.txt.gz', + url: 'https://hgdownload.soe.ucsc.edu/goldenPath/hg38/database/ncbiRefSeq.txt.gz', indexed: false, visibilityWindow: -1, removable: false, order: 1000000, + infoURL: 'https://www.ncbi.nlm.nih.gov/gene/?term=$$', }, ], }, { id: 'hg38_1kg', name: 'Human (hg38 1kg/GATK)', - compressedFastaURL: - 'https://s3.amazonaws.com/igv.org.genomes/hg38/Homo_sapiens_assembly38.fasta.gz', - fastaURL: 'https://s3.amazonaws.com/igv.broadinstitute.org/genomes/seq/hg38/hg38.fa', - indexURL: 'https://s3.amazonaws.com/igv.broadinstitute.org/genomes/seq/hg38/hg38.fa.fai', + fastaURL: + 'https://1000genomes.s3.amazonaws.com/technical/reference/GRCh38_reference_genome/GRCh38_full_analysis_set_plus_decoy_hla.fa', + indexURL: + 'https://1000genomes.s3.amazonaws.com/technical/reference/GRCh38_reference_genome/GRCh38_full_analysis_set_plus_decoy_hla.fa.fai', cytobandURL: 'https://s3.amazonaws.com/igv.org.genomes/hg38/annotations/cytoBandIdeo.txt.gz', tracks: [ { name: 'Refseq Genes', format: 'refgene', - url: 'https://s3.amazonaws.com/igv.org.genomes/hg38/ncbiRefGene.txt.gz', + id: 'hg19_genes', + url: 'https://hgdownload.soe.ucsc.edu/goldenPath/hg38/database/ncbiRefSeq.txt.gz', indexed: false, visibilityWindow: -1, removable: false, order: 1000000, + infoURL: 'https://www.ncbi.nlm.nih.gov/gene/?term=$$', }, ], }, { id: 'hg19', - name: 'Human (CRCh37/hg19)', - fastaURL: 'https://s3.amazonaws.com/igv.broadinstitute.org/genomes/seq/hg19/hg19.fasta', - indexURL: 'https://s3.amazonaws.com/igv.broadinstitute.org/genomes/seq/hg19/hg19.fasta.fai', - cytobandURL: 'https://s3.amazonaws.com/igv.broadinstitute.org/genomes/seq/hg19/cytoBand.txt', + name: 'Human (GRCh37/hg19)', + fastaURL: 'https://igv-genepattern-org.s3.amazonaws.com/genomes/seq/hg19/hg19.fasta', + indexURL: 'https://igv-genepattern-org.s3.amazonaws.com/genomes/seq/hg19/hg19.fasta.fai', + cytobandURL: 'https://igv-genepattern-org.s3.amazonaws.com/genomes/seq/hg19/cytoBand.txt', + aliasURL: 'https://s3.amazonaws.com/igv.org.genomes/hg19/hg19_alias.tab', tracks: [ { name: 'Refseq Genes', format: 'refgene', - url: 'https://s3.amazonaws.com/igv.org.genomes/hg19/ncbiRefGene.txt.gz', + id: 'hg19_genes', + url: 'https://hgdownload.soe.ucsc.edu/goldenPath/hg19/database/ncbiRefSeq.txt.gz', indexed: false, - visibilityWindow: -1, removable: false, order: 1000000, + infoURL: 'https://www.ncbi.nlm.nih.gov/gene/?term=$$', + visibilityWindow: -1, }, ], }, diff --git a/src/containers/subjects/IGV/index.tsx b/src/containers/subjects/IGV/index.tsx index 045158a..df8bbe3 100644 --- a/src/containers/subjects/IGV/index.tsx +++ b/src/containers/subjects/IGV/index.tsx @@ -1,13 +1,13 @@ -import React, { useState, useCallback } from 'react'; +import React, { useState, useCallback, useEffect } from 'react'; import { ITrack } from 'igv'; import { useQuery } from 'react-query'; import { ProgressBar } from 'primereact/progressbar'; - import { Button } from 'primereact/button'; import { Dropdown, DropdownChangeEvent } from 'primereact/dropdown'; import { Toolbar } from 'primereact/toolbar'; +import { Dialog } from 'primereact/dialog'; + import LoadSubjectDataButton from './LoadSubjectDataButton'; -import { getBaseNameFromKey } from '../../../api/utils'; import { GDSRow } from '../../../api/gds'; import { S3Row } from '../../../api/s3'; import { @@ -21,6 +21,10 @@ import { } from './utils'; import LoadCustomTrackDataButton from './LoadCustomTrackDataButton'; import { getJwtToken } from '../../../utils/signer'; +import CircularLoaderWithText from '../../../components/CircularLoaderWithText'; +import { SubjectApiRes, usePortalSubjectDataAPI } from '../../../api/subject'; +import { useToastContext } from '../../../providers/ToastProvider'; +import { constructIgvNameParameter } from '../../../components/OpenInIgvDialog'; const toolbarGenomeList = [ { label: 'hg38', value: 'hg38' }, @@ -36,6 +40,15 @@ export type LoadSubjectDataType = { type Props = { subjectId: string }; function IGV({ subjectId }: Props) { + const { toastShow } = useToastContext(); + + const { + isLoading: isSubjectLoading, + isError: subjectIsError, + error: subjectError, + data: subjectData, + } = usePortalSubjectDataAPI(subjectId); + // IGV init const igv = useQuery( ['initIGV', subjectId], @@ -70,14 +83,19 @@ function IGV({ subjectId }: Props) { if (!igvBrowser) return; // Find and *remove* necessary current Track Data - const removalTrackNameList: string[] = createRemovalIgvTrackNameList( - igvSubjectTrackData, - newChange - ); + const removalTrackNameList: string[] = createRemovalIgvTrackNameList({ + subjectData: subjectData!, + oldTrackData: igvSubjectTrackData, + newTrackData: newChange, + }); removeIgvLoadTrackFromName({ trackNameList: removalTrackNameList, igvBrowser: igvBrowser }); // Find and *add* necessary current Track Data - const newIgvTrackList = await createNewIgvTrackList(igvSubjectTrackData, newChange); + const newIgvTrackList = await createNewIgvTrackList({ + subjectData: subjectData!, + oldTrackData: igvSubjectTrackData, + newTrackData: newChange, + }); await addIgvLoadTrackFromITrackList({ iTrackList: newIgvTrackList, igvBrowser: igvBrowser, @@ -86,7 +104,7 @@ function IGV({ subjectId }: Props) { // Save changes to current track data state setIgvSubjectTrackData(newChange); }, - [igvBrowser, igvSubjectTrackData] + [igvBrowser, igvSubjectTrackData, subjectData] ); // Custom State and Handler @@ -95,7 +113,12 @@ function IGV({ subjectId }: Props) { async (s3Row: RequiredS3RowType) => { if (!igvBrowser) return; - const newCustomLoadTrack = convertS3RowToHtsgetIgvTrack(s3Row); + const igvName = constructIgvNameParameter({ + pathOrKey: s3Row.key, + subjectData: subjectData!, + }); + + const newCustomLoadTrack = convertS3RowToHtsgetIgvTrack({ s3Row, igvName }); if (newCustomLoadTrack) { await addIgvLoadTrackFromITrackList({ iTrackList: [newCustomLoadTrack], @@ -103,17 +126,24 @@ function IGV({ subjectId }: Props) { }); } - const basename = getBaseNameFromKey(s3Row.key); - setCustomTrackDataNameList((prev) => [...prev, basename]); + setCustomTrackDataNameList((prev) => [...prev, igvName]); }, - [igvBrowser] + [igvBrowser, subjectData] ); const handleCustomIgvGDSTrackDataChange = useCallback( async (gdsRow: RequiredGDSRowType) => { if (!igvBrowser) return; - const newCustomLoadTrack = await convertGdsRowToIgvTrack(gdsRow); + const igvName = constructIgvNameParameter({ + pathOrKey: gdsRow.path, + subjectData: subjectData!, + }); + + const newCustomLoadTrack = await convertGdsRowToIgvTrack({ + gdsRow, + igvName, + }); if (newCustomLoadTrack) { await addIgvLoadTrackFromITrackList({ iTrackList: [newCustomLoadTrack], @@ -121,19 +151,22 @@ function IGV({ subjectId }: Props) { }); } - const basename = getBaseNameFromKey(gdsRow.path); - setCustomTrackDataNameList((prev) => [...prev, basename]); + setCustomTrackDataNameList((prev) => [...prev, igvName]); }, - [igvBrowser] + [igvBrowser, subjectData] ); // Handle remove IGV trackdata const handleRemoveAllTrackData = () => { if (!igvBrowser) return; - let removalTrackNameList: string[] = createRemovalIgvTrackNameList(igvSubjectTrackData, { - s3RowList: [], - gdsRowList: [], + let removalTrackNameList: string[] = createRemovalIgvTrackNameList({ + subjectData: subjectData!, + oldTrackData: igvSubjectTrackData, + newTrackData: { + s3RowList: [], + gdsRowList: [], + }, }); if (customTrackDataNameList.length) { @@ -149,6 +182,18 @@ function IGV({ subjectId }: Props) { }); }; + // IsError handling + useEffect(() => { + if (subjectError && subjectIsError) { + toastShow({ + severity: 'error', + summary: 'Error on retrieving subject data.', + detail: `${subjectError}`, + sticky: true, + }); + } + }, [subjectError, subjectIsError]); + const leftToolbarContents = ( <> + {(isSubjectLoading || !subjectData) && ( + {}}> + + + )}
- + {igv.isLoading && ( { +const createRemovalIgvTrackNameList = ({ + subjectData, + oldTrackData, + newTrackData, +}: { + subjectData: SubjectApiRes; + oldTrackData: LoadSubjectDataType; + newTrackData: LoadSubjectDataType; +}): string[] => { const loadTrackNameList: string[] = []; // Find in S3 @@ -252,15 +314,26 @@ const createRemovalIgvTrackNameList = ( arrayA: oldTrackData.s3RowList, arrayB: newTrackData.s3RowList, }) as unknown as S3Row[]; - for (const s3Row of s3RemovalObjectList) loadTrackNameList.push(getBaseNameFromKey(s3Row.key)); + for (const s3Row of s3RemovalObjectList) { + const name = constructIgvNameParameter({ + pathOrKey: s3Row.key, + subjectData: subjectData!, + }); + loadTrackNameList.push(name); + } // Find in GDS const gdsRemovalObjectList = diffArrayAlphaAndArrayBetaOnObjData({ arrayA: oldTrackData.gdsRowList, arrayB: newTrackData.gdsRowList, }) as unknown as GDSRow[]; - for (const gdsRow of gdsRemovalObjectList) - loadTrackNameList.push(getBaseNameFromKey(gdsRow.path)); + for (const gdsRow of gdsRemovalObjectList) { + const name = constructIgvNameParameter({ + pathOrKey: gdsRow.path, + subjectData: subjectData!, + }); + loadTrackNameList.push(name); + } return loadTrackNameList; }; @@ -271,10 +344,15 @@ const createRemovalIgvTrackNameList = ( * @param newTrackData * @returns */ -const createNewIgvTrackList = async ( - oldTrackData: LoadSubjectDataType, - newTrackData: LoadSubjectDataType -): Promise => { +const createNewIgvTrackList = async ({ + subjectData, + oldTrackData, + newTrackData, +}: { + subjectData: SubjectApiRes; + oldTrackData: LoadSubjectDataType; + newTrackData: LoadSubjectDataType; +}): Promise => { const newIgvLoadTrackList: ITrack[] = []; // Find new IGV Track Data for S3 @@ -283,7 +361,12 @@ const createNewIgvTrackList = async ( arrayB: oldTrackData.s3RowList, }) as unknown as S3Row[]; for (const s3Row of newS3ObjectList) { - const newS3Itrack = convertS3RowToHtsgetIgvTrack(s3Row); + const igvName = constructIgvNameParameter({ + pathOrKey: s3Row.key, + subjectData: subjectData!, + }); + + const newS3Itrack = convertS3RowToHtsgetIgvTrack({ s3Row, igvName }); if (newS3Itrack != null) newIgvLoadTrackList.push(newS3Itrack); } @@ -293,7 +376,12 @@ const createNewIgvTrackList = async ( arrayB: oldTrackData.gdsRowList, }) as unknown as GDSRow[]; for (const gdsRow of newGdsObjectList) { - const newGdsTrack = await convertGdsRowToIgvTrack(gdsRow); + const igvName = constructIgvNameParameter({ + pathOrKey: gdsRow.path, + subjectData: subjectData!, + }); + + const newGdsTrack = await convertGdsRowToIgvTrack({ gdsRow, igvName }); if (newGdsTrack != null) newIgvLoadTrackList.push(newGdsTrack); } return newIgvLoadTrackList; diff --git a/src/containers/subjects/IGV/utils.ts b/src/containers/subjects/IGV/utils.ts index d917f8b..54476cb 100644 --- a/src/containers/subjects/IGV/utils.ts +++ b/src/containers/subjects/IGV/utils.ts @@ -1,9 +1,11 @@ import config from '../../../config'; -import { getBaseNameFromKey } from '../../../api/utils'; -import { constructGDSUrl } from '../../../api/gds'; +import { GDSRow, constructGDSUrl } from '../../../api/gds'; import igv, { IGVBrowser, ITrack } from 'igv'; import { post } from 'aws-amplify/api'; +import { constructIgvNameParameter } from '../../../components/OpenInIgvDialog'; import genomes from './genomes'; +import { SubjectApiRes } from '../../../api/subject'; +import { S3Row } from '../../../api/s3'; /** * IGV OPERATIONS @@ -23,13 +25,15 @@ export const initIgv = async (props: { initRefGenome: string; oAuthToken: string return igvBrowser; }; -export type RequiredS3RowType = { - key: string; - bucket: string; -} & Record; -export const convertS3RowToHtsgetIgvTrack = (s3row: RequiredS3RowType): ITrack => { - const { key, bucket } = s3row; - const baseName = getBaseNameFromKey(key); +export type RequiredS3RowType = Pick; +export const convertS3RowToHtsgetIgvTrack = ({ + s3Row, + igvName, +}: { + s3Row: RequiredS3RowType; + igvName: string; +}): ITrack => { + const { key, bucket } = s3Row; // we have umccr specific rule about how our htsget ids are constructed const id = bucket + '/' + key; @@ -42,7 +46,7 @@ export const convertS3RowToHtsgetIgvTrack = (s3row: RequiredS3RowType): ITrack = url: config.htsget.URL, endpoint: config.htsget.ENDPOINT_READS, id: id.replace('.bam', ''), - name: baseName, + name: igvName, removable: false, }; } else if (key.endsWith('vcf') || key.endsWith('vcf.gz')) { @@ -53,7 +57,7 @@ export const convertS3RowToHtsgetIgvTrack = (s3row: RequiredS3RowType): ITrack = url: config.htsget.URL, endpoint: config.htsget.ENDPOINT_VARIANTS, id: id.replace('.vcf', '').replace('.gz', ''), - name: baseName, + name: igvName, removable: false, visibilityWindow: -1, }; @@ -62,13 +66,14 @@ export const convertS3RowToHtsgetIgvTrack = (s3row: RequiredS3RowType): ITrack = } }; -export type RequiredGDSRowType = { - volume_name: string; - path: string; -} & Record; -export const convertGdsRowToIgvTrack = async ( - gdsRow: RequiredGDSRowType -): Promise => { +export type RequiredGDSRowType = Pick; +export const convertGdsRowToIgvTrack = async ({ + gdsRow, + igvName, +}: { + gdsRow: RequiredGDSRowType; + igvName: string; +}): Promise => { const { volume_name, path } = gdsRow; // Find gds index path let idxFilePath: string; @@ -107,8 +112,6 @@ export const convertGdsRowToIgvTrack = async ( idxFilePresignUrl = presigned_url; } } - - const baseName = getBaseNameFromKey(path); if (path.endsWith('vcf') || path.endsWith('vcf.gz')) { return { type: 'variant', @@ -117,7 +120,7 @@ export const convertGdsRowToIgvTrack = async ( url: filePresignUrl, indexURL: idxFilePresignUrl, id: fileGdsUrl, - name: baseName, + name: igvName, removable: false, visibilityWindow: -1, }; @@ -129,7 +132,7 @@ export const convertGdsRowToIgvTrack = async ( url: filePresignUrl, indexURL: idxFilePresignUrl, id: fileGdsUrl, - name: baseName, + name: igvName, removable: false, }; } else if (path.endsWith('cram')) { @@ -140,7 +143,7 @@ export const convertGdsRowToIgvTrack = async ( url: filePresignUrl, indexURL: idxFilePresignUrl, id: fileGdsUrl, - name: baseName, + name: igvName, removable: false, }; } diff --git a/src/pages/subjects/SubjectDataPage/index.tsx b/src/pages/subjects/SubjectDataPage/index.tsx index 07a91ea..a7eef28 100644 --- a/src/pages/subjects/SubjectDataPage/index.tsx +++ b/src/pages/subjects/SubjectDataPage/index.tsx @@ -10,7 +10,7 @@ function SubjectDataPage() { const { subjectId } = useParams(); if (!subjectId) { - return
No Subject ID Provided
; + return
No Subject Id Provided
; } const chipDataS3: Record[] = PresetDataFactory.buildAnalysisDataS3();