-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
20 changed files
with
1,819 additions
and
434 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
249 changes: 126 additions & 123 deletions
249
applications/visualizer/frontend/src/components/ViewerContainer/Neurons.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,150 +1,153 @@ | ||
import AddIcon from "@mui/icons-material/Add"; | ||
import { Box, IconButton, Stack, Typography } from "@mui/material"; | ||
import {Box, IconButton, Stack, Typography} from "@mui/material"; | ||
import Tooltip from "@mui/material/Tooltip"; | ||
import { debounce } from "lodash"; | ||
import { useCallback, useState } from "react"; | ||
import { useGlobalContext } from "../../contexts/GlobalContext.tsx"; | ||
import type { Neuron } from "../../rest"; | ||
import { NeuronsService } from "../../rest"; | ||
import { vars } from "../../theme/variables.ts"; | ||
import {debounce} from "lodash"; | ||
import {useCallback, useState} from "react"; | ||
import {useGlobalContext} from "../../contexts/GlobalContext.tsx"; | ||
import type {Neuron} from "../../rest"; | ||
import {NeuronsService} from "../../rest"; | ||
import {vars} from "../../theme/variables.ts"; | ||
import CustomEntitiesDropdown from "./CustomEntitiesDropdown.tsx"; | ||
import CustomListItem from "./CustomListItem.tsx"; | ||
import {EnhancedNeuron} from "../../models/models.ts"; | ||
|
||
const { gray900, gray500 } = vars; | ||
const {gray900, gray500} = vars; | ||
const mapNeuronsToListItem = (neuron: string, isActive: boolean) => ({ | ||
id: neuron, | ||
label: neuron, | ||
checked: isActive, | ||
id: neuron, | ||
label: neuron, | ||
checked: isActive, | ||
}); | ||
const mapNeuronsAvailableNeuronsToOptions = (neuron: Neuron) => ({ | ||
id: neuron.name, | ||
label: neuron.name, | ||
content: [], | ||
id: neuron.name, | ||
label: neuron.name, | ||
content: [], | ||
}); | ||
|
||
const Neurons = ({ children }) => { | ||
const { workspaces, datasets, currentWorkspaceId } = useGlobalContext(); | ||
const currentWorkspace = workspaces[currentWorkspaceId]; | ||
const activeNeurons = currentWorkspace.activeNeurons; | ||
const allNeurons = currentWorkspace.allWorkspaceNeurons; | ||
const availableNeurons = currentWorkspace.availableNeurons; | ||
const Neurons = ({children}) => { | ||
const {workspaces, datasets, currentWorkspaceId} = useGlobalContext(); | ||
const currentWorkspace = workspaces[currentWorkspaceId]; | ||
const activeNeurons = currentWorkspace.activeNeurons; | ||
const recentNeurons = Object.values(currentWorkspace.availableNeurons).filter( | ||
(neuron) => neuron.isInteractant | ||
); | ||
const availableNeurons = currentWorkspace.availableNeurons; | ||
|
||
const [neurons, setNeurons] = useState(availableNeurons); | ||
const [neurons, setNeurons] = useState(availableNeurons); | ||
|
||
const handleSwitchChange = async (neuronId: string, checked: boolean) => { | ||
const neuron = availableNeurons[neuronId]; | ||
const handleSwitchChange = async (neuronId: string, checked: boolean) => { | ||
const neuron = availableNeurons[neuronId]; | ||
|
||
if (!neuron) return; | ||
if (checked) { | ||
await currentWorkspace.activateNeuron(neuron); | ||
} else { | ||
await currentWorkspace.deactivateNeuron(neuronId); | ||
} | ||
}; | ||
if (!neuron) return; | ||
if (checked) { | ||
await currentWorkspace.activateNeuron(neuron); | ||
} else { | ||
await currentWorkspace.deactivateNeuron(neuronId); | ||
} | ||
}; | ||
|
||
const onNeuronClick = (option) => { | ||
const neuron = availableNeurons[option.id]; | ||
if (neuron && !activeNeurons.has(option.id)) { | ||
currentWorkspace.activateNeuron(neuron); | ||
} else { | ||
currentWorkspace.deleteNeuron(option.id); | ||
} | ||
}; | ||
const handleDeleteNeuron = (neuronId: string) => { | ||
currentWorkspace.deleteNeuron(neuronId); | ||
}; | ||
const onNeuronClick = (option) => { | ||
const neuron = availableNeurons[option.id]; | ||
if (neuron && !activeNeurons.has(option.id)) { | ||
currentWorkspace.activateNeuron(neuron); | ||
} else { | ||
currentWorkspace.deleteNeuron(option.id); | ||
} | ||
}; | ||
const handleDeleteNeuron = (neuronId: string) => { | ||
currentWorkspace.deleteNeuron(neuronId); | ||
}; | ||
|
||
const fetchNeurons = async (name: string, datasetsIds: { id: string }[]) => { | ||
try { | ||
const Ids = datasetsIds.map((dataset) => dataset.id); | ||
const response = await NeuronsService.searchCells({ name: name, datasetIds: Ids }); | ||
const fetchNeurons = async (name: string, datasetsIds: { id: string }[]) => { | ||
try { | ||
const ids = datasetsIds.map((dataset) => dataset.id); | ||
const response = await NeuronsService.searchCells({name: name, datasetIds: ids}); | ||
|
||
// Convert the object to a Record<string, Neuron> | ||
const neuronsRecord = Object.entries(response).reduce((acc: Record<string, Neuron>, [_, neuron]: [string, Neuron]) => { | ||
acc[neuron.name] = neuron; | ||
return acc; | ||
}, {}); | ||
// Convert the object to a Record<string, Neuron> | ||
const neuronsRecord = Object.entries(response).reduce((acc: Record<string, EnhancedNeuron>, [_, neuron]: [string, EnhancedNeuron]) => { | ||
acc[neuron.name] = neuron; | ||
return acc; | ||
}, {}); | ||
|
||
setNeurons(neuronsRecord); | ||
} catch (error) { | ||
console.error("Failed to fetch datasets", error); | ||
} | ||
}; | ||
setNeurons(neuronsRecord); | ||
} catch (error) { | ||
console.error("Failed to fetch datasets", error); | ||
} | ||
}; | ||
|
||
const debouncedFetchNeurons = useCallback(debounce(fetchNeurons, 300), []); | ||
const debouncedFetchNeurons = useCallback(debounce(fetchNeurons, 300), []); | ||
|
||
const onSearchNeurons = (value) => { | ||
const datasetsIds = Object.keys(datasets); | ||
debouncedFetchNeurons(value, datasetsIds); | ||
}; | ||
const onSearchNeurons = (value) => { | ||
const datasetsIds = Object.keys(datasets); | ||
debouncedFetchNeurons(value, datasetsIds); | ||
}; | ||
|
||
const autoCompleteOptions = Object.values(neurons).map((neuron: Neuron) => mapNeuronsAvailableNeuronsToOptions(neuron)); | ||
const autoCompleteOptions = Object.values(neurons).map((neuron: Neuron) => mapNeuronsAvailableNeuronsToOptions(neuron)); | ||
|
||
return ( | ||
<Box | ||
sx={{ | ||
height: "100%", | ||
display: "flex", | ||
flexDirection: "column", | ||
}} | ||
> | ||
<Stack spacing=".25rem" p=".75rem" mb="1.5rem" pb="0"> | ||
<Typography variant="body1" component="p" color={gray900} fontWeight={500}> | ||
Neurons | ||
</Typography> | ||
return ( | ||
<Box | ||
sx={{ | ||
height: "100%", | ||
display: "flex", | ||
flexDirection: "column", | ||
}} | ||
> | ||
<Stack spacing=".25rem" p=".75rem" mb="1.5rem" pb="0"> | ||
<Typography variant="body1" component="p" color={gray900} fontWeight={500}> | ||
Neurons | ||
</Typography> | ||
|
||
<Typography variant="body1" component="p" color={gray500}> | ||
Search for the neurons and add it to your workspace. This will affect all viewers. | ||
</Typography> | ||
</Stack> | ||
{children} | ||
<CustomEntitiesDropdown | ||
options={autoCompleteOptions} | ||
activeNeurons={activeNeurons} | ||
onNeuronClick={onNeuronClick} | ||
onSearchNeurons={onSearchNeurons} | ||
setNeurons={setNeurons} | ||
availableNeurons={availableNeurons} | ||
/> | ||
<Box | ||
sx={{ | ||
height: "100%", | ||
overflow: "auto", | ||
flex: 1, | ||
}} | ||
> | ||
<Stack spacing=".5rem" p="0 .25rem" mt=".75rem"> | ||
<Box display="flex" alignItems="center" justifyContent="space-between" padding=".25rem .5rem"> | ||
<Typography color={gray500} variant="subtitle1"> | ||
All Neurons | ||
</Typography> | ||
<Tooltip title="Create new group"> | ||
<IconButton | ||
<Typography variant="body1" component="p" color={gray500}> | ||
Search for the neurons and add it to your workspace. This will affect all viewers. | ||
</Typography> | ||
</Stack> | ||
{children} | ||
<CustomEntitiesDropdown | ||
options={autoCompleteOptions} | ||
activeNeurons={activeNeurons} | ||
onNeuronClick={onNeuronClick} | ||
onSearchNeurons={onSearchNeurons} | ||
setNeurons={setNeurons} | ||
availableNeurons={availableNeurons} | ||
/> | ||
<Box | ||
sx={{ | ||
padding: ".25rem", | ||
borderRadius: ".25rem", | ||
height: "100%", | ||
overflow: "auto", | ||
flex: 1, | ||
}} | ||
> | ||
<AddIcon fontSize="medium" /> | ||
</IconButton> | ||
</Tooltip> | ||
</Box> | ||
{Array.from(allNeurons).map((neuronId) => ( | ||
<CustomListItem | ||
key={neuronId} | ||
data={mapNeuronsToListItem(neuronId, activeNeurons.has(neuronId))} | ||
showTooltip={false} | ||
showExtraActions={true} | ||
listType="neurons" | ||
onSwitchChange={handleSwitchChange} | ||
onDelete={handleDeleteNeuron} | ||
deleteTooltipTitle="Remove neuron from the workspace" | ||
/> | ||
))} | ||
</Stack> | ||
</Box> | ||
</Box> | ||
); | ||
> | ||
<Stack spacing=".5rem" p="0 .25rem" mt=".75rem"> | ||
<Box display="flex" alignItems="center" justifyContent="space-between" padding=".25rem .5rem"> | ||
<Typography color={gray500} variant="subtitle1"> | ||
All Neurons | ||
</Typography> | ||
<Tooltip title="Create new group"> | ||
<IconButton | ||
sx={{ | ||
padding: ".25rem", | ||
borderRadius: ".25rem", | ||
}} | ||
> | ||
<AddIcon fontSize="medium"/> | ||
</IconButton> | ||
</Tooltip> | ||
</Box> | ||
{Array.from(recentNeurons).map((neuron) => ( | ||
<CustomListItem | ||
key={neuron.name} | ||
data={mapNeuronsToListItem(neuron.name, activeNeurons.has(neuron.name))} | ||
showTooltip={false} | ||
showExtraActions={true} | ||
listType="neurons" | ||
onSwitchChange={handleSwitchChange} | ||
onDelete={handleDeleteNeuron} | ||
deleteTooltipTitle="Remove neuron from the workspace" | ||
/> | ||
))} | ||
</Stack> | ||
</Box> | ||
</Box> | ||
); | ||
}; | ||
|
||
export default Neurons; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.