Skip to content

Commit 96005cc

Browse files
committed
Feature: Add statistics banner displaying databases, datasets, subjects, links and size
1 parent 2197025 commit 96005cc

File tree

8 files changed

+578
-273
lines changed

8 files changed

+578
-273
lines changed

public/index.html

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,11 @@
4444
rel="stylesheet"
4545
/>
4646

47+
<!-- <link
48+
rel="stylesheet"
49+
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.2/css/all.min.css"
50+
/> -->
51+
4752
<title>NeuroJSON.io - Free Data Worth Sharing</title>
4853
</head>
4954
<body>
Lines changed: 257 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,257 @@
1+
import ContentPasteSearchIcon from "@mui/icons-material/ContentPasteSearch";
2+
import DatasetLinkedIcon from "@mui/icons-material/DatasetLinked";
3+
import PeopleAltIcon from "@mui/icons-material/PeopleAlt";
4+
import StorageIcon from "@mui/icons-material/Storage";
5+
import TopicIcon from "@mui/icons-material/Topic";
6+
import { Box, Typography } from "@mui/material";
7+
import axios from "axios";
8+
import { Colors } from "design/theme";
9+
import { useAppDispatch } from "hooks/useAppDispatch";
10+
import { useAppSelector } from "hooks/useAppSelector";
11+
import React, { useEffect } from "react";
12+
import { fetchDbStats } from "redux/neurojson/neurojson.action";
13+
import { DbStatsItem } from "redux/neurojson/types/neurojson.interface";
14+
import { RootState } from "redux/store";
15+
16+
// function for calculate links and size
17+
const calculateLinksAndSize = (dbStats: DbStatsItem[] | null) => {
18+
if (!dbStats) return { totalLinks: 0, totalSizeTB: "0.00" };
19+
20+
const filtered = dbStats.filter(
21+
(item) => item.view !== "dbinfo" && item.view !== "subjects"
22+
);
23+
24+
const totalLinks = filtered.reduce((acc, item) => acc + item.num, 0);
25+
const totalSizeBytes = filtered.reduce((acc, item) => acc + item.size, 0);
26+
const totalSizeTB = Math.floor(totalSizeBytes / 1024 ** 4);
27+
return { totalLinks, totalSizeTB };
28+
};
29+
30+
const StatisticsBanner: React.FC = () => {
31+
const dispatch = useAppDispatch();
32+
const dbstats = useAppSelector((state: RootState) => state.neurojson.dbStats);
33+
const registry = useAppSelector(
34+
(state: RootState) => state.neurojson.registry
35+
);
36+
37+
const databaseCount = registry?.length ?? "-";
38+
const datasetStat = dbstats?.find((item) => item.view === "dbinfo");
39+
const subjectStat = dbstats?.find((item) => item.view === "subjects");
40+
const { totalLinks, totalSizeTB } = calculateLinksAndSize(dbstats);
41+
42+
// format numbers with commas
43+
const formatNumber = (num: number | undefined) =>
44+
num?.toLocaleString() ?? "—";
45+
46+
useEffect(() => {
47+
dispatch(fetchDbStats());
48+
}, [dispatch]);
49+
50+
return (
51+
<Box
52+
sx={{
53+
backgroundColor: "rgba(0, 0, 0, 0.5)",
54+
borderRadius: "8px",
55+
backdropFilter: "blur(20px)",
56+
zIndex: 100,
57+
padding: "1rem 2rem",
58+
position: "absolute",
59+
bottom: "5%",
60+
left: "50%",
61+
transform: "translateX(-50%)",
62+
display: "flex",
63+
gap: "5rem",
64+
}}
65+
>
66+
{/* Databases */}
67+
<Box
68+
sx={{
69+
display: "flex",
70+
flexDirection: "row",
71+
alignItems: "center",
72+
}}
73+
>
74+
<StorageIcon
75+
sx={{
76+
marginRight: 1,
77+
verticalAlign: "middle",
78+
color: Colors.lightGray,
79+
// color: Colors.darkPurple,
80+
fontSize: "2.5rem",
81+
}}
82+
/>
83+
<Box>
84+
<Typography
85+
sx={{
86+
// color: Colors.darkPurple,
87+
color: Colors.green,
88+
fontWeight: "bold",
89+
textAlign: "center",
90+
fontSize: "1.4rem",
91+
}}
92+
>
93+
{databaseCount.toLocaleString()}
94+
</Typography>
95+
<Typography
96+
sx={{
97+
// color: Colors.darkPurple,
98+
color: Colors.lightGray,
99+
fontWeight: "medium",
100+
fontSize: "0.9rem",
101+
textAlign: "center",
102+
}}
103+
>
104+
Databases
105+
</Typography>
106+
</Box>
107+
</Box>
108+
109+
{/* Datasets */}
110+
<Box sx={{ display: "flex", flexDirection: "row", alignItems: "center" }}>
111+
<ContentPasteSearchIcon
112+
sx={{
113+
marginRight: 1,
114+
verticalAlign: "middle",
115+
// color: Colors.darkPurple,
116+
color: Colors.lightGray,
117+
fontSize: "2.5rem",
118+
}}
119+
/>
120+
<Box>
121+
<Typography
122+
sx={{
123+
// color: Colors.darkPurple,
124+
color: Colors.green,
125+
fontWeight: "bold",
126+
textAlign: "center",
127+
fontSize: "1.4rem",
128+
}}
129+
>
130+
{formatNumber(datasetStat?.num)}
131+
</Typography>
132+
<Typography
133+
sx={{
134+
// color: Colors.darkPurple,
135+
color: Colors.lightGray,
136+
fontWeight: "medium",
137+
fontSize: "0.9rem",
138+
textAlign: "center",
139+
}}
140+
>
141+
Datasets
142+
</Typography>
143+
</Box>
144+
</Box>
145+
{/* Subjects */}
146+
<Box sx={{ display: "flex", flexDirection: "row", alignItems: "center" }}>
147+
<PeopleAltIcon
148+
sx={{
149+
marginRight: 1,
150+
verticalAlign: "middle",
151+
// color: Colors.darkPurple,
152+
color: Colors.lightGray,
153+
fontSize: "2.5rem",
154+
}}
155+
/>
156+
<Box>
157+
<Typography
158+
sx={{
159+
// color: Colors.darkPurple,
160+
color: Colors.green,
161+
fontWeight: "bold",
162+
textAlign: "center",
163+
fontSize: "1.4rem",
164+
}}
165+
>
166+
{formatNumber(subjectStat?.num)}
167+
</Typography>
168+
<Typography
169+
sx={{
170+
// color: Colors.darkPurple,
171+
color: Colors.lightGray,
172+
fontWeight: "medium",
173+
fontSize: "0.9rem",
174+
textAlign: "center",
175+
}}
176+
>
177+
Subjects
178+
</Typography>
179+
</Box>
180+
</Box>
181+
{/* Links */}
182+
<Box sx={{ display: "flex", flexDirection: "row", alignItems: "center" }}>
183+
<DatasetLinkedIcon
184+
sx={{
185+
marginRight: 1,
186+
verticalAlign: "middle",
187+
// color: Colors.darkPurple,
188+
color: Colors.lightGray,
189+
fontSize: "2.5rem",
190+
}}
191+
/>
192+
<Box>
193+
<Typography
194+
sx={{
195+
// color: Colors.darkPurple,
196+
color: Colors.green,
197+
fontWeight: "bold",
198+
textAlign: "center",
199+
fontSize: "1.4rem",
200+
}}
201+
>
202+
{totalLinks.toLocaleString() ?? "-"}
203+
</Typography>
204+
<Typography
205+
sx={{
206+
// color: Colors.darkPurple,
207+
color: Colors.lightGray,
208+
fontWeight: "medium",
209+
fontSize: "0.9rem",
210+
textAlign: "center",
211+
}}
212+
>
213+
Links
214+
</Typography>
215+
</Box>
216+
</Box>
217+
{/* Size */}
218+
<Box sx={{ display: "flex", flexDirection: "row", alignItems: "center" }}>
219+
<TopicIcon
220+
sx={{
221+
marginRight: 1,
222+
verticalAlign: "middle",
223+
// color: Colors.darkPurple,
224+
color: Colors.lightGray,
225+
fontSize: "2.5rem",
226+
}}
227+
/>
228+
<Box>
229+
<Typography
230+
sx={{
231+
// color: Colors.darkPurple,
232+
color: Colors.green,
233+
fontWeight: "bold",
234+
textAlign: "center",
235+
fontSize: "1.4rem",
236+
}}
237+
>
238+
{totalSizeTB ?? "-"}&nbsp;TB
239+
</Typography>
240+
<Typography
241+
sx={{
242+
// color: Colors.darkPurple,
243+
color: Colors.lightGray,
244+
fontWeight: "medium",
245+
fontSize: "0.9rem",
246+
textAlign: "center",
247+
}}
248+
>
249+
Size
250+
</Typography>
251+
</Box>
252+
</Box>
253+
</Box>
254+
);
255+
};
256+
257+
export default StatisticsBanner;

src/modules/universe/NeuroJsonGraph.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,7 @@ const NeuroJsonGraph: React.FC<{
246246
});
247247

248248
Graph.d3Force("link")?.distance(100);
249+
Graph.cameraPosition({ z: 1000 }); // Adjust zoom level
249250

250251
// Initialize CSS2DRenderer for 2D labels
251252
const labelRenderer = new CSS2DRenderer();

src/pages/Home.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
} from "@mui/material";
99
import NodeInfoPanel from "components/NodeInfoPanel";
1010
import FilterMenu from "components/NodesFilter/FilterMenu";
11+
import StatisticsBanner from "components/StatisticsBanner";
1112
import { Colors } from "design/theme";
1213
import { useAppDispatch } from "hooks/useAppDispatch";
1314
import { useAppSelector } from "hooks/useAppSelector";
@@ -184,6 +185,7 @@ const Home: React.FC = () => {
184185
onClose={() => setPanelOpen(false)}
185186
nodeData={selectedNode}
186187
/>
188+
<StatisticsBanner />
187189
</Container>
188190
);
189191
};

0 commit comments

Comments
 (0)