diff --git a/__tests__/components/exportToPlatform.test.tsx b/__tests__/components/exportToPlatform.test.tsx new file mode 100644 index 000000000..c85048105 --- /dev/null +++ b/__tests__/components/exportToPlatform.test.tsx @@ -0,0 +1,266 @@ +import type { + FileLocation, + UseRequestFileLocationResult, +} from "@databiosphere/findable-ui/lib/hooks/useRequestFileLocation"; +import type { FileManifestState } from "@databiosphere/findable-ui/lib/providers/fileManifestState"; +import { createAppTheme } from "@databiosphere/findable-ui/lib/theme/theme"; +import { ThemeProvider } from "@mui/material"; +import { render, screen } from "@testing-library/react"; +import { ExportToPlatform } from "../../app/components/Export/components/AnVILExplorer/platform/ExportToPlatform/exportToPlatform"; +import type { + PlatformImport, + Props, +} from "../../app/components/Export/components/AnVILExplorer/platform/ExportToPlatform/types"; +import { + buildPlatformImportUrl, + getPlatformImportUrl, + isPlatformImportAvailable, +} from "../../app/components/Export/components/AnVILExplorer/platform/ExportToPlatform/utils"; +import { FEATURES } from "../../app/shared/entities"; + +const mockUseRequestFileLocation = jest.fn(); + +jest.mock("@databiosphere/findable-ui/lib/hooks/useDownloadStatus", () => ({ + useDownloadStatus: (): { + disabled: boolean; + isLoading: boolean; + message: string; + } => ({ disabled: false, isLoading: false, message: "" }), +})); + +jest.mock( + "@databiosphere/findable-ui/lib/hooks/useFileManifest/useFileManifest", + () => ({ useFileManifest: jest.fn() }) +); + +jest.mock( + "@databiosphere/findable-ui/lib/hooks/useFileManifest/useFileManifestFileCount", + () => ({ useFileManifestFileCount: jest.fn() }) +); + +jest.mock("@databiosphere/findable-ui/lib/hooks/useFileManifestState", () => ({ + useFileManifestState: (): { + fileManifestDispatch: jest.Mock; + fileManifestState: { isLoading: boolean }; + } => ({ + fileManifestDispatch: jest.fn(), + fileManifestState: { isLoading: false }, + }), +})); + +jest.mock( + "@databiosphere/findable-ui/lib/hooks/useRequestFileLocation", + () => ({ + useRequestFileLocation: (): UseRequestFileLocationResult => + mockUseRequestFileLocation(), + }) +); + +jest.mock( + "@databiosphere/findable-ui/lib/hooks/useRequestManifest/useRequestManifest", + () => ({ + useRequestManifest: (): { requestMethod: string; requestUrl: string } => ({ + requestMethod: "PUT", + requestUrl: "https://service.example.org/manifest/files", + }), + }) +); + +jest.mock("@databiosphere/findable-ui/lib/providers/loginGuard/hook", () => ({ + useLoginGuard: (): { requireLogin: jest.Mock } => ({ + requireLogin: jest.fn(), + }), +})); + +const PLATFORM_IMPORT: PlatformImport = { + baseUrl: "https://platform.sb.biodatacatalyst.nhlbi.nih.gov/import/pfb", + source: "bdc", +}; + +const SIGNED_URL = + "https://storage.googleapis.com/bucket/manifest.avro?X-Goog-Signature=a%2Fb&X-Goog-Expires=3600"; + +const IMPORT_URL = + "https://platform.sb.biodatacatalyst.nhlbi.nih.gov/import/pfb?URL=https%3A%2F%2Fstorage.googleapis.com%2Fbucket%2Fmanifest.avro%3FX-Goog-Signature%3Da%252Fb%26X-Goog-Expires%3D3600&source=bdc"; + +const FILE_LOCATION: FileLocation = { location: SIGNED_URL, status: 302 }; + +describe("buildPlatformImportUrl", () => { + it("encodes the signed URL and appends the source", () => { + expect(buildPlatformImportUrl(PLATFORM_IMPORT, SIGNED_URL)).toBe( + IMPORT_URL + ); + }); + + it("round-trips the signed URL through the URL parameter", () => { + const url = new URL(buildPlatformImportUrl(PLATFORM_IMPORT, SIGNED_URL)); + expect(url.searchParams.get("URL")).toBe(SIGNED_URL); + expect(url.searchParams.get("source")).toBe("bdc"); + }); +}); + +describe("getPlatformImportUrl", () => { + it("returns the import URL when enabled with a config and file location", () => { + expect(getPlatformImportUrl(true, PLATFORM_IMPORT, FILE_LOCATION)).toBe( + IMPORT_URL + ); + }); + + it("returns undefined when the feature flag is off", () => { + expect( + getPlatformImportUrl(false, PLATFORM_IMPORT, FILE_LOCATION) + ).toBeUndefined(); + }); + + it("returns undefined when the platform has no import config", () => { + expect( + getPlatformImportUrl(true, undefined, FILE_LOCATION) + ).toBeUndefined(); + }); + + it("returns undefined before the file location is available", () => { + expect( + getPlatformImportUrl(true, PLATFORM_IMPORT, undefined) + ).toBeUndefined(); + }); +}); + +describe("isPlatformImportAvailable", () => { + it("returns true when enabled with a config", () => { + expect(isPlatformImportAvailable(true, PLATFORM_IMPORT)).toBe(true); + }); + + it("returns false when the feature flag is off", () => { + expect(isPlatformImportAvailable(false, PLATFORM_IMPORT)).toBe(false); + }); + + it("returns false when the platform has no import config", () => { + expect(isPlatformImportAvailable(true, undefined)).toBe(false); + }); +}); + +const BUTTON_LABEL = "Open BioData Catalyst"; + +const REQUEST_LINK = "Request Link"; + +const FILE_MANIFEST_STATE: FileManifestState = { + fileCount: undefined, + fileSummary: undefined, + fileSummaryFacetName: undefined, + fileSummaryFilters: [], + filesFacets: [], + filters: [], + isEnabled: true, + isFacetsLoading: false, + isFacetsSuccess: true, + isFileSummaryLoading: false, + isLoading: false, + isSummaryLoading: false, + summary: undefined, +}; + +const PROPS: Props = { + buttonLabel: BUTTON_LABEL, + description: "BDC-SB is a cloud workspace.", + fileManifestState: FILE_MANIFEST_STATE, + fileSummaryFacetName: "files.file_format", + filters: [], + formFacet: {}, + platformImport: PLATFORM_IMPORT, + speciesFacetName: "donors.organism_type", + successTitle: "Your BioData Catalyst Workspace Link is Ready", + title: "Analyze in BioData Catalyst", +}; + +const THEME = createAppTheme(); + +/** + * Builds a useRequestFileLocation result. + * @param data - File location returned by the manifest request. + * @returns useRequestFileLocation result. + */ +function buildFileLocationResult( + data: FileLocation | undefined +): UseRequestFileLocationResult { + return { + data, + isIdle: !data, + isLoading: false, + isSuccess: !!data, + run: jest.fn(), + }; +} + +/** + * Returns the "Request Link" button. + * @returns "Request Link" button element. + */ +function getRequestLinkButton(): HTMLElement { + return screen.getByRole("button", { name: REQUEST_LINK }); +} + +/** + * Renders ExportToPlatform within the app theme. + * @param props - Export to platform props. + */ +function renderExportToPlatform(props: Props): void { + render( + + + + ); +} + +describe("ExportToPlatform", () => { + afterEach(() => { + localStorage.clear(); + mockUseRequestFileLocation.mockReset(); + }); + + it("disables Request Link when the Velsera export flag is off", () => { + mockUseRequestFileLocation.mockReturnValue( + buildFileLocationResult(undefined) + ); + renderExportToPlatform(PROPS); + expect(getRequestLinkButton().hasAttribute("disabled")).toBe(true); + }); + + it("disables Request Link when the platform has no import endpoint", () => { + localStorage.setItem(FEATURES.VELSERA_EXPORT, "true"); + mockUseRequestFileLocation.mockReturnValue( + buildFileLocationResult(undefined) + ); + renderExportToPlatform({ ...PROPS, platformImport: undefined }); + expect(getRequestLinkButton().hasAttribute("disabled")).toBe(true); + }); + + it("enables Request Link when the Velsera export flag is on", () => { + localStorage.setItem(FEATURES.VELSERA_EXPORT, "true"); + mockUseRequestFileLocation.mockReturnValue( + buildFileLocationResult(undefined) + ); + renderExportToPlatform(PROPS); + expect(getRequestLinkButton().hasAttribute("disabled")).toBe(false); + }); + + it("links to the import URL once the PFB location is available", () => { + localStorage.setItem(FEATURES.VELSERA_EXPORT, "true"); + mockUseRequestFileLocation.mockReturnValue( + buildFileLocationResult(FILE_LOCATION) + ); + renderExportToPlatform(PROPS); + const link = screen.getByRole("link", { name: BUTTON_LABEL }); + expect(link.getAttribute("href")).toBe(IMPORT_URL); + expect(link.getAttribute("target")).toBe("_blank"); + expect(link.getAttribute("rel")).toBe("noopener noreferrer"); + }); + + it("keeps the form when the flag is off, even with a PFB location", () => { + mockUseRequestFileLocation.mockReturnValue( + buildFileLocationResult(FILE_LOCATION) + ); + renderExportToPlatform(PROPS); + expect(screen.queryByRole("link", { name: BUTTON_LABEL })).toBeNull(); + expect(getRequestLinkButton().hasAttribute("disabled")).toBe(true); + }); +}); diff --git a/__tests__/components/velseraExportMethod.test.tsx b/__tests__/components/velseraExportMethod.test.tsx new file mode 100644 index 000000000..4e34a0340 --- /dev/null +++ b/__tests__/components/velseraExportMethod.test.tsx @@ -0,0 +1,58 @@ +import { createAppTheme } from "@databiosphere/findable-ui/lib/theme/theme"; +import { ThemeProvider } from "@mui/material"; +import { render, screen } from "@testing-library/react"; +import type { ComponentProps } from "react"; +import { VelseraExportMethod } from "../../app/components/Export/components/AnVILExplorer/platform/VelseraExportMethod/velseraExportMethod"; +import { FEATURES } from "../../app/shared/entities"; + +jest.mock("@databiosphere/findable-ui/lib/hooks/useDownloadStatus", () => ({ + useDownloadStatus: (): { disabled: boolean; message: string } => ({ + disabled: false, + message: "", + }), +})); + +const COMING_SOON = "Coming Soon"; + +const THEME = createAppTheme(); + +const PROPS = { + description: "BDC-SB is a cloud workspace.", + route: "/export/biodata-catalyst", + title: "Export to BioData Catalyst", +}; + +/** + * Renders VelseraExportMethod within the app theme. + * @param props - Export method props. + */ +function renderMethod(props: ComponentProps): void { + render( + + + + ); +} + +describe("VelseraExportMethod", () => { + afterEach(() => { + localStorage.clear(); + }); + + it("shows coming soon when the Velsera export flag is off", () => { + renderMethod(PROPS); + expect(screen.getByText(COMING_SOON)).toBeTruthy(); + }); + + it("enables the method when the Velsera export flag is on", () => { + localStorage.setItem(FEATURES.VELSERA_EXPORT, "true"); + renderMethod(PROPS); + expect(screen.queryByText(COMING_SOON)).toBeNull(); + }); + + it("shows coming soon when configured so, even with the flag on", () => { + localStorage.setItem(FEATURES.VELSERA_EXPORT, "true"); + renderMethod({ ...PROPS, comingSoon: true }); + expect(screen.getByText(COMING_SOON)).toBeTruthy(); + }); +}); diff --git a/__tests__/site-config/export-constants.test.ts b/__tests__/site-config/export-constants.test.ts index d269aec0e..705f07a22 100644 --- a/__tests__/site-config/export-constants.test.ts +++ b/__tests__/site-config/export-constants.test.ts @@ -54,24 +54,24 @@ describe("EXPORTS constants", () => { }); it.each(Object.entries(EXPORTS))( - "%s has all required keys", + "%s has non-empty string values for all required keys", (_, config) => { for (const key of REQUIRED_EXPORT_KEYS) { - expect(config).toHaveProperty(key); - expect(config[key]).toBeTruthy(); + expect(typeof config[key]).toBe("string"); + expect(config[key].trim().length).toBeGreaterThan(0); } } ); + }); - it.each(Object.entries(EXPORTS))( - "%s has all non-empty string values", - (_, config) => { - for (const [, value] of Object.entries(config)) { - expect(typeof value).toBe("string"); - expect(value.trim().length).toBeGreaterThan(0); - } - } - ); + describe("platform import config", () => { + it.each( + Object.entries(EXPORTS).filter(([, config]) => config.platformImport) + )("%s has a valid import base URL and source", (_, config) => { + const { baseUrl, source } = config.platformImport!; + expect(new URL(baseUrl).protocol).toBe("https:"); + expect(source.trim().length).toBeGreaterThan(0); + }); }); describe("BioData Catalyst export config", () => { @@ -96,6 +96,13 @@ describe("EXPORTS constants", () => { it("description mentions BDC-SB", () => { expect(EXPORTS.BIO_DATA_CATALYST.description).toContain("BDC-SB"); }); + + it("has the BDC-SB PFB import endpoint and source", () => { + expect(EXPORTS.BIO_DATA_CATALYST.platformImport).toEqual({ + baseUrl: "https://platform.sb.biodatacatalyst.nhlbi.nih.gov/import/pfb", + source: "bdc", + }); + }); }); describe("CAVATICA export config", () => { @@ -153,6 +160,15 @@ describe("EXPORT_METHODS constants", () => { expect(EXPORT_METHODS.CANCER_GENOMICS_CLOUD).toBeDefined(); }); + it("marks CAVATICA and Cancer Genomics Cloud as coming soon", () => { + expect(EXPORT_METHODS.CAVATICA.comingSoon).toBe(true); + expect(EXPORT_METHODS.CANCER_GENOMICS_CLOUD.comingSoon).toBe(true); + }); + + it("leaves BioData Catalyst coming soon to the Velsera export feature flag", () => { + expect(EXPORT_METHODS.BIO_DATA_CATALYST.comingSoon).toBeUndefined(); + }); + it.each(Object.entries(EXPORT_METHODS))( "%s has all required keys", (_, config) => { diff --git a/__tests__/viewModelBuilders/dataset-export.test.ts b/__tests__/viewModelBuilders/dataset-export.test.ts index b2fc36117..63ea8d40e 100644 --- a/__tests__/viewModelBuilders/dataset-export.test.ts +++ b/__tests__/viewModelBuilders/dataset-export.test.ts @@ -271,6 +271,33 @@ describe("buildDatasetExportToPlatformHero", () => { }); describe("buildDatasetExportToPlatformMethod", () => { + describe("coming soon", () => { + it.each([EXPORT_METHODS.CANCER_GENOMICS_CLOUD, EXPORT_METHODS.CAVATICA])( + "returns comingSoon true for $title", + (props) => { + const builder = buildDatasetExportToPlatformMethod(props); + const response = createMockDatasetsResponse(); + const viewContext = createMockViewContext(); + + const result = builder(response, viewContext); + + expect(result.comingSoon).toBe(true); + } + ); + + it("returns comingSoon undefined for BioData Catalyst", () => { + const builder = buildDatasetExportToPlatformMethod( + EXPORT_METHODS.BIO_DATA_CATALYST + ); + const response = createMockDatasetsResponse(); + const viewContext = createMockViewContext(); + + const result = builder(response, viewContext); + + expect(result.comingSoon).toBeUndefined(); + }); + }); + it("returns route with dataset path prefix", () => { const props = EXPORT_METHODS.BIO_DATA_CATALYST; const builder = buildDatasetExportToPlatformMethod(props); diff --git a/__tests__/viewModelBuilders/export.test.ts b/__tests__/viewModelBuilders/export.test.ts index 98cffa0ab..758cc28ce 100644 --- a/__tests__/viewModelBuilders/export.test.ts +++ b/__tests__/viewModelBuilders/export.test.ts @@ -229,6 +229,31 @@ describe("buildExportToPlatformHero", () => { }); describe("buildExportToPlatformMethod", () => { + describe("coming soon", () => { + it.each([EXPORT_METHODS.CANCER_GENOMICS_CLOUD, EXPORT_METHODS.CAVATICA])( + "returns comingSoon true for $title", + (props) => { + const builder = buildExportToPlatformMethod(props); + const viewContext = createMockViewContext(); + + const result = builder(undefined, viewContext); + + expect(result.comingSoon).toBe(true); + } + ); + + it("returns comingSoon undefined for BioData Catalyst", () => { + const builder = buildExportToPlatformMethod( + EXPORT_METHODS.BIO_DATA_CATALYST + ); + const viewContext = createMockViewContext(); + + const result = builder(undefined, viewContext); + + expect(result.comingSoon).toBeUndefined(); + }); + }); + it("returns route from props", () => { const props = EXPORT_METHODS.BIO_DATA_CATALYST; const builder = buildExportToPlatformMethod(props); diff --git a/app/components/Export/components/AnVILExplorer/platform/ExportToPlatform/exportToPlatform.tsx b/app/components/Export/components/AnVILExplorer/platform/ExportToPlatform/exportToPlatform.tsx index 108c9197f..c61740991 100644 --- a/app/components/Export/components/AnVILExplorer/platform/ExportToPlatform/exportToPlatform.tsx +++ b/app/components/Export/components/AnVILExplorer/platform/ExportToPlatform/exportToPlatform.tsx @@ -15,14 +15,17 @@ import { REL_ATTRIBUTE, } from "@databiosphere/findable-ui/lib/components/Links/common/entities"; import { Loading } from "@databiosphere/findable-ui/lib/components/Loading/loading"; +import { useFeatureFlag } from "@databiosphere/findable-ui/lib/hooks/useFeatureFlag/useFeatureFlag"; 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 { Button } from "@mui/material"; +import { FEATURES } from "app/shared/entities"; import { JSX } from "react"; import { Props } from "./types"; +import { getPlatformImportUrl, isPlatformImportAvailable } from "./utils"; export const ExportToPlatform = ({ buttonLabel, @@ -31,6 +34,7 @@ export const ExportToPlatform = ({ fileSummaryFacetName, filters, formFacet, + platformImport, speciesFacetName, successTitle, title, @@ -47,7 +51,9 @@ export const ExportToPlatform = ({ const { requestMethod, requestUrl } = requestManifest; const response = useRequestFileLocation(requestUrl, requestMethod); - const url = ""; + const isEnabled = useFeatureFlag(FEATURES.VELSERA_EXPORT); + const canImport = isPlatformImportAvailable(isEnabled, platformImport); + const url = getPlatformImportUrl(isEnabled, platformImport, response.data); return url ? ( @@ -81,7 +87,7 @@ export const ExportToPlatform = ({

{description}

response.run()} @@ -105,3 +111,15 @@ export const ExportToPlatform = ({ function renderButton({ ...props }): JSX.Element { return Request Link; } + +/** + * Build the export button, disabled while the platform import is unavailable. + * @returns disabled button element. + */ +function renderDisabledButton(): JSX.Element { + return ( + + ); +} diff --git a/app/components/Export/components/AnVILExplorer/platform/ExportToPlatform/types.ts b/app/components/Export/components/AnVILExplorer/platform/ExportToPlatform/types.ts index 3c8b37810..373e97e60 100644 --- a/app/components/Export/components/AnVILExplorer/platform/ExportToPlatform/types.ts +++ b/app/components/Export/components/AnVILExplorer/platform/ExportToPlatform/types.ts @@ -2,6 +2,14 @@ import { Filters } from "@databiosphere/findable-ui/lib/common/entities"; import { FormFacet } from "@databiosphere/findable-ui/lib/components/Export/common/entities"; import { FileManifestState } from "@databiosphere/findable-ui/lib/providers/fileManifestState"; +/** + * Platform endpoint that imports a PFB from a signed URL. + */ +export interface PlatformImport { + baseUrl: string; + source: string; +} + export interface Props { buttonLabel: string; description: string; @@ -9,6 +17,7 @@ export interface Props { fileSummaryFacetName: string; filters: Filters; formFacet: FormFacet; + platformImport?: PlatformImport; speciesFacetName: string; successTitle: string; title: string; diff --git a/app/components/Export/components/AnVILExplorer/platform/ExportToPlatform/utils.ts b/app/components/Export/components/AnVILExplorer/platform/ExportToPlatform/utils.ts new file mode 100644 index 000000000..95fc69fe1 --- /dev/null +++ b/app/components/Export/components/AnVILExplorer/platform/ExportToPlatform/utils.ts @@ -0,0 +1,47 @@ +import type { FileLocation } from "@databiosphere/findable-ui/lib/hooks/useRequestFileLocation"; +import type { PlatformImport } from "./types"; + +/** + * Builds the platform import URL for the given signed PFB URL. + * @param platformImport - Platform import endpoint and source. + * @param signedUrl - Signed URL of the PFB to import. + * @returns import URL, with the signed URL and source as query parameters. + */ +export function buildPlatformImportUrl( + platformImport: PlatformImport, + signedUrl: string +): string { + const url = new URL(platformImport.baseUrl); + url.searchParams.set("URL", signedUrl); + url.searchParams.set("source", platformImport.source); + return url.toString(); +} + +/** + * Returns the platform import URL once the PFB location is available. + * @param isEnabled - Whether the platform export feature flag is on. + * @param platformImport - Platform import endpoint and source; undefined when the platform has none. + * @param fileLocation - PFB file location; undefined until the manifest request succeeds. + * @returns import URL, or undefined when the flag is off, the platform has no import endpoint, or the PFB location is not yet available. + */ +export function getPlatformImportUrl( + isEnabled: boolean, + platformImport: PlatformImport | undefined, + fileLocation: FileLocation | undefined +): string | undefined { + if (!isEnabled || !platformImport || !fileLocation) return undefined; + return buildPlatformImportUrl(platformImport, fileLocation.location); +} + +/** + * Returns true if the platform import is available: the feature flag is on and the platform has an import endpoint. + * @param isEnabled - Whether the platform export feature flag is on. + * @param platformImport - Platform import endpoint and source; undefined when the platform has none. + * @returns true if a platform import link can be built. + */ +export function isPlatformImportAvailable( + isEnabled: boolean, + platformImport: PlatformImport | undefined +): boolean { + return isEnabled && platformImport !== undefined; +} diff --git a/app/components/Export/components/AnVILExplorer/platform/VelseraExportMethod/velseraExportMethod.tsx b/app/components/Export/components/AnVILExplorer/platform/VelseraExportMethod/velseraExportMethod.tsx new file mode 100644 index 000000000..0957f4e82 --- /dev/null +++ b/app/components/Export/components/AnVILExplorer/platform/VelseraExportMethod/velseraExportMethod.tsx @@ -0,0 +1,18 @@ +import { ExportMethod } 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"; +import type { ComponentProps, JSX } from "react"; + +/** + * Export method for a Velsera platform; shown as "coming soon" when configured so, or when the Velsera export feature flag is off. + * @param props - Export method component props. + * @returns Export method component. + */ +export const VelseraExportMethod = ( + props: ComponentProps +): JSX.Element => { + const isEnabled = useFeatureFlag(FEATURES.VELSERA_EXPORT); + return ( + + ); +}; diff --git a/app/components/index.tsx b/app/components/index.tsx index f52d8ab97..8e5030072 100644 --- a/app/components/index.tsx +++ b/app/components/index.tsx @@ -95,6 +95,7 @@ export { AtlasSection } from "./Detail/components/Section/components/AtlasSectio export { ExportEntity as AnVILExportEntity } from "./Export/components/AnVILExplorer/components/ExportEntity/exportEntity"; export { ManifestDownloadEntity as AnVILManifestDownloadEntity } from "./Export/components/AnVILExplorer/components/ManifestDownload/components/ManifestDownloadEntity/manifestDownloadEntity"; export { ExportToPlatform } from "./Export/components/AnVILExplorer/platform/ExportToPlatform/exportToPlatform"; +export { VelseraExportMethod } from "./Export/components/AnVILExplorer/platform/VelseraExportMethod/velseraExportMethod"; export { BioNetworkCell } from "./Index/components/BioNetworkCell/bioNetworkCell"; export { ConsentCodesCell } from "./Index/components/ConsentCodesCell/consentCodesCell"; export { CopyCell } from "./Index/components/CopyCell/copyCell"; diff --git a/app/shared/entities.ts b/app/shared/entities.ts index 27dfc0bf2..6ae400b52 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 { + VELSERA_EXPORT = "velseraexport", +} diff --git a/app/viewModelBuilders/azul/anvil-cmg/common/viewModelBuilders.tsx b/app/viewModelBuilders/azul/anvil-cmg/common/viewModelBuilders.tsx index 3922818fc..52a5e18f0 100644 --- a/app/viewModelBuilders/azul/anvil-cmg/common/viewModelBuilders.tsx +++ b/app/viewModelBuilders/azul/anvil-cmg/common/viewModelBuilders.tsx @@ -530,7 +530,7 @@ export const buildDatasetDownloadCurlCommand = ( export const buildDatasetExportToPlatform = ( props: Pick< ComponentProps, - "buttonLabel" | "description" | "successTitle" | "title" + "buttonLabel" | "description" | "platformImport" | "successTitle" | "title" > ): (( response: DatasetsResponse, @@ -576,7 +576,7 @@ export const buildDatasetExportToPlatformMethod = ({ ...props }: Pick< ComponentProps, - "description" | "icon" | "route" | "title" + "comingSoon" | "description" | "icon" | "route" | "title" >): (( response: DatasetsResponse, viewContext: ViewContext @@ -586,7 +586,6 @@ export const buildDatasetExportToPlatformMethod = ({ return { ...props, ...getExportMethodAccessibility(viewContext), - comingSoon: true, route: `${datasetPath}${route}`, }; }; @@ -954,7 +953,7 @@ export const buildExportSelectedDataSummary = ( export const buildExportToPlatform = ( props: Pick< ComponentProps, - "buttonLabel" | "description" | "successTitle" | "title" + "buttonLabel" | "description" | "platformImport" | "successTitle" | "title" > ): (( _: unknown, @@ -1003,7 +1002,7 @@ export const buildExportToPlatformHero = ( export const buildExportToPlatformMethod = ( props: Pick< ComponentProps, - "description" | "icon" | "route" | "title" + "comingSoon" | "description" | "icon" | "route" | "title" > ): (( _: unknown, @@ -1013,7 +1012,6 @@ export const buildExportToPlatformMethod = ( return { ...props, ...getExportMethodAccessibility(viewContext), - comingSoon: true, }; }; }; 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 f4db4f1f1..bead0af4b 100644 --- a/site-config/anvil-cmg/dev/detail/dataset/export/export.ts +++ b/site-config/anvil-cmg/dev/detail/dataset/export/export.ts @@ -386,11 +386,11 @@ export const exportConfig: ExportConfig = { viewBuilder: V.buildDatasetExportMethodTerra, } as ComponentConfig, { - component: C.ExportMethod, + component: C.VelseraExportMethod, viewBuilder: V.buildDatasetExportToPlatformMethod( EXPORT_METHODS.BIO_DATA_CATALYST ), - } as ComponentConfig, + } as ComponentConfig, { component: C.ExportMethod, viewBuilder: V.buildDatasetExportToPlatformMethod( diff --git a/site-config/anvil-cmg/dev/export/constants.tsx b/site-config/anvil-cmg/dev/export/constants.tsx index b2d2dc83c..7f3fc8f6d 100644 --- a/site-config/anvil-cmg/dev/export/constants.tsx +++ b/site-config/anvil-cmg/dev/export/constants.tsx @@ -8,13 +8,17 @@ export const EXPORTS: Record< string, Pick< ComponentProps, - "buttonLabel" | "description" | "successTitle" | "title" + "buttonLabel" | "description" | "platformImport" | "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.", + platformImport: { + baseUrl: "https://platform.sb.biodatacatalyst.nhlbi.nih.gov/import/pfb", + source: "bdc", + }, successTitle: "Your BioData Catalyst Workspace Link is Ready", title: "Analyze in BioData Catalyst", }, @@ -38,7 +42,7 @@ export const EXPORT_METHODS: Record< string, Pick< ComponentProps, - "description" | "icon" | "route" | "title" + "comingSoon" | "description" | "icon" | "route" | "title" > > = { BIO_DATA_CATALYST: { @@ -48,12 +52,14 @@ export const EXPORT_METHODS: Record< title: "Export to BioData Catalyst Powered by Seven Bridges (BDC-SB)", }, CANCER_GENOMICS_CLOUD: { + comingSoon: true, description: EXPORTS.CANCER_GENOMICS_CLOUD.description, icon: , route: ROUTES.CANCER_GENOMICS_CLOUD, title: "Export to Cancer Genomics Cloud (CGC)", }, CAVATICA: { + comingSoon: true, description: EXPORTS.CAVATICA.description, icon: , route: ROUTES.CAVATICA, diff --git a/site-config/anvil-cmg/dev/export/export.ts b/site-config/anvil-cmg/dev/export/export.ts index 818fc6e49..6ed31163d 100644 --- a/site-config/anvil-cmg/dev/export/export.ts +++ b/site-config/anvil-cmg/dev/export/export.ts @@ -188,11 +188,11 @@ export const exportConfig: ExportConfig = { viewBuilder: V.buildExportMethodTerra, } as ComponentConfig, { - component: C.ExportMethod, + component: C.VelseraExportMethod, viewBuilder: V.buildExportToPlatformMethod( EXPORT_METHODS.BIO_DATA_CATALYST ), - } as ComponentConfig, + } as ComponentConfig, { component: C.ExportMethod, viewBuilder: V.buildExportToPlatformMethod(