Skip to content
Open
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
122 changes: 122 additions & 0 deletions src/features/modals/EditNodeModal/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
import React from "react";
import type { ModalProps } from "@mantine/core";
import { Modal, Stack, Text, TextInput, Group, Button, CloseButton, Flex, ScrollArea } from "@mantine/core";
import { useModal } from "../../../store/useModal";
import { CodeHighlight } from "@mantine/code-highlight";
import type { NodeData } from "../../../types/graph";
import useGraph from "../../editor/views/GraphView/stores/useGraph";
import useJson from "../../../store/useJson";

export const EditNodeModal = ({ opened, onClose }: ModalProps) => {
const nodeData = useGraph(state => state.selectedNode);
const setVisible = useModal(state => state.setVisible);
const [editedValues, setEditedValues] = React.useState<Record<string, string | number>>({});
const json = useJson(state => state.getJson());
const setJson = useJson(state => state.setJson);

React.useEffect(() => {
if (nodeData?.text) {
const values: Record<string, string | number> = {};
nodeData.text.forEach(row => {
if (row.key && row.type !== "object" && row.type !== "array") {
values[row.key] = row.value ?? "";
}
});
setEditedValues(values);
} else {
setEditedValues({});
}
}, [nodeData]);

const handleSave = React.useCallback(() => {
if (!nodeData?.path) return;

try {
const data = JSON.parse(json);
let current: any = data;

// Navigate to the target object using the path
for (let i = 0; i < nodeData.path!.length; i++) {
current = current[nodeData.path![i]];
}

// Update the values
Object.entries(editedValues).forEach(([key, value]) => {
current[key] = value;
});

const updatedJson = JSON.stringify(data, null, 2);
setJson(updatedJson);
onClose();
} catch (error) {
console.error("Error updating node:", error);
}
}, [nodeData, editedValues, json, setJson, onClose]);

const jsonPathToString = (path?: NodeData["path"]) => {
if (!path || path.length === 0) return "$";
const segments = path.map(seg => (typeof seg === "number" ? seg : `"${seg}"`));
return `$[${segments.join("][")}]`;
};

return (
<Modal size="auto" opened={opened} onClose={onClose} centered withCloseButton={false}>
<Stack pb="sm" gap="sm">
<Flex justify="space-between" align="center">
<Text fz="xs" fw={500}>
Content
</Text>

<Group>
<Button size="sm" color="green" onClick={handleSave}>
Save
</Button>
<Button size="sm" color="red" variant="filled" onClick={() => onClose()}>
Cancel
</Button>
<CloseButton onClick={onClose} />
</Group>
</Flex>

<Stack gap="sm">
{nodeData?.text
.filter(row => row.key && row.type !== "object" && row.type !== "array")
.map((row, index) => (
<div key={index}>
<Text fz="xs" fw={500} mb={4} style={{ textTransform: "lowercase" }}>
{row.key}
</Text>
<TextInput
placeholder={`Enter ${row.key}`}
value={editedValues[row.key!] ?? ""}
onChange={e =>
setEditedValues(prev => ({
...prev,
[row.key!]: e.currentTarget.value,
}))
}
size="sm"
/>
</div>
))}
</Stack>

<Text fz="xs" fw={500}>
JSON Path
</Text>

<ScrollArea.Autosize maw={600}>
<CodeHighlight
code={jsonPathToString(nodeData?.path)}
miw={350}
mah={250}
language="json"
copyLabel="Copy to clipboard"
copiedLabel="Copied to clipboard"
withCopyButton
/>
</ScrollArea.Autosize>
</Stack>
</Modal>
);
};
11 changes: 9 additions & 2 deletions src/features/modals/NodeModal/index.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import React 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, Group } from "@mantine/core";
import { CodeHighlight } from "@mantine/code-highlight";
import type { NodeData } from "../../../types/graph";
import useGraph from "../../editor/views/GraphView/stores/useGraph";
import { useModal } from "../../../store/useModal";

// return object from json removing array and object fields
const normalizeNodeData = (nodeRows: NodeData["text"]) => {
Expand All @@ -28,6 +29,7 @@ const jsonPathToString = (path?: NodeData["path"]) => {

export const NodeModal = ({ opened, onClose }: ModalProps) => {
const nodeData = useGraph(state => state.selectedNode);
const setVisible = useModal(state => state.setVisible);

return (
<Modal size="auto" opened={opened} onClose={onClose} centered withCloseButton={false}>
Expand All @@ -37,7 +39,12 @@ export const NodeModal = ({ opened, onClose }: ModalProps) => {
<Text fz="xs" fw={500}>
Content
</Text>
<CloseButton onClick={onClose} />
<Group>
<Button size="xs" onClick={() => setVisible("EditNodeModal", true)}>
Edit
</Button>
<CloseButton onClick={onClose} />
</Group>
</Flex>
<ScrollArea.Autosize mah={250} maw={600}>
<CodeHighlight
Expand Down
1 change: 1 addition & 0 deletions src/features/modals/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
export { DownloadModal } from "./DownloadModal";
export { ImportModal } from "./ImportModal";
export { NodeModal } from "./NodeModal";
export { EditNodeModal } from "./EditNodeModal";
export { JWTModal } from "./JWTModal";
export { SchemaModal } from "./SchemaModal";
export { JQModal } from "./JQModal";
Expand Down