Skip to content

Commit 59ee25c

Browse files
authored
Merge pull request #225 from MetaCell/feature/VFB-240
VFB-240 - Change the datasource for the NG widget to file serve here Index of /data/VFB/i/
2 parents ff67b2e + c651534 commit 59ee25c

11 files changed

Lines changed: 270 additions & 100 deletions

File tree

applications/virtual-fly-brain/frontend/src/components/Layout.jsx

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import { removeAllInstances } from './../reducers/actions/instances';
1818
import { Box, Button,Modal, useMediaQuery, useTheme, Typography, CircularProgress, Link } from "@mui/material";
1919
import { activateCircuits, activateImages } from "../reducers/actions/layout";
2020
import { widgetsIDs } from "./layout/widgets";
21+
import { bottomNavClearAll, bottomNavDownload, bottomNavLayers, bottomNavQuery, bottomNavSearch, bottomNavSnapshot, bottomNavUpload } from "../utils/constants";
2122

2223
const {
2324
secondaryBg,
@@ -80,14 +81,14 @@ const MainLayout = ({ bottomNav, setBottomNav }) => {
8081
const queryComponentOpened = useSelector( state => state.globalInfo?.queryComponentOpened );
8182

8283
useEffect( () => {
83-
if ( queryComponentOpened && bottomNav !== 2 ){
84-
setBottomNav(2)
84+
if ( queryComponentOpened && bottomNav !== bottomNavQuery ){
85+
setBottomNav(bottomNavQuery)
8586
}
8687
}, [bottomNav, queryComponentOpened, setBottomNav]);
8788

8889
// Handle Clear All functionality
8990
useEffect(() => {
90-
if (bottomNav === 4) {
91+
if (bottomNav === bottomNavClearAll) {
9192
if (allLoadedInstances?.length > 1) {
9293
removeAllInstances();
9394
}
@@ -97,7 +98,7 @@ const MainLayout = ({ bottomNav, setBottomNav }) => {
9798
}, [bottomNav, allLoadedInstances?.length, setBottomNav]);
9899

99100
useEffect( () => {
100-
if ( bottomNav === 3 ){
101+
if ( bottomNav === bottomNavLayers ){
101102
const layoutManager = getLayoutManagerInstance();
102103
if (!layoutManager.model.getNodeById("listViewerWidget").isVisible()) {
103104
const newWidget = { ...widgets[widgetsIDs.listViewerWidgetID] }
@@ -252,22 +253,22 @@ const MainLayout = ({ bottomNav, setBottomNav }) => {
252253
{desktopScreen ? (
253254
<>
254255
{tabContent}
255-
{bottomNav === 0 && < VFBSnapshot open={true} setBottomNav={setBottomNav} />}
256-
{bottomNav === 1 && < VFBUploader open={true} setBottomNav={setBottomNav} />}
257-
{bottomNav === 2 && <VFBDownloadContents open={true} setBottomNav={setBottomNav} />}
258-
{bottomNav === 3 && <QueryBuilder setBottomNav={setBottomNav} fullWidth={sidebarOpen} tabSelected={0}/>}
259-
{bottomNav === 6 && <QueryBuilder setBottomNav={setBottomNav} fullWidth={sidebarOpen} tabSelected={1}/>}
256+
{bottomNav === bottomNavSnapshot && < VFBSnapshot open={true} setBottomNav={setBottomNav} />}
257+
{bottomNav === bottomNavUpload && < VFBUploader open={true} setBottomNav={setBottomNav} />}
258+
{bottomNav === bottomNavDownload && <VFBDownloadContents open={true} setBottomNav={setBottomNav} />}
259+
{bottomNav === bottomNavQuery && <QueryBuilder setBottomNav={setBottomNav} fullWidth={sidebarOpen} tabSelected={0}/>}
260+
{bottomNav === bottomNavSearch && <QueryBuilder setBottomNav={setBottomNav} fullWidth={sidebarOpen} tabSelected={1}/>}
260261
</>
261262
) : (
262263
<>
263264
{
264-
bottomNav != 3 && tabContent
265+
bottomNav != bottomNavQuery && tabContent
265266
}
266-
{bottomNav === 0 && <VFBSnapshot open={true} setBottomNav={setBottomNav} />}
267-
{bottomNav === 1 && <VFBUploader open={true} setBottomNav={setBottomNav} />}
268-
{bottomNav === 2 && <VFBDownloadContents open={true} setBottomNav={setBottomNav} />}
269-
{bottomNav === 3 && <QueryBuilder setBottomNav={setBottomNav} fullWidth={sidebarOpen} tabSelected={0}/>}
270-
{bottomNav === 6 && <QueryBuilder setBottomNav={setBottomNav} fullWidth={sidebarOpen} tabSelected={1}/>}
267+
{bottomNav === bottomNavSnapshot && <VFBSnapshot open={true} setBottomNav={setBottomNav} />}
268+
{bottomNav === bottomNavUpload && <VFBUploader open={true} setBottomNav={setBottomNav} />}
269+
{bottomNav === bottomNavDownload && <VFBDownloadContents open={true} setBottomNav={setBottomNav} />}
270+
{bottomNav === bottomNavQuery && <QueryBuilder setBottomNav={setBottomNav} fullWidth={sidebarOpen} tabSelected={0}/>}
271+
{bottomNav === bottomNavSearch && <QueryBuilder setBottomNav={setBottomNav} fullWidth={sidebarOpen} tabSelected={1}/>}
271272
</>
272273
)}
273274
</Box>

applications/virtual-fly-brain/frontend/src/components/NeuroglassViewer.jsx

Lines changed: 39 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React, { useState, useEffect, useMemo } from 'react';
1+
import React, { useState, useEffect } from 'react';
22
import { useSelector } from 'react-redux';
33
import { Box, Typography, useMediaQuery } from '@mui/material';
44
import { useTheme } from '@mui/material/styles';
@@ -8,6 +8,7 @@ const NEUROGLASS_URL = import.meta.env.NEUROGLASS_URL ?? '';
88

99
export default function NeuroglassViewer() {
1010
const [debouncedSrc, setDebouncedSrc] = useState('');
11+
const [iframeSrc, setIframeSrc] = useState('');
1112

1213
const allLoadedInstances = useSelector(state => state.instances?.allLoadedInstances);
1314
const focusedInstance = useSelector(state => state.instances?.focusedInstance);
@@ -16,16 +17,43 @@ export default function NeuroglassViewer() {
1617
const theme = useTheme();
1718
const isMobile = !useMediaQuery(theme.breakpoints.up('lg'));
1819

19-
// Rebuilds whenever instances, focused item, layout preference, or viewport size changes.
20-
const iframeSrc = useMemo(() => {
21-
const layout = resolveNeuroglassLayout(neuroglassView, isMobile);
22-
const state = buildNeuroglassState(
23-
allLoadedInstances,
24-
focusedInstance?.metadata?.Id,
25-
layout,
26-
);
27-
if (!state || !NEUROGLASS_URL) return '';
28-
return `${NEUROGLASS_URL}/embed#!${encodeURIComponent(JSON.stringify(state))}`;
20+
useEffect(() => {
21+
let cancelled = false;
22+
const abortController = new AbortController();
23+
async function buildSrc() {
24+
const layout = resolveNeuroglassLayout(neuroglassView, isMobile);
25+
try{
26+
const state = await buildNeuroglassState(
27+
allLoadedInstances,
28+
focusedInstance?.metadata?.Id,
29+
layout,
30+
abortController.signal
31+
);
32+
33+
if (cancelled || abortController.signal.aborted) return;
34+
35+
if (!state || !NEUROGLASS_URL) {
36+
setIframeSrc('');
37+
return;
38+
}
39+
40+
setIframeSrc(
41+
`${NEUROGLASS_URL}/embed#!${encodeURIComponent(JSON.stringify(state))}`
42+
);
43+
} catch (error) {
44+
if (error?.name === 'AbortError' || abortController.signal.aborted) {
45+
return;
46+
}
47+
throw error;
48+
}
49+
}
50+
51+
buildSrc();
52+
53+
return () => {
54+
cancelled = true;
55+
abortController.abort();
56+
};
2957
}, [allLoadedInstances, focusedInstance?.metadata?.Id, neuroglassView, isMobile]);
3058

3159
useEffect(() => {

applications/virtual-fly-brain/frontend/src/components/configuration/VFBToolbar/vfbtoolbarMenuConfiguration.jsx

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import React from 'react';
22
import vars from "../../../theme/variables";
33
import { widgets } from "../../layout/widgets";
4+
import { bottomNavDownload, bottomNavQuery, bottomNavSearch, bottomNavUpload } from '../../../utils/constants';
45
const { primaryFont, whiteColor, tabActiveColor, primaryBg } = vars;
56

67
const ACTIONS = {
@@ -199,15 +200,15 @@ export const toolbarMenu = (autoSaveLayout) => { return {
199200
icon: "fa fa-search",
200201
action: {
201202
handlerAction: ACTIONS.SHOW_COMPONENT,
202-
parameters: [5]
203+
parameters: [bottomNavSearch]
203204
}
204205
},
205206
{
206207
label: "Query",
207208
icon: "fa fa-clipboard-question",
208209
action: {
209210
handlerAction: ACTIONS.SHOW_COMPONENT,
210-
parameters: [2]
211+
parameters: [bottomNavQuery]
211212
}
212213
},
213214
{
@@ -279,15 +280,15 @@ export const toolbarMenu = (autoSaveLayout) => { return {
279280
icon: "fa fa-download",
280281
action: {
281282
handlerAction: ACTIONS.SHOW_COMPONENT,
282-
parameters: [1]
283+
parameters: [bottomNavDownload]
283284
}
284285
},
285286
{
286287
label: "NBLAST Uploader",
287288
icon: "fa fa-upload",
288289
action: {
289290
handlerAction: ACTIONS.SHOW_COMPONENT,
290-
parameters: [0]
291+
parameters: [bottomNavUpload]
291292
}
292293
},
293294
{

applications/virtual-fly-brain/frontend/src/components/queryBuilder/Query.jsx

Lines changed: 41 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -26,15 +26,15 @@ const getQueries = (newQueries, searchTerm) => {
2626
if (!newQueries || newQueries.length === 0) return [];
2727

2828
let updatedQueries = [];
29-
const term = searchTerm ? searchTerm.toLowerCase() : undefined;
29+
const term = searchTerm ? searchTerm.toLowerCase() : "";
3030

3131
newQueries.forEach((query) => {
3232
if (query.queries) {
3333
Object.keys(query.queries).forEach((key) => {
3434
if (query.queries[key]?.active) {
35-
let rows = query.queries[key]?.rows || [];
35+
let rows = query.queries[key]?.rows || query.queries[key]?.preview_results?.rows || [];
3636

37-
if (term) {
37+
if (term != undefined) {
3838
rows = rows.filter(row => {
3939
// Cache the string conversion for performance
4040
const values = Object.values(row);
@@ -95,20 +95,41 @@ const Query = forwardRef(({ fullWidth, queries, searchTerm }, ref) => {
9595
const [sortDirection, setSortDirection] = useState(1); // 1 for ascending, -1 for descending
9696

9797
// Memoize filtered searches
98-
const filteredSearches = useMemo(() => getQueries(queries, searchTerm), [queries, searchTerm]);
98+
const filteredSearches = useMemo(() => {
99+
return getQueries(queries, searchTerm);
100+
}, [queries, searchTerm]);
101+
102+
const getRows = (item) => {
103+
if (item?.rows?.length > 0) {
104+
return item.rows;
105+
}
106+
107+
if (item?.preview_results?.rows?.length > 0) {
108+
return item.preview_results.rows;
109+
}
110+
111+
return null;
112+
};
99113

100114
// Memoize the final filtered results based on both search term and active chip tags
101115
const finalFilteredResults = useMemo(() => {
102116
if (!filteredSearches || filteredSearches.length === 0) return [];
103117

104-
const activeChipLabels = chipTags.filter(f => f.active).map(tag => tag.label);
118+
const rows = filteredSearches.flatMap(item => {
119+
const nestedRows = getRows(item);
120+
return nestedRows || [item];
121+
});
105122

106-
// Filter by active chip tags
123+
const activeChipLabels = chipTags
124+
.filter(f => f.active)
125+
.map(tag => tag.label);
126+
107127
let filtered;
128+
108129
if (activeChipLabels.length === 0) {
109-
filtered = filteredSearches;
130+
filtered = rows;
110131
} else {
111-
filtered = filteredSearches.filter(row => {
132+
filtered = rows.filter(row => {
112133
const tags = getTags(row.tags);
113134
return activeChipLabels.some(label => tags.includes(label));
114135
});
@@ -146,13 +167,22 @@ const Query = forwardRef(({ fullWidth, queries, searchTerm }, ref) => {
146167
if (!queries || queries.length === 0) return [];
147168

148169
const tagMap = new Map();
170+
149171
queries.forEach(query => {
150172
if (query.queries) {
151173
Object.keys(query.queries).forEach(q => {
152-
if (query.queries[q]?.active) {
153-
query.queries[q]?.rows?.forEach(row => {
174+
const currentQuery = query.queries[q];
175+
176+
if (currentQuery?.active) {
177+
const rows =
178+
currentQuery?.rows?.length > 0
179+
? currentQuery.rows
180+
: currentQuery?.preview_results?.rows || [];
181+
182+
rows.forEach(row => {
154183
if (row.tags) {
155184
const rowTags = getTags(row.tags);
185+
156186
rowTags.forEach(rowTag => {
157187
if (!tagMap.has(rowTag)) {
158188
tagMap.set(rowTag, { label: rowTag, active: true });
@@ -343,7 +373,7 @@ const Query = forwardRef(({ fullWidth, queries, searchTerm }, ref) => {
343373
onClick={() => null}
344374
disabled={!tag.active}
345375
onDelete={() => handleChipDelete(tag.label)}
346-
key={tag}
376+
key={tag?.label}
347377
deleteIcon={
348378
<Cross
349379
size={12}

applications/virtual-fly-brain/frontend/src/shared/bottomNav/index.jsx

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { Box, Button } from "@mui/material";
33
import React from "react";
44
import { ClearAll, Download, Query, Upload, Layers } from "../../icons";
55
import vars from "../../theme/variables";
6+
import { bottomNavClearAll, bottomNavDownload, bottomNavQuery, bottomNavSnapshot } from "../../utils/constants";
67

78
const {
89
whiteColor,
@@ -12,22 +13,22 @@ const {
1213

1314
const navArr = [
1415
{
15-
id: 0,
16+
id: bottomNavSnapshot,
1617
icon: Upload,
1718
name: 'Upload'
1819
},
1920
{
20-
id: 1,
21+
id: bottomNavDownload,
2122
icon: Download,
2223
name: 'Download'
2324
},
2425
{
25-
id: 2,
26+
id: bottomNavQuery,
2627
icon: Query,
2728
name: 'Query'
2829
},
2930
{
30-
id: 3,
31+
id: bottomNavClearAll,
3132
icon: ClearAll,
3233
name: 'Clear all'
3334
},
@@ -72,7 +73,7 @@ const BottomNav = ({ setBottomNav, bottomNav }) => {
7273
flexWrap='wrap'
7374
sx={classes.root}
7475
>
75-
{navArr.map((item, index) => (
76+
{navArr.map((item) => (
7677
<Button
7778
sx={{
7879
height: '100%',
@@ -83,7 +84,7 @@ const BottomNav = ({ setBottomNav, bottomNav }) => {
8384
flexDirection: 'column',
8485
}}
8586

86-
onClick={() => setBottomNav(index)}
87+
onClick={() => setBottomNav(item?.id)}
8788
key={item.id}
8889
>
8990
<item.icon color={item?.id === bottomNav ? tabActiveColor : 'white'} />

applications/virtual-fly-brain/frontend/src/shared/header/index.jsx

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import layout2 from "../../components/layout/layout2";
1717
import layout3 from "../../components/layout/layout3";
1818
import { WidgetStatus } from "@metacell/geppetto-meta-client/common/layout/model";
1919
import { getLayoutManagerInstance } from "@metacell/geppetto-meta-client/common/layout/LayoutManager";
20+
import { bottomNavQuery } from "../../utils/constants";
2021

2122
const { primaryBg, headerBoxShadow } = vars;
2223

@@ -68,7 +69,7 @@ const Header = ({ setBottomNav }) => {
6869
}
6970

7071
// Open the query component panel
71-
setBottomNav(2);
72+
setBottomNav(bottomNavQuery);
7273
}
7374
}
7475

@@ -140,13 +141,13 @@ const Header = ({ setBottomNav }) => {
140141
Object.keys(query.queries)?.forEach(q => query.queries[q].active = false);
141142
}
142143
});
143-
if (matchQuery?.queries?.[action?.parameters[1]]) {
144-
matchQuery.queries[action.parameters[1]].active = true;
144+
if (matchQuery?.short_form == action?.parameters[0]) {
145+
Object.keys(matchQuery.queries)?.forEach(q => matchQuery.queries[q].active = true);
145146
updateQueries(updatedQueries);
146-
setBottomNav(2)
147+
setBottomNav(bottomNavQuery)
147148
} else {
148149
getQueries(action.parameters[0], action.parameters[1])
149-
setBottomNav(2)
150+
setBottomNav(bottomNavQuery)
150151
}
151152
break;
152153
}
@@ -310,7 +311,7 @@ const Header = ({ setBottomNav }) => {
310311
<MediaQuery minWidth={1200}>
311312
{focusedInstance?.metadata?.Id && (focusedInstance?.metadata?.Queries?.length > 0 || queries?.find(q => q.short_form === focusedInstance.metadata.Id)) && (
312313
<Button
313-
onClick={() => setBottomNav((prev) => prev === 2 ? null : 2)}
314+
onClick={() => setBottomNav((prev) => prev === bottomNavQuery ? null : bottomNavQuery)}
314315
variant="outlined"
315316
>
316317
<QueryStats size={16} />

0 commit comments

Comments
 (0)