|
import React from "react"; |
|
import { Modal, Stack, Text, ScrollArea, ModalProps, Button } from "@mantine/core"; |
|
import { CodeHighlight } from "@mantine/code-highlight"; |
|
import Editor from "@monaco-editor/react"; |
|
import { VscLock } from "react-icons/vsc"; |
|
import { isIframe } from "src/lib/utils/widget"; |
|
import useConfig from "src/store/useConfig"; |
|
import useFile from "src/store/useFile"; |
|
import useGraph from "src/store/useGraph"; |
|
import useModal from "src/store/useModal"; |
|
import useUser from "src/store/useUser"; |
|
|
|
const dataToString = (data: any) => { |
|
const text = Array.isArray(data) ? Object.fromEntries(data) : data; |
|
const replacer = (_: string, v: string) => { |
|
if (typeof v === "string") return v.replaceAll('"', ""); |
|
return v; |
|
}; |
|
|
|
return JSON.stringify(text, replacer, 2); |
|
}; |
|
|
|
export const NodeModal: React.FC<ModalProps> = ({ opened, onClose }) => { |
|
const isPremium = useUser(state => state.premium); |
|
const editContents = useFile(state => state.editContents); |
|
const setVisible = useModal(state => state.setVisible); |
|
const darkmodeEnabled = useConfig(state => (state.darkmodeEnabled ? "vs-dark" : "light")); |
|
const nodeData = useGraph(state => dataToString(state.selectedNode?.text)); |
|
const path = useGraph(state => state.selectedNode?.path || ""); |
|
const isParent = useGraph(state => state.selectedNode?.data?.isParent); |
|
const [editMode, setEditMode] = React.useState(false); |
|
const [value, setValue] = React.useState(nodeData || ""); |
|
|
|
const onUpdate = () => { |
|
if (!value) return setEditMode(false); |
|
if (!isPremium) return; |
|
editContents(path!, value, () => { |
|
setEditMode(false); |
|
onModalClose(); |
|
}); |
|
}; |
|
|
|
const onModalClose = () => { |
|
setEditMode(false); |
|
setValue(""); |
|
onClose(); |
|
}; |
|
|
|
const onEditClick = () => { |
|
if (isPremium) return setEditMode(true); |
|
setVisible("premium")(true); |
|
}; |
|
|
|
const isEditVisible = React.useMemo( |
|
() => path !== "{Root}" && !isParent && !isIframe(), |
|
[isParent, path] |
|
); |
|
|
|
return ( |
|
<Modal title="Node Content" size="auto" opened={opened} onClose={onModalClose} centered> |
|
<Stack py="sm" gap="sm"> |
|
<Stack gap="xs"> |
|
<Text fz="sm" fw={700}> |
|
Content |
|
</Text> |
|
{editMode ? ( |
|
<Editor |
|
theme={darkmodeEnabled} |
|
defaultValue={nodeData} |
|
onChange={e => setValue(e!)} |
|
height={200} |
|
language="json" |
|
options={{ |
|
readOnly: !editMode, |
|
minimap: { |
|
enabled: false, |
|
}, |
|
}} |
|
/> |
|
) : ( |
|
<ScrollArea> |
|
<CodeHighlight |
|
code={nodeData} |
|
miw={350} |
|
mah={250} |
|
maw={600} |
|
language="json" |
|
withCopyButton |
|
/> |
|
</ScrollArea> |
|
)} |
|
</Stack> |
|
{isEditVisible && ( |
|
<Stack gap="xs"> |
|
{editMode ? ( |
|
<Button |
|
variant={value ? "filled" : "light"} |
|
color={value ? "green" : "blue"} |
|
onClick={onUpdate} |
|
> |
|
{value.length ? "Update Document" : "Cancel"} |
|
</Button> |
|
) : ( |
|
<Button |
|
onClick={onEditClick} |
|
leftSection={!isPremium && <VscLock />} |
|
variant="filled" |
|
> |
|
Edit |
|
</Button> |
|
)} |
|
</Stack> |
|
)} |
|
<Text fz="sm" fw={700}> |
|
Node Path |
|
</Text> |
|
<ScrollArea> |
|
<CodeHighlight |
|
code={path} |
|
miw={350} |
|
mah={250} |
|
language="json" |
|
copyLabel="Copy to clipboard" |
|
copiedLabel="Copied to clipboard" |
|
withCopyButton |
|
/> |
|
</ScrollArea> |
|
</Stack> |
|
</Modal> |
|
); |
|
}; |
|
|