Skip to content
Open
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
21 changes: 12 additions & 9 deletions applications/virtual-fly-brain/frontend/src/components/Layout.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import ErrorDialog from "./ErrorDialog";
import QueryBuilder from "./queryBuilder";
import MediaQuery from 'react-responsive';
import VFBUploader from "./VFBUploader/VFBUploader";
import VFBSnapshot from "./VFBSnapshot/VFBSnapshot";
import { useDispatch, useSelector, useStore } from 'react-redux';
import { widgets } from "./layout/widgets";
import VFBDownloadContents from "./VFBDownloadContents/VFBDownloadContents";
Expand Down Expand Up @@ -251,20 +252,22 @@ const MainLayout = ({ bottomNav, setBottomNav }) => {
{desktopScreen ? (
<>
{tabContent}
{bottomNav === 0 && < VFBUploader open={true} setBottomNav={setBottomNav} />}
{bottomNav === 1 && <VFBDownloadContents open={true} setBottomNav={setBottomNav} />}
{bottomNav === 2 && <QueryBuilder setBottomNav={setBottomNav} fullWidth={sidebarOpen} tabSelected={0}/>}
{bottomNav === 5 && <QueryBuilder setBottomNav={setBottomNav} fullWidth={sidebarOpen} tabSelected={1}/>}
{bottomNav === 0 && < VFBSnapshot open={true} setBottomNav={setBottomNav} />}
{bottomNav === 1 && < VFBUploader open={true} setBottomNav={setBottomNav} />}
{bottomNav === 2 && <VFBDownloadContents open={true} setBottomNav={setBottomNav} />}
{bottomNav === 3 && <QueryBuilder setBottomNav={setBottomNav} fullWidth={sidebarOpen} tabSelected={0}/>}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Move list-viewer trigger off the new Query ID

Query is remapped to bottomNav === 3 here, but Layout already has a side-effect on bottomNav === 3 that opens listViewerWidget and then resets bottomNav to undefined. After this change, clicking Query can immediately trigger the layer behavior and close the query panel, so the list-viewer side-effect should be moved to the new Layer ID.

Useful? React with 👍 / 👎.

Comment on lines +257 to +258
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Keep queryComponentOpened aligned with remapped IDs

With this remap, bottomNav === 2 now renders Download and Query moved to bottomNav === 3, but the queryComponentOpened effect in Layout still drives navigation to 2. When query-opening flows set that flag, users are taken to Download instead of QueryBuilder.

Useful? React with 👍 / 👎.

{bottomNav === 6 && <QueryBuilder setBottomNav={setBottomNav} fullWidth={sidebarOpen} tabSelected={1}/>}
</>
) : (
<>
{
bottomNav != 2 && tabContent
bottomNav != 3 && tabContent
}
{bottomNav === 0 && <VFBUploader open={true} setBottomNav={setBottomNav} />}
{bottomNav === 1 && <VFBDownloadContents open={true} setBottomNav={setBottomNav} />}
{bottomNav === 2 && <QueryBuilder setBottomNav={setBottomNav} fullWidth={sidebarOpen} tabSelected={0}/>}
{bottomNav === 5 && <QueryBuilder setBottomNav={setBottomNav} fullWidth={sidebarOpen} tabSelected={1}/>}
{bottomNav === 0 && <VFBSnapshot open={true} setBottomNav={setBottomNav} />}
{bottomNav === 1 && <VFBUploader open={true} setBottomNav={setBottomNav} />}
{bottomNav === 2 && <VFBDownloadContents open={true} setBottomNav={setBottomNav} />}
{bottomNav === 3 && <QueryBuilder setBottomNav={setBottomNav} fullWidth={sidebarOpen} tabSelected={0}/>}
{bottomNav === 6 && <QueryBuilder setBottomNav={setBottomNav} fullWidth={sidebarOpen} tabSelected={1}/>}
</>
)}
</Box>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import React, { useEffect } from "react";
import * as htmlToImage from "html-to-image";

const VFBSnapshot = ({ open, setBottomNav }) => {
useEffect(() => {
if (!open) return;

// screenshot flash effect
const flash = document.createElement("div");
flash.style.position = "fixed";
flash.style.left = 0;
flash.style.top = 0;
flash.style.width = "100vw";
flash.style.height = "100vh";
flash.style.background = "white";
flash.style.opacity = "0.7";
flash.style.zIndex = "2147483647";
flash.style.pointerEvents = "none";
flash.style.transition = "opacity 100ms";
document.body.appendChild(flash);

setTimeout(() => {
flash.style.opacity = "0";
setTimeout(() => { document.body.removeChild(flash); }, 120);
}, 100);

// Hide scrollbars and remove container max-height/overflow for all scrollable area
const selectors = [
".MuiBox-root",
".MuiPaper-root",
".scrollable",
".vfb-scrollable",
".subheader-content",
".VFBMainPanel",
];
const containers = Array.from(document.querySelectorAll(selectors.join(',')));

// Save previous styles so we can restore exactly
const previousStyles = containers.map(el => ({
el,
overflow: el.style.overflow,
overflowX: el.style.overflowX,
overflowY: el.style.overflowY,
maxHeight: el.style.maxHeight,
maxWidth: el.style.maxWidth,
}));

// Apply snapshot styles (no overflow, no artificial maxHeight/Width)
containers.forEach(el => {
el.style.overflow = "visible";
el.style.overflowX = "visible";
el.style.overflowY = "visible";
el.style.maxHeight = "unset";
el.style.maxWidth = "unset";
});

(async () => {
try {
const el = document.getElementById('root') || document.body;
const dataUrl = await htmlToImage.toPng(el, { cacheBust: true });
const link = document.createElement("a");
link.download = "vfb-snapshot.png";
link.href = dataUrl;
link.click();
} catch (err) {
console.error("[VFBSnapshot] Error capturing snapshot:", err);
}

// Restore overflow/maxHeight styles
previousStyles.forEach(({ el, overflow, overflowX, overflowY, maxHeight, maxWidth }) => {
el.style.overflow = overflow;
el.style.overflowX = overflowX;
el.style.overflowY = overflowY;
el.style.maxHeight = maxHeight;
el.style.maxWidth = maxWidth;
});

setBottomNav(undefined);
})();

return () => {
previousStyles.forEach(({ el, overflow, overflowX, overflowY, maxHeight, maxWidth }) => {
el.style.overflow = overflow;
el.style.overflowX = overflowX;
el.style.overflowY = overflowY;
el.style.maxHeight = maxHeight;
el.style.maxWidth = maxWidth;
});
};

}, [open, setBottomNav]);

return null;
};

export default VFBSnapshot;
18 changes: 18 additions & 0 deletions applications/virtual-fly-brain/frontend/src/icons/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,24 @@ export const Search = (props) => {
)
};

export const Screenshot = (props) => {
return (
<svg {...props} width={props.size || 21} height={props.size || 20} viewBox="0 0 21 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clipPath="url(#clip0_screenshot)">
<rect x="3.5" y="5" width="14" height="10" rx="2" stroke={props.color || "white"} strokeWidth="1.5" fill="none"/>
<circle cx="10.5" cy="10" r="2.5" stroke={props.color || "white"} strokeWidth="1.5" fill="none"/>
<rect x="7" y="4" width="1.5" height="2" rx=".5" fill={props.color || "white"} opacity="0.7"/>
<rect x="12.5" y="4" width="2" height="1.2" rx=".6" fill={props.color || "white"} opacity="0.7"/>
</g>
<defs>
<clipPath id="clip0_screenshot">
<rect width={props.size || 20} height={props.size || 20} fill={props.color || "white"} transform="translate(0.5)" />
</clipPath>
</defs>
</svg>
)
};

export const Upload = (props) => {
return (
<svg {...props} width={props.size || 21} height={props.size || 20} viewBox="0 0 21 20" fill="none" xmlns="http://www.w3.org/2000/svg">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,9 @@ import {
Layers,
Query,
Search,
Upload,
Upload
} from "../../icons";
import Screenshot from '@mui/icons-material/CameraAlt';
import vars from "../../theme/variables";
import MediaQuery from "react-responsive";
import { useDispatch, useSelector } from "react-redux";
Expand All @@ -25,31 +26,36 @@ import { resetLoadingState } from "../../reducers/actions/instances";
const navArr = [
{
id: 0,
icon: Screenshot,
name: "Screenshot",
},
{
id: 1,
icon: Upload,
name: "Upload",
},
{
id: 1,
id: 2,
icon: Download,
name: "Download",
},
{
id: 2,
id: 3,
icon: Query,
name: "Query",
},
{
id: 3,
id: 4,
icon: Layers,
name: "Layer",
},
{
id: 4,
id: 5,
icon: ClearAll,
name: "Clear all",
Comment on lines +48 to 55
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Rebind Clear all after shifting nav item IDs

This commit moves Layer to id: 4 and Clear all to id: 5, but the desktop handlers still treat 4 as the clear-all action (index === 4 in SubHeader and bottomNav === 4 in Layout). In the desktop toolbar, clicking Layer can now invoke removeAllInstances() and wipe loaded instances, while the new Clear all item (id 5) no longer triggers the clear-all effect.

Useful? React with 👍 / 👎.

},
{
id: 5,
id: 6,
icon: History,
name: "Recent",
},
Expand Down
Loading