diff --git a/app/components/Export/components/AnVILExplorer/platform/ExportMethod/exportMethod.tsx b/app/components/Export/components/AnVILExplorer/platform/ExportMethod/exportMethod.tsx new file mode 100644 index 000000000..6ff470cb8 --- /dev/null +++ b/app/components/Export/components/AnVILExplorer/platform/ExportMethod/exportMethod.tsx @@ -0,0 +1,21 @@ +import { JSX } from "react"; +import { ComponentProps } from "react"; +import { ExportMethod as DXExportMethod } from "@databiosphere/findable-ui/lib/components/Export/components/ExportMethod/exportMethod"; +import { useFeatureFlag } from "@databiosphere/findable-ui/lib/hooks/useFeatureFlag/useFeatureFlag"; +import { FEATURES } from "app/shared/entities"; + +/** + * Export method component for platform based export. + * Hidden if the platform based export feature is not enabled (NCPI Export). + * @param props - Export method component props. + * @returns Export method component. + */ +export const ExportMethod = ( + props: ComponentProps +): JSX.Element | null => { + const isEnabled = useFeatureFlag(FEATURES.NCPI_EXPORT); + + if (!isEnabled) return null; + + return ; +}; diff --git a/app/components/Export/components/AnVILExplorer/platform/ExportToPlatform/exportToPlatform.tsx b/app/components/Export/components/AnVILExplorer/platform/ExportToPlatform/exportToPlatform.tsx new file mode 100644 index 000000000..d6135d32a --- /dev/null +++ b/app/components/Export/components/AnVILExplorer/platform/ExportToPlatform/exportToPlatform.tsx @@ -0,0 +1,107 @@ +import { JSX } from "react"; +import { BUTTON_PROPS } from "@databiosphere/findable-ui/lib/components/common/Button/constants"; +import { useFileManifest } from "@databiosphere/findable-ui/lib/hooks/useFileManifest/useFileManifest"; +import { useFileManifestFileCount } from "@databiosphere/findable-ui/lib/hooks/useFileManifest/useFileManifestFileCount"; +import { useFileManifestFormat } from "@databiosphere/findable-ui/lib/hooks/useFileManifest/useFileManifestFormat"; +import { useRequestFileLocation } from "@databiosphere/findable-ui/lib/hooks/useRequestFileLocation"; +import { useRequestManifest } from "@databiosphere/findable-ui/lib/hooks/useRequestManifest/useRequestManifest"; +import { FluidPaper } from "@databiosphere/findable-ui/lib/components/common/Paper/components/FluidPaper/fluidPaper"; +import { Loading } from "@databiosphere/findable-ui/lib/components/Loading/loading"; +import { ExportManifestDownloadFormatForm } from "@databiosphere/findable-ui/lib/components/Export/components/ExportForm/components/ExportManifestDownloadFormatForm/exportManifestDownloadFormatForm"; +import { ExportButton } from "@databiosphere/findable-ui/lib/components/Export/components/ExportForm/components/ExportButton/exportButton"; +import { ExportForm } from "@databiosphere/findable-ui/lib/components/Export/components/ExportForm/exportForm"; +import { + Section, + SectionActions, + SectionContent, +} from "@databiosphere/findable-ui/lib/components/Export/export.styles"; +import { Button } from "@mui/material"; +import { + REL_ATTRIBUTE, + ANCHOR_TARGET, +} from "@databiosphere/findable-ui/lib/components/Links/common/entities"; +import { PAPER_PANEL_STYLE } from "@databiosphere/findable-ui/lib/components/common/Paper/paper"; +import { MANIFEST_DOWNLOAD_FORMAT } from "@databiosphere/findable-ui/lib/apis/azul/common/entities"; +import { Props } from "./types"; + +export const ExportToPlatform = ({ + buttonLabel, + description, + fileManifestState, + fileSummaryFacetName, + filters, + formFacet, + speciesFacetName, + successTitle, + title, +}: Props): JSX.Element => { + useFileManifest(filters, fileSummaryFacetName); + useFileManifestFileCount(filters, speciesFacetName, fileSummaryFacetName); + + const fileManifestFormatState = useFileManifestFormat( + MANIFEST_DOWNLOAD_FORMAT.VERBATIM_PFB + ); + const { fileManifestFormat } = fileManifestFormatState; + + const requestManifest = useRequestManifest(fileManifestFormat, formFacet); + const { requestMethod, requestUrl } = requestManifest; + + const response = useRequestFileLocation(requestUrl, requestMethod); + const url = ""; + + return url ? ( + +
+ +

{successTitle}

+
+ + + +
+
+ ) : ( +
+ + +
+ +

{title}

+

{description}

+
+ response.run()} + > + + +
+
+
+ ); +}; + +/** + * Build the export button. + * @param props - Button props e.g. "onClick" to request manifest. + * @returns button element. + */ +function renderButton({ ...props }): JSX.Element { + return Request Link; +} diff --git a/app/components/Export/components/AnVILExplorer/platform/ExportToPlatform/types.ts b/app/components/Export/components/AnVILExplorer/platform/ExportToPlatform/types.ts new file mode 100644 index 000000000..f82d77276 --- /dev/null +++ b/app/components/Export/components/AnVILExplorer/platform/ExportToPlatform/types.ts @@ -0,0 +1,15 @@ +import { FormFacet } from "@databiosphere/findable-ui/lib/components/Export/common/entities"; +import { FileManifestState } from "@databiosphere/findable-ui/lib/providers/fileManifestState"; +import { Filters } from "@databiosphere/findable-ui/lib/common/entities"; + +export interface Props { + buttonLabel: string; + description: string; + fileManifestState: FileManifestState; + fileSummaryFacetName: string; + filters: Filters; + formFacet: FormFacet; + speciesFacetName: string; + successTitle: string; + title: string; +} diff --git a/app/components/index.tsx b/app/components/index.tsx index 858bc122b..3183607e8 100644 --- a/app/components/index.tsx +++ b/app/components/index.tsx @@ -13,6 +13,7 @@ export { DownloadIconSmall, InventoryIconSmall, } from "@databiosphere/findable-ui/lib/components/common/CustomIcon/common/constants"; +export { ExportToPlatform } from "./Export/components/AnVILExplorer/platform/ExportToPlatform/exportToPlatform"; export { DiscourseIcon } from "@databiosphere/findable-ui/lib/components/common/CustomIcon/components/DiscourseIcon/discourseIcon"; export { GitHubIcon } from "@databiosphere/findable-ui/lib/components/common/CustomIcon/components/GitHubIcon/gitHubIcon"; export { OpenInNewIcon } from "@databiosphere/findable-ui/lib/components/common/CustomIcon/components/OpenInNewIcon/openInNewIcon"; diff --git a/app/shared/entities.ts b/app/shared/entities.ts index 27dfc0bf2..854471865 100644 --- a/app/shared/entities.ts +++ b/app/shared/entities.ts @@ -1,4 +1,6 @@ /** * Set of possible feature flags. */ -export enum FEATURES {} +export enum FEATURES { + NCPI_EXPORT = "ncpiexport", +} diff --git a/app/viewModelBuilders/azul/anvil-cmg/common/viewModelBuilders.ts b/app/viewModelBuilders/azul/anvil-cmg/common/viewModelBuilders.ts index 286aa397f..241409f50 100644 --- a/app/viewModelBuilders/azul/anvil-cmg/common/viewModelBuilders.ts +++ b/app/viewModelBuilders/azul/anvil-cmg/common/viewModelBuilders.ts @@ -39,16 +39,13 @@ import { ChipProps as MChipProps, FadeProps as MFadeProps, } from "@mui/material"; -import React, { ReactNode } from "react"; +import React, { ComponentProps, ReactNode } from "react"; import { ANVIL_CMG_CATEGORY_KEY, ANVIL_CMG_CATEGORY_LABEL, DATASET_RESPONSE, } from "../../../../../site-config/anvil-cmg/category"; -import { - ROUTE_EXPORT_TO_TERRA, - ROUTE_MANIFEST_DOWNLOAD, -} from "../../../../../site-config/anvil-cmg/dev/export/constants"; +import { ROUTES } from "../../../../../site-config/anvil-cmg/dev/export/routes"; import { AggregatedBioSampleResponse, AggregatedDatasetResponse, @@ -452,7 +449,7 @@ export const buildDatasetExportMethodManifestDownload = ( buttonLabel: "Request File Manifest", description: "Request a file manifest suitable for downloading this dataset to your HPC cluster or local machine.", - route: `${datasetPath}${ROUTE_MANIFEST_DOWNLOAD}`, + route: `${datasetPath}${ROUTES.MANIFEST_DOWNLOAD}`, title: "Download a File Manifest with Metadata", }; }; @@ -486,7 +483,7 @@ export const buildDatasetExportMethodTerra = ( buttonLabel: "Analyze in Terra", description: "Terra is a biomedical research platform to analyze data using workflows, Jupyter Notebooks, RStudio, and Galaxy.", - route: `${datasetPath}${ROUTE_EXPORT_TO_TERRA}`, + route: `${datasetPath}${ROUTES.TERRA}`, title: "Export Dataset Data and Metadata to Terra Workspace", }; }; @@ -744,7 +741,7 @@ export const buildExportMethodManifestDownload = ( buttonLabel: "Request File Manifest", description: "Request a file manifest for the current query containing the full list of selected files and the metadata for each file.", - route: ROUTE_MANIFEST_DOWNLOAD, + route: ROUTES.MANIFEST_DOWNLOAD, title: "Download a File Manifest with Metadata for the Selected Data", }; }; @@ -764,7 +761,7 @@ export const buildExportMethodTerra = ( buttonLabel: "Analyze in Terra", description: "Terra is a biomedical research platform to analyze data using workflows, Jupyter Notebooks, RStudio, and Galaxy.", - route: ROUTE_EXPORT_TO_TERRA, + route: ROUTES.TERRA, title: "Export Study Data and Metadata to Terra Workspace", }; }; @@ -793,6 +790,77 @@ export const buildExportSelectedDataSummary = ( }; }; +/** + * Build props for ExportToPlatform component. + * @param props - Props to pass to the ExportToPlatform component. + * @returns model to be used as props for the ExportToPlatform component. + */ +export const buildExportToPlatform = ( + props: Pick< + ComponentProps, + "buttonLabel" | "description" | "successTitle" | "title" + > +): (( + _: unknown, + viewContext: ViewContext +) => ComponentProps) => { + return (_: unknown, viewContext: ViewContext) => { + const { + exploreState: { filterState }, + fileManifestState, + } = viewContext; + return { + ...props, + fileManifestState, + fileSummaryFacetName: ANVIL_CMG_CATEGORY_KEY.FILE_FILE_FORMAT, + filters: filterState, + formFacet: getFormFacets(fileManifestState), + speciesFacetName: ANVIL_CMG_CATEGORY_KEY.DONOR_ORGANISM_TYPE, + }; + }; +}; + +/** + * Build props for ExportToPlatform BackPageHero component. + * @param title - Title of the export method. + * @returns model to be used as props for the BackPageHero component. + */ +export const buildExportToPlatformHero = ( + title: string +): (( + _: unknown, + viewContext: ViewContext +) => React.ComponentProps) => { + return (_, viewContext) => { + const { + exploreState: { tabValue }, + } = viewContext; + return getExportMethodHero(tabValue, title); + }; +}; + +/** + * Build props for ExportMethod component for display of the export to [platform] metadata section. + * @param props - Props to pass to the ExportMethod component. + * @returns model to be used as props for the ExportMethod component. + */ +export const buildExportToPlatformMethod = ( + props: Pick< + ComponentProps, + "buttonLabel" | "description" | "route" | "title" + > +): (( + _: unknown, + viewContext: ViewContext +) => ComponentProps) => { + return (_: unknown, viewContext: ViewContext) => { + return { + ...props, + ...getExportMethodAccessibility(viewContext), + }; + }; +}; + /** * Build props for ExportToTerra component. * @param _ - Unused. diff --git a/e2e/anvil/anvil-dataset.spec.ts b/e2e/anvil/anvil-dataset.spec.ts index 1120431a0..ad84ef18e 100644 --- a/e2e/anvil/anvil-dataset.spec.ts +++ b/e2e/anvil/anvil-dataset.spec.ts @@ -10,7 +10,7 @@ import { DatasetAccess, } from "./common/constants"; import { MUI_CLASSES } from "../features/common/constants"; -import { ROUTE_MANIFEST_DOWNLOAD } from "../../site-config/anvil-cmg/dev/export/constants"; +import { ROUTES } from "../../site-config/anvil-cmg/dev/export/routes"; import { ANVIL_CMG_CATEGORY_KEY } from "../../site-config/anvil-cmg/category"; const { describe } = test; @@ -88,7 +88,7 @@ describe("Dataset", () => { // Navigate to the export file manifest page. const currentUrl = page.url(); - await page.goto(`${currentUrl}${ROUTE_MANIFEST_DOWNLOAD}`); + await page.goto(`${currentUrl}${ROUTES.MANIFEST_DOWNLOAD}`); // Confirm the login alert is displayed. await expect( diff --git a/pages/export/biodata-catalyst.tsx b/pages/export/biodata-catalyst.tsx new file mode 100644 index 000000000..5ba041464 --- /dev/null +++ b/pages/export/biodata-catalyst.tsx @@ -0,0 +1,28 @@ +import { JSX } from "react"; +import { ExportMethodView } from "@databiosphere/findable-ui/lib/views/ExportMethodView/exportMethodView"; +import { GetStaticProps } from "next"; +import { useFeatureFlag } from "@databiosphere/findable-ui/lib/hooks/useFeatureFlag/useFeatureFlag"; +import { FEATURES } from "../../app/shared/entities"; +import Error from "next/error"; + +export const getStaticProps: GetStaticProps = async () => { + return { + props: { + pageTitle: "Export to NHLBI BioData Catalyst", + }, + }; +}; + +/** + * Export method page for BioData Catalyst. + * @returns export method view component. + */ +const ExportMethodPage = (): JSX.Element => { + const isEnabled = useFeatureFlag(FEATURES.NCPI_EXPORT); + + if (!isEnabled) return ; + + return ; +}; + +export default ExportMethodPage; diff --git a/site-config/anvil-cmg/dev/detail/dataset/export/export.ts b/site-config/anvil-cmg/dev/detail/dataset/export/export.ts index eb12eb170..98729284b 100644 --- a/site-config/anvil-cmg/dev/detail/dataset/export/export.ts +++ b/site-config/anvil-cmg/dev/detail/dataset/export/export.ts @@ -6,10 +6,7 @@ import { sideColumn as exportSideColumn } from "../../../export/exportSideColumn import * as V from "../../../../../../app/viewModelBuilders/azul/anvil-cmg/common/viewModelBuilders"; import * as C from "../../../../../../app/components"; import { DatasetsResponse } from "app/apis/azul/anvil-cmg/common/responses"; -import { - ROUTE_EXPORT_TO_TERRA, - ROUTE_MANIFEST_DOWNLOAD, -} from "../../../export/constants"; +import { ROUTES } from "../../../export/routes"; import * as MDX from "../../../../../../app/components/common/MDXContent/anvil-cmg"; /** @@ -66,7 +63,7 @@ export const exportConfig: ExportConfig = { viewBuilder: V.renderDatasetExport, } as ComponentConfig, ], - route: ROUTE_EXPORT_TO_TERRA, + route: ROUTES.TERRA, top: [ { children: [DATASET_ACCESSIBILITY_BADGE], @@ -119,7 +116,7 @@ export const exportConfig: ExportConfig = { viewBuilder: V.renderDatasetExport, } as ComponentConfig, ], - route: ROUTE_MANIFEST_DOWNLOAD, + route: ROUTES.MANIFEST_DOWNLOAD, top: [ { children: [DATASET_ACCESSIBILITY_BADGE], diff --git a/site-config/anvil-cmg/dev/export/constants.ts b/site-config/anvil-cmg/dev/export/constants.ts index 1af8b4659..c6cec8685 100644 --- a/site-config/anvil-cmg/dev/export/constants.ts +++ b/site-config/anvil-cmg/dev/export/constants.ts @@ -1,2 +1,35 @@ -export const ROUTE_EXPORT_TO_TERRA = "/export/export-to-terra"; -export const ROUTE_MANIFEST_DOWNLOAD = "/export/download-manifest"; +import { ROUTES } from "./routes"; +import { ComponentProps } from "react"; +import { ExportMethod } from "@databiosphere/findable-ui/lib/components/Export/components/ExportMethod/exportMethod"; +import { ExportToPlatform } from "../../../../app/components"; + +export const EXPORTS: Record< + string, + Pick< + ComponentProps, + "buttonLabel" | "description" | "successTitle" | "title" + > +> = { + BIO_DATA_CATALYST: { + buttonLabel: "Open BioData Catalyst", + description: + "BDC-SB is a cloud workspace for analysis, storage, and computation using workflows, Jupyter Notebooks, and RStudio.", + successTitle: "Your BioData Catalyst Workspace Link is Ready", + title: "Analyze in BioData Catalyst", + }, +}; + +export const EXPORT_METHODS: Record< + string, + Pick< + ComponentProps, + "buttonLabel" | "description" | "route" | "title" + > +> = { + BIO_DATA_CATALYST: { + buttonLabel: "Analyze in NHLBI BioData Catalyst", + description: EXPORTS.BIO_DATA_CATALYST.description, + route: ROUTES.BIO_DATA_CATALYST, + title: "Export to BioData Catalyst Powered by Seven Bridges (BDC-SB)", + }, +}; diff --git a/site-config/anvil-cmg/dev/export/export.ts b/site-config/anvil-cmg/dev/export/export.ts index fcd1209b8..7a666313b 100644 --- a/site-config/anvil-cmg/dev/export/export.ts +++ b/site-config/anvil-cmg/dev/export/export.ts @@ -4,9 +4,11 @@ import { } from "@databiosphere/findable-ui/lib/config/entities"; import * as C from "../../../../app/components"; import * as V from "../../../../app/viewModelBuilders/azul/anvil-cmg/common/viewModelBuilders"; -import { ROUTE_EXPORT_TO_TERRA, ROUTE_MANIFEST_DOWNLOAD } from "./constants"; +import { ROUTES } from "./routes"; import { mainColumn as exportMainColumn } from "./exportMainColumn"; import { sideColumn as exportSideColumn } from "./exportSideColumn"; +import { ExportMethod } from "../../../../app/components/Export/components/AnVILExplorer/platform/ExportMethod/exportMethod"; +import { EXPORT_METHODS, EXPORTS } from "./constants"; export const exportConfig: ExportConfig = { exportMethods: [ @@ -27,7 +29,7 @@ export const exportConfig: ExportConfig = { /* sideColumn */ ...exportSideColumn, ], - route: ROUTE_EXPORT_TO_TERRA, + route: ROUTES.TERRA, top: [ { component: C.BackPageHero, @@ -35,6 +37,33 @@ export const exportConfig: ExportConfig = { } as ComponentConfig, ], }, + { + mainColumn: [ + /* mainColumn - top section - warning - some datasets are not available */ + ...exportMainColumn, + /* mainColumn */ + { + children: [ + { + component: C.ExportToPlatform, + viewBuilder: V.buildExportToPlatform(EXPORTS.BIO_DATA_CATALYST), + } as ComponentConfig, + ], + component: C.BackPageContentMainColumn, + } as ComponentConfig, + /* sideColumn */ + ...exportSideColumn, + ], + route: ROUTES.BIO_DATA_CATALYST, + top: [ + { + component: C.BackPageHero, + viewBuilder: V.buildExportToPlatformHero( + "Export to BioData Catalyst" + ), + } as ComponentConfig, + ], + }, { mainColumn: [ /* mainColumn - top section - warning - some datasets are not available */ @@ -52,7 +81,7 @@ export const exportConfig: ExportConfig = { /* sideColumn */ ...exportSideColumn, ], - route: ROUTE_MANIFEST_DOWNLOAD, + route: ROUTES.MANIFEST_DOWNLOAD, top: [ { component: C.BackPageHero, @@ -75,6 +104,12 @@ export const exportConfig: ExportConfig = { component: C.ExportMethod, viewBuilder: V.buildExportMethodTerra, } as ComponentConfig, + { + component: ExportMethod, + viewBuilder: V.buildExportToPlatformMethod( + EXPORT_METHODS.BIO_DATA_CATALYST + ), + } as ComponentConfig, { component: C.ExportMethod, viewBuilder: V.buildExportMethodManifestDownload, diff --git a/site-config/anvil-cmg/dev/export/routes.ts b/site-config/anvil-cmg/dev/export/routes.ts new file mode 100644 index 000000000..b7c69a5d1 --- /dev/null +++ b/site-config/anvil-cmg/dev/export/routes.ts @@ -0,0 +1,5 @@ +export const ROUTES = { + BIO_DATA_CATALYST: "/export/biodata-catalyst", + MANIFEST_DOWNLOAD: "/export/download-manifest", + TERRA: "/export/export-to-terra", +} as const;