Skip to content

Commit

Permalink
Merge branch 'master' into fix_unit_tests_jest
Browse files Browse the repository at this point in the history
  • Loading branch information
pieterlukasse authored Oct 14, 2022
2 parents 9e8d509 + 5b69d8e commit 524d086
Show file tree
Hide file tree
Showing 25 changed files with 1,205 additions and 148 deletions.
14 changes: 8 additions & 6 deletions src/Analysis/AnalysisApp.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { analysisApps } from '../localconf';
import './AnalysisApp.css';
import sessionMonitor from '../SessionMonitor';
import GWASWorkflowList from './GWASUIApp/GWASWorkflowList';
import GWASContainer from "./GWASV2/GWASContainer";

const queryClient = new QueryClient();

Expand Down Expand Up @@ -55,10 +56,6 @@ class AnalysisApp extends React.Component {
this.props.checkJobStatus();
}

refreshWorkflows = () => {
queryClient.invalidateQueries('workflows');
}

processAppMessages = (event) => {
const pathArray = this.state.app.applicationUrl.split('/');
const protocol = pathArray[0];
Expand Down Expand Up @@ -112,16 +109,21 @@ class AnalysisApp extends React.Component {
}}
>
<div className='analysis-app_flex_col'>
<ReduxGWASUIApp refreshWorkflows={this.refreshWorkflows} />
<ReduxGWASUIApp />
</div>
</TourProvider>
);
case 'GWASResults':
return (
<div className='analysis-app_flex_row'>
<GWASWorkflowList refreshWorkflows={this.refreshWorkflows} />
<GWASWorkflowList refetchInterval={5000} />
</div>
);
case 'GWAS++': {
return <div>
<GWASContainer refreshWorkflows={this.refreshWorkflows}/>
</div>
}
default:
// this will ensure the main window will process the app messages (if any):
window.addEventListener('message', this.processAppMessages);
Expand Down
21 changes: 20 additions & 1 deletion src/Analysis/GWASUIApp/GWASUIApp.css
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
border: 1px dashed #e9e9e9;
border-radius: 2px;
background-color: #fafafa;
padding-top: 40px;
padding-top: 25px;
padding-bottom: 40px;
display: flex;
flex-direction: column;
Expand Down Expand Up @@ -332,6 +332,12 @@
text-overflow: ellipsis;
}

.GWASUI-asterisk:before {
content: "*";
margin: 0 3px 0 -10px;
color: red;
}

.GWASUI-attritionTable {
display: flex;
width: 100%;
Expand Down Expand Up @@ -383,3 +389,16 @@
align-items: right;
flex: 7;
}

.GWASUI-mt-15 {
margin-top: 15px;
}

.GWASUI-no-padding {
padding: 0;
}

.GWASUI-no-top-spacing {
padding-top: 0;
margin-top: 0;
}
7 changes: 0 additions & 7 deletions src/Analysis/GWASUIApp/GWASUIApp.jsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import React, { useState, useEffect } from 'react';
import PropTypes from 'prop-types';
import { Card, Space } from 'antd';
import { fetchAndSetCsrfToken } from '../../configs';
import GWASQuantitative from '../GWASWizard/GWASQuantitative';
Expand Down Expand Up @@ -89,21 +88,15 @@ const GWASUIApp = (props) => {
{gwasTypeSelected && gwasType === 'caseControl' && (
<GWASCaseControl
resetGWASType={resetGWASType}
refreshWorkflows={props.refreshWorkflows}
/>
)}
{gwasTypeSelected && gwasType === 'quantitative' && (
<GWASQuantitative
resetGWASType={resetGWASType}
refreshWorkflows={props.refreshWorkflows}
/>
)}
</React.Fragment>
);
};

GWASUIApp.propTypes = {
refreshWorkflows: PropTypes.func.isRequired,
};

export default GWASUIApp;
10 changes: 8 additions & 2 deletions src/Analysis/GWASUIApp/GWASWorkflowList.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@ import { Collapse, List, Spin } from 'antd';
import './GWASUIApp.css';
import { useQuery } from 'react-query';
import { gwasWorkflowPath } from '../../localconf';
import PropTypes from 'prop-types';
import GWASJob from '../GWASWizard/shared/GWASJob';

const GWASWorkflowList = () => {
const GWASWorkflowList = ({refetchInterval}) => {
const { Panel } = Collapse;

async function fetchGwasWorkflows() {
Expand All @@ -19,7 +20,7 @@ const GWASWorkflowList = () => {
refetchOnMount: false,
refetchOnWindowFocus: false,
refetchOnReconnect: false,
refetchInterval: 60000,
refetchInterval: refetchInterval,
});
if (status === 'loading') {
return <React.Fragment><div className='GWASUI-spinnerContainer'><Spin /></div></React.Fragment>;
Expand Down Expand Up @@ -52,6 +53,11 @@ const GWASWorkflowList = () => {
<GWASWorkflows />
</div>
);

};

GWASWorkflowList.propTypes = {
refetchInterval: PropTypes.number.isRequired
};

export default GWASWorkflowList;
125 changes: 125 additions & 0 deletions src/Analysis/GWASUIApp/GWASWorkflowList.stories.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
import React, { useState } from 'react';
import { QueryClient, QueryClientProvider } from 'react-query';
import { rest } from 'msw';
import GWASWorkflowList from './GWASWorkflowList';
import { gwasStatus } from '../GWASWizard/shared/constants';

export default {
title: 'Tests2/GWASUI/WorkflowList',
component: GWASWorkflowList,
};

const mockedQueryClient = new QueryClient({
defaultOptions: {
queries: { retry: false },
},
});

const MockTemplate = () => {

return (
<QueryClientProvider client={mockedQueryClient}>
<GWASWorkflowList refetchInterval={1000} />
</QueryClientProvider>
);
};

let requestCount = 0;
let rowCount = 1;
const getMockPhase = (requestCount) => {
if (requestCount % 2 == 0) {
return gwasStatus.running;
} else if (requestCount % 5 == 0) {
return gwasStatus.failed;
} else {
return gwasStatus.succeeded;
}
}

let workflowList = [];

const getMockWorkflowList = () => {
requestCount++;
// simulate a new workflow only at each 3rd request:
if (requestCount % 3 == 0) {
workflowList.splice(0, 0, {"name" : "argo-wrapper-workflow-" + requestCount, "phase": getMockPhase(requestCount)});
rowCount++;
}
// simulate status change of some recent items at each 10th request:
if (rowCount % 5 == 0) {
// just some status that is not used in getMockPhase:
workflowList[2].phase = gwasStatus.pending;
workflowList[3].phase = gwasStatus.pending;
}
return workflowList;
}

export const MockedSuccess = MockTemplate.bind({});
MockedSuccess.parameters = {
msw: {
handlers: [
rest.get('http://:argowrapperpath/ga4gh/wes/v2/workflows', (req, res, ctx) => {
const { argowrapperpath } = req.params;
console.log(argowrapperpath);
return res(
ctx.delay(200),
ctx.json(getMockWorkflowList()),
);
}),
rest.get('http://:argowrapperpath/ga4gh/wes/v2/status/:workflowid', (req, res, ctx) => {
const { argowrapperpath } = req.params;
const { workflowid } = req.params;
console.log(argowrapperpath);
console.log(workflowid);

return res(
ctx.delay(500),
ctx.json({"name": workflowid,
"wf_name": workflowid + " name",
"arguments":{"parameters":[
{"name":"source_id","value":"2"},
{"name":"case_cohort_definition_id","value":"300"},
{"name":"control_cohort_definition_id","default":"-1","value":"-1"},
{"name":"n_pcs","value":"3"},
{"name":"covariates","value":"ID_2000006885 ID_2000000708"},
{"name":"outcome","value":"ID_2000006886"},
{"name":"out_prefix","default":"genesis_vadc","value":"123456789"},
{"name":"maf_threshold","value":"0.01"},{"name":"imputation_score_cutoff","value":"0.3"},
{"name":"hare_population","value":"Hispanic"},
{"name":"prefixed_hare_concept_id","default":"ID_2000007027","value":"ID_2000007027"},
{"name":"internal_api_env","default":"default","value":"qa-mickey"},
{"name":"genome_build","default":"hg19","value":"hg19","enum":["hg38","hg19"]},
{"name":"pca_file","value":"/commons-data/pcs.RData"},
{"name":"relatedness_matrix_file","value":"/commons-data/abc.RData"},
{"name":"n_segments","value":"0"},
{"name":"segment_length","default":"2000","value":"2000"},
{"name":"variant_block_size","default":"1024","value":"100"},
{"name":"mac_threshold","value":"0"},
{"name":"gds_files","value":"[\"/commons-data/gds/chr1.merged.vcf.gz.gds\", \"/commons-data/gds/chr2.merged.vcf.gz.gds\"]"}]},
"phase": getMockPhase(requestCount),
"progress":"6/6",
"startedAt":"2022-07-01T17:29:29Z",
"finishedAt":"2022-07-01T17:33:13Z",
"outputs":{"parameters":[{"name":"gwas_archive_index",
"value":
"{\n \"baseid\": \"123456-789-1023-1234-d123545e\",\n \"did\": \"123456-654-123-123-f654987123\",\n \"rev\": \"123456c789\"\n}"}
]
}
}),
);
}),
],
},
};

export const MockedError = MockTemplate.bind({});
MockedError.parameters = {
msw: {
handlers: [
rest.post('', (req, res, ctx) => res(
ctx.delay(800),
ctx.status(403),
)),
],
},
};
116 changes: 116 additions & 0 deletions src/Analysis/GWASV2/GWASContainer.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
import React, { useState } from "react";
import { Space, Button, Popconfirm } from "antd";
import SelectStudyPopulation from "./SelectStudyPopulation/SelectStudyPopulation";
import "./GWASV2.css";

const GWASContainer = () => {
const [current, setCurrent] = useState(0);
const [
selectedStudyPopulationCohort,
setSelectedStudyPopulationCohort,
] = useState({});
const gwasSteps = [
{
title: "Step 1",
description: "Select Study Population",
},
{
title: "Step 2",
description: "Select Outcome Phenotypes",
},
{
title: "Step 3",
description: "Select Covariate Phenotype",
},
{
title: "Step 4",
description: "Configure GWAS",
},
];

const generateStep = () => {
// steps 2 & 3 very similar
switch (current) {
case 0:
// select study population
return (
<SelectStudyPopulation
selectedStudyPopulationCohort={selectedStudyPopulationCohort}
setSelectedStudyPopulationCohort={setSelectedStudyPopulationCohort}
current={current}
/>
);
case 1:
// outcome (customdichotomous or not)
return <React.Fragment>step 2</React.Fragment>;
case 2:
// covariates (customdichtomous or not)
return <React.Fragment>step 3</React.Fragment>;
case 3:
// all other input (mafs, imputation, etc), review, and submit
return <React.Fragment>step 4</React.Fragment>;
default:
// required for eslint
return null;
}
};
return (
<React.Fragment>
{/* Inline style block needed so centering rule doesn't impact other workflows */}
<style>{`.analysis-app__actions > div:nth-child(1) {margin: 0 auto; }`}</style>
<div className="GWASV2">
<Space direction={"vertical"} style={{ width: "100%" }}>
<div className="steps-content">
<Space
direction={"vertical"}
align={"center"}
style={{ width: "100%" }}
>
{generateStep(current)}
</Space>
</div>
<div className="steps-action">
<Button
className="GWASUI-navBtn GWASUI-navBtn__next"
type="primary"
onClick={() => {
setCurrent(current - 1);
}}
disabled={current < 1 ? true : false}
>
Previous
</Button>
<Popconfirm
title="Are you sure you want to leave this page?"
// onConfirm={() => resetGWASType()}
okText="Yes"
cancelText="No"
>
<Button type="link" size="medium">
Select Different GWAS Type
</Button>
</Popconfirm>
{current < gwasSteps.length - 1 && (
<Button
data-tour="next-button"
className="GWASUI-navBtn GWASUI-navBtn__next"
type="primary"
onClick={() => {
setCurrent(current + 1);
}}
// disabled={!nextButtonEnabled}
>
Next
</Button>
)}
{current === gwasSteps.length - 1 && (
<div className="GWASUI-navBtn" />
)}
</div>
</Space>
</div>
</React.Fragment>
);
};

export default GWASContainer;
Loading

0 comments on commit 524d086

Please sign in to comment.