Added Tooltips and Misc Fixes

This commit is contained in:
2025-05-01 00:51:05 -06:00
parent cf14ee0111
commit a6f40d2502
8 changed files with 543 additions and 459 deletions

View File

@ -6,10 +6,10 @@ import React, {
useEffect, useEffect,
useCallback, useCallback,
useRef useRef
} from "react"; } from "react";
// Material UI - Components // Material UI - Components
import { import {
AppBar, AppBar,
Toolbar, Toolbar,
Typography, Typography,
@ -20,54 +20,54 @@ import React, {
CssBaseline, CssBaseline,
ThemeProvider, ThemeProvider,
createTheme createTheme
} from "@mui/material"; } from "@mui/material";
// Material UI - Icons // Material UI - Icons
import { import {
KeyboardArrowDown as KeyboardArrowDownIcon, KeyboardArrowDown as KeyboardArrowDownIcon,
InfoOutlined as InfoOutlinedIcon, InfoOutlined as InfoOutlinedIcon,
MergeType as MergeTypeIcon, MergeType as MergeTypeIcon,
People as PeopleIcon People as PeopleIcon
} from "@mui/icons-material"; } from "@mui/icons-material";
// React Flow // React Flow
import { ReactFlowProvider } from "reactflow"; import { ReactFlowProvider } from "reactflow";
// Styles // Styles
import "reactflow/dist/style.css"; import "reactflow/dist/style.css";
// Import Borealis Modules // Import Borealis Modules
import FlowTabs from "./Flow_Tabs"; import FlowTabs from "./Flow_Tabs";
import FlowEditor from "./Flow_Editor"; import FlowEditor from "./Flow_Editor";
import NodeSidebar from "./Node_Sidebar"; import NodeSidebar from "./Node_Sidebar";
import { import {
CloseAllDialog, CloseAllDialog,
CreditsDialog, CreditsDialog,
RenameTabDialog, RenameTabDialog,
TabContextMenu TabContextMenu
} from "./Dialogs"; } from "./Dialogs";
import StatusBar from "./Status_Bar"; import StatusBar from "./Status_Bar";
// Websocket Functionality // Websocket Functionality
import { io } from "socket.io-client"; import { io } from "socket.io-client";
if (!window.BorealisSocket) { if (!window.BorealisSocket) {
window.BorealisSocket = io(window.location.origin, { window.BorealisSocket = io(window.location.origin, {
transports: ["websocket"] transports: ["websocket"]
}); });
} }
// Global Node Update Timer Variable // Global Node Update Timer Variable
if (!window.BorealisUpdateRate) { if (!window.BorealisUpdateRate) {
window.BorealisUpdateRate = 200; window.BorealisUpdateRate = 200;
} }
// Dynamically load all node components via Vite // Dynamically load all node components via Vite
const modules = import.meta.glob('./nodes/**/*.jsx', { eager: true }); const modules = import.meta.glob('./nodes/**/*.jsx', { eager: true });
const nodeTypes = {}; const nodeTypes = {};
const categorizedNodes = {}; const categorizedNodes = {};
Object.entries(modules).forEach(([path, mod]) => { Object.entries(modules).forEach(([path, mod]) => {
const comp = mod.default; const comp = mod.default;
if (!comp) return; if (!comp) return;
const { type, component } = comp; const { type, component } = comp;
@ -82,9 +82,9 @@ import React, {
} }
categorizedNodes[category].push(comp); categorizedNodes[category].push(comp);
nodeTypes[type] = component; nodeTypes[type] = component;
}); });
const darkTheme = createTheme({ const darkTheme = createTheme({
palette: { palette: {
mode: "dark", mode: "dark",
background: { background: {
@ -94,10 +94,26 @@ import React, {
text: { text: {
primary: "#ffffff" primary: "#ffffff"
} }
},
components: {
MuiTooltip: {
styleOverrides: {
tooltip: {
backgroundColor: "#2a2a2a",
color: "#ccc",
fontSize: "0.75rem",
border: "1px solid #444"
},
arrow: {
color: "#2a2a2a"
} }
}); }
}
}
});
export default function App() {
export default function App() {
const [tabs, setTabs] = useState([ const [tabs, setTabs] = useState([
{ {
id: "flow_1", id: "flow_1",
@ -457,5 +473,4 @@ import React, {
/> />
</ThemeProvider> </ThemeProvider>
); );
} }

View File

@ -164,3 +164,37 @@ label {
width: auto !important; width: auto !important;
max-width: 1000px; /* or whatever max width you like */ max-width: 1000px; /* or whatever max width you like */
} }
/* ======================================= */
/* NUMBER INPUT SPINNER OVERRIDE */
/* ======================================= */
input[type="number"] {
background-color: #2c2c2c;
color: #ccc;
border: 1px solid #444;
padding: 4px;
font-size: 12px;
}
/* Webkit browsers */
input[type="number"]::-webkit-inner-spin-button,
input[type="number"]::-webkit-outer-spin-button {
appearance: none;
background-color: #2c2c2c;
border-left: 1px solid #444;
border-right: 1px solid #444;
height: 100%;
width: 16px;
background-image: url("data:image/svg+xml;charset=UTF-8,%3Csvg width='12' height='12' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M6 4l3 3H3z' fill='%2358a6ff'/%3E%3Cpath d='M6 8l3-3H3z' fill='%2358a6ff'/%3E%3C/svg%3E");
background-repeat: no-repeat;
background-position: center;
background-size: 10px 10px;
cursor: pointer;
}
/* Firefox */
input[type="number"] {
-moz-appearance: textfield;
}

View File

@ -33,10 +33,23 @@ export function CloseAllDialog({ open, onClose, onConfirm }) {
export function CreditsDialog({ open, onClose }) { export function CreditsDialog({ open, onClose }) {
return ( return (
<Dialog open={open} onClose={onClose} PaperProps={{ sx: { bgcolor: "#121212", color: "#fff" } }}> <Dialog open={open} onClose={onClose} PaperProps={{ sx: { bgcolor: "#121212", color: "#fff" } }}>
<DialogTitle>Borealis Workflow Automation Tool</DialogTitle> <DialogContent sx={{ textAlign: "center", pt: 3 }}>
<DialogContent> <img
src="/Borealis_Logo.png"
alt="Borealis Logo"
style={{ width: "120px", marginBottom: "12px" }}
/>
<DialogTitle sx={{ p: 0, mb: 1 }}>Borealis Workflow Automation Tool</DialogTitle>
<DialogContentText sx={{ color: "#ccc" }}> <DialogContentText sx={{ color: "#ccc" }}>
Designed by Nicole Rappe @ Bunny Lab Designed by Nicole Rappe @{" "}
<a
href="https://bunny-lab.io"
target="_blank"
rel="noopener noreferrer"
style={{ color: "#58a6ff", textDecoration: "none" }}
>
Bunny Lab
</a>
</DialogContentText> </DialogContentText>
</DialogContent> </DialogContent>
<DialogActions> <DialogActions>

View File

@ -1,7 +1,7 @@
////////// PROJECT FILE SEPARATION LINE ////////// CODE AFTER THIS LINE ARE FROM: <ProjectRoot>/Data/WebUI/src/Flow_Tabs.jsx ////////// PROJECT FILE SEPARATION LINE ////////// CODE AFTER THIS LINE ARE FROM: <ProjectRoot>/Data/WebUI/src/Flow_Tabs.jsx
import React from "react"; import React from "react";
import { Box, Tabs, Tab } from "@mui/material"; import { Box, Tabs, Tab, Tooltip } from "@mui/material";
import { Add as AddIcon } from "@mui/icons-material"; import { Add as AddIcon } from "@mui/icons-material";
/** /**
@ -82,6 +82,7 @@ export default function FlowTabs({
/> />
))} ))}
{/* The "plus" tab has a special value */} {/* The "plus" tab has a special value */}
<Tooltip title="Create a New Concurrent Tab" arrow>
<Tab <Tab
icon={<AddIcon />} icon={<AddIcon />}
value="__addtab__" value="__addtab__"
@ -92,6 +93,7 @@ export default function FlowTabs({
textTransform: "none" textTransform: "none"
}} }}
/> />
</Tooltip>
</Tabs> </Tabs>
</Box> </Box>
); );

View File

@ -8,7 +8,8 @@ import {
Button, Button,
Tooltip, Tooltip,
Typography, Typography,
IconButton IconButton,
Box
} from "@mui/material"; } from "@mui/material";
import { import {
ExpandMore as ExpandMoreIcon, ExpandMore as ExpandMoreIcon,
@ -71,15 +72,21 @@ export default function NodeSidebar({
</Typography> </Typography>
</AccordionSummary> </AccordionSummary>
<AccordionDetails sx={{ p: 0, bgcolor: "#232323" }}> <AccordionDetails sx={{ p: 0, bgcolor: "#232323" }}>
<Tooltip title="Export Current Tab to a JSON File" placement="right" arrow>
<Button fullWidth startIcon={<SaveIcon />} onClick={handleExportFlow} sx={buttonStyle}> <Button fullWidth startIcon={<SaveIcon />} onClick={handleExportFlow} sx={buttonStyle}>
Export Current Flow Export Current Flow
</Button> </Button>
</Tooltip>
<Tooltip title="Import JSON File into New Flow Tab" placement="right" arrow>
<Button fullWidth startIcon={<FileOpenIcon />} onClick={handleImportFlow} sx={buttonStyle}> <Button fullWidth startIcon={<FileOpenIcon />} onClick={handleImportFlow} sx={buttonStyle}>
Import Flow Import Flow
</Button> </Button>
</Tooltip>
<Tooltip title="Destroy all Flow Tabs Immediately" placement="right" arrow>
<Button fullWidth startIcon={<DeleteForeverIcon />} onClick={handleOpenCloseAllDialog} sx={buttonStyle}> <Button fullWidth startIcon={<DeleteForeverIcon />} onClick={handleOpenCloseAllDialog} sx={buttonStyle}>
Close All Flows Close All Flows
</Button> </Button>
</Tooltip>
</AccordionDetails> </AccordionDetails>
</Accordion> </Accordion>
@ -176,18 +183,31 @@ export default function NodeSidebar({
</div> </div>
{/* Bottom toggle button */} {/* Bottom toggle button */}
<div style={{ padding: "6px", borderTop: "1px solid #333", display: "flex", justifyContent: "center" }}> <Tooltip title={collapsed ? "Expand Sidebar" : "Collapse Sidebar"} placement="left">
<Tooltip title={collapsed ? "Expand Sidebar" : "Collapse Sidebar"} placement="right"> <Box
<IconButton
onClick={() => setCollapsed(!collapsed)} onClick={() => setCollapsed(!collapsed)}
size="small" sx={{
sx={{ color: "#888" }} height: "36px",
borderTop: "1px solid #333",
cursor: "pointer",
display: "flex",
alignItems: "center",
justifyContent: "center",
color: "#888",
backgroundColor: "#121212",
transition: "background-color 0.2s ease",
"&:hover": {
backgroundColor: "#1e1e1e"
},
"&:active": {
backgroundColor: "#2a2a2a"
}
}}
> >
{collapsed ? <ChevronRightIcon /> : <ChevronLeftIcon />} {collapsed ? <ChevronLeftIcon /> : <ChevronRightIcon />}
</IconButton> </Box>
</Tooltip> </Tooltip>
</div> </div>
</div>
); );
} }

View File

@ -211,8 +211,9 @@ const AlertSoundNode = ({ id, data }) => {
{data?.label || "Alert Sound"} {data?.label || "Alert Sound"}
<div style={{ <div style={{
position: "absolute", position: "absolute",
top: "12px", // Adjusted from 6px to 12px for better centering top: "50%",
right: "6px", right: "8px",
transform: "translateY(-50%)",
width: "10px", width: "10px",
height: "10px", height: "10px",
borderRadius: "50%", borderRadius: "50%",

View File

@ -234,9 +234,7 @@ const numberInputStyle = {
export default { export default {
type: "OCR_Text_Extraction", type: "OCR_Text_Extraction",
label: "OCR Text Extraction", label: "OCR Text Extraction",
description: ` description: `Extract text from upstream image using backend OCR engine via API. Includes rate limiting and sensitivity detection for smart processing.`,
Extract text from upstream image using backend OCR engine via API.
Includes rate limiting and sensitivity detection for smart processing.`,
content: "Extract Multi-Line Text from Upstream Image Node", content: "Extract Multi-Line Text from Upstream Image Node",
component: OCRNode component: OCRNode
}; };

View File

@ -70,9 +70,10 @@ const KeyPressNode = ({ id, data }) => {
<div <div
style={{ style={{
position: "absolute", position: "absolute",
top: "12px", top: "50%",
right: "6px", right: "8px",
width: "10px", width: "10px",
transform: "translateY(-50%)",
height: "10px", height: "10px",
borderRadius: "50%", borderRadius: "50%",
backgroundColor: "#333", backgroundColor: "#333",