Skip to content

Commit

Permalink
[Platform]: Upload suggestions component (#313)
Browse files Browse the repository at this point in the history
  • Loading branch information
carcruz authored Dec 5, 2023
1 parent 3033f2a commit 8b05cb2
Show file tree
Hide file tree
Showing 5 changed files with 174 additions and 45 deletions.
1 change: 1 addition & 0 deletions apps/platform/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
"smiles-drawer": "^1.1.22",
"tsparticles": "^2.0.6",
"typeface-inter": "^3.3.0",
"typeface-roboto-mono": "^1.1.13",
"ui": "*",
"uuid": "^9.0.0"
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,21 @@ import {
Box,
List,
ListSubheader,
Accordion,
AccordionSummary,
AccordionDetails,
} from "@mui/material";
import { useDropzone } from "react-dropzone";
import { styled } from "@mui/material/styles";
import { v1 } from "uuid";
import { faFileImport, faChevronLeft, faCheck } from "@fortawesome/free-solid-svg-icons";
import {
faFileImport,
faChevronLeft,
faCheck,
faChevronDown,
faClipboard,
faPlay,
} from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { Tooltip } from "ui";

Expand All @@ -24,6 +34,12 @@ import ValidationQuery from "./ValidationQuery.gql";
import client from "../../../client";
import NestedItem from "./NestedItem";

const BorderAccordion = styled(Accordion)(({ theme }) => ({
boxShadow: "none",
border: `1px solid ${theme.palette.primary.light}`,
borderRadius: `${theme.spacing(1)} !important`,
}));

const StyledContainer = styled("div")`
.dropzone {
flex: 1;
Expand All @@ -45,6 +61,32 @@ const StyledContainer = styled("div")`
}
`;

const SuggestionBlockHeader = styled("div")`
background-color: #cccccc;
border-radius: 8px 8px 0px 0px;
border-width: 2px;
border-style: solid;
border-color: #cccccc;
padding: 5px;
padding-left: 20px;
`;

const SuggestionContainer = styled("div")`
position: relative;
flex: 1;
display: flex;
flex-direction: column;
padding-left: 20px;
padding-top: 10px;
padding-bottom: 10px;
border-width: 2px;
border-color: #eeeeee;
border-style: solid;
border-radius: 0px 0px 8px 8px;
background-color: #fafafa;
border-top: none;
`;

const steps = ["Add a file", "Entity validation"];

const getEntityToUploadLabel = {
Expand All @@ -58,6 +100,71 @@ const getValidationResults = async (entity, queryTerms) =>
variables: { entity, queryTerms },
});

const uploadSuggestions = {
target: ["ENSG00000232810", "interleukin 6", "TP53", "ENSG00000105329", "P15692", "CD4"],
disease: ["EFO_0000508", "neoplasm", "MONDO_0004992", "EFO_0000182", "infection", "OBI_1110021"],
};

const FileExample = ({ entity = "target", runAction }) => {
const examples = uploadSuggestions[entity];

const [open, setExpanded] = useState(false);

const handleChange = () => {
setExpanded(open ? false : true);
};

function handleClickRun() {
runAction(examples);
setExpanded(false);
}

function copyToClipboard() {
navigator.clipboard.writeText(JSON.stringify(examples));
}
return (
<Box sx={{ mb: 6 }}>
<BorderAccordion expanded={open} onChange={() => handleChange()}>
<AccordionSummary
aria-controls="panel1a-content"
id="panel1a-header"
expandIcon={<FontAwesomeIcon icon={faChevronDown} />}
>
<Typography>Example format</Typography>
</AccordionSummary>
<AccordionDetails>
<Box>
<SuggestionBlockHeader>
<Typography variant="monoText" display="block">
fileName.txt
</Typography>
</SuggestionBlockHeader>
<SuggestionContainer>
<Box sx={{ position: "absolute", right: 10, display: "flex", gap: 1 }}>
<Tooltip placement="bottom" title="Run this sample">
<Button onClick={() => handleClickRun()}>
<FontAwesomeIcon icon={faPlay} />
</Button>
</Tooltip>
<Tooltip placement="bottom" title="Copy to clipboard">
<Button onClick={() => copyToClipboard()}>
<FontAwesomeIcon icon={faClipboard} />
</Button>
</Tooltip>
</Box>
{examples.map(ex => (
<Typography key={v1()} variant="monoText" display="block" gutterBottom>
{ex}
</Typography>
))}
</SuggestionContainer>
</Box>
</AccordionDetails>
</BorderAccordion>
</Box>
);
};

function DataUploader({ fileStem }) {
const [activeStep, setActiveStep] = useState(0);
const [queryTermsResults, setQueryTermsResults] = useState(null);
Expand All @@ -80,6 +187,12 @@ function DataUploader({ fileStem }) {
},
});

const handleRunExample = async terms => {
const result = await getValidationResults([entityToGet], terms);
setQueryTermsResults(result.data.mapIds.mappings);
setActiveStep(1);
};

const entityToUploadLabel = getEntityToUploadLabel[entityToGet];

const handlePinElements = () => {
Expand Down Expand Up @@ -151,6 +264,7 @@ function DataUploader({ fileStem }) {
should contain a single {entityToGet} in every row. You will be able to visualise all
the potential matches upon validation of your input.
</Typography>
<FileExample entity={entityToGet} runAction={handleRunExample} />
<Box sx={{ m: theme => `${theme.spacing(1)} 0 ${theme.spacing(4)} 0` }}>
<Stepper activeStep={activeStep}>
{steps.map(label => {
Expand All @@ -164,13 +278,16 @@ function DataUploader({ fileStem }) {
})}
</Stepper>
</Box>

{activeStep === 0 && (
<StyledContainer>
<div {...getRootProps({ className: "dropzone" })}>
<input {...getInputProps()} />
<p>Drag and drop a .txt file here, or click to select file</p>
</div>
</StyledContainer>
<>
<StyledContainer>
<div {...getRootProps({ className: "dropzone" })}>
<input {...getInputProps()} />
<p>Drag and drop a .txt file here, or click to select file</p>
</div>
</StyledContainer>
</>
)}
{activeStep === 1 && (
<Box>
Expand Down
17 changes: 9 additions & 8 deletions apps/platform/src/index.jsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import * as ReactDOMClient from 'react-dom/client';
import TagManager from 'react-gtm-module';
import { loadErrorMessages, loadDevMessages } from '@apollo/client/dev';
import * as ReactDOMClient from "react-dom/client";
import TagManager from "react-gtm-module";
import { loadErrorMessages, loadDevMessages } from "@apollo/client/dev";

import App from './App';
import config from './config';
import App from "./App";
import config from "./config";

import 'typeface-inter';
import './index.scss';
import "typeface-inter";
import "typeface-roboto-mono";
import "./index.scss";

if (import.meta.env.MODE) {
loadDevMessages();
Expand All @@ -17,5 +18,5 @@ if (config.googleTagManagerID) {
TagManager.initialize({ gtmId: config.googleTagManagerID });
}

const root = ReactDOMClient.createRoot(document.getElementById('root'));
const root = ReactDOMClient.createRoot(document.getElementById("root"));
root.render(<App />);
65 changes: 35 additions & 30 deletions apps/platform/src/theme.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { lighten, darken } from 'polished';
import config from './config';
import { lighten, darken } from "polished";
import config from "./config";

const PRIMARY = config.profile.primaryColor;
const SECONDARY = '#ff6350';
const SECONDARY = "#ff6350";

const theme = {
shape: {
Expand All @@ -11,27 +11,32 @@ const theme = {
typography: {
fontFamily: '"Inter", sans-serif',
assoc_header: {
fontSize: '.90rem',
fontSize: ".90rem",
fontWeight: 700,
},
monoText: {
fontFamily: "'Roboto Mono', monospace",
fontWeight: 500,
fontSize: ".80rem",
},
},
palette: {
primary: {
light: lighten(0.2, PRIMARY),
main: PRIMARY,
dark: darken(0.2, PRIMARY),
contrastText: '#fff',
contrastText: "#fff",
},
secondary: {
light: lighten(0.2, SECONDARY),
main: SECONDARY,
dark: darken(0.2, SECONDARY),
contrastText: '#fff',
contrastText: "#fff",
},
text: {
primary: '#5A5F5F',
primary: "#5A5F5F",
},
footer: '#2e2d35',
footer: "#2e2d35",
},
props: {
MuiTab: {
Expand All @@ -45,14 +50,14 @@ const theme = {
},
styleOverrides: {
root: {
border: '1px solid',
padding: '6px 12px',
minWidth: '32px',
minHeight: '32px',
height: '32px',
textTransform: 'none',
color: '#5A5F5F',
borderColor: 'rgb(196,196,196)',
border: "1px solid",
padding: "6px 12px",
minWidth: "32px",
minHeight: "32px",
height: "32px",
textTransform: "none",
color: "#5A5F5F",
borderColor: "rgb(196,196,196)",
},
},
},
Expand All @@ -62,19 +67,19 @@ const theme = {
},
styleOverrides: {
root: {
border: '1px solid',
borderColor: 'rgb(196,196,196)',
padding: '6px 12px',
textTransform: 'none',
height: '32px',
color: '#5A5F5F',
border: "1px solid",
borderColor: "rgb(196,196,196)",
padding: "6px 12px",
textTransform: "none",
height: "32px",
color: "#5A5F5F",
},
},
},
MuiTabs: {
styleOverrides: {
indicator: {
transition: 'none',
transition: "none",
},
},
},
Expand All @@ -84,18 +89,18 @@ const theme = {
},
styleOverrides: {
root: {
textTransform: 'none',
textTransform: "none",
},
},
},
MuiTooltip: {
variants: [
{
props: { variant: 'aotf' },
props: { variant: "aotf" },
style: {
root: {
backgroundColor: `red`,
color: '#fff',
color: "#fff",
},
},
},
Expand All @@ -104,17 +109,17 @@ const theme = {
MuiSnackbar: {
defaultProps: {
anchorOrigin: {
vertical: 'bottom',
horizontal: 'center',
vertical: "bottom",
horizontal: "center",
},
},
},
MuiSnackbarContent: {
styleOverrides: {
root: {
background: PRIMARY,
color: 'white',
borderRadius: '4px',
color: "white",
borderRadius: "4px",
},
},
},
Expand Down
5 changes: 5 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -17753,6 +17753,11 @@ typeface-inter@^3.3.0:
resolved "https://registry.yarnpkg.com/typeface-inter/-/typeface-inter-3.18.1.tgz#24cccdf29923f318589783997be20a662cd3ab9c"
integrity sha512-c+TBanYFCvmg3j5vPk+zxK4ocMZbPxMEmjnwG7rPQoV87xvQ6b07VbAOC0Va0XBbbZCGw6cWNeFuLeg1YQru3Q==

typeface-roboto-mono@^1.1.13:
version "1.1.13"
resolved "https://registry.yarnpkg.com/typeface-roboto-mono/-/typeface-roboto-mono-1.1.13.tgz#2af8662db8f9119c00efd55d6ed8877d2a69ec94"
integrity sha512-pnzDc70b7ywJHin/BUFL7HZX8DyOTBLT2qxlJ92eH1UJOFcENIBXa9IZrxsJX/gEKjbEDKhW5vz/TKRBNk/ufQ==

typescript@^4.9.5:
version "4.9.5"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.5.tgz#095979f9bcc0d09da324d58d03ce8f8374cbe65a"
Expand Down

0 comments on commit 8b05cb2

Please sign in to comment.