Skip to content

Commit f43d13d

Browse files
Fran McDadeFran McDade
authored andcommitted
feat: add launch galaxy button to workflow stepper (#437)
1 parent 80d5ae8 commit f43d13d

File tree

26 files changed

+397
-69
lines changed

26 files changed

+397
-69
lines changed

app/components/Entity/components/ConfigureWorkflowInputs/components/Main/components/Stepper/components/Step/GTFStep/gtfStep.tsx

Lines changed: 61 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -3,51 +3,91 @@ import { StepLabel } from "@databiosphere/findable-ui/lib/components/Stepper/com
33
import { Icon } from "@databiosphere/findable-ui/lib/components/Stepper/components/Step/components/StepLabel/components/Label/components/Icon/icon";
44
import { StepProps } from "../types";
55
import { Step } from "@databiosphere/findable-ui/lib/components/Stepper/components/Step/step";
6-
import { useUCSCFiles } from "./hooks/UseUCSCFiles/useUCSCFiles";
7-
import { FormControlLabel, Radio, RadioGroup, Typography } from "@mui/material";
8-
import { useRadioGroup } from "../hooks/UseRadioGroup/hook";
6+
import {
7+
Button,
8+
FormControlLabel,
9+
Radio,
10+
RadioGroup,
11+
Typography,
12+
} from "@mui/material";
913
import { StyledGrid2 } from "./gtfStep.styles";
1014
import { TYPOGRAPHY_PROPS } from "./constants";
11-
import { getGeneModelLabel, getInitialValue } from "./utils";
15+
import { TYPOGRAPHY_PROPS as MUI_TYPOGRAPHY_PROPS } from "@databiosphere/findable-ui/lib/styles/common/mui/typography";
16+
import { configureGTFStep } from "./utils";
17+
import { BUTTON_PROPS } from "../components/Button/constants";
18+
import { useUCSCFiles } from "./hooks/UseUCSCFiles/hook";
19+
import { useRadioGroup } from "./hooks/UseRadioGroup/hook";
1220
import { useEffect } from "react";
1321

1422
export const GTFStep = ({
1523
active,
1624
completed,
1725
description,
26+
entryKey,
27+
entryLabel,
1828
genome,
1929
index,
20-
label,
30+
launchStatus,
31+
onConfigure,
32+
onLaunch,
2133
}: StepProps): JSX.Element => {
2234
const { geneModelUrls } = useUCSCFiles(genome);
23-
const { onChange, onValueChange, value } = useRadioGroup("");
24-
const hasGeneModels = geneModelUrls.length > 0;
35+
const { controls, onChange, onValueChange, value } =
36+
useRadioGroup(geneModelUrls);
2537

2638
useEffect(() => {
27-
onValueChange(getInitialValue(geneModelUrls));
28-
}, [geneModelUrls, onValueChange]);
39+
configureGTFStep(
40+
geneModelUrls,
41+
entryKey,
42+
entryLabel,
43+
onConfigure,
44+
onValueChange
45+
);
46+
}, [geneModelUrls, entryKey, entryLabel, onConfigure, onValueChange]);
2947

3048
return (
31-
<Step active={active && hasGeneModels} completed={completed} index={index}>
49+
<Step
50+
active={active && !!geneModelUrls}
51+
completed={completed}
52+
index={index}
53+
>
3254
<StepLabel>
33-
{label}
55+
{entryLabel}
3456
<Icon slotProps={{ tooltip: { title: description } }} />
3557
</StepLabel>
3658
<StepContent>
3759
<StyledGrid2>
3860
<Typography {...TYPOGRAPHY_PROPS}>
3961
Genes and Gene Predictions
4062
</Typography>
41-
<RadioGroup onChange={onChange} value={value}>
42-
{geneModelUrls.map((url, index) => (
43-
<FormControlLabel
44-
control={<Radio />}
45-
key={index}
46-
label={getGeneModelLabel(url)}
47-
value={url}
48-
/>
49-
))}
50-
</RadioGroup>
63+
{controls.length > 0 ? (
64+
<RadioGroup onChange={onChange} value={value}>
65+
{controls.map(({ label, value }, i) => (
66+
<FormControlLabel
67+
control={<Radio />}
68+
key={i}
69+
onChange={() =>
70+
onConfigure(entryKey, entryLabel, [
71+
{ key: value, value: label },
72+
])
73+
}
74+
label={label}
75+
value={value}
76+
/>
77+
))}
78+
</RadioGroup>
79+
) : (
80+
<Typography variant={MUI_TYPOGRAPHY_PROPS.VARIANT.TEXT_BODY_400}>
81+
No gene predictions found.
82+
</Typography>
83+
)}
84+
<Button
85+
{...BUTTON_PROPS}
86+
disabled={launchStatus.disabled || launchStatus.loading}
87+
onClick={onLaunch}
88+
>
89+
Launch Galaxy
90+
</Button>
5191
</StyledGrid2>
5292
</StepContent>
5393
</Step>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { useRadioGroup as useBaseRadioGroup } from "../../../hooks/UseRadioGroup/hook";
2+
import { useMemo } from "react";
3+
import { UseRadioGroup } from "../../../hooks/UseRadioGroup/types";
4+
import { mapControl } from "./utils";
5+
6+
export const useRadioGroup = (
7+
geneModelUrls: string[] | undefined
8+
): UseRadioGroup & {
9+
controls: { label: string; value: string }[];
10+
} => {
11+
const { onChange, onValueChange, value } = useBaseRadioGroup("");
12+
13+
const controls = useMemo(() => {
14+
return (geneModelUrls || []).map(mapControl);
15+
}, [geneModelUrls]);
16+
17+
return { controls, onChange, onValueChange, value };
18+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import { getGeneModelLabel } from "../../utils";
2+
3+
/**
4+
* Maps a gene model URL to a form control with display label and value.
5+
* @param value - The gene model URL.
6+
* @returns The form control with label and value.
7+
*/
8+
export function mapControl(value: string): { label: string; value: string } {
9+
return {
10+
label: getGeneModelLabel(value),
11+
value,
12+
};
13+
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { UseUCSCFiles } from "./types";
66

77
export const useUCSCFiles = (genome: BRCDataCatalogGenome): UseUCSCFiles => {
88
const assemblyId = genome.accession;
9-
const [geneModelUrls, setGeneModelUrls] = useState<string[]>([]);
9+
const [geneModelUrls, setGeneModelUrls] = useState<string[] | undefined>();
1010

1111
useEffect(() => {
1212
fetch(`${UCSC_FILES_ENDPOINT}?genome=${assemblyId}`)

app/components/Entity/components/ConfigureWorkflowInputs/components/Main/components/Stepper/components/Step/GTFStep/hooks/UseUCSCFiles/types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,5 @@ export interface UrlList {
77
}
88

99
export interface UseUCSCFiles {
10-
geneModelUrls: string[];
10+
geneModelUrls: string[] | undefined;
1111
}

app/components/Entity/components/ConfigureWorkflowInputs/components/Main/components/Stepper/components/Step/GTFStep/hooks/UseUCSCFiles/utils.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
import { Result } from "./types";
22
import { DOWNLOAD_BASE_URL } from "./constants";
33

4+
/**
5+
* Parses the result from the UCSC files API to extract GTF file URLs.
6+
* @param response - Response.
7+
* @returns A list of GTF file URLs.
8+
*/
49
export function parseUCSCFilesResult(response: Result): string[] {
510
const { urlList } = response;
611
return urlList
@@ -9,6 +14,11 @@ export function parseUCSCFilesResult(response: Result): string[] {
914
.map((url) => `${DOWNLOAD_BASE_URL}/${url}`);
1015
}
1116

17+
/**
18+
* Filters the GTF file URLs from the UCSC files API response.
19+
* @param url - URL.
20+
* @returns True if the URL ends with ".gtf.gz".
21+
*/
1222
function filterGFTFile(url: string): boolean {
1323
return url.endsWith(".gtf.gz");
1424
}

app/components/Entity/components/ConfigureWorkflowInputs/components/Main/components/Stepper/components/Step/GTFStep/step.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,6 @@ import { GTFStep } from "./gtfStep";
44
export const STEP: StepConfig = {
55
Step: GTFStep,
66
description: "Select the GTF files for the workflow",
7-
key: "gtf-files",
7+
key: "geneModelUrl",
88
label: "GTF Files",
99
};

app/components/Entity/components/ConfigureWorkflowInputs/components/Main/components/Stepper/components/Step/GTFStep/utils.ts

Lines changed: 58 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,75 @@
1+
import { LABEL } from "@databiosphere/findable-ui/lib/apis/azul/common/entities";
2+
import { ConfiguredValue } from "../hooks/UseLaunchGalaxy/types";
3+
import { UseRadioGroup } from "../hooks/UseRadioGroup/types";
4+
import { OnConfigure } from "../../../../../../../../../../../views/WorkflowInputsView/hooks/UseConfigureInputs/types";
5+
6+
/**
7+
* Configures the GTF step.
8+
* @param geneModelUrls - Gene model URLs.
9+
* @param entryKey - Configured value key.
10+
* @param entryLabel - Configured value display label.
11+
* @param onConfigure - Callback function to configure the step.
12+
* @param onValueChange - Callback function to handle value changes.
13+
*/
14+
export const configureGTFStep = (
15+
geneModelUrls: string[] | undefined,
16+
entryKey: keyof ConfiguredValue,
17+
entryLabel: string,
18+
onConfigure: OnConfigure,
19+
onValueChange: UseRadioGroup["onValueChange"]
20+
): void => {
21+
// Gene model URLs are not yet loaded.
22+
if (!geneModelUrls) return;
23+
24+
// Gene model URLs are not available for this workflow.
25+
if (geneModelUrls.length === 0) {
26+
onConfigure(entryKey, entryLabel, [{ key: null, value: LABEL.NONE }]);
27+
return;
28+
}
29+
30+
// Get the priority value and update radio group state.
31+
const value = getPriorityValue(geneModelUrls);
32+
onValueChange(value);
33+
34+
// If no priority value is found, do nothing.
35+
if (!value) return;
36+
37+
// Otherwise, use the priority value to configure the step.
38+
onConfigure(entryKey, entryLabel, [
39+
{ key: value, value: getGeneModelLabel(value) },
40+
]);
41+
};
42+
143
/**
244
* Maps a gene model URL to a display label.
345
* @param url - Gene model URL.
446
* @returns The display label for the gene model.
547
*/
648
export const getGeneModelLabel = (url: string): string => {
749
const filename = url.split("/").pop() || "";
8-
if (filename.includes(".augustus.")) {
9-
return "Augustus";
10-
} else if (filename.includes(".ncbiRefSeq.")) {
11-
return "NCBI RefSeq";
12-
} else {
13-
return filename;
50+
51+
const labelPatterns: [RegExp, string][] = [
52+
[/\.augustus\./, "Augustus"],
53+
[/\.ncbiRefSeq\./, "NCBI RefSeq"],
54+
[/\.ncbiGene\./, "NCBI Gene"],
55+
];
56+
57+
for (const [pattern, label] of labelPatterns) {
58+
if (pattern.test(filename)) {
59+
return label;
60+
}
1461
}
62+
63+
return filename;
1564
};
1665

1766
/**
18-
* Returns the initial value for the radio group based on the provided gene model URLs.
67+
* Returns the priority value based on the order of preference for gene model URLs.
1968
* Preference is given to NCBI RefSeq, NCBI Gene, then Augustus, otherwise empty string.
2069
* @param geneModelUrls - Gene model URLs.
21-
* @returns The initial value for the radio group.
70+
* @returns The priority value.
2271
*/
23-
export const getInitialValue = (geneModelUrls: string[]): string => {
72+
export const getPriorityValue = (geneModelUrls: string[]): string => {
2473
const priorityTypes = ["ncbiRefSeq", "ncbiGene", "augustus"];
2574
for (const priorityType of priorityTypes) {
2675
for (const url of geneModelUrls) {

app/components/Entity/components/ConfigureWorkflowInputs/components/Main/components/Stepper/components/Step/ReferenceAssemblyStep/referenceAssemblyStep.tsx

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,25 +8,23 @@ import { useEffect } from "react";
88
export const ReferenceAssemblyStep = ({
99
active,
1010
completed,
11+
entryKey,
12+
entryLabel,
1113
genome,
1214
index,
13-
label,
1415
onConfigure,
1516
}: StepProps): JSX.Element => {
1617
const { accession } = genome;
1718

1819
useEffect(() => {
19-
onConfigure({
20-
"reference-assembly": {
21-
label,
22-
values: [{ key: accession, value: accession }],
23-
},
24-
});
25-
}, [accession, label, onConfigure]);
20+
onConfigure(entryKey, entryLabel, [{ key: accession, value: accession }]);
21+
}, [accession, entryKey, entryLabel, onConfigure]);
2622

2723
return (
2824
<Step active={active} completed={completed} index={index}>
29-
<StepLabel optional={<Optional>{accession}</Optional>}>{label}</StepLabel>
25+
<StepLabel optional={<Optional>{accession}</Optional>}>
26+
{entryLabel}
27+
</StepLabel>
3028
<StepContent>None</StepContent>
3129
</Step>
3230
);

app/components/Entity/components/ConfigureWorkflowInputs/components/Main/components/Stepper/components/Step/ReferenceAssemblyStep/step.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,6 @@ import { ReferenceAssemblyStep } from "./referenceAssemblyStep";
44
export const STEP: StepConfig = {
55
Step: ReferenceAssemblyStep,
66
disabled: true,
7-
key: "reference-assembly",
7+
key: "referenceAssembly",
88
label: "Reference Assembly",
99
};

0 commit comments

Comments
 (0)