Skip to content
Merged
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
32 changes: 22 additions & 10 deletions frontend/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,11 @@ import {
Controls,
} from "@xyflow/react";
import { v4 as uuidv4 } from "uuid";

import { nodeRegistry } from "./components/nodes/nodeRegistry";
import ContextMenu from "./components/ui/ContextMenu";
import PackageManager from "./components/ui/PackageManager";

import type { AppNode, AppNodeData } from "./nodeTypes";
import type { NodeStatus, SearchSettings } from "./types";

import "./App.css";
import { ThemeToggle } from "./components/ui/ThemeToggle";
import {
Expand All @@ -34,6 +31,7 @@ import { HelpIcon, GearIcon } from "./components/ui/icons";
const localKey = "neurocircuit-flow";
const themeKey = "neurocircuit-theme";
const settingsKey = "neurocircuit-settings";

const defaultSearchSettings: SearchSettings = { fuzzy: true, delay: 50 };

const nodeTypes = nodeRegistry;
Expand Down Expand Up @@ -70,22 +68,27 @@ function App() {
const [searchSettings, setSearchSettings] = useState<SearchSettings>(() => {
const saved = localStorage.getItem(settingsKey);
if (!saved) return defaultSearchSettings;

try {
const parsed = JSON.parse(saved);
// Validate parsed object has the expected structure
if (
typeof parsed === 'object' &&
typeof parsed === "object" &&
parsed !== null &&
typeof parsed.fuzzy === 'boolean' &&
typeof parsed.delay === 'number'
typeof parsed.fuzzy === "boolean" &&
typeof parsed.delay === "number"
) {
return parsed as SearchSettings;
}
console.warn('Invalid search settings structure in localStorage, using defaults');
console.warn(
"Invalid search settings structure in localStorage, using defaults",
);
return defaultSearchSettings;
} catch (error) {
console.error('Failed to parse search settings from localStorage:', error);
console.error(
"Failed to parse search settings from localStorage:",
error,
);
return defaultSearchSettings;
}
});
Expand Down Expand Up @@ -248,6 +251,7 @@ function App() {
const onConnect = useCallback(
(connection: Connection) => {
// Use functional update so we always work with the latest edges

const newEdge = {
...connection,
// style: {
Expand All @@ -256,8 +260,15 @@ function App() {
// strokeWidth: 2
// },
};

setEdges((eds) => {
const newEdges = addEdge(newEdge, eds);
// since target handles are built for accepting only a single input therefore we need to check and remove the prev. connections so that only one connection (edge) is made (at max)
const targetHandleId = connection.targetHandle;
const oldEdges = eds.filter(
(edge) => edge.targetHandle !== targetHandleId,
);

const newEdges = addEdge(newEdge, oldEdges);

if (connection.target) {
// fire-and-forget async inspect using the up-to-date edge list
Expand Down Expand Up @@ -675,6 +686,7 @@ function App() {
actions={availableNodes.map((node) => ({
label: node.label,
category: node.category,
description: node.description,
onSelect: () => {
addNode(node.nodeType);
setMenu(null);
Expand Down
18 changes: 0 additions & 18 deletions frontend/src/components/handle/LimitedConnectionHandle.tsx

This file was deleted.

5 changes: 0 additions & 5 deletions frontend/src/components/handle/handleTypes.ts

This file was deleted.

19 changes: 12 additions & 7 deletions frontend/src/components/nodes/rotateImageNode.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Handle, Position } from "@xyflow/react";
import { Position } from "@xyflow/react";
import type { ChangeEvent } from "react";
import type { RotateImageNodeProps } from "../../nodeTypes";
import LimitedConnectionHandle from "../handle/LimitedConnectionHandle";
import { TypedHandle } from "../ui/TypedHandle";

// Shared class for form elements
const formElementClasses =
Expand All @@ -21,7 +21,10 @@ const RotateIcon = () => (
strokeLinecap="round"
strokeLinejoin="round"
>
<path fillRule="evenodd" d="M4.98313549,11.0001422 C5.49589839,10.9914935 5.92501998,11.3703506 5.99116425,11.8666444 L5.99985778,11.9831355 L6.00348884,12.2068855 C6.11245031,15.4321748 8.76323537,17.9999971 11.9999971,17.9999971 C12.1869612,17.9999971 12.3726725,17.9914753 12.5567465,17.9745765 L12.2928932,17.7071068 C11.9023689,17.3165825 11.9023689,16.6834175 12.2928932,16.2928932 C12.6834175,15.9023689 13.3165825,15.9023689 13.7071068,16.2928932 L15.7071068,18.2928932 C16.0976311,18.6834175 16.0976311,19.3165825 15.7071068,19.7071068 L13.7071068,21.7071068 C13.3165825,22.0976311 12.6834175,22.0976311 12.2928932,21.7071068 C11.9023689,21.3165825 11.9023689,20.6834175 12.2928932,20.2928932 L12.6111505,19.9769552 C12.4086045,19.9922816 12.2047796,19.9999971 11.9999971,19.9999971 C7.7687005,19.9999971 4.28886152,16.7094374 4.01666425,12.5105203 L4.00420123,12.2575143 L4.00014222,12.0168645 C3.9908282,11.4646583 4.43092928,11.0094562 4.98313549,11.0001422 Z M11.7071068,2.29289322 C12.0675907,2.65337718 12.0953203,3.22060824 11.7902954,3.61289944 L11.7071068,3.70710678 L11.3891629,4.0230186 C11.5916051,4.00770767 11.7953244,4 12,4 C16.418278,4 20,7.581722 20,12 C20,12.5522847 19.5522847,13 19,13 C18.4477153,13 18,12.5522847 18,12 C18,8.6862915 15.3137085,6 12,6 C11.8129339,6 11.6271216,6.00853145 11.4429483,6.02544919 L11.7071068,6.29289322 C12.0976311,6.68341751 12.0976311,7.31658249 11.7071068,7.70710678 C11.3466228,8.06759074 10.7793918,8.09532028 10.3871006,7.79029539 L10.2928932,7.70710678 L8.29289322,5.70710678 C7.93240926,5.34662282 7.90467972,4.77939176 8.20970461,4.38710056 L8.29289322,4.29289322 L10.2928932,2.29289322 C10.6834175,1.90236893 11.3165825,1.90236893 11.7071068,2.29289322 Z" />
<path
fillRule="evenodd"
d="M4.98313549,11.0001422 C5.49589839,10.9914935 5.92501998,11.3703506 5.99116425,11.8666444 L5.99985778,11.9831355 L6.00348884,12.2068855 C6.11245031,15.4321748 8.76323537,17.9999971 11.9999971,17.9999971 C12.1869612,17.9999971 12.3726725,17.9914753 12.5567465,17.9745765 L12.2928932,17.7071068 C11.9023689,17.3165825 11.9023689,16.6834175 12.2928932,16.2928932 C12.6834175,15.9023689 13.3165825,15.9023689 13.7071068,16.2928932 L15.7071068,18.2928932 C16.0976311,18.6834175 16.0976311,19.3165825 15.7071068,19.7071068 L13.7071068,21.7071068 C13.3165825,22.0976311 12.6834175,22.0976311 12.2928932,21.7071068 C11.9023689,21.3165825 11.9023689,20.6834175 12.2928932,20.2928932 L12.6111505,19.9769552 C12.4086045,19.9922816 12.2047796,19.9999971 11.9999971,19.9999971 C7.7687005,19.9999971 4.28886152,16.7094374 4.01666425,12.5105203 L4.00420123,12.2575143 L4.00014222,12.0168645 C3.9908282,11.4646583 4.43092928,11.0094562 4.98313549,11.0001422 Z M11.7071068,2.29289322 C12.0675907,2.65337718 12.0953203,3.22060824 11.7902954,3.61289944 L11.7071068,3.70710678 L11.3891629,4.0230186 C11.5916051,4.00770767 11.7953244,4 12,4 C16.418278,4 20,7.581722 20,12 C20,12.5522847 19.5522847,13 19,13 C18.4477153,13 18,12.5522847 18,12 C18,8.6862915 15.3137085,6 12,6 C11.8129339,6 11.6271216,6.00853145 11.4429483,6.02544919 L11.7071068,6.29289322 C12.0976311,6.68341751 12.0976311,7.31658249 11.7071068,7.70710678 C11.3466228,8.06759074 10.7793918,8.09532028 10.3871006,7.79029539 L10.2928932,7.70710678 L8.29289322,5.70710678 C7.93240926,5.34662282 7.90467972,4.77939176 8.20970461,4.38710056 L8.29289322,4.29289322 L10.2928932,2.29289322 C10.6834175,1.90236893 11.3165825,1.90236893 11.7071068,2.29289322 Z"
/>
</svg>
);

Expand Down Expand Up @@ -138,17 +141,19 @@ function RotateImageNode({ id, data }: RotateImageNodeProps) {
</div>

{/* Handles */}
<LimitedConnectionHandle
<TypedHandle
type="target"
position={Position.Left}
className="!bg-[var(--color-accent)]"
aria-label="Image input"
id="image_in"
dataType="IMAGE"
/>
<Handle
<TypedHandle
type="source"
position={Position.Right}
className="!bg-[var(--color-accent)]"
aria-label="Converted image output"
id="image_out"
dataType="IMAGE"
/>
</div>
);
Expand Down
Loading