Skip to content
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
7 changes: 3 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,7 @@
]
},
"resolutions": {
"postcss": "^8.4.31",
"nth-check": "^2.0.1"
}

"postcss": "^8.4.31",
"nth-check": "^2.0.1"
}
}
221 changes: 221 additions & 0 deletions src/components/NodeInfoPanel.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,221 @@
import React, { useEffect } from "react";
import { Box, Typography, IconButton, Drawer, Grid, Card, CardContent, CardActions, Button } from "@mui/material";
import CloseIcon from "@mui/icons-material/Close";
import { NodeObject } from "modules/universe/NeuroJsonGraph";
import { Colors} from "design/theme";
import { useNavigate } from "react-router-dom";
import { useAppDispatch } from "hooks/useAppDispatch";
import { useAppSelector } from "hooks/useAppSelector";
import { RootState } from "redux/store";
import { fetchDbInfo } from "redux/neurojson/neurojson.action";


interface NodeInfoPanelProps {
open: boolean;
onClose: () => void;
nodeData: NodeObject | null;
}

// helper function to covert the database size format
const formatSize = (bytes?: number): string =>{
if (bytes === undefined) return "N/A";
if (bytes >= 1_073_741_824) {
return `${Math.floor(bytes / 1_073_741_824)} Gb`;
} else if (bytes >= 1_048_576) {
return `${Math.floor(bytes / 1_048_576)} Mb`;
} else if (bytes >= 1024) {
return `${Math.floor(bytes / 1024)} Kb`;
} else {
return `${bytes} Bytes`;
}
};

// 1 Kilobyte (KB) = 1,024 Bytes
// 1 Megabyte (MB) = 1,024 KB = 1,048,576 Bytes (1024*1024)
// 1 Gigabyte (GB) = 1,024 MB = 1,073,741,824 Bytes (1024*1024*1024)

const NodeInfoPanel: React.FC<NodeInfoPanelProps> = ({ open, onClose, nodeData }) => {
const navigate = useNavigate();
const dispatch = useAppDispatch();
const dbInfo = useAppSelector((state: RootState) => state.neurojson.dbInfo);
const loading = useAppSelector((state: RootState) => state.neurojson.loading);
console.log("dbInfo", dbInfo);

useEffect(() => {
if (nodeData?.id) {
dispatch(fetchDbInfo(nodeData.id.toLowerCase()));
}
}, [nodeData, dispatch])

return (
<Drawer
anchor="right"
open={open}
onClose={onClose}
container={document.body}
sx={{
"& .MuiDrawer-paper": {
width: "30%",
padding: "1rem",
backgroundColor: Colors.lightGray,
boxShadow: "-2px 0 8px rgba(0, 0, 0, 0.2)",
},
}}
>
<Box>
{nodeData? (
<>
{/* Close Button */}
<Box display="flex" justifyContent="space-between" alignItems="center">
<Typography variant="h6" sx={{color: Colors.primary.dark}}>{nodeData.name}</Typography>
<IconButton onClick={onClose} sx={{color: Colors.primary.main}}>
<CloseIcon />
</IconButton>
</Box>
{/* Node Metadata */}
<Grid container spacing={2}>
<Grid item xs={12}>
<Typography>Website</Typography>
<Typography>
<a href={nodeData.url} target="_blank">{nodeData.url}</a>
</Typography>
</Grid>

<Grid item xs={12}>
<Typography>Number of Datasets</Typography>
<Typography>{nodeData.datasets}</Typography>
</Grid>

<Grid item xs={12}>
<Typography>Data Types</Typography>
<Typography>{nodeData.datatype.join(", ")}</Typography>
</Grid>

<Grid item xs={12}>
<Typography>Data Standards</Typography>
<Typography>{nodeData.standard.join(", ")}</Typography>
</Grid>

<Grid item xs={12}>
<Typography>Upstream Contact</Typography>
<a href={`mailto:${nodeData.support}`} style={{ textDecoration: "none", color: "blue"}}>
<Typography>{nodeData.support}</Typography>
</a>
</Grid>

<Grid item xs={12}>
<Typography>NeuroJSON-Cuated Datasets</Typography>
{dbInfo?(<Typography>{dbInfo.doc_count - 1}</Typography>) : "Coming soon "}
</Grid>
</Grid>
{/*database info card*/}
{dbInfo? (
<Card sx={{ mt:2, backgroundColor: Colors.white }}>
<CardContent>
<Grid container spacing={1}>
<Grid item xs={12}>
<Typography>NeuroJSON.io Database Name</Typography>
<Typography>{dbInfo.db_name}</Typography>
</Grid>
<Grid item xs={12}>
<Typography>REST-API URL</Typography>
<a href={`https://neurojson.io:7777/${dbInfo.db_name}`} target="_blank" rel="noopener noreferrer">
{`https://neurojson.io:7777/${dbInfo.db_name}`}
</a>
</Grid>
<Grid item xs={12}>
<Typography>Database Creation Time</Typography>
<Typography></Typography>
</Grid>
<Grid item xs={12}>
<Typography>Searchable Database Size</Typography>
<Typography>{formatSize(dbInfo.sizes?.external)}</Typography>
</Grid>
<Grid item xs={12}>
<Typography>DatabaseDisk Size (compressed)</Typography>
<Typography>{formatSize(dbInfo.sizes?.file)}</Typography>
</Grid>
</Grid>
</CardContent>
<CardActions>
<Grid container direction="column" spacing={1}>
<Grid item xs={12}>
<Button
variant="contained"
fullWidth
sx={{
backgroundColor: Colors.primary.main,
color: Colors.white,
"&:hover": {
backgroundColor: Colors.primary.dark,
},
}}
onClick={() => navigate(`/databases/${nodeData.id}`)}
>
Browse Database
</Button>
</Grid>
<Grid item xs={12}>
<Button
variant="contained"
fullWidth
sx={{
backgroundColor: Colors.primary.main,
color: Colors.white,
"&:hover": {
backgroundColor: Colors.primary.dark,
},
}}
>
Search Subjects
</Button>
</Grid>
<Grid item xs={12}>
<Button
variant="contained"
fullWidth
sx={{
backgroundColor: Colors.primary.main,
color: Colors.white,
"&:hover": {
backgroundColor: Colors.primary.dark,
},
}}
>
Advanced Search
</Button>
</Grid>
<Grid item xs={12}>
<Button
variant="contained"
fullWidth
sx={{
backgroundColor: Colors.primary.main,
color: Colors.white,
"&:hover": {
backgroundColor: Colors.primary.dark,
},
}}
onClick={() => window.open(`https://github.com/NeuroJSON-io/${nodeData.id}`, "_blank", "noopener noreferrer")}
>
DownLoad Database
</Button>
</Grid>
</Grid>
</CardActions>

</Card>
) : (
<Typography>Select a node to see database info.</Typography>
)}

</>
) : (
<Typography>Select a node to see database info.</Typography>
)}
</Box>
</Drawer>
)
};

export default NodeInfoPanel;
9 changes: 7 additions & 2 deletions src/modules/universe/NeuroJsonGraph.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,10 @@ export interface NodeObject {
support: string;
url: string;
datasets: number;
standard: string[]; // define type of standard property
}

const NeuroJsonGraph: React.FC<{ registry: Database[] }> = ({ registry }) => {
const NeuroJsonGraph: React.FC<{ registry: Database[], onNodeClick?: (node: NodeObject) => void }> = ({ registry, onNodeClick }) => {
const navigate = useNavigate();
const graphRef = useRef<HTMLDivElement>(null);

Expand Down Expand Up @@ -57,6 +58,7 @@ const NeuroJsonGraph: React.FC<{ registry: Database[] }> = ({ registry }) => {
url: db.url,
datasets: db.datasets,
size: size,
standard: db.standard || [],// add standard property
};
}),
links: registry.flatMap((db, index) => {
Expand Down Expand Up @@ -87,7 +89,10 @@ const NeuroJsonGraph: React.FC<{ registry: Database[] }> = ({ registry }) => {
})
.onNodeClick((node) => {
const castNode = node as NodeObject;
navigate(`/databases/${castNode.id}`);
if (onNodeClick) {
onNodeClick(castNode);
}
// navigate(`/databases/${castNode.id}`);
})
.nodeThreeObject((node) => {
const castNode = node as NodeObject;
Expand Down
18 changes: 16 additions & 2 deletions src/pages/Home.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,32 @@ import { Colors } from "design/theme";
import { useAppDispatch } from "hooks/useAppDispatch";
import { useAppSelector } from "hooks/useAppSelector";
import NeuroJsonGraph from "modules/universe/NeuroJsonGraph";
import React, { useEffect } from "react";
import React, { useEffect, useState } from "react";
import { useNavigate } from "react-router-dom";
import { fetchRegistry } from "redux/neurojson/neurojson.action";
import { NeurojsonSelector } from "redux/neurojson/neurojson.selector";
import NodeInfoPanel from "components/NodeInfoPanel";
import { NodeObject } from "modules/universe/NeuroJsonGraph";

const Home: React.FC = () => {
const navigate = useNavigate();
const dispatch = useAppDispatch();
const { registry, loading } = useAppSelector(NeurojsonSelector);

// State for selected node and panel visibility
const [selectedNode, setSelectedNode] = useState<NodeObject | null>(null);
const [panelOpen, setPanelOpen] = useState(false);

useEffect(() => {
dispatch(fetchRegistry());
}, [dispatch]);

// Handle node click: Set selected node and open panel
const handleNodeClick = (node: NodeObject) => {
setSelectedNode(node);
setPanelOpen(true);
};

return (
<Container
style={{
Expand All @@ -47,7 +59,7 @@ const Home: React.FC = () => {
<CircularProgress sx={{ color: Colors.primary.main }} />
</Box>
) : registry && registry.length > 0 ? (
<NeuroJsonGraph registry={registry} />
<NeuroJsonGraph registry={registry} onNodeClick={handleNodeClick} />
) : (
<Box sx={{ textAlign: "center", mt: 4 }}>
<Typography variant="h6" color={Colors.textSecondary}>
Expand Down Expand Up @@ -101,6 +113,8 @@ const Home: React.FC = () => {
</Button>
</Box>
</Box>

<NodeInfoPanel open={panelOpen} onClose={() => setPanelOpen(false)} nodeData={selectedNode} />
</Container>
);
};
Expand Down
2 changes: 2 additions & 0 deletions src/redux/neurojson/neurojson.slice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ const initialState: INeuroJsonState = {
limit: 100,
hasMore: true,
registry: null,
dbInfo: null, // add dbInfo in neurojson.interface.ts
};

const neurojsonSlice = createSlice({
Expand Down Expand Up @@ -124,6 +125,7 @@ const neurojsonSlice = createSlice({
})
.addCase(fetchDbInfo.fulfilled, (state, action: PayloadAction<any>) => {
state.loading = false;
state.dbInfo = action.payload; // store database info in Redux
})
.addCase(fetchDbInfo.rejected, (state, action) => {
state.loading = false;
Expand Down
1 change: 1 addition & 0 deletions src/redux/neurojson/types/neurojson.interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export interface INeuroJsonState {
offset: number;
limit: number;
hasMore: boolean;
dbInfo: DBParticulars | null; // add dbInfo type
}

export interface DBParticulars {
Expand Down
Loading