From 2bfa3d38e5b312029911f9f3584727c3973dddd9 Mon Sep 17 00:00:00 2001 From: Charlie Stoner Date: Tue, 18 Nov 2025 15:09:44 -0500 Subject: [PATCH] Add edit, save, and cancel buttons to node modal --- .../views/GraphView/CustomNode/index.tsx | 2 +- src/features/modals/NodeModal/index.tsx | 93 ++++++++++++++++--- 2 files changed, 82 insertions(+), 13 deletions(-) diff --git a/src/features/editor/views/GraphView/CustomNode/index.tsx b/src/features/editor/views/GraphView/CustomNode/index.tsx index ea3ac6be981..ff21de588ad 100644 --- a/src/features/editor/views/GraphView/CustomNode/index.tsx +++ b/src/features/editor/views/GraphView/CustomNode/index.tsx @@ -56,4 +56,4 @@ const CustomNodeWrapper = (nodeProps: NodeProps) => { ); }; -export const CustomNode = React.memo(CustomNodeWrapper); +export const CustomNode = React.memo(CustomNodeWrapper); \ No newline at end of file diff --git a/src/features/modals/NodeModal/index.tsx b/src/features/modals/NodeModal/index.tsx index caba85febac..55c922962fa 100644 --- a/src/features/modals/NodeModal/index.tsx +++ b/src/features/modals/NodeModal/index.tsx @@ -1,6 +1,6 @@ -import React from "react"; +import React, { useState } from "react"; import type { ModalProps } from "@mantine/core"; -import { Modal, Stack, Text, ScrollArea, Flex, CloseButton } from "@mantine/core"; +import { Modal, Stack, Text, ScrollArea, Flex, CloseButton, Button, TextInput, Group } from "@mantine/core"; import { CodeHighlight } from "@mantine/code-highlight"; import type { NodeData } from "../../../types/graph"; import useGraph from "../../editor/views/GraphView/stores/useGraph"; @@ -16,6 +16,7 @@ const normalizeNodeData = (nodeRows: NodeData["text"]) => { if (row.key) obj[row.key] = row.value; } }); + return JSON.stringify(obj, null, 2); }; @@ -28,6 +29,46 @@ const jsonPathToString = (path?: NodeData["path"]) => { export const NodeModal = ({ opened, onClose }: ModalProps) => { const nodeData = useGraph(state => state.selectedNode); + const [isEditing, setIsEditing] = useState(false); + const [editedData, setEditedData] = useState>({}); + + // Initialize edited data when entering edit mode + const handleEdit = () => { + const obj: Record = {}; + nodeData?.text?.forEach(row => { + if (row.type !== "array" && row.type !== "object" && row.key) { + obj[row.key] = row.value || ""; + } + }); + setEditedData(obj); + setIsEditing(true); + }; + + const handleSave = () => { + // Update the node data with edited values + if (nodeData?.text) { + nodeData.text.forEach(row => { + if (row.key && editedData[row.key] !== undefined) { + row.value = editedData[row.key]; + } + }); + } + setIsEditing(false); + }; + + const handleCancel = () => { + setEditedData({}); + setIsEditing(false); + }; + + const handleInputChange = (key: string, value: string) => { + setEditedData(prev => ({ ...prev, [key]: value })); + }; + + // Get editable fields (primitive values only) + const editableFields = nodeData?.text?.filter( + row => row.type !== "array" && row.type !== "object" && row.key + ) || []; return ( @@ -39,16 +80,44 @@ export const NodeModal = ({ opened, onClose }: ModalProps) => { - - - + + {isEditing ? ( + + {editableFields.map((row, index) => ( + handleInputChange(row.key, e.target.value)} + /> + ))} + + + + + + ) : ( + <> + + + + + + )} + JSON Path @@ -66,4 +135,4 @@ export const NodeModal = ({ opened, onClose }: ModalProps) => { ); -}; +}; \ No newline at end of file