mirror of
https://github.com/bunny-lab-io/Borealis.git
synced 2025-07-27 05:28:29 -06:00
Added Collapsible Sidebar
This commit is contained in:
@ -82,7 +82,7 @@
|
|||||||
input,
|
input,
|
||||||
select,
|
select,
|
||||||
button {
|
button {
|
||||||
background-color: #2a2a2a;
|
background-color: #1d1d1d;
|
||||||
color: #ccc;
|
color: #ccc;
|
||||||
border: 1px solid #444;
|
border: 1px solid #444;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
@ -91,7 +91,7 @@ button {
|
|||||||
/* Label / Dark Text styling */
|
/* Label / Dark Text styling */
|
||||||
label {
|
label {
|
||||||
color: #aaa;
|
color: #aaa;
|
||||||
font-size: 10px;
|
font-size: 9px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ======================================= */
|
/* ======================================= */
|
||||||
|
@ -7,7 +7,8 @@ import {
|
|||||||
AccordionDetails,
|
AccordionDetails,
|
||||||
Button,
|
Button,
|
||||||
Tooltip,
|
Tooltip,
|
||||||
Typography
|
Typography,
|
||||||
|
IconButton
|
||||||
} from "@mui/material";
|
} from "@mui/material";
|
||||||
import {
|
import {
|
||||||
ExpandMore as ExpandMoreIcon,
|
ExpandMore as ExpandMoreIcon,
|
||||||
@ -15,7 +16,9 @@ import {
|
|||||||
FileOpen as FileOpenIcon,
|
FileOpen as FileOpenIcon,
|
||||||
DeleteForever as DeleteForeverIcon,
|
DeleteForever as DeleteForeverIcon,
|
||||||
DragIndicator as DragIndicatorIcon,
|
DragIndicator as DragIndicatorIcon,
|
||||||
Polyline as PolylineIcon
|
Polyline as PolylineIcon,
|
||||||
|
ChevronLeft as ChevronLeftIcon,
|
||||||
|
ChevronRight as ChevronRightIcon
|
||||||
} from "@mui/icons-material";
|
} from "@mui/icons-material";
|
||||||
|
|
||||||
export default function NodeSidebar({
|
export default function NodeSidebar({
|
||||||
@ -27,6 +30,7 @@ export default function NodeSidebar({
|
|||||||
onFileInputChange
|
onFileInputChange
|
||||||
}) {
|
}) {
|
||||||
const [expandedCategory, setExpandedCategory] = useState(null);
|
const [expandedCategory, setExpandedCategory] = useState(null);
|
||||||
|
const [collapsed, setCollapsed] = useState(false);
|
||||||
|
|
||||||
const handleAccordionChange = (category) => (_, isExpanded) => {
|
const handleAccordionChange = (category) => (_, isExpanded) => {
|
||||||
setExpandedCategory(isExpanded ? category : null);
|
setExpandedCategory(isExpanded ? category : null);
|
||||||
@ -35,132 +39,154 @@ export default function NodeSidebar({
|
|||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
width: 300, //Width of the Node Sidebar
|
width: collapsed ? 40 : 300,
|
||||||
backgroundColor: "#121212",
|
backgroundColor: "#121212",
|
||||||
borderRight: "1px solid #333",
|
borderRight: "1px solid #333",
|
||||||
overflowY: "auto"
|
overflow: "hidden",
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "column",
|
||||||
|
height: "100%"
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{/* Workflows Section */}
|
<div style={{ flex: 1, overflowY: "auto" }}>
|
||||||
<Accordion
|
{!collapsed && (
|
||||||
defaultExpanded
|
<>
|
||||||
square
|
{/* Workflows Section */}
|
||||||
disableGutters
|
|
||||||
sx={{ "&:before": { display: "none" }, margin: 0, border: 0 }}
|
|
||||||
>
|
|
||||||
<AccordionSummary
|
|
||||||
expandIcon={<ExpandMoreIcon />}
|
|
||||||
sx={{
|
|
||||||
backgroundColor: "#2c2c2c",
|
|
||||||
minHeight: "36px",
|
|
||||||
"& .MuiAccordionSummary-content": { margin: 0 }
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Typography sx={{ fontSize: "0.9rem", color: "#0475c2" }}>
|
|
||||||
<b>Workflows</b>
|
|
||||||
</Typography>
|
|
||||||
</AccordionSummary>
|
|
||||||
<AccordionDetails sx={{ p: 0, bgcolor: "#232323" }}>
|
|
||||||
<Button fullWidth startIcon={<SaveIcon />} onClick={handleExportFlow} sx={buttonStyle}>
|
|
||||||
Export Current Flow
|
|
||||||
</Button>
|
|
||||||
<Button fullWidth startIcon={<FileOpenIcon />} onClick={handleImportFlow} sx={buttonStyle}>
|
|
||||||
Import Flow
|
|
||||||
</Button>
|
|
||||||
<Button fullWidth startIcon={<DeleteForeverIcon />} onClick={handleOpenCloseAllDialog} sx={buttonStyle}>
|
|
||||||
Close All Flows
|
|
||||||
</Button>
|
|
||||||
</AccordionDetails>
|
|
||||||
</Accordion>
|
|
||||||
|
|
||||||
{/* Nodes Section */}
|
|
||||||
<Accordion
|
|
||||||
defaultExpanded
|
|
||||||
square
|
|
||||||
disableGutters
|
|
||||||
sx={{ "&:before": { display: "none" }, margin: 0, border: 0 }}
|
|
||||||
>
|
|
||||||
<AccordionSummary
|
|
||||||
expandIcon={<ExpandMoreIcon />}
|
|
||||||
sx={{
|
|
||||||
backgroundColor: "#2c2c2c",
|
|
||||||
minHeight: "36px",
|
|
||||||
"& .MuiAccordionSummary-content": { margin: 0 }
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Typography sx={{ fontSize: "0.9rem", color: "#0475c2" }}>
|
|
||||||
<b>Nodes</b>
|
|
||||||
</Typography>
|
|
||||||
</AccordionSummary>
|
|
||||||
<AccordionDetails sx={{ p: 0 }}>
|
|
||||||
{Object.entries(categorizedNodes).map(([category, items]) => (
|
|
||||||
<Accordion
|
<Accordion
|
||||||
key={category}
|
defaultExpanded
|
||||||
square
|
square
|
||||||
expanded={expandedCategory === category}
|
|
||||||
onChange={handleAccordionChange(category)}
|
|
||||||
disableGutters
|
disableGutters
|
||||||
sx={{
|
sx={{ "&:before": { display: "none" }, margin: 0, border: 0 }}
|
||||||
bgcolor: "#232323",
|
|
||||||
"&:before": { display: "none" },
|
|
||||||
margin: 0,
|
|
||||||
border: 0
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
<AccordionSummary
|
<AccordionSummary
|
||||||
expandIcon={<ExpandMoreIcon />}
|
expandIcon={<ExpandMoreIcon />}
|
||||||
sx={{
|
sx={{
|
||||||
bgcolor: "#1e1e1e",
|
backgroundColor: "#2c2c2c",
|
||||||
px: 2,
|
minHeight: "36px",
|
||||||
minHeight: "32px",
|
|
||||||
"& .MuiAccordionSummary-content": { margin: 0 }
|
"& .MuiAccordionSummary-content": { margin: 0 }
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Typography sx={{ color: "#888", fontSize: "0.75rem" }}>
|
<Typography sx={{ fontSize: "0.9rem", color: "#0475c2" }}>
|
||||||
{category}
|
<b>Workflows</b>
|
||||||
</Typography>
|
</Typography>
|
||||||
</AccordionSummary>
|
</AccordionSummary>
|
||||||
<AccordionDetails sx={{ px: 1, py: 0 }}>
|
<AccordionDetails sx={{ p: 0, bgcolor: "#232323" }}>
|
||||||
{items.map((nodeDef) => (
|
<Button fullWidth startIcon={<SaveIcon />} onClick={handleExportFlow} sx={buttonStyle}>
|
||||||
<Tooltip
|
Export Current Flow
|
||||||
key={`${category}-${nodeDef.type}`}
|
</Button>
|
||||||
title={
|
<Button fullWidth startIcon={<FileOpenIcon />} onClick={handleImportFlow} sx={buttonStyle}>
|
||||||
<span style={{ whiteSpace: "pre-line", wordWrap: "break-word", maxWidth: 220 }}>
|
Import Flow
|
||||||
{nodeDef.description || "Drag & Drop into Editor"}
|
</Button>
|
||||||
</span>
|
<Button fullWidth startIcon={<DeleteForeverIcon />} onClick={handleOpenCloseAllDialog} sx={buttonStyle}>
|
||||||
}
|
Close All Flows
|
||||||
placement="right"
|
</Button>
|
||||||
arrow
|
</AccordionDetails>
|
||||||
|
</Accordion>
|
||||||
|
|
||||||
|
{/* Nodes Section */}
|
||||||
|
<Accordion
|
||||||
|
defaultExpanded
|
||||||
|
square
|
||||||
|
disableGutters
|
||||||
|
sx={{ "&:before": { display: "none" }, margin: 0, border: 0 }}
|
||||||
|
>
|
||||||
|
<AccordionSummary
|
||||||
|
expandIcon={<ExpandMoreIcon />}
|
||||||
|
sx={{
|
||||||
|
backgroundColor: "#2c2c2c",
|
||||||
|
minHeight: "36px",
|
||||||
|
"& .MuiAccordionSummary-content": { margin: 0 }
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Typography sx={{ fontSize: "0.9rem", color: "#0475c2" }}>
|
||||||
|
<b>Nodes</b>
|
||||||
|
</Typography>
|
||||||
|
</AccordionSummary>
|
||||||
|
<AccordionDetails sx={{ p: 0 }}>
|
||||||
|
{Object.entries(categorizedNodes).map(([category, items]) => (
|
||||||
|
<Accordion
|
||||||
|
key={category}
|
||||||
|
square
|
||||||
|
expanded={expandedCategory === category}
|
||||||
|
onChange={handleAccordionChange(category)}
|
||||||
|
disableGutters
|
||||||
|
sx={{
|
||||||
|
bgcolor: "#232323",
|
||||||
|
"&:before": { display: "none" },
|
||||||
|
margin: 0,
|
||||||
|
border: 0
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<Button
|
<AccordionSummary
|
||||||
fullWidth
|
expandIcon={<ExpandMoreIcon />}
|
||||||
sx={nodeButtonStyle}
|
sx={{
|
||||||
draggable
|
bgcolor: "#1e1e1e",
|
||||||
onDragStart={(event) => {
|
px: 2,
|
||||||
event.dataTransfer.setData("application/reactflow", nodeDef.type);
|
minHeight: "32px",
|
||||||
event.dataTransfer.effectAllowed = "move";
|
"& .MuiAccordionSummary-content": { margin: 0 }
|
||||||
}}
|
}}
|
||||||
startIcon={<DragIndicatorIcon sx={{ color: "#666", fontSize: 18 }} />}
|
|
||||||
>
|
>
|
||||||
<span style={{ flexGrow: 1, textAlign: "left" }}>{nodeDef.label}</span>
|
<Typography sx={{ color: "#888", fontSize: "0.75rem" }}>
|
||||||
<PolylineIcon sx={{ color: "#58a6ff", fontSize: 18, ml: 1 }} />
|
{category}
|
||||||
</Button>
|
</Typography>
|
||||||
</Tooltip>
|
</AccordionSummary>
|
||||||
|
<AccordionDetails sx={{ px: 1, py: 0 }}>
|
||||||
|
{items.map((nodeDef) => (
|
||||||
|
<Tooltip
|
||||||
|
key={`${category}-${nodeDef.type}`}
|
||||||
|
title={
|
||||||
|
<span style={{ whiteSpace: "pre-line", wordWrap: "break-word", maxWidth: 220 }}>
|
||||||
|
{nodeDef.description || "Drag & Drop into Editor"}
|
||||||
|
</span>
|
||||||
|
}
|
||||||
|
placement="right"
|
||||||
|
arrow
|
||||||
|
>
|
||||||
|
<Button
|
||||||
|
fullWidth
|
||||||
|
sx={nodeButtonStyle}
|
||||||
|
draggable
|
||||||
|
onDragStart={(event) => {
|
||||||
|
event.dataTransfer.setData("application/reactflow", nodeDef.type);
|
||||||
|
event.dataTransfer.effectAllowed = "move";
|
||||||
|
}}
|
||||||
|
startIcon={<DragIndicatorIcon sx={{ color: "#666", fontSize: 18 }} />}
|
||||||
|
>
|
||||||
|
<span style={{ flexGrow: 1, textAlign: "left" }}>{nodeDef.label}</span>
|
||||||
|
<PolylineIcon sx={{ color: "#58a6ff", fontSize: 18, ml: 1 }} />
|
||||||
|
</Button>
|
||||||
|
</Tooltip>
|
||||||
|
))}
|
||||||
|
</AccordionDetails>
|
||||||
|
</Accordion>
|
||||||
))}
|
))}
|
||||||
</AccordionDetails>
|
</AccordionDetails>
|
||||||
</Accordion>
|
</Accordion>
|
||||||
))}
|
|
||||||
</AccordionDetails>
|
|
||||||
</Accordion>
|
|
||||||
|
|
||||||
{/* Hidden file input fallback for older browsers */}
|
{/* Hidden file input */}
|
||||||
<input
|
<input
|
||||||
type="file"
|
type="file"
|
||||||
accept=".json,application/json"
|
accept=".json,application/json"
|
||||||
style={{ display: "none" }}
|
style={{ display: "none" }}
|
||||||
ref={fileInputRef}
|
ref={fileInputRef}
|
||||||
onChange={onFileInputChange}
|
onChange={onFileInputChange}
|
||||||
/>
|
/>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Bottom toggle button */}
|
||||||
|
<div style={{ padding: "6px", borderTop: "1px solid #333", display: "flex", justifyContent: "center" }}>
|
||||||
|
<Tooltip title={collapsed ? "Expand Sidebar" : "Collapse Sidebar"} placement="right">
|
||||||
|
<IconButton
|
||||||
|
onClick={() => setCollapsed(!collapsed)}
|
||||||
|
size="small"
|
||||||
|
sx={{ color: "#888" }}
|
||||||
|
>
|
||||||
|
{collapsed ? <ChevronRightIcon /> : <ChevronLeftIcon />}
|
||||||
|
</IconButton>
|
||||||
|
</Tooltip>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -104,7 +104,7 @@ const BorealisAgentNode = ({ id, data }) => {
|
|||||||
>
|
>
|
||||||
<option value="">-- Select --</option>
|
<option value="">-- Select --</option>
|
||||||
{Object.entries(agents).map(([id, info]) => {
|
{Object.entries(agents).map(([id, info]) => {
|
||||||
const label = info.status === "provisioned" ? "(Provisioned)" : "(Idle)";
|
const label = info.status === "provisioned" ? "(Provisioned)" : "(Not Provisioned)";
|
||||||
return (
|
return (
|
||||||
<option key={id} value={id}>
|
<option key={id} value={id}>
|
||||||
{id} {label}
|
{id} {label}
|
||||||
@ -123,16 +123,8 @@ const BorealisAgentNode = ({ id, data }) => {
|
|||||||
<hr style={{ margin: "6px 0", borderColor: "#444" }} />
|
<hr style={{ margin: "6px 0", borderColor: "#444" }} />
|
||||||
|
|
||||||
<div style={{ fontSize: "8px", color: "#aaa" }}>
|
<div style={{ fontSize: "8px", color: "#aaa" }}>
|
||||||
Connect <strong>Instruction Nodes</strong> below to define roles.
|
Connect <strong>Agent Role Nodes</strong> below to define roles for this agent.
|
||||||
Each instruction node will send back its results (like screenshots) and act as a separate data output.
|
Each connected <strong>Agent Role Node</strong> will send back its collected data (like screenshots) through the role node itself and act as a separate data output.
|
||||||
</div>
|
|
||||||
|
|
||||||
<div style={{ fontSize: "8px", color: "#aaa", marginTop: "4px" }}>
|
|
||||||
<strong>Supported Roles:</strong>
|
|
||||||
<ul style={{ paddingLeft: "14px", marginTop: "2px", marginBottom: "0" }}>
|
|
||||||
<li><code>screenshot</code>: Capture a region with interval and overlay</li>
|
|
||||||
{/* Future roles will be listed here */}
|
|
||||||
</ul>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,25 +1,24 @@
|
|||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"target": "ESNext",
|
"target": "ESNext",
|
||||||
"useDefineForClassFields": true,
|
"useDefineForClassFields": true,
|
||||||
"lib": ["DOM", "DOM.Iterable", "ESNext"],
|
"lib": ["DOM", "DOM.Iterable", "ESNext"],
|
||||||
"allowJs": false,
|
"allowJs": false,
|
||||||
"skipLibCheck": true,
|
"skipLibCheck": true,
|
||||||
"esModuleInterop": false,
|
"esModuleInterop": false,
|
||||||
"allowSyntheticDefaultImports": true,
|
"allowSyntheticDefaultImports": true,
|
||||||
"strict": true,
|
"strict": true,
|
||||||
"forceConsistentCasingInFileNames": true,
|
"forceConsistentCasingInFileNames": true,
|
||||||
"module": "ESNext",
|
"module": "ESNext",
|
||||||
"moduleResolution": "Node",
|
"moduleResolution": "Node",
|
||||||
"resolveJsonModule": true,
|
"resolveJsonModule": true,
|
||||||
"isolatedModules": true,
|
"isolatedModules": true,
|
||||||
"jsx": "react-jsx",
|
"jsx": "react-jsx",
|
||||||
"baseUrl": ".",
|
"baseUrl": ".",
|
||||||
"paths": {
|
"paths": {
|
||||||
"@/*": ["src/*"]
|
"@/*": ["src/*"]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"include": ["src"],
|
"include": ["src"],
|
||||||
"exclude": ["node_modules", "build", "dist"]
|
"exclude": ["node_modules", "build", "dist"]
|
||||||
}
|
}
|
||||||
|
|
Reference in New Issue
Block a user