Skip to content

Commit

Permalink
Merge pull request #81 from MetaCell/feature/CELE-124
Browse files Browse the repository at this point in the history
#124 updated landing page
  • Loading branch information
ddelpiano authored Jan 8, 2025
2 parents d1e9296 + 1ebde8d commit bd93eba
Show file tree
Hide file tree
Showing 5 changed files with 228 additions and 77 deletions.
208 changes: 136 additions & 72 deletions applications/visualizer/frontend/src/components/AppLauncher.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,32 @@
import { AppBar, Box, Button, Card, CardActionArea, CardContent, Container, Grid, Toolbar, Typography } from "@mui/material";
import footerImage from "../assets/summary-neurons.png";
import { BarChart } from "@mui/icons-material";
import ArrowForwardIcon from "@mui/icons-material/ArrowForward";
import { AppBar, Box, Button, Chip, Container, Grid, IconButton, Toolbar, Typography } from "@mui/material";
import { debounce } from "lodash";
import { useCallback, useEffect, useState } from "react";
import { Link, useLocation } from "react-router-dom";
import { useGlobalContext } from "../contexts/GlobalContext.tsx";
import { parseURLParams } from "../helpers/parseURLHelper.ts";
import { TEMPLATE_ACTIVE_DATASETS, TEMPLATE_ACTIVE_NEURONS } from "../settings/templateWorkspaceSettings.ts";
function AppLauncher() {
const { workspaces, createWorkspace, setCurrentWorkspace, setSelectedWorkspacesIds } = useGlobalContext();
import { CaretIcon, CheckIcon, CloseIcon } from "../icons";
import Logo from "../icons/Logo.svg";
import { GlobalError } from "../models/Error.ts";
import { NeuronsService } from "../rest";
import { TEMPLATE_ACTIVE_DATASETS } from "../settings/templateWorkspaceSettings.ts";
import { vars } from "../theme/variables.ts";
import CustomAutocomplete from "./CustomAutocomplete.tsx";

function AppLauncher() {
const location = useLocation();
const { workspaces, createWorkspace, setCurrentWorkspace, setSelectedWorkspacesIds, handleErrors } = useGlobalContext();
const [selectedNeurons, setSelectedNeurons] = useState<string[]>([]);
const [neuronNames, setNeuronsNames] = useState<string[]>([]);
const [searchedNeuron, setSearchedNeuron] = useState("");
const isActive = (path) => location.pathname === path;
const handleTemplateClick = async () => {
const workspaceId = `workspace-${Date.now()}`;
const workspaceName = `Template Workspace ${Object.keys(workspaces).length + 1}`;
createWorkspace(workspaceId, workspaceName, new Set(TEMPLATE_ACTIVE_DATASETS), new Set(TEMPLATE_ACTIVE_NEURONS));
createWorkspace(workspaceId, workspaceName, new Set(TEMPLATE_ACTIVE_DATASETS), new Set(selectedNeurons));
setCurrentWorkspace(workspaceId);
setSelectedWorkspacesIds(new Set<string>([workspaceId]));
};

const handleBlankClick = () => {
const workspaceId = `workspace-${Date.now()}`;
const workspaceName = `Workspace ${Object.keys(workspaces).length + 1}`;
Expand All @@ -22,90 +35,141 @@ function AppLauncher() {
setCurrentWorkspace(workspaceId);
setSelectedWorkspacesIds(new Set<string>([workspaceId]));
};
const fetchNeurons = async () => {
try {
const neuronArrays = await NeuronsService.searchCells({ name: searchedNeuron, datasetIds: TEMPLATE_ACTIVE_DATASETS });
const uniqueNeurons = new Set<string>();
for (const neuron of neuronArrays.flat()) {
uniqueNeurons.add(neuron.name);
uniqueNeurons.add(neuron.nclass);
}

const handlePasteUrlClick = () => {
const exampleURL = "http://localhost:8080/mode=default&ws_name=workspace1&ids=ADAL,AIBR,RIML&ws_name=workspace3&ids=RIFL,REMV&ws_name=test&ids=ADAL";
setNeuronsNames([...uniqueNeurons]);
} catch (error) {
handleErrors(new GlobalError(error.message));
}
};

const parsedParams = parseURLParams(exampleURL);
console.log(parsedParams);
const onSearchNeurons = (value) => {
setSearchedNeuron(value);
debouncedFetchNeurons(value, TEMPLATE_ACTIVE_DATASETS);
};

const handleNeuronChange = (value) => {
setSelectedNeurons(value);
};

const debouncedFetchNeurons = useCallback(debounce(fetchNeurons, 300), []);

useEffect(() => {
debouncedFetchNeurons();
}, []);

const getSortedNeuronNames = () => {
const uniqueNeurons = new Set(selectedNeurons.concat(neuronNames));
return Array.from(uniqueNeurons);
};

return (
<>
<Box>
<AppBar component="nav">
<AppBar
component="nav"
sx={{
backgroundColor: vars.gray50,
}}
>
<Toolbar>
<Typography variant="h6" component="div" sx={{ flexGrow: 1, display: { xs: "none", sm: "block" } }} />
<Button color="secondary" variant="outlined">
About Zhen Lab
</Button>
<Box gap=".25rem" display="flex" alignItems="center">
<Button
component={Link}
to="/"
color="secondary"
variant="text"
sx={{
backgroundColor: isActive("/") ? vars.gray100 : "transparent",
}}
>
Home
</Button>
<Button color="secondary" variant="text" onClick={handleBlankClick}>
Viewer
</Button>
<Button color="secondary" variant="text">
About Nemanode
</Button>
</Box>
<Chip
icon={<BarChart />}
label={`${TEMPLATE_ACTIVE_DATASETS.length} datasets, ${neuronNames.length} neurons`}
variant="outlined"
className="basic"
/>
</Toolbar>
</AppBar>
<Box className="MuiBox-container">
<Box className="MuiBox-title">
<Typography variant="h3" component="h1" gutterBottom>
Welcome to C. Elegans
</Typography>
<Typography variant="h6" component="p">
Explore, query and visualize C. elegans datasets. To get started, choose from one of the options below.
</Typography>
</Box>
<Container className="MuiContainer-center">
<Grid container spacing={4} justifyContent="center">
<Grid item xs={12} sm={6} md={4} display="flex">
<Card>
<CardActionArea onClick={handleTemplateClick}>
<CardContent>
<Box>
<Typography variant="h4"> Start with a simple dataset</Typography>
<Typography className="success" variant="caption">
Simple
</Typography>
</Box>
<Typography variant="body2">
Start exploring the application without a particular dataset in mind. We’ll load a simple dataset for you to start exploring.
</Typography>
</CardContent>
</CardActionArea>
</Card>
</Grid>
<Grid item xs={12} sm={6} md={4} display="flex">
<Card>
<CardActionArea onClick={handleBlankClick}>
<CardContent>
<Box>
<Typography variant="h4">Blank canvas</Typography>
<Typography className="info" variant="caption">
Advanced
</Typography>
</Box>
<Typography variant="body2">Start with a blank canvas and select the datasets and neurons of your choice.</Typography>
</CardContent>
</CardActionArea>
</Card>
<Grid item xs={12} display="flex" justifyContent="center">
<img src={Logo} alt="logo" />
</Grid>
<Grid item xs={12} sm={6} md={4} display="flex">
<Card>
<CardActionArea onClick={handlePasteUrlClick}>
<CardContent>
<Box>
<Typography variant="h4">Paste URL</Typography>
</Box>
<Typography variant="body2">Paste URL from your pre-designed view or from one that your collaborators sent to you</Typography>
</CardContent>
</CardActionArea>
</Card>
<Grid item xs={12} display="flex" justifyContent="center" alignItems="center" gap=".75rem">
<CustomAutocomplete
options={getSortedNeuronNames()}
renderOption={(props, option) => (
<li {...props}>
<CheckIcon />
<Typography>{option}</Typography>
</li>
)}
onInputChange={onSearchNeurons}
placeholder="Start typing to select cell(s) to start with"
className="secondary"
id="tags-standard"
popupIcon={<CaretIcon />}
ChipProps={{
deleteIcon: (
<IconButton sx={{ p: "0 !important", margin: "0 !important" }}>
<CloseIcon />
</IconButton>
),
}}
clearIcon={false}
value={selectedNeurons}
onChange={handleNeuronChange}
sx={{
flex: 1,
maxWidth: "37.5rem",
"& .MuiInputBase-root": {
backgroundColor: vars.white,
padding: "0.75rem 0.875rem",
},
}}
/>
<Button
color="info"
variant="contained"
sx={{
p: "0.625rem 1rem",
boxShadow: "0px 1px 2px 0px rgba(16, 24, 40, 0.05)",
height: "2.75rem",
fontSize: "1rem",
fontWeight: "600",
}}
endIcon={<ArrowForwardIcon />}
onClick={handleTemplateClick}
>
Launch viewer
</Button>
</Grid>
<Grid item xs={12}>
<Box textAlign="center">
<Button className="MuiButton-summary">Summary of available datasets and neurons</Button>
<Box textAlign="center" onClick={handleBlankClick}>
<Button variant="outlined">Start with a blank canvas</Button>
</Box>
</Grid>
</Grid>
</Container>
</Box>
<Box px={2} className="MuiFooterImage">
<img src={footerImage} alt="footerimage" width="100%" height="48" />
</Box>
</Box>
</>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ const CommonAutocomplete = <T,>({
// @ts-ignore
return (
<Autocomplete
disableCloseOnSelect={true}
value={value}
multiple={multiple}
className={className}
Expand Down
Loading

0 comments on commit bd93eba

Please sign in to comment.