Skip to content

Commit 6f6ada2

Browse files
feat: enable curl download for anvil-cmg datasets (#4725)
* feat: enable curl download for anvil-cmg datasets #4692 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: gate curl download route and add AWS ODP disclaimer #4692 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
1 parent bae0b7a commit 6f6ada2

9 files changed

Lines changed: 163 additions & 0 deletions

File tree

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import { JSX } from "react";
2+
import { ComponentProps } from "react";
3+
import { ExportMethod as DXExportMethod } from "@databiosphere/findable-ui/lib/components/Export/components/ExportMethod/exportMethod";
4+
import { useFeatureFlag } from "@databiosphere/findable-ui/lib/hooks/useFeatureFlag/useFeatureFlag";
5+
import { FEATURES } from "app/shared/entities";
6+
7+
/**
8+
* Export method component for curl download.
9+
* Hidden if the curl download feature is not enabled.
10+
* @param props - Export method component props.
11+
* @returns Export method component.
12+
*/
13+
export const CurlDownloadExportMethod = (
14+
props: ComponentProps<typeof DXExportMethod>
15+
): JSX.Element | null => {
16+
const isEnabled = useFeatureFlag(FEATURES.CURL_DOWNLOAD);
17+
18+
if (!isEnabled) return null;
19+
20+
return <DXExportMethod {...props} />;
21+
};
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
### Download via curl
2+
3+
<TagWarning>Please note</TagWarning> This download includes only files available
4+
through the AWS Open Data Program. Files hosted exclusively on Google Cloud are
5+
not included in this command.
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
### Your curl Command is Ready
2+
3+
Execute the curl command below in your terminal to download the selected data.

app/components/common/MDXContent/anvil-cmg/index.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ export { default as AlertExportWarning } from "./alertExportWarning.mdx";
77
export { default as AlertExportWarningContent } from "./alertExportWarningContent.mdx";
88
export { default as AlertLoginReminder } from "./alertLoginReminder.mdx";
99
export { default as DataReleasePolicy } from "./dataReleasePolicy.mdx";
10+
export { default as DownloadCurlCommandStart } from "./downloadCurlCommandStart.mdx";
11+
export { default as DownloadCurlCommandSuccess } from "./downloadCurlCommandSuccess.mdx";
1012
export { default as LoginTermsOfService } from "./loginTermsOfService.mdx";
1113
export { default as LoginText } from "./loginText.mdx";
1214
export { default as LoginWarning } from "./loginWarning.mdx";

app/shared/entities.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,6 @@
33
*/
44
export enum FEATURES {
55
AZUL_DOWNLOAD = "azuldownload",
6+
CURL_DOWNLOAD = "curldownload",
67
NCPI_EXPORT = "ncpiexport",
78
}

app/viewModelBuilders/azul/anvil-cmg/common/viewModelBuilders.ts

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -485,6 +485,62 @@ export const buildDatasetExportMethodTerra = (
485485
};
486486
};
487487

488+
/**
489+
* Build props for dataset curl download BackPageHero component.
490+
* @param datasetsResponse - Response model return from datasets API.
491+
* @returns model to be used as props for the BackPageHero component.
492+
*/
493+
export const buildDatasetExportMethodHeroCurlCommand = (
494+
datasetsResponse: DatasetsResponse
495+
): React.ComponentProps<typeof C.BackPageHero> => {
496+
const title = 'Download Selected Data Using "curl"';
497+
return getDatasetExportMethodHero(datasetsResponse, title);
498+
};
499+
500+
/**
501+
* Build props for ExportMethod component for display of the dataset curl download section.
502+
* @param datasetsResponse - Response model return from datasets API.
503+
* @returns model to be used as props for the dataset curl download export method component.
504+
*/
505+
export const buildDatasetExportMethodCurlCommand = (
506+
datasetsResponse: DatasetsResponse
507+
): React.ComponentProps<typeof C.ExportMethod> => {
508+
const datasetPath = buildDatasetPath(datasetsResponse);
509+
return {
510+
buttonLabel: "Request curl Command",
511+
description: "Obtain a curl command for downloading the selected data.",
512+
route: `${datasetPath}${ROUTES.CURL_DOWNLOAD}`,
513+
title: "Download Study Data and Metadata (curl Command)",
514+
};
515+
};
516+
517+
/**
518+
* Build props for DownloadCurlCommand component from the given datasets response.
519+
* @param datasetsResponse - Response model return from datasets API.
520+
* @param viewContext - View context.
521+
* @returns model to be used as props for the DownloadCurlCommand component.
522+
*/
523+
export const buildDatasetDownloadCurlCommand = (
524+
datasetsResponse: DatasetsResponse,
525+
viewContext: ViewContext<DatasetsResponse>
526+
): React.ComponentProps<typeof C.DownloadCurlCommand> => {
527+
const { fileManifestState } = viewContext;
528+
// Get the initial filters.
529+
const filters = getExportEntityFilters(datasetsResponse);
530+
// Get the form facets.
531+
const formFacet = getFormFacets(fileManifestState);
532+
return {
533+
DownloadCurlForm: C.DownloadCurlCommandForm,
534+
DownloadCurlStart: MDX.DownloadCurlCommandStart,
535+
DownloadCurlSuccess: MDX.DownloadCurlCommandSuccess,
536+
fileManifestState,
537+
fileSummaryFacetName: ANVIL_CMG_CATEGORY_KEY.FILE_FILE_FORMAT,
538+
filters,
539+
formFacet,
540+
speciesFacetName: ANVIL_CMG_CATEGORY_KEY.DONOR_ORGANISM_TYPE,
541+
};
542+
};
543+
488544
/**
489545
* Build props for the dataset ExportToPlatform component.
490546
* @param props - Props to pass to the ExportToPlatform component.

pages/[entityListType]/[...params].tsx

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ const NCPI_EXPORT_PATHS = [
4242
ROUTES.CAVATICA,
4343
];
4444

45+
const CURL_DOWNLOAD_PATH = ROUTES.CURL_DOWNLOAD;
46+
4547
interface StaticPath {
4648
params: PageUrl;
4749
}
@@ -64,11 +66,14 @@ export interface EntityDetailPageProps extends AzulEntityStaticResponse {
6466
*/
6567
const EntityDetailPage = (props: EntityDetailPageProps): JSX.Element => {
6668
const isNCPIExportEnabled = useFeatureFlag(FEATURES.NCPI_EXPORT);
69+
const isCurlDownloadEnabled = useFeatureFlag(FEATURES.CURL_DOWNLOAD);
6770
const { query } = useRouter();
6871
if (!props.entityListType) return <></>;
6972
if (props.override) return <EntityGuard override={props.override} />;
7073
if (!isNCPIExportEnabled && isNCPIExportRoute(query))
7174
return <NextError statusCode={404} />;
75+
if (!isCurlDownloadEnabled && isCurlDownloadRoute(query))
76+
return <NextError statusCode={404} />;
7277
if (isChooseExportView(query)) return <EntityExportView {...props} />;
7378
if (isExportMethodView(query)) return <EntityExportMethodView {...props} />;
7479
return <EntityDetailView {...props} />;
@@ -103,6 +108,17 @@ function isNCPIExportRoute(query: ParsedUrlQuery): boolean {
103108
);
104109
}
105110

111+
/**
112+
* Returns true if the current route is a curl download route.
113+
* @param query - Parsed URL query.
114+
* @returns True if the route matches the curl download path.
115+
*/
116+
function isCurlDownloadRoute(query: ParsedUrlQuery): boolean {
117+
const params = query.params as string[] | undefined;
118+
const lastParam = params?.[params.length - 1] || "";
119+
return lastParam === CURL_DOWNLOAD_PATH.replace("/export/", "");
120+
}
121+
106122
/**
107123
* Returns true if the entity is a special case e.g. an "override".
108124
* @param override - Override.

site-config/anvil-cmg/dev/detail/dataset/export/export.ts

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import * as C from "../../../../../../app/components";
88
import { DatasetsResponse } from "app/apis/azul/anvil-cmg/common/responses";
99
import { ROUTES } from "../../../export/routes";
1010
import * as MDX from "../../../../../../app/components/common/MDXContent/anvil-cmg";
11+
import { CurlDownloadExportMethod } from "../../../../../../app/components/Export/components/AnVILExplorer/CurlDownload/curlDownloadExportMethod";
1112
import { ExportMethod } from "../../../../../../app/components/Export/components/AnVILExplorer/platform/ExportMethod/exportMethod";
1213
import { EXPORT_METHODS, EXPORTS } from "../../../export/constants";
1314
import { ExportToPlatform } from "../../../../../../app/components/Export/components/AnVILExplorer/platform/ExportToPlatform/exportToPlatform";
@@ -25,6 +26,59 @@ const DATASET_ACCESSIBILITY_BADGE = {
2526
*/
2627
export const exportConfig: ExportConfig = {
2728
exportMethods: [
29+
{
30+
mainColumn: [
31+
/* --------- */
32+
/* Dataset is not accessible; render warning */
33+
/* --------- */
34+
{
35+
children: [
36+
{
37+
children: [
38+
{
39+
component: MDX.Alert,
40+
viewBuilder: V.buildAlertDatasetExportWarning,
41+
} as ComponentConfig<typeof MDX.Alert, DatasetsResponse>,
42+
],
43+
component: C.BackPageContentSingleColumn,
44+
} as ComponentConfig<typeof C.BackPageContentSingleColumn>,
45+
],
46+
component: C.ConditionalComponent,
47+
viewBuilder: V.renderDatasetExportWarning,
48+
} as ComponentConfig<typeof C.ConditionalComponent, DatasetsResponse>,
49+
/* ------ */
50+
/* Dataset is accessible; render curl download method */
51+
/* ------ */
52+
{
53+
children: [
54+
{
55+
children: [
56+
{
57+
component: C.DownloadCurlCommand,
58+
viewBuilder: V.buildDatasetDownloadCurlCommand,
59+
} as ComponentConfig<
60+
typeof C.DownloadCurlCommand,
61+
DatasetsResponse
62+
>,
63+
],
64+
component: C.BackPageContentMainColumn,
65+
} as ComponentConfig<typeof C.BackPageContentMainColumn>,
66+
/* sideColumn */
67+
...exportSideColumn,
68+
],
69+
component: C.ConditionalComponent,
70+
viewBuilder: V.renderDatasetExport,
71+
} as ComponentConfig<typeof C.ConditionalComponent, DatasetsResponse>,
72+
],
73+
route: ROUTES.CURL_DOWNLOAD,
74+
top: [
75+
{
76+
children: [DATASET_ACCESSIBILITY_BADGE],
77+
component: C.BackPageHero,
78+
viewBuilder: V.buildDatasetExportMethodHeroCurlCommand,
79+
} as ComponentConfig<typeof C.BackPageHero>,
80+
],
81+
},
2882
{
2983
mainColumn: [
3084
/* --------- */
@@ -324,6 +378,10 @@ export const exportConfig: ExportConfig = {
324378
component: C.AnVILExportEntity,
325379
viewBuilder: V.buildDatasetExportPropsWithFilter,
326380
} as ComponentConfig<typeof C.AnVILExportEntity>,
381+
{
382+
component: CurlDownloadExportMethod,
383+
viewBuilder: V.buildDatasetExportMethodCurlCommand,
384+
} as ComponentConfig<typeof CurlDownloadExportMethod>,
327385
{
328386
component: C.ExportMethod,
329387
viewBuilder: V.buildDatasetExportMethodTerra,

site-config/anvil-cmg/dev/export/routes.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ export const ROUTES = {
22
BIO_DATA_CATALYST: "/export/biodata-catalyst",
33
CANCER_GENOMICS_CLOUD: "/export/cancer-genomics-cloud",
44
CAVATICA: "/export/cavatica",
5+
CURL_DOWNLOAD: "/export/get-curl-command",
56
MANIFEST_DOWNLOAD: "/export/download-manifest",
67
TERRA: "/export/export-to-terra",
78
} as const;

0 commit comments

Comments
 (0)