Skip to content

Commit

Permalink
Merge pull request #1 from MetaCell/feature/CELE-17
Browse files Browse the repository at this point in the history
Feature/cele 17
  • Loading branch information
aranega authored Apr 24, 2024
2 parents ff7026e + f452cc4 commit d817833
Show file tree
Hide file tree
Showing 19 changed files with 1,086 additions and 616 deletions.
2 changes: 1 addition & 1 deletion applications/visualizer/frontend/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/favicon.png" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite + React + TS + Material + Layout-Manager</title>
<title>C.Elegans UI</title>
</head>
<body>
<div id="root"></div>
Expand Down
3 changes: 2 additions & 1 deletion applications/visualizer/frontend/src/App.css
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@
margin: 0 auto;
}

#layout-manager-container {
.layout-manager-container {
display: flex;
flex-direction: column;
position: relative;
width: 100%;
height: 100%;
Expand Down
98 changes: 70 additions & 28 deletions applications/visualizer/frontend/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,51 +1,93 @@
import {useDispatch, useStore} from "react-redux";
import React, {useEffect, useState} from "react";
import {Provider} from "react-redux";
import {ThemeProvider} from '@mui/material/styles';
import {Box, CircularProgress, CssBaseline} from "@mui/material";
import {getLayoutManagerInstance} from "@metacell/geppetto-meta-client/common/layout/LayoutManager";
import {addWidget} from '@metacell/geppetto-meta-client/common/layout/actions';
import {Box, Button, CssBaseline, Typography} from "@mui/material";
import '@metacell/geppetto-meta-ui/flex-layout/style/dark.scss';
import {leftComponentWidget, rightComponentWidget} from "./layout-manager/widgets.ts";
import theme from './theme/index.tsx';
import './App.css'

import {useGlobalContext} from "./contexts/GlobalContext.tsx";
import AppLauncher from "./components/AppLauncher.tsx";
import Workspace from "./components/Workspace.tsx";
import React from "react";
import {createEmptyWorkspace} from "./helpers/initialWorkspacesHelper.ts";
import {ViewMode} from "./models.ts";

function App() {
const {
workspaces,
currentWorkspaceId,
switchWorkspace,
addWorkspace,
viewMode,
setViewMode,
selectedWorkspacesIds,
setSelectedWorkspacesIds
} = useGlobalContext();

const store = useStore();
const dispatch = useDispatch();
const [LayoutComponent, setLayoutComponent] = useState<React.ComponentType | undefined>(undefined);

useEffect(() => {
if (LayoutComponent === undefined) {
const myManager = getLayoutManagerInstance();
if (myManager) {
setLayoutComponent(myManager.getComponent());
const TEST_toggleViewMode = () => {
if (viewMode === ViewMode.Default) {
setViewMode(ViewMode.Compare);
// Ensure at least two workspaces are selected for comparison
const keys = Object.keys(workspaces);
if (selectedWorkspacesIds.size < 2) {
if (keys.length < 2) {
// Create a new workspace if there aren't enough
const newWorkspace = createEmptyWorkspace(`Workspace ${keys.length + 1}`);
addWorkspace(newWorkspace);
setSelectedWorkspacesIds(new Set([currentWorkspaceId, newWorkspace.id]));
} else {
setSelectedWorkspacesIds(new Set([currentWorkspaceId, keys.find(key => key !== currentWorkspaceId)]));
}
}
} else {
setViewMode(ViewMode.Default);
setSelectedWorkspacesIds(new Set([currentWorkspaceId]));
}
}, [store, dispatch, LayoutComponent])
};
const TEST_change_workspace = () => {

useEffect(() => {
dispatch(addWidget(leftComponentWidget()));
dispatch(addWidget(rightComponentWidget()));
}, [LayoutComponent, dispatch])
const keys = Object.keys(workspaces);
const otherKeys = keys.filter(key => key !== currentWorkspaceId);

if (otherKeys.length > 0) {
switchWorkspace(otherKeys[0]);
} else {
const newWorkspace = createEmptyWorkspace(`Workspace ${Object.keys(workspaces).length + 1}`);
addWorkspace(newWorkspace);
switchWorkspace(newWorkspace.id);
}
}

const isLoading = LayoutComponent === undefined
const hasLaunched = currentWorkspaceId != undefined

return (
<>
<ThemeProvider theme={theme}>
<CssBaseline/>
{isLoading ?
<CircularProgress/> :
<Box id="layout-manager-container">
<LayoutComponent/>
</Box>
}
</ThemeProvider>
{hasLaunched ? (
<Box className={"layout-manager-container"}>
<Button variant="contained" color="primary" onClick={TEST_change_workspace}>
Change Workspace
</Button>
<Button variant="contained" color="secondary" onClick={TEST_toggleViewMode}>
Change View mode
</Button>
{viewMode === ViewMode.Compare ?
Array.from(selectedWorkspacesIds).map(id => (
<Provider key={id} store={workspaces[id].store}>
<Workspace workspaceId={id}/>
</Provider>
))
:
<Provider store={workspaces[currentWorkspaceId].store}>
<Workspace workspaceId={currentWorkspaceId}/>
</Provider>
}

</Box>

) : <AppLauncher/>}
</ThemeProvider>
</>
)
}
Expand Down
72 changes: 72 additions & 0 deletions applications/visualizer/frontend/src/components/AppLauncher.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import React from 'react';
import {Typography, Card, CardContent, CardActionArea, Grid, Container} from '@mui/material';
import {createEmptyWorkspace} from "../helpers/initialWorkspacesHelper.ts";
import {useGlobalContext} from "../contexts/GlobalContext.tsx";

function AppLauncher() {

const {workspaces, addWorkspace, switchWorkspace} = useGlobalContext();


const handleTemplateClick = () => {
console.log('Template option clicked');
};

const handleBlankClick = () => {
const workspace =createEmptyWorkspace(`Workspace ${Object.keys(workspaces).length + 1}`)
addWorkspace(workspace)
switchWorkspace(workspace.id)
};

const handlePasteUrlClick = () => {
console.log('Paste URL option clicked');
};

return (
<Container maxWidth="md" style={{marginTop: '50px'}}>
<Typography variant="h3" component="h1" gutterBottom align="center">
Welcome to C. Elegans
</Typography>
<Typography variant="h6" component="p" gutterBottom align="center">
Choose one of the options below to get started.
</Typography>
<Grid container spacing={4} justifyContent="center" style={{marginTop: '20px'}}>
<Grid item xs={12} sm={6} md={4}>
<Card>
<CardActionArea onClick={handleTemplateClick}>
<CardContent>
<Typography variant="h5" component="h2" align="center">
Start from Template
</Typography>
</CardContent>
</CardActionArea>
</Card>
</Grid>
<Grid item xs={12} sm={6} md={4}>
<Card>
<CardActionArea onClick={handleBlankClick}>
<CardContent>
<Typography variant="h5" component="h2" align="center">
Start with a Blank Canvas
</Typography>
</CardContent>
</CardActionArea>
</Card>
</Grid>
<Grid item xs={12} sm={6} md={4}>
<Card>
<CardActionArea onClick={handlePasteUrlClick}>
<CardContent>
<Typography variant="h5" component="h2" align="center">
Paste URL
</Typography>
</CardContent>
</CardActionArea>
</Card>
</Grid>
</Grid>
</Container>
);
}

export default AppLauncher;
43 changes: 15 additions & 28 deletions applications/visualizer/frontend/src/components/LeftComponent.tsx
Original file line number Diff line number Diff line change
@@ -1,46 +1,33 @@
import { Box, Button, Typography } from "@mui/material";
import { useEffect, useState } from "react";
import { Dataset, DatasetsService, HeathcheckService, Neuron, NeuronsService } from "../rest";
import {Box, Typography} from "@mui/material";

export default function LeftComponent() {
const [ready, setReady] = useState("Not ready")
const [dataset, setDataset] = useState<Dataset>()
const [allDataset, setAllDataset] = useState<Dataset[]>()
const [currentPage, setCurrentPage] = useState<{ page: number, loadedElements: number, totalElements: number }>({ page: 0, loadedElements: 0, totalElements: 1 })
const [neurons, setNeurons] = useState<Neuron[]>([])

useEffect(() => {
HeathcheckService.ready().then(answer => setReady(answer))
DatasetsService.getDataset({ dataset: 'white_1986_whole' }).then(answer => setDataset(answer))
DatasetsService.getAllDatasets().then(answer => setAllDataset(answer))
loadMoreNeurons()
}, [])
import {useGlobalContext} from "../contexts/GlobalContext.tsx";

const loadMoreNeurons = async () => {
const page = currentPage.page + 1
const neuronPage = await NeuronsService.getAllCells({ page: page })
setNeurons([...neurons, ...neuronPage.items])
setCurrentPage({ page: page, loadedElements: neurons.length, totalElements: neuronPage.count })
}
export default function LeftComponent() {
const {datasets, neurons} = useGlobalContext();

const datasetArray = datasets ? Object.values(datasets) : [];
const neuronArray = neurons ? Object.values(neurons) : [];
return (
<Box>
<Typography variant="h1">Vite + React + Typescript</Typography>
<Typography variant="h3">API state: {ready}</Typography>
<Typography variant="h3">Dataset: {JSON.stringify(dataset)}</Typography>
<Typography variant="h3">All datasets names:</Typography>
<Box>
{
allDataset?.map(x => <Typography key={x.name} variant="body1">{x.name}</Typography>)
// Render each dataset name
datasetArray.map(dataset => (
<Typography key={dataset.id} variant="body1">{dataset.name}</Typography>
))
}
</Box>
<Typography variant="h3">Neurons:</Typography>
<Box>
{
neurons?.map(x => <Typography key={x.name} variant="body1">{x.name} ({JSON.stringify(x)})</Typography>)
// Render each neuron name
neuronArray.map(neuron => (
<Typography key={neuron.id} variant="body1">{neuron.name}</Typography>
))
}
<Button disabled={currentPage.loadedElements >= currentPage.totalElements} onClick={loadMoreNeurons}>Load more</Button>
</Box>
</Box>
)
);
}
Loading

0 comments on commit d817833

Please sign in to comment.