Skip to content
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,67 @@ import { UcscTrack } from "../../../../../../../../../../../../utils/ucsc-tracks
import { COLUMN_TYPE } from "../../SampleSheetClassificationStep/types";
import { Strandedness } from "../../StrandednessStep/types";

export interface ConfiguredValue {
// Base configured values shared across all scopes
export interface BaseConfiguredValue {
readRunsPaired: EnaSequencingReads[] | null;
readRunsSingle: EnaSequencingReads[] | null;
tracks: UcscTrack[] | null;
}

// ASSEMBLY scope: workflows that operate on a specific genome assembly
export interface AssemblyConfiguredValue extends BaseConfiguredValue {
_scope: "ASSEMBLY";
designFormula: string | null;
geneModelUrl: string | null;
numberOfHits?: number;
primaryContrasts: PrimaryContrasts | null;
readRunsPaired: EnaSequencingReads[] | null;
readRunsSingle: EnaSequencingReads[] | null;
referenceAssembly: string;
sampleSheet: Record<string, string>[] | null;
sampleSheetClassification: Record<string, COLUMN_TYPE | null> | null;
sequence?: string;
strandedness: Strandedness | undefined;
tracks: UcscTrack[] | null;
}

// ORGANISM scope: workflows that operate at organism level (may not require specific assembly)
// Organism scope workflows may have collection_spec (defined in workflow YAML) and variables.
// fastaCollection can be either:
// - User-selected assembly accessions (string[]) for user-defined FASTA collections
// - Auto-configured via collection_spec in workflow YAML (handled by Galaxy API)
export interface OrganismConfiguredValue extends BaseConfiguredValue {
_scope: "ORGANISM";
fastaCollection: string[] | null;
}

// SEQUENCE scope: workflows that operate on user-provided sequences
export interface SequenceConfiguredValue extends BaseConfiguredValue {
_scope: "SEQUENCE";
numberOfHits?: number;
sequence?: string;
}

// Type guards for ConfiguredValue discrimination
export function isAssemblyConfiguredValue(
value: ConfiguredValue
): value is AssemblyConfiguredValue {
return value._scope === "ASSEMBLY";
}

export function isOrganismConfiguredValue(
value: ConfiguredValue
): value is OrganismConfiguredValue {
return value._scope === "ORGANISM";
}

export function isSequenceConfiguredValue(
value: ConfiguredValue
): value is SequenceConfiguredValue {
return value._scope === "SEQUENCE";
}

// Union type for all configured values
export type ConfiguredValue =
| AssemblyConfiguredValue
| OrganismConfiguredValue
| SequenceConfiguredValue;

export interface Status {
disabled: boolean;
error: string | null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,105 @@ import { CUSTOM_WORKFLOW } from "../../../../../../../../../../../../views/Analy
import { DIFFERENTIAL_EXPRESSION_ANALYSIS } from "../../../../../../../../../../../../views/AnalyzeWorkflowsView/differentialExpressionAnalysis/constants";
import { LEXICMAP } from "../../../../../../../../../../../../views/AnalyzeWorkflowsView/lexicmap/constants";
import { LOGAN_SEARCH } from "../../../../../../../../../../../../views/AnalyzeWorkflowsView/loganSearch/constants";
import { Props, UseLaunchGalaxy } from "./types";
import { Workflow } from "../../../../../../../../../../../../apis/catalog/brc-analytics-catalog/common/entities";
import {
ConfiguredValue,
isAssemblyConfiguredValue,
isSequenceConfiguredValue,
Props,
UseLaunchGalaxy,
} from "./types";
import { getConfiguredValues, launchGalaxy } from "./utils";

/**
* Gets the appropriate landing URL based on workflow type.
* @param workflow - Workflow to launch.
* @param configuredValue - Configured values for the workflow.
* @param origin - Origin URL for the Galaxy instance.
* @returns Promise resolving to the Galaxy workflow landing URL.
*/
async function getLandingUrlForWorkflow(
workflow: Workflow,
configuredValue: ConfiguredValue,
origin: string
): Promise<string> {
if (workflow.trsId === CUSTOM_WORKFLOW.trsId) {
if (!isAssemblyConfiguredValue(configuredValue)) {
throw new Error("Invalid configured value for CUSTOM workflow");
}
return getDataLandingUrl(
configuredValue.referenceAssembly,
configuredValue.geneModelUrl,
configuredValue.readRunsSingle,
configuredValue.readRunsPaired,
null,
configuredValue.tracks,
origin
);
}

if (
workflow.trsId === LOGAN_SEARCH.trsId ||
workflow.trsId === LEXICMAP.trsId
) {
if (!workflow.workflowId) {
throw new Error("Missing workflow ID for LMLS workflow");
}
if (
!isSequenceConfiguredValue(configuredValue) ||
!configuredValue.numberOfHits ||
!configuredValue.sequence
) {
throw new Error("Missing required values for LMLS workflow");
}
return getLMLSLandingUrl(
workflow.workflowId,
configuredValue.numberOfHits,
configuredValue.sequence,
origin
);
}

if (workflow.trsId === DIFFERENTIAL_EXPRESSION_ANALYSIS.trsId) {
if (
!workflow.workflowId ||
!isAssemblyConfiguredValue(configuredValue) ||
!configuredValue.geneModelUrl ||
!configuredValue.sampleSheet ||
!configuredValue.sampleSheetClassification ||
!configuredValue.designFormula
) {
throw new Error("Missing required values for DE workflow");
}
return getDeSeq2LandingUrl(
workflow.workflowId,
configuredValue.referenceAssembly,
configuredValue.geneModelUrl,
configuredValue.sampleSheet,
configuredValue.sampleSheetClassification,
configuredValue.designFormula,
configuredValue.primaryContrasts,
configuredValue.strandedness,
origin
);
}

return getWorkflowLandingUrl(
workflow.trsId,
isAssemblyConfiguredValue(configuredValue)
? configuredValue.referenceAssembly
: "",
isAssemblyConfiguredValue(configuredValue)
? configuredValue.geneModelUrl
: null,
configuredValue.readRunsSingle,
configuredValue.readRunsPaired,
null,
workflow.parameters,
origin
);
}

export const useLaunchGalaxy = ({
configuredInput,
workflow,
Expand All @@ -27,79 +123,14 @@ export const useLaunchGalaxy = ({
if (!configuredValue) return;
const origin = config.browserURL || window.location.origin;

let landingUrl = "";

if (workflow.trsId === CUSTOM_WORKFLOW.trsId) {
landingUrl = await run(
getDataLandingUrl(
configuredValue.referenceAssembly,
configuredValue.geneModelUrl,
configuredValue.readRunsSingle,
configuredValue.readRunsPaired,
null, // fastaCollection - not yet supported in UI
configuredValue.tracks,
origin
)
);
} else if (
workflow.trsId === LOGAN_SEARCH.trsId ||
workflow.trsId === LEXICMAP.trsId
) {
// LMLS workflows use stored workflow IDs with sequence and numberOfHits parameters
if (!workflow.workflowId) {
throw new Error("Missing workflow ID for LMLS workflow");
}
landingUrl = await run(
getLMLSLandingUrl(
workflow.workflowId,
configuredValue.numberOfHits!,
configuredValue.sequence!,
origin
)
);
} else if (workflow.trsId === DIFFERENTIAL_EXPRESSION_ANALYSIS.trsId) {
if (
!workflow.workflowId ||
!configuredValue.geneModelUrl ||
!configuredValue.sampleSheet ||
!configuredValue.sampleSheetClassification ||
!configuredValue.designFormula
) {
throw new Error("Missing required values for DE workflow");
}
landingUrl = await run(
getDeSeq2LandingUrl(
workflow.workflowId,
configuredValue.referenceAssembly,
configuredValue.geneModelUrl,
configuredValue.sampleSheet,
configuredValue.sampleSheetClassification,
configuredValue.designFormula,
configuredValue.primaryContrasts,
configuredValue.strandedness,
origin
)
);
} else {
landingUrl = await run(
getWorkflowLandingUrl(
workflow.trsId,
configuredValue.referenceAssembly,
configuredValue.geneModelUrl,
configuredValue.readRunsSingle,
configuredValue.readRunsPaired,
null, // fastaCollection - not yet supported in UI
workflow.parameters,
origin
)
);
}
const landingUrl = await run(
getLandingUrlForWorkflow(workflow, configuredValue, origin)
);

if (!landingUrl) {
throw new Error("Failed to retrieve Galaxy workflow launch URL.");
}

// Launch the Galaxy workflow.
launchGalaxy(landingUrl);
}, [config, configuredValue, run, workflow]);

Expand Down
Loading
Loading