Skip to content

Commit

Permalink
Add a skeleton page for VEP development (#1142)
Browse files Browse the repository at this point in the history
- Added routes for the new VEP tools app
- Added the first page with initial components
   - A Launchbar icon and the "Ensembl VEP" logo
   - Standard content for the "App bar", i.e. the list of committed and enabled species, and a link to the species manager
   - Rough outline of the content of the "top bar" (i.e. the grey bar below the species tabs)
   - Rough outline of the start page (the first two sections of the VEP form)
  • Loading branch information
azangru authored Jun 7, 2024
1 parent 478e02f commit 7c9bbaa
Show file tree
Hide file tree
Showing 25 changed files with 743 additions and 57 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
.topBar {
min-height: 74px;
display: flex;
flex-direction: column;
background-color: var(--color-light-grey);
padding: 24px 30px 20px;
box-shadow: 0 3px 5px var(--global-box-shadow-color);
Expand Down
61 changes: 61 additions & 0 deletions src/content/app/tools/vep/VepPage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/**
* See the NOTICE file distributed with this work for additional information
* regarding copyright ownership.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import { lazy, useEffect } from 'react';

import { useAppDispatch } from 'src/store';
import useHasMounted from 'src/shared/hooks/useHasMounted';

import { updatePageMeta } from 'src/shared/state/page-meta/pageMetaSlice';

import type { ServerFetch } from 'src/routes/routesConfig';

const VepPageContent = lazy(() => import('./VepPageContent'));

// Copied these from the current Ensembl site; will probably need changing in the future.
const pageTitle = 'Ensembl Variant Effect Predictor (VEP)';
const pageDescription = `
VEP determines the effect of your variants (SNPs, insertions, deletions, CNVs or structural variants)
on genes, transcripts, and protein sequence, as well as regulatory regions.
`;

const VepPage = () => {
const hasMounted = useHasMounted();
const dispatch = useAppDispatch();

useEffect(() => {
dispatch(
updatePageMeta({
title: pageTitle,
description: pageDescription
})
);
}, []);

return hasMounted ? <VepPageContent /> : null;
};

export default VepPage;

// not really fetching anything; just setting page meta
export const serverFetch: ServerFetch = async (params) => {
params.store.dispatch(
updatePageMeta({
title: pageTitle,
description: pageDescription
})
);
};
57 changes: 57 additions & 0 deletions src/content/app/tools/vep/VepPageContent.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/**
* See the NOTICE file distributed with this work for additional information
* regarding copyright ownership.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import { Route, Routes } from 'react-router-dom';

import VepAppBar from './components/vep-app-bar/VepAppBar';
import VepTopBar from './components/vep-top-bar/VepTopBar';
import VepForm from './views/vep-form/VepForm';
import { NotFoundErrorScreen } from 'src/shared/components/error-screen';

const VepPageContent = () => {
return (
<div>
<VepAppBar />
<Main />
</div>
);
};

const Main = () => {
return (
<div>
<VepTopBar />

<Routes>
<Route index={true} element={<VepForm />} />
<Route
path="unviewed-submissions"
element={<div>List of unviewed submissions</div>}
/>
<Route path="submissions">
<Route index={true} element={<div>List of viewed submissions</div>} />
<Route
path=":submissionId"
element={<div>Results of a single VEP analysis</div>}
/>
</Route>
<Route path="*" element={<NotFoundErrorScreen />} />
</Routes>
</div>
);
};

export default VepPageContent;
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
.container {
border-width: 1px;
border-style: solid;
border-color: var(--form-section-border-color, var(--color-medium-light-grey));
}

.container + .container {
border-top: none;
}
56 changes: 56 additions & 0 deletions src/content/app/tools/vep/components/form-section/FormSection.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/**
* See the NOTICE file distributed with this work for additional information
* regarding copyright ownership.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import classNames from 'classnames';

import type { ReactNode } from 'react';

import styles from './FormSection.module.css';

/**
* This component has first appeared in VEP submission form;
* but it is almost a certainty that it will be used in other places as well.
*
* There already exist two similar components: Accordion and ExpandableSection;
* however, this new components doesn't seem to fit either of those:
* - Both the Accordion and the ExpandableSection components have a predefined
* toggle element (an upwards- or downwards-pointing chevron); and in case of
* the Accordion, the whole area of the closed section acts as a button.
* In contrast, this new component can have anything in the right-hand corner.
* - Both the Accordion and the ExpandableSection components have a clear
* distinction between the "closed" (collapsed) and the "opened" (expanded)
* states. In contrast, this new component can show none of its content,
* a little bit of its content, or its full content (see e.g. behaviour of
* a VEP options section, which may show none of the options, some of the options,
* or all options)
*
* Here is what this component needs to be able to do:
* - It has a border; yet, when it is immediately followed by another FormSection,
* their adjacent borders should visually collapse into one.
*/

type Props = {
children: ReactNode;
className?: string;
};

const FormSection = (props: Props) => {
const componentClasses = classNames(styles.container, props.className);

return <div className={componentClasses}>{props.children}</div>;
};

export default FormSection;
50 changes: 50 additions & 0 deletions src/content/app/tools/vep/components/vep-app-bar/VepAppBar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/**
* See the NOTICE file distributed with this work for additional information
* regarding copyright ownership.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import { useAppSelector } from 'src/store';
import { getEnabledCommittedSpecies } from 'src/content/app/species-selector/state/species-selector-general-slice/speciesSelectorGeneralSelectors';

import AppBar, { AppName } from 'src/shared/components/app-bar/AppBar';
import SpeciesManagerIndicator from 'src/shared/components/species-manager-indicator/SpeciesManagerIndicator';
import { SelectedSpecies } from 'src/shared/components/selected-species';
import SpeciesTabsSlider from 'src/shared/components/species-tabs-slider/SpeciesTabsSlider';
import { AppName as AppNameText } from 'src/global/globalConfig';

const VepAppBar = () => {
return (
<AppBar
mainContent={<SpeciesTabs />}
topRight={<SpeciesManagerIndicator />}
topLeft={<AppName>{AppNameText.TOOLS}</AppName>}
/>
);
};

const SpeciesTabs = () => {
const speciesList = useAppSelector(getEnabledCommittedSpecies);

const speciesTabs = speciesList.map((species) => (
<SelectedSpecies
key={species.genome_id}
species={species}
disabled={true}
/>
));

return <SpeciesTabsSlider>{speciesTabs}</SpeciesTabsSlider>;
};

export default VepAppBar;
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
.grid {
display: grid;
flex-grow: 1;
align-items: center;
grid-template-columns:
[vep-logo] max-content
[form-title] max-content
[transcript-set] auto
[submit-button] min-content
[vep-version] auto
[job-lists-navigation] auto;
column-gap: 32px;
white-space: nowrap;
}

.logo {
grid-column: vep-logo;
height: 16px;
}

.runAJob {
grid-column: form-title;
margin-left: 20px;
font-weight: var(--font-weight-bold);
}

.transcriptSet {
grid-column: transcript-set;
justify-self: end;
}

.transcriptSetSelector {
margin-left: 20px;
min-width: 300px;
}

.submit {
grid-column: submit-button;
}

.vepVersion {
grid-column: vep-version;
justify-self: end;
display: flex;
align-items: baseline;
white-space: pre;
color: var(--color-medium-dark-grey);
}

.vepVersion svg {
height: 11px;
margin-right: 0.6ch;
fill: var(--color-medium-dark-grey);
}

.vepVersion span {
color: var(--color-black);
}

.jobListsNavigation {
grid-column: job-lists-navigation;
display: flex;
column-gap: 12px;
}
60 changes: 60 additions & 0 deletions src/content/app/tools/vep/components/vep-top-bar/VepTopBar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/**
* See the NOTICE file distributed with this work for additional information
* regarding copyright ownership.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import ToolsTopBar from 'src/content/app/tools/shared/components/tools-top-bar/ToolsTopBar';
import { PrimaryButton } from 'src/shared/components/button/Button';
import Logotype from 'static/img/brand/logotype.svg';
import SimpleSelect from 'src/shared/components/simple-select/SimpleSelect';
import ButtonLink from 'src/shared/components/button-link/ButtonLink';

import logoUrl from 'static/img/tools/vep/ensembl-vep.svg?url';

import styles from './VepTopBar.module.css';

const VepTopBar = () => {
return (
<ToolsTopBar>
<div className={styles.grid}>
<img src={logoUrl} alt="Ensembl VEP logo" className={styles.logo} />
<div className={styles.runAJob}>Run a job</div>
<div className={styles.transcriptSet}>
Transcript set
<SimpleSelect
options={[{ label: 'Select', value: 'none' }]}
disabled={true}
className={styles.transcriptSetSelector}
/>
</div>
<PrimaryButton disabled={true}>Run</PrimaryButton>
<div className={styles.vepVersion}>
<Logotype />
<span>Variant effect predictor </span>
v111
</div>
<div className={styles.jobListsNavigation}>
<ButtonLink to="" isDisabled={true}>
Unviewed jobs
</ButtonLink>
<ButtonLink to="" isDisabled={true}>
Jobs list
</ButtonLink>
</div>
</div>
</ToolsTopBar>
);
};

export default VepTopBar;
Loading

0 comments on commit 7c9bbaa

Please sign in to comment.