diff --git a/src/api/s3.ts b/src/api/s3.ts index bfb6cac..39a8d0d 100644 --- a/src/api/s3.ts +++ b/src/api/s3.ts @@ -48,6 +48,8 @@ export type PresignApiData = { signed_url: string; error?: string; } & Record; +// NOTE: This function is used to get the 'preview' presigned URL for the S3 object +// By default, the 'Content-Disposition' header is set to 'inline' to open the file in the browser export function usePortalS3PresignAPI(s3Id?: string | number) { return useQuery( ['portal-s3-presign', s3Id], @@ -55,6 +57,11 @@ export function usePortalS3PresignAPI(s3Id?: string | number) { const response = await get({ apiName: 'portal', path: `/s3/${s3Id}/presign`, + options: { + headers: { + 'Content-Disposition': 'inline', + }, + }, }).response; return (await response.body.json()) as PresignApiData; }, @@ -122,6 +129,8 @@ export function usePortalS3StatusAPI(s3Id?: string | number) { }); } +// NOTE: This function is used to get the 'download' presigned URL for the S3 object +// By default, the 'Content-Disposition' header is set to 'attachment' in the api side to download the file export async function getS3PreSignedUrl(id: number) { const response = await get({ apiName: 'portal', diff --git a/src/containers/subjects/AnalysisResultTable/index.tsx b/src/containers/subjects/AnalysisResultTable/index.tsx index c349364..3763ee7 100644 --- a/src/containers/subjects/AnalysisResultTable/index.tsx +++ b/src/containers/subjects/AnalysisResultTable/index.tsx @@ -30,18 +30,18 @@ type AnalysisResultS3TableProps = { data: S3Row[]; }; -const filenameTemplate = (rowData: Record) => { +const filenameTemplate = (rowData: S3Row | GDSRow) => { const toast = useRef(null); const [blockedPanel, setBlockedPanel] = useState(false); let filename; - if (rowData.path) filename = rowData.path.split('/').pop(); - if (rowData.key) filename = rowData.key.split('/').pop(); - const split_path = filename.split('.'); + if ('path' in rowData && rowData.path) filename = rowData.path.split('/').pop(); + if ('key' in rowData && rowData.key) filename = rowData.key.split('/').pop(); + const split_path = filename ? filename.split('.') : []; const filetype = split_path[split_path.length - 1].toLowerCase(); - const handleOpenInBrowser = async (rowData: Record) => { + const handleOpenInBrowser = async (rowData: S3Row | GDSRow) => { setBlockedPanel(true); - if (rowData.path) { + if ('path' in rowData && rowData.path) { try { const signed_url = await getGDSPreSignedUrl(rowData.id, { headers: { @@ -65,7 +65,7 @@ const filenameTemplate = (rowData: Record) => { // throw e; } } - if (rowData.key) { + if ('key' in rowData && rowData.key) { try { const signed_url = await getS3PreSignedUrl(rowData.id); window.open(signed_url, '_blank'); @@ -85,7 +85,10 @@ const filenameTemplate = (rowData: Record) => { setBlockedPanel(false); }; - if (filename.endsWith('html') || filename.endsWith('png') || filename.endsWith('pdf')) { + if ( + filename && + (filename.endsWith('html') || filename.endsWith('png') || filename.endsWith('pdf')) + ) { return ( <> @@ -108,8 +111,10 @@ const filenameTemplate = (rowData: Record) => { * Note that the variable naming might be specific to S3 or GDS. */ -const portalRunIdTemplate = (rowData: Record) => { - const portalRunId = rowData.key ? getPortalRunIdFromS3Key(rowData.key) : rowData.path.split('/')[4]; +const portalRunIdTemplate = (rowData: S3Row | GDSRow) => { + let portalRunId; + if ('key' in rowData && rowData.key) portalRunId = getPortalRunIdFromS3Key(rowData.key); + if ('path' in rowData && rowData.path) portalRunId = rowData.path.split('/')[4]; return (
{portalRunId} @@ -119,10 +124,10 @@ const portalRunIdTemplate = (rowData: Record) => { // Fix: cttsov2 have one more layer than other data in the s3 key const getPortalRunIdFromS3Key = (key: string) => { - const tmp = key.split('/')[3] + const tmp = key.split('/')[3]; // if tmp not shtart with 8 digits, then it is the extra layer return /^\d{8}/.test(tmp) ? tmp : key.split('/')[4]; -} +}; const actionGDSTemplate = (rowData: GDSRow) => { return ( @@ -236,7 +241,7 @@ const downloadTemplate = ({ }: { id: number; keyOrPath: string; - getPresignedUrl: (id: number) => Promise; + getPresignedUrl: (id: number) => Promise; }) => { /** * For now download option is the special case that only offer within Analysis Results summary panel. @@ -519,7 +524,12 @@ function groupResultsData({ (r) => r.key.includes('cttsov2') && r.key.endsWith('bam') ); const cttsov2Vcfs = results_cttsov2.filter( - (r) => r.key.includes('cttsov2') && (r.key.endsWith('.vcf') || r.key.endsWith('.vcf.gz')) + (r) => + r.key.includes('cttsov2') && + (r.key.endsWith('.vcf') || + r.key.endsWith('.gvcf') || + r.key.endsWith('.vcf.gz') || + r.key.endsWith('.gvcf.gz')) ); const cttsov2Tsv = results_cttsov2.filter( (r) => r.key.includes('cttsov2') && r.key.endsWith('tsv')