Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#124 updated landing page #81

Merged
merged 3 commits into from
Jan 8, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading