Skip to content
Open
Changes from 1 commit
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
e1cab5c
feat: Implement utility functions for managing component aliases with…
ogabrielluiz Sep 10, 2025
2de3451
feat: Add migration support for existing flows to handle duplicate co…
ogabrielluiz Sep 10, 2025
08694dc
feat: Enhance alias handling in NodeName and TweakComponent, add util…
ogabrielluiz Sep 10, 2025
a7c0e27
feat: Implement alias conversion for tweaks in API code generation fu…
ogabrielluiz Sep 10, 2025
bcc40ac
feat: Add alias assignment for new components in useAddComponent hook
ogabrielluiz Sep 10, 2025
ded8e08
feat: Enhance alias validation functions to improve safety checks for…
ogabrielluiz Sep 10, 2025
0918d53
feat: Refactor alias utility tests to enhance pattern detection and i…
ogabrielluiz Sep 10, 2025
c5feac7
feat: Implement alias update on display name change in NodeName compo…
ogabrielluiz Sep 10, 2025
ed582ef
feat: Enhance renumbering logic for auto-generated aliases and update…
ogabrielluiz Sep 10, 2025
d8bde89
feat: Refactor alias detection and update logic for improved clarity …
ogabrielluiz Sep 10, 2025
f6f88c5
feat: Add dynamic alias assignment for duplicate components in graph …
ogabrielluiz Sep 10, 2025
0ff5cee
fix: Update alias formatting for consistency in graph dump tests
ogabrielluiz Sep 10, 2025
98b63f7
fix: Preserve existing alias for duplicate components in graph dump test
ogabrielluiz Sep 10, 2025
0f00c71
feat: Update documentation for Tweaks class to clarify alias usage an…
ogabrielluiz Sep 10, 2025
87f5261
feat: Enhance process_tweaks function to support alias and display na…
ogabrielluiz Sep 10, 2025
d952ca5
feat: Add unit tests for alias-enabled tweak processing functionality
ogabrielluiz Sep 10, 2025
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
Prev Previous commit
Next Next commit
feat: Add alias assignment for new components in useAddComponent hook
  • Loading branch information
ogabrielluiz committed Sep 10, 2025
commit bcc40ac89992da4a23e15564c2fc1d1d8d624d0c
30 changes: 28 additions & 2 deletions src/frontend/src/hooks/use-add-component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,15 @@ import { track } from "@/customization/utils/analytics";
import useFlowStore from "@/stores/flowStore";
import type { APIClassType } from "@/types/api";
import type { AllNodeType } from "@/types/flow";
import { assignAliasToNewComponent } from "@/utils/aliasUtils";
import { getNodeId } from "@/utils/reactflowUtils";
import { getNodeRenderType } from "@/utils/utils";

export function useAddComponent() {
const store = useStoreApi();
const paste = useFlowStore((state) => state.paste);
const nodes = useFlowStore((state) => state.nodes);
const setNodes = useFlowStore((state) => state.setNodes);

const addComponent = useCallback(
(
Expand Down Expand Up @@ -55,16 +58,39 @@ export function useAddComponent() {
type: getNodeRenderType("genericnode"),
position: { x: 0, y: 0 },
data: {
node: component,
node: { ...component }, // Clone component to avoid mutation
showNode: !component.minimized,
type: type,
id: newId,
},
};

// Generate alias for the new component and update existing ones if needed
assignAliasToNewComponent(newNode, nodes);

// Check if we need to update existing nodes (when adding second component of same type)
const displayName = newNode.data.node.display_name;
const sameTypeNodes = nodes.filter(
(n) =>
n.type === "genericNode" && n.data.node.display_name === displayName,
);

if (sameTypeNodes.length === 1 && !sameTypeNodes[0].data.node.alias) {
// This is the second component - need to assign aliases to both
const firstNode = sameTypeNodes[0];
if (firstNode.type === "genericNode") {
firstNode.data.node.alias = `${displayName}#1`;
}

// Update the first node in the store
setNodes((currentNodes) =>
currentNodes.map((n) => (n.id === firstNode.id ? firstNode : n)),
);
}

Comment on lines +68 to +90
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix: store mutation via utility is not persisted; reorder logic to ensure setNodes runs

assignAliasToNewComponent mutates the existing nodes array by reference. Because the zustand store isn’t updated unless setNodes is called, your subsequent condition can be skipped (alias already set in-memory), leading to no store update and missing re-render. Compute the “second-of-its-type” condition before calling the utility, then always persist the first node’s alias immutably when needed.

Apply:

-      // Generate alias for the new component and update existing ones if needed
-      assignAliasToNewComponent(newNode, nodes);
-
-      // Check if we need to update existing nodes (when adding second component of same type)
-      const displayName = newNode.data.node.display_name;
-      const sameTypeNodes = nodes.filter(
-        (n) =>
-          n.type === "genericNode" && n.data.node.display_name === displayName,
-      );
-
-      if (sameTypeNodes.length === 1 && !sameTypeNodes[0].data.node.alias) {
-        // This is the second component - need to assign aliases to both
-        const firstNode = sameTypeNodes[0];
-        if (firstNode.type === "genericNode") {
-          firstNode.data.node.alias = `${displayName}#1`;
-        }
-
-        // Update the first node in the store
-        setNodes((currentNodes) =>
-          currentNodes.map((n) => (n.id === firstNode.id ? firstNode : n)),
-        );
-      }
+      // Precompute if we are adding the second component of this display_name with no existing alias
+      const displayName = newNode.data.node.display_name;
+      const sameTypeNodesBefore = nodes.filter(
+        (n) => n.type === "genericNode" && n.data.node.display_name === displayName,
+      );
+      const needsPromoteFirst =
+        sameTypeNodesBefore.length === 1 &&
+        !sameTypeNodesBefore[0].data.node.alias;
+
+      // Assign alias to the new node (the utility will also compute target aliases)
+      assignAliasToNewComponent(newNode, nodes);
+
+      // Persist alias on the first existing node immutably so subscribers re-render
+      if (needsPromoteFirst) {
+        const firstId = sameTypeNodesBefore[0].id;
+        setNodes((currentNodes) =>
+          currentNodes.map((n) =>
+            n.id === firstId && n.type === "genericNode"
+              ? {
+                  ...n,
+                  data: {
+                    ...n.data,
+                    node: {
+                      ...n.data.node,
+                      alias: `${displayName}#1`,
+                    },
+                  },
+                }
+              : n,
+          ),
+        );
+      }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Generate alias for the new component and update existing ones if needed
assignAliasToNewComponent(newNode, nodes);
// Check if we need to update existing nodes (when adding second component of same type)
const displayName = newNode.data.node.display_name;
const sameTypeNodes = nodes.filter(
(n) =>
n.type === "genericNode" && n.data.node.display_name === displayName,
);
if (sameTypeNodes.length === 1 && !sameTypeNodes[0].data.node.alias) {
// This is the second component - need to assign aliases to both
const firstNode = sameTypeNodes[0];
if (firstNode.type === "genericNode") {
firstNode.data.node.alias = `${displayName}#1`;
}
// Update the first node in the store
setNodes((currentNodes) =>
currentNodes.map((n) => (n.id === firstNode.id ? firstNode : n)),
);
}
// Precompute if we are adding the second component of this display_name with no existing alias
const displayName = newNode.data.node.display_name;
const sameTypeNodesBefore = nodes.filter(
(n) => n.type === "genericNode" && n.data.node.display_name === displayName,
);
const needsPromoteFirst =
sameTypeNodesBefore.length === 1 &&
!sameTypeNodesBefore[0].data.node.alias;
// Assign alias to the new node (the utility will also compute target aliases)
assignAliasToNewComponent(newNode, nodes);
// Persist alias on the first existing node immutably so subscribers re-render
if (needsPromoteFirst) {
const firstId = sameTypeNodesBefore[0].id;
setNodes((currentNodes) =>
currentNodes.map((n) =>
n.id === firstId && n.type === "genericNode"
? {
...n,
data: {
...n.data,
node: {
...n.data.node,
alias: `${displayName}#1`,
},
},
}
: n,
),
);
}

paste({ nodes: [newNode], edges: [] }, pos);
},
[store, paste],
[store, paste, nodes, setNodes],
);

return addComponent;
Expand Down