Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,12 @@ backend/**/.env
# Playwright test artifacts
/test-results
/tests/screenshots
/playwright-report

# python
venv
__pycache__
playwright-report/


## public api
/public/api
Original file line number Diff line number Diff line change
@@ -1,17 +1,14 @@
import { useEffect, useState } from "react";
import { BRCDataCatalogGenome } from "../../../../../../../../../../../../../apis/catalog/brc-analytics-catalog/common/entities";
import { parseUCSCFilesResult } from "./utils";
import { UCSC_FILES_ENDPOINT } from "./constants";
import { UseUCSCFiles } from "./types";
import { GA2AssemblyEntity } from "../../../../../../../../../../../../../apis/catalog/ga2/entities";
import { Assembly } from "../../../../../../../../../../../../../views/WorkflowInputsView/types";

const SPECIAL_CASE_ASSEMBLY_LOOKUP: Record<string, string> = {
"GCF_000001405.40": "hg38",
} as const;

export const useUCSCFiles = (
genome: BRCDataCatalogGenome | GA2AssemblyEntity
): UseUCSCFiles => {
export const useUCSCFiles = (genome: Assembly): UseUCSCFiles => {
const assemblyId =
SPECIAL_CASE_ASSEMBLY_LOOKUP[genome.accession] ?? genome.accession;
const [geneModelUrls, setGeneModelUrls] = useState<string[] | undefined>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,11 @@ import { ReadRun } from "../../../../../../types";
import { UseRequirementsMatches } from "./types";
import { useMemo } from "react";
import { buildRequirementWarnings } from "./utils";
import { BRCDataCatalogGenome } from "../../../../../../../../../../../../../../../../../../../apis/catalog/brc-analytics-catalog/common/entities";
import { GA2AssemblyEntity } from "../../../../../../../../../../../../../../../../../../../apis/catalog/ga2/entities";
import { Assembly } from "../../../../../../../../../../../../../../../../../../../views/WorkflowInputsView/types";

export const useRequirementsMatches = (
table: Table<ReadRun>,
genome: BRCDataCatalogGenome | GA2AssemblyEntity
genome: Assembly
): UseRequirementsMatches => {
const { getSelectedRowModel, initialState } = table;
const { columnFilters } = initialState;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import { ColumnFiltersState, Row } from "@tanstack/react-table";
import { ReadRun } from "../../../../../../types";
import { COLUMN_KEY_TO_LABEL } from "./constants";
import { BRCDataCatalogGenome } from "../../../../../../../../../../../../../../../../../../../apis/catalog/brc-analytics-catalog/common/entities";
import { GA2AssemblyEntity } from "../../../../../../../../../../../../../../../../../../../apis/catalog/ga2/entities";
import { LABEL } from "@databiosphere/findable-ui/lib/apis/azul/common/entities";
import { Assembly } from "../../../../../../../../../../../../../../../../../../../views/WorkflowInputsView/types";

/**
* Builds warnings for column filter mismatches.
Expand Down Expand Up @@ -61,7 +60,7 @@ function buildDataWarnings(
export function buildRequirementWarnings(
initialColumnFilters: ColumnFiltersState,
rows: Row<ReadRun>[],
genome: BRCDataCatalogGenome | GA2AssemblyEntity
genome: Assembly
): string[] {
if (rows.length === 0) return [];
const speciesWarnings = buildSpeciesWarnings(rows, genome);
Expand All @@ -77,7 +76,7 @@ export function buildRequirementWarnings(
*/
function buildSpeciesWarnings(
rows: Row<ReadRun>[],
genome: BRCDataCatalogGenome | GA2AssemblyEntity
genome: Assembly
): string[] {
const { ncbiTaxonomyId, taxonomicLevelSpecies } = genome;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,12 @@ import { UseENADataByTaxonomyId } from "./types";
import { fetchENAData } from "./request";
import { useAsync } from "@databiosphere/findable-ui/lib/hooks/useAsync";
import { isEligible } from "./utils";
import { BRCDataCatalogGenome } from "../../../../../../../../../../../../../../../apis/catalog/brc-analytics-catalog/common/entities";
import { GA2AssemblyEntity } from "../../../../../../../../../../../../../../../apis/catalog/ga2/entities";
import { useConfig } from "@databiosphere/findable-ui/lib/hooks/useConfig";
import { AppSiteConfig } from "../../../../../../../../../../../../../../../../site-config/common/entities";
import { Assembly } from "../../../../../../../../../../../../../../../views/WorkflowInputsView/types";

export const useENADataByTaxonomyId = <T>(
genome: BRCDataCatalogGenome | GA2AssemblyEntity
genome: Assembly
): UseENADataByTaxonomyId<T> => {
const { ncbiTaxonomyId: taxonomyId } = genome;
const { config } = useConfig();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,13 @@
import { ComponentType, ReactNode } from "react";
import { StepProps as MStepProps } from "@mui/material";
import {
BRCDataCatalogGenome,
Workflow,
} from "../../../../../../../../../../apis/catalog/brc-analytics-catalog/common/entities";
import { Workflow } from "../../../../../../../../../../apis/catalog/brc-analytics-catalog/common/entities";
import {
ConfiguredInput,
OnConfigure,
} from "../../../../../../../../../../views/WorkflowInputsView/hooks/UseConfigureInputs/types";
import { Status, OnLaunchGalaxy } from "./hooks/UseLaunchGalaxy/types";
import { OnContinue, OnEdit } from "../../hooks/UseStepper/types";
import { GA2AssemblyEntity } from "../../../../../../../../../../apis/catalog/ga2/entities";
import { Assembly } from "../../../../../../../../../../views/WorkflowInputsView/types";

export interface StepConfig {
description?: ReactNode;
Expand All @@ -27,7 +24,7 @@ export interface StepProps
Required<Pick<MStepProps, "index" | "active">> {
configuredInput: ConfiguredInput;
entryLabel: string;
genome: BRCDataCatalogGenome | GA2AssemblyEntity;
genome: Assembly;
onConfigure: OnConfigure;
onContinue: OnContinue;
onEdit: OnEdit;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,17 @@
import {
BRCDataCatalogGenome,
Workflow,
} from "../../../../../../../../apis/catalog/brc-analytics-catalog/common/entities";
import { Workflow } from "../../../../../../../../apis/catalog/brc-analytics-catalog/common/entities";
import { OnConfigure } from "../../../../../../../../views/WorkflowInputsView/hooks/UseConfigureInputs/types";
import {
Status,
OnLaunchGalaxy,
} from "./components/Step/hooks/UseLaunchGalaxy/types";
import { GA2AssemblyEntity } from "../../../../../../../../apis/catalog/ga2/entities";
import { StepConfig } from "./components/Step/types";
import { ConfiguredInput } from "../../../../../../../../views/WorkflowInputsView/hooks/UseConfigureInputs/types";
import { Assembly } from "../../../../../../../../views/WorkflowInputsView/types";

export interface Props {
configuredInput: ConfiguredInput;
configuredSteps: StepConfig[];
genome: BRCDataCatalogGenome | GA2AssemblyEntity;
genome: Assembly;
onConfigure: OnConfigure;
onLaunchGalaxy: OnLaunchGalaxy;
status: Status;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,15 @@
import {
BRCDataCatalogGenome,
Workflow,
} from "../../../../../../apis/catalog/brc-analytics-catalog/common/entities";
import { Workflow } from "../../../../../../apis/catalog/brc-analytics-catalog/common/entities";
import {
ConfiguredInput,
OnConfigure,
} from "../../../../../../views/WorkflowInputsView/hooks/UseConfigureInputs/types";
import { GA2AssemblyEntity } from "../../../../../../apis/catalog/ga2/entities";
import { StepConfig } from "./components/Stepper/components/Step/types";
import { Assembly } from "../../../../../../views/WorkflowInputsView/types";

export interface Props {
configuredInput: ConfiguredInput;
configuredSteps: StepConfig[];
genome: BRCDataCatalogGenome | GA2AssemblyEntity;
genome: Assembly;
onConfigure: OnConfigure;
workflow: Workflow;
}
Original file line number Diff line number Diff line change
@@ -1,14 +1,11 @@
import {
BRCDataCatalogGenome,
Workflow,
} from "../../../../../../apis/catalog/brc-analytics-catalog/common/entities";
import { Workflow } from "../../../../../../apis/catalog/brc-analytics-catalog/common/entities";
import { ConfiguredInput } from "../../../../../../views/WorkflowInputsView/hooks/UseConfigureInputs/types";
import { GA2AssemblyEntity } from "../../../../../../apis/catalog/ga2/entities";
import { StepConfig } from "../../../../../../components/Entity/components/ConfigureWorkflowInputs/components/Main/components/Stepper/components/Step/types";
import { Assembly } from "../../../../../../views/WorkflowInputsView/types";

export interface Props {
configuredInput: ConfiguredInput;
configuredSteps: StepConfig[];
genome: BRCDataCatalogGenome | GA2AssemblyEntity;
genome: Assembly;
workflow: Workflow;
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Props } from "../../../../../../views/WorkflowInputsView/types";
import { Props } from "./types";
import { getBreadcrumbs } from "./utils";
import { BackPageHero } from "@databiosphere/findable-ui/lib/components/Layout/components/BackPage/components/BackPageHero/backPageHero";

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { Workflow } from "../../../../../../apis/catalog/brc-analytics-catalog/common/entities";
import { Assembly } from "../../../../../../views/WorkflowInputsView/types";

export interface Props {
entityId: string;
genome: Assembly;
workflow: Workflow;
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { ROUTES } from "routes/constants";
import { Props } from "../../../../../../views/WorkflowInputsView/types";
import { ROUTES } from "../../../../../../../routes/constants";
import { Breadcrumb } from "@databiosphere/findable-ui/lib/components/common/Breadcrumbs/breadcrumbs";
import { replaceParameters } from "@databiosphere/findable-ui/lib/utils/replaceParameters";
import { Props } from "./types";

/**
* Returns breadcrumbs for the workflow input view.
Expand Down
45 changes: 45 additions & 0 deletions app/services/workflows/entities.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import {
BRCDataCatalogGenome,
Workflow,
WorkflowCategory,
} from "../../apis/catalog/brc-analytics-catalog/common/entities";
import { getEntities, getEntity } from "./query";
import { GA2AssemblyEntity } from "../../apis/catalog/ga2/entities";

/**
* Gets assemblies.
* @returns Assemblies.
*/
export function getAssemblies<
T extends BRCDataCatalogGenome | GA2AssemblyEntity,
>(): T[] {
return getEntities<T>("assemblies");
}

/**
* Gets assembly by entity id.
* @param entityId - Entity id.
* @returns Assembly.
*/
export function getAssembly<T extends BRCDataCatalogGenome | GA2AssemblyEntity>(
entityId: string
): T {
return getEntity<T>("assemblies", entityId);
}

/**
* Gets workflow by TRS id.
* @param trsId - TRS id.
* @returns Workflow.
*/
export function getWorkflow(trsId: string): Workflow {
return getEntity<Workflow>("workflows", trsId);
}

/**
* Gets workflows.
* @returns Workflows.
*/
export function getWorkflows(): WorkflowCategory[] {
return getEntities<WorkflowCategory>("workflows");
}
21 changes: 21 additions & 0 deletions app/services/workflows/hooks/UseEntities/hook.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { useEffect, useState } from "react";
import { ensureEntitiesLoaded } from "./utils";
import { getConfig } from "@databiosphere/findable-ui/lib/config/config";

export function useEntities(): boolean {
const [isLoaded, setIsLoaded] = useState(false);

const config = getConfig();

useEffect(() => {
if (!config) return;

ensureEntitiesLoaded(config)
.then(() => setIsLoaded(true))
.catch((err) => {
throw new Error(`Failed to load entities: ${err}`);
});
}, [config]);

return isLoaded;
}
20 changes: 20 additions & 0 deletions app/services/workflows/hooks/UseEntities/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { SiteConfig } from "@databiosphere/findable-ui/lib/config/entities";
import { loadEntities, loadWorkflows } from "../../loader";

let loadPromise: Promise<void> | null = null;

/**
* Ensures that the entities and workflows are loaded.
* @param config - Site config.
* @returns Promise that resolves when the entities and workflows are loaded.
*/
export function ensureEntitiesLoaded(config: SiteConfig): Promise<void> {
if (loadPromise) return loadPromise;

loadPromise = (async (): Promise<void> => {
await loadWorkflows();
await loadEntities(config);
})();

return loadPromise;
}
86 changes: 86 additions & 0 deletions app/services/workflows/loader.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import { API } from "./routes";
import { SiteConfig } from "@databiosphere/findable-ui/lib/config/entities";
import { getEntitiesById, setEntitiesById, setEntitiesByType } from "./store";
import { EntityRoute } from "./types";
import {
Workflow,
WorkflowCategory,
} from "../../apis/catalog/brc-analytics-catalog/common/entities";
import { formatTrsId } from "../../components/Entity/components/AnalysisMethodsCatalog/utils";
import { CUSTOM_WORKFLOW } from "../../components/Entity/components/AnalysisMethod/components/CustomWorkflow/constants";

/**
* Fetches entities from the API.
* @param url - URL.
* @returns Entity list.
*/
async function fetchEntities(url: string): Promise<unknown[]> {
const res = await fetch(url);

if (!res.ok) throw new Error(`Failed to fetch: ${url}`);

return (await res.json()) as unknown[];
}

/**
* Checks if the route is an entity route.
* @param route - Route.
* @returns True if the route is an entity route; false otherwise.
*/
function isEntityRoute(route: string): route is EntityRoute {
return route in API;
}

/**
* Loads the entities store with entities from the API.
* @param config - Site config.
*/
export async function loadEntities(config: SiteConfig): Promise<void> {
for (const entity of config.entities) {
const { getId, route } = entity;

if (!isEntityRoute(route)) continue;

const apiRoute = API[route];

// Entities are already loaded; skip.
if (getEntitiesById().has(route)) continue;

// Get id function is not configured; entities are excluded from preloading.
if (!getId) continue;

// Fetch the entities.
const entities = await fetchEntities(apiRoute);

const entityById = new Map<string, unknown>();
for (const entity of entities) entityById.set(getId(entity), entity);

setEntitiesById(route, entityById);
setEntitiesByType(route, entities);
}
}

/**
* Loads the workflows store with workflows from the API.
*/
export async function loadWorkflows(): Promise<void> {
if (getEntitiesById().has("workflows")) return;

const workflowCategories = (await fetchEntities(
API.workflows
)) as WorkflowCategory[];

const workflows = workflowCategories.flatMap((w) => w.workflows);

const workflowById = new Map<string, Workflow>();

for (const workflow of workflows) {
workflowById.set(formatTrsId(workflow.trsId), workflow);
}

// Add custom workflow.
workflowById.set(CUSTOM_WORKFLOW.trsId, CUSTOM_WORKFLOW);

setEntitiesById("workflows", workflowById);
setEntitiesByType("workflows", workflowCategories);
}
Loading
Loading