Skip to content

Commit 0959188

Browse files
frano-mclaude
andauthored
feat: update ordering and wording of cohort and dataset export options (#4744) (#4748)
* feat: update ordering and wording of cohort and dataset export options (#4744) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: replace div with span inside Typography to fix invalid HTML nesting (#4744) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: rename renderCurlDownload to renderCohortCurlDownload and update JSDoc (#4744) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: anvil dataset export e2e tests (#4744) * fix: update download section description wording (#4744) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Fran McDade <18710366+frano-m@users.noreply.github.com> Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 8417a5b commit 0959188

File tree

10 files changed

+282
-46
lines changed

10 files changed

+282
-46
lines changed
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import { TYPOGRAPHY_PROPS } from "@databiosphere/findable-ui/lib/styles/common/mui/typography";
2+
import { Stack, Typography } from "@mui/material";
3+
import type { JSX } from "react";
4+
import { isNRESConsentGroup } from "../../../../../../../../viewModelBuilders/azul/anvil-cmg/common/viewModelBuilders";
5+
import { Props } from "./types";
6+
7+
/**
8+
* Returns section title and description for downloading cohort files and metadata.
9+
* @param props - Component props.
10+
* @param props.viewContext - View context.
11+
* @returns Download section title and description.
12+
*/
13+
export const DownloadSection = ({ viewContext }: Props): JSX.Element => {
14+
const isNRES = isNRESConsentGroup(viewContext);
15+
return (
16+
<Stack gap={1}>
17+
<Typography
18+
component="h2"
19+
variant={TYPOGRAPHY_PROPS.VARIANT.HEADING_SMALL}
20+
>
21+
Download
22+
</Typography>
23+
<Typography variant={TYPOGRAPHY_PROPS.VARIANT.BODY_LARGE_400}>
24+
{isNRES ? (
25+
<span>
26+
To download the open-access data in the current selection, first use
27+
the <code>curl</code> command option to download the open-access
28+
data files. Then download a TSV manifest containing metadata for all
29+
data files in the current selection, including managed-access files.
30+
The manifest contains metadata only and does not include file data.
31+
Open-access data files are hosted through AWS Open Data, with
32+
storage and data transfer costs covered by the AWS Open Data
33+
Sponsorship Program.
34+
</span>
35+
) : (
36+
<span>
37+
Download a TSV manifest containing metadata for all selected files.
38+
The manifest contains metadata only and does not include file data.
39+
</span>
40+
)}
41+
</Typography>
42+
</Stack>
43+
);
44+
};
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import { ViewContext } from "@databiosphere/findable-ui/lib/config/entities";
2+
import { DatasetsResponse } from "../../../../../../../../apis/azul/anvil-cmg/common/responses";
3+
4+
export interface Props {
5+
viewContext: ViewContext<DatasetsResponse>;
6+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import { TYPOGRAPHY_PROPS } from "@databiosphere/findable-ui/lib/styles/common/mui/typography";
2+
import { Stack, Typography } from "@mui/material";
3+
import type { JSX } from "react";
4+
5+
/**
6+
* Returns section title and description for exporting cohort files and metadata.
7+
* @returns Export section title and description.
8+
*/
9+
export const ExportSection = (): JSX.Element => {
10+
return (
11+
<Stack gap={1}>
12+
<Typography
13+
component="h2"
14+
variant={TYPOGRAPHY_PROPS.VARIANT.HEADING_SMALL}
15+
>
16+
Export
17+
</Typography>
18+
<Typography variant={TYPOGRAPHY_PROPS.VARIANT.BODY_LARGE_400}>
19+
Send selected files and metadata to a supported cloud workspace for
20+
analysis.
21+
</Typography>
22+
</Stack>
23+
);
24+
};
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import { TYPOGRAPHY_PROPS } from "@databiosphere/findable-ui/lib/styles/common/mui/typography";
2+
import { Stack, Typography } from "@mui/material";
3+
import { isDatasetNRESConsentGroup } from "app/viewModelBuilders/azul/anvil-cmg/common/viewModelBuilders";
4+
import type { JSX } from "react";
5+
import type { Props } from "./types";
6+
7+
/**
8+
* Returns section title and description for downloading dataset files and metadata.
9+
* @param props - Component props.
10+
* @param props.dataset - Dataset response.
11+
* @returns Download section title and description.
12+
*/
13+
export const DownloadSection = ({ dataset }: Props): JSX.Element => {
14+
const isNRES = isDatasetNRESConsentGroup(dataset);
15+
return (
16+
<Stack gap={1}>
17+
<Typography
18+
component="h2"
19+
variant={TYPOGRAPHY_PROPS.VARIANT.HEADING_SMALL}
20+
>
21+
Download
22+
</Typography>
23+
<Typography variant={TYPOGRAPHY_PROPS.VARIANT.BODY_LARGE_400}>
24+
{isNRES ? (
25+
<span>
26+
To download data from this dataset, first download the open-access
27+
data files using the <code>curl</code> command option. Then download
28+
the TSV metadata manifest for the dataset. Open-access data files
29+
are hosted through AWS Open Data, with storage and data transfer
30+
costs covered by the AWS Open Data Sponsorship Program.
31+
</span>
32+
) : (
33+
<span>
34+
Download a TSV manifest with metadata for all files in the
35+
managed-access dataset. No file data is included.
36+
</span>
37+
)}
38+
</Typography>
39+
</Stack>
40+
);
41+
};
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import { DatasetsResponse } from "../../../../../../../../apis/azul/anvil-cmg/common/responses";
2+
3+
export interface Props {
4+
dataset: DatasetsResponse;
5+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import { TYPOGRAPHY_PROPS } from "@databiosphere/findable-ui/lib/styles/common/mui/typography";
2+
import { Stack, Typography } from "@mui/material";
3+
import type { JSX } from "react";
4+
5+
/**
6+
* Returns section title and description for exporting dataset files and metadata.
7+
* @returns Export section title and description.
8+
*/
9+
export const ExportSection = (): JSX.Element => {
10+
return (
11+
<Stack gap={1}>
12+
<Typography
13+
component="h2"
14+
variant={TYPOGRAPHY_PROPS.VARIANT.HEADING_SMALL}
15+
>
16+
Export
17+
</Typography>
18+
<Typography variant={TYPOGRAPHY_PROPS.VARIANT.BODY_LARGE_400}>
19+
Send this dataset&apos;s files and metadata to a supported cloud
20+
workspace for analysis.
21+
</Typography>
22+
</Stack>
23+
);
24+
};

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

Lines changed: 92 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,19 @@ export const buildConsentGroup = (
278278
};
279279
};
280280

281+
/**
282+
* Build props for the cohort DownloadSection component.
283+
* @param _ - Unused.
284+
* @param viewContext - View context.
285+
* @returns model to be used as props for the DownloadSection component.
286+
*/
287+
export const buildCohortDownloadSectionProps = (
288+
_: unknown,
289+
viewContext: ViewContext<DatasetsResponse>
290+
): { viewContext: ViewContext<DatasetsResponse> } => {
291+
return { viewContext };
292+
};
293+
281294
/**
282295
* Build props for data modality NTagCell component from the given response.
283296
* @param response - Response model return from API.
@@ -342,6 +355,17 @@ export const buildDatasetDescription = (
342355
};
343356
};
344357

358+
/**
359+
* Build props for the dataset detail DownloadSection component.
360+
* @param datasetsResponse - Response model return from datasets API.
361+
* @returns model to be used as props for the DownloadSection component.
362+
*/
363+
export const buildDatasetDownloadSectionProps = (
364+
datasetsResponse: DatasetsResponse
365+
): { dataset: DatasetsResponse } => {
366+
return { dataset: datasetsResponse };
367+
};
368+
345369
/**
346370
* Build props for Details component from the given datasets response.
347371
* TODO revisit - separate from entity builder, generalize modeling/component?, revisit transformer
@@ -447,9 +471,9 @@ export const buildDatasetExportMethodManifestDownload = (
447471
const datasetPath = buildDatasetPath(datasetsResponse);
448472
return {
449473
description:
450-
"Request a file manifest suitable for downloading this dataset to your HPC cluster or local machine.",
474+
"Download a TSV manifest containing metadata for all data files in the dataset.",
451475
route: `${datasetPath}${ROUTES.MANIFEST_DOWNLOAD}`,
452-
title: "Download a File Manifest with Metadata",
476+
title: "Download TSV Manifest",
453477
};
454478
};
455479

@@ -482,7 +506,7 @@ export const buildDatasetExportMethodTerra = (
482506
description:
483507
"Terra is a biomedical research platform to analyze data using workflows, Jupyter Notebooks, RStudio, and Galaxy.",
484508
route: `${datasetPath}${ROUTES.TERRA}`,
485-
title: "Export Dataset Data and Metadata to Terra Workspace",
509+
title: "Export to Terra",
486510
};
487511
};
488512

@@ -508,15 +532,10 @@ export const buildDatasetExportMethodCurlCommand = (
508532
): React.ComponentProps<typeof C.ExportMethod> => {
509533
const datasetPath = buildDatasetPath(datasetsResponse);
510534
return {
511-
description: (
512-
<div>
513-
Generate a <code>curl</code> command to download this dataset. This
514-
open-access dataset is hosted through the AWS Open Data Sponsorship
515-
Program, which covers storage and data transfer costs.
516-
</div>
517-
),
535+
description:
536+
"Generate a curl command to download all files in this open-access dataset.",
518537
route: `${datasetPath}${ROUTES.CURL_DOWNLOAD}`,
519-
title: "Download Open-Access Data and Metadata (No Egress Fees)",
538+
title: "Download Open-Access Data Files (No Data Transfer Fees)",
520539
};
521540
};
522541

@@ -867,9 +886,9 @@ export const buildExportMethodManifestDownload = (
867886
return {
868887
...getExportMethodAccessibility(viewContext),
869888
description:
870-
"Request a file manifest for the current query containing the full list of selected files and the metadata for each file.",
889+
"Download a TSV manifest containing metadata for all data files in the current selection, including managed-access files.",
871890
route: ROUTES.MANIFEST_DOWNLOAD,
872-
title: "Download a File Manifest with Metadata for the Selected Data",
891+
title: "Download TSV Manifest for All Selected Data Files",
873892
};
874893
};
875894

@@ -888,7 +907,7 @@ export const buildExportMethodTerra = (
888907
description:
889908
"Terra is a biomedical research platform to analyze data using workflows, Jupyter Notebooks, RStudio, and Galaxy.",
890909
route: ROUTES.TERRA,
891-
title: "Export Study Data and Metadata to Terra Workspace",
910+
title: "Export to Terra",
892911
};
893912
};
894913

@@ -931,10 +950,14 @@ export const buildExportMethodBulkDownload = (
931950
): React.ComponentProps<typeof C.ExportMethod> => {
932951
return {
933952
...getExportMethodAccessibility(viewContext),
934-
description:
935-
"Generate a curl command for downloading the open-access portion of the selected data. Open-access datasets are hosted through the AWS Open Data Sponsorship Program, which covers storage and data transfer costs.",
953+
description: (
954+
<div>
955+
Generate a <code>curl</code> command to download the open-access data
956+
files in the current selection.
957+
</div>
958+
),
936959
route: ROUTES.CURL_DOWNLOAD,
937-
title: "Download Open-Access Data and Metadata (curl Command)",
960+
title: "Download Open-Access Data Files (No Data Transfer Fees)",
938961
};
939962
};
940963

@@ -1711,6 +1734,21 @@ function isDatasetAccessible(datasetsResponse: DatasetsResponse): boolean {
17111734
return datasetsResponse.datasets[0].accessible;
17121735
}
17131736

1737+
/**
1738+
* Returns true if the dataset has NRES or Unrestricted access consent group.
1739+
* @param datasetsResponse - Response model return from datasets API.
1740+
* @returns true if the dataset has NRES or Unrestricted access consent group.
1741+
*/
1742+
export function isDatasetNRESConsentGroup(
1743+
datasetsResponse: DatasetsResponse
1744+
): boolean {
1745+
const consentGroups = getConsentGroup(datasetsResponse);
1746+
return (
1747+
consentGroups.includes("NRES") ||
1748+
consentGroups.includes("Unrestricted access")
1749+
);
1750+
}
1751+
17141752
/**
17151753
* Returns true if the "accessible" file facet has a term value of "true".
17161754
* @param fileManifestState - File manifest state.
@@ -1734,6 +1772,28 @@ function isFileManifestSummaryFileCountValid(
17341772
return fileCount > 0;
17351773
}
17361774

1775+
/**
1776+
* Returns true if the dataset has NRES or Unrestricted access consent group.
1777+
* @param viewContext - View context.
1778+
* @returns true if the dataset has NRES or Unrestricted access consent group.
1779+
*/
1780+
export function isNRESConsentGroup(
1781+
viewContext: ViewContext<DatasetsResponse>
1782+
): boolean {
1783+
const { fileManifestState } = viewContext;
1784+
1785+
const facet = findFacet(
1786+
fileManifestState.filesFacets,
1787+
ANVIL_CMG_CATEGORY_KEY.DATASET_CONSENT_GROUP
1788+
);
1789+
1790+
if (!facet) return false;
1791+
1792+
const termsByName = facet.termsByName;
1793+
1794+
return termsByName.has("NRES") || termsByName.has("Unrestricted access");
1795+
}
1796+
17371797
/**
17381798
* Returns true if the response is ready (for use) for the given authorization state.
17391799
* The response is ready when the response is no longer loading (loading is false).
@@ -1805,18 +1865,28 @@ export const renderWhenUnAuthenticated = (
18051865
};
18061866

18071867
/**
1808-
* Renders dataset curl download components when the given dataset is accessible
1809-
* and has NRES consent group.
1868+
* Renders cohort curl download component when the current query includes NRES or Unrestricted access consent groups.
1869+
* @param _ - Unused.
1870+
* @param viewContext - View context.
1871+
* @returns model to be used as props for the ConditionalComponent component.
1872+
*/
1873+
export const renderCohortCurlDownload = (
1874+
_: unknown,
1875+
viewContext: ViewContext<DatasetsResponse>
1876+
): ComponentProps<typeof C.ConditionalComponent> => {
1877+
return { isIn: isNRESConsentGroup(viewContext) };
1878+
};
1879+
1880+
/**
1881+
* Renders dataset curl download components when the given dataset has NRES consent group.
18101882
* @param datasetsResponse - Response model return from datasets API.
18111883
* @returns model to be used as props for the ConditionalComponent component.
18121884
*/
18131885
export const renderDatasetCurlDownload = (
18141886
datasetsResponse: DatasetsResponse
18151887
): React.ComponentProps<typeof C.ConditionalComponent> => {
1816-
const consentGroups = getConsentGroup(datasetsResponse);
1817-
const isNRES = consentGroups.includes("NRES");
18181888
return {
1819-
isIn: isDatasetAccessible(datasetsResponse) && isNRES,
1889+
isIn: isDatasetNRESConsentGroup(datasetsResponse),
18201890
};
18211891
};
18221892

e2e/anvil/common/constants.tsx

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,8 @@ export const BUTTON_TEXT_EXPORT = "Export";
55
export const BUTTON_TEXT_REQUEST_ACCESS = "Request Access";
66
export const BUTTON_TEXT_REQUEST_LINK = "Request Link";
77
export const BUTTON_TEXT_REQUEST_FILE_MANIFEST = "Request File Manifest";
8-
export const TITLE_TEXT_ANALYZE_IN_TERRA =
9-
"Export Dataset Data and Metadata to Terra Workspace";
10-
export const TITLE_TEXT_REQUEST_FILE_MANIFEST =
11-
"Download a File Manifest with Metadata";
8+
export const TITLE_TEXT_ANALYZE_IN_TERRA = "Export to Terra";
9+
export const TITLE_TEXT_REQUEST_FILE_MANIFEST = "Download TSV Manifest";
1210

1311
export type DatasetAccess =
1412
| typeof CHIP_TEXT_ACCESS_GRANTED

0 commit comments

Comments
 (0)