-
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
1 parent
d989e4b
commit e3db63c
Showing
7 changed files
with
340 additions
and
349 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
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
250 changes: 124 additions & 126 deletions
250
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,153 +1,151 @@ | ||
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 type {EnhancedNeuron} from "../../models/models.ts"; | ||
import type { 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 recentNeurons = Object.values(currentWorkspace.availableNeurons).filter( | ||
(neuron) => neuron.isInteractant | ||
); | ||
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, EnhancedNeuron>, [_, neuron]: [string, EnhancedNeuron]) => { | ||
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 | ||
<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 | ||
sx={{ | ||
height: "100%", | ||
overflow: "auto", | ||
flex: 1, | ||
padding: ".25rem", | ||
borderRadius: ".25rem", | ||
}} | ||
> | ||
<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> | ||
); | ||
> | ||
<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.