From 2ebbcf4dbcc428a19bcb0eefa6f0d993fe33d7f3 Mon Sep 17 00:00:00 2001 From: Sam ouhra Date: Tue, 29 Oct 2024 22:23:28 +0100 Subject: [PATCH 1/3] remove X in viewer mode --- src/Components/OneCademyCollaborationModel.js | 51 ++++++++++--------- 1 file changed, 26 insertions(+), 25 deletions(-) diff --git a/src/Components/OneCademyCollaborationModel.js b/src/Components/OneCademyCollaborationModel.js index 22cd35c7..a3028e54 100644 --- a/src/Components/OneCademyCollaborationModel.js +++ b/src/Components/OneCademyCollaborationModel.js @@ -434,31 +434,32 @@ const OneCademyCollaborationModel = () => { let buttonBody = button.append("xhtml:body").style("margin", "0px").style("padding", "0px"); - buttonBody - .append("xhtml:button") - .style("background", "white") - .style("color", "black") - .style("border", "1px solid black") - .style("border-radius", "50%") - .style("width", "20px") - .style("height", "20px") - .style("font-weight", "bold") - .style("font-size", "12px") - .style("line-height", "18px") - .style("text-align", "center") - .style("padding", "0") - .text("X") - .on("click", function (e) { - e.stopPropagation(); - removeNode(v); - }) - .on("mouseover", function () { - d3.select(this).style("background", "orange"); - }) - .on("mouseout", function () { - d3.select(this).style("background", "white"); - }); - + if (editor) { + buttonBody + .append("xhtml:button") + .style("background", "white") + .style("color", "black") + .style("border", "1px solid black") + .style("border-radius", "50%") + .style("width", "20px") + .style("height", "20px") + .style("font-weight", "bold") + .style("font-size", "12px") + .style("line-height", "18px") + .style("text-align", "center") + .style("padding", "0") + .text("X") + .on("click", function (e) { + e.stopPropagation(); + removeNode(v); + }) + .on("mouseover", function () { + d3.select(this).style("background", "orange"); + }) + .on("mouseout", function () { + d3.select(this).style("background", "white"); + }); + } if (selectedNode || openAddNode) { let button2 = nodeElement .append("foreignObject") From 9a6b0ec6c9dd823d81467aeb7c8001ef7b259c7f Mon Sep 17 00:00:00 2001 From: Sam ouhra Date: Wed, 30 Oct 2024 00:54:34 +0100 Subject: [PATCH 2/3] add download svg button --- src/Components/OneCademyCollaborationModel.js | 254 ++++++++++-------- 1 file changed, 141 insertions(+), 113 deletions(-) diff --git a/src/Components/OneCademyCollaborationModel.js b/src/Components/OneCademyCollaborationModel.js index a3028e54..115bffae 100644 --- a/src/Components/OneCademyCollaborationModel.js +++ b/src/Components/OneCademyCollaborationModel.js @@ -15,7 +15,7 @@ import FormControl from "@mui/material/FormControl"; import MenuItem from "@mui/material/MenuItem"; import Paper from "@mui/material/Paper"; import Grid from "@mui/material/Grid"; -import { Typography } from "@mui/material"; +import { Tooltip, Typography } from "@mui/material"; import IconButton from "@mui/material/IconButton"; import DeleteIcon from "@mui/icons-material/Delete"; import TrendingFlatIcon from "@mui/icons-material/TrendingFlat"; @@ -36,6 +36,8 @@ import { useThemeContext } from "../ThemeContext"; import FormControlLabel from "@mui/material/FormControlLabel"; import Switch from "@mui/material/Switch"; import AddNodeTypeModal from "./CollaborativeModel/AddNodeTypeModal"; +import GetAppIcon from "@mui/icons-material/GetApp"; + const d3 = require("d3"); const legends = [ @@ -56,9 +58,9 @@ const OneCademyCollaborationModel = () => { const [title, setTitle] = useState(""); const [type, setType] = useState("Positive Outcome"); const [nodesChanges, setNodesChanges] = useState([]); - const [nodesLoded, setNodesLoded] = useState(false); + const [nodesLoaded, setNodesLoaded] = useState(false); const svgRef = useRef(); - const [allNodes, setAllNodes] = useState([]); + const [allNodes, setAllNodes] = useState({}); const [explanation, setExplanation] = useState(""); const [label, setLabel] = useState(""); const [explanationLink, setExplanationLink] = useState(""); @@ -78,7 +80,7 @@ const OneCademyCollaborationModel = () => { const [stepLink, setStepLink] = useState(0); const [maxDepth, setMaxDepth] = useState(0); const [openSideBar, setOpenSideBar] = useState(false); - const [ingnorOrder, setIngnorOrder] = useState(true); + const [ignoreOrder, setIgnoreOrder] = useState(true); const [deleteDialogLinkOpen, setDeleteDialogLinkOpen] = useState(false); const [openLegend, setOpenLegend] = useState(false); const [selectedDiagram, setSelectedDiagram] = useState({}); @@ -266,69 +268,54 @@ const OneCademyCollaborationModel = () => { useEffect(() => { let collabModelNodesQuery = firebase.db.collection("collabModelNodes"); - const _allNodes = [...allNodes]; + const _allNodes = {}; const collabModelNodesSnapshot = collabModelNodesQuery.onSnapshot(snapshot => { const changes = snapshot.docChanges(); for (let change of changes) { const data = change.doc.data(); if (change.type === "added") { if (!data.deleted) { - const findIndex = _allNodes.findIndex(node => node.id === change.doc.id); - if (findIndex === -1) { - _allNodes.push({ id: change.doc.id, ...data }); - } else { - _allNodes[findIndex] = { id: change.doc.id, ...data }; - } - } else if (data.deleted) { - const findIndex = _allNodes.findIndex(node => node.id === change.doc.id); - if (findIndex !== -1) { - _allNodes.splice(findIndex, 1); - } + _allNodes[change.doc.id] = { ...data, id: change.doc.id }; + } else { + delete _allNodes[change.doc.id]; } } else if (change.type === "modified") { if (!data.deleted) { - const findIndex = _allNodes.findIndex(node => node.id === change.doc.id); - if (findIndex !== -1) { - _allNodes[findIndex] = { id: change.doc.id, ...data }; - } - } else if (data.deleted) { - const findIndex = _allNodes.findIndex(node => node.id === change.doc.id); - if (findIndex !== -1) { - _allNodes.splice(findIndex, 1); - } + _allNodes[change.doc.id] = { ...data, id: change.doc.id }; + } else { + delete _allNodes[change.doc.id]; } } else if (change.type === "removed") { - const findIndex = _allNodes.findIndex(node => node.id === change.doc.id); - if (findIndex !== -1) { - _allNodes.splice(findIndex, 1); - } + delete _allNodes[change.doc.id]; } } setNodesChanges(oldChanges => [...oldChanges, ...changes]); - setNodesLoded(true); + setNodesLoaded(true); setLoadData(false); - _allNodes.sort((a, b) => (a.title > b.title ? 1 : -1)); setAllNodes(_allNodes); - setShowAll(_allNodes.length === visibleNodes.length); + setShowAll(Object.keys(_allNodes).length === visibleNodes.length); }); return () => { collabModelNodesSnapshot(); - setNodesLoded(false); + setNodesLoaded(false); setLoadData(false); }; }, [firebase, loadData, selectedDiagram]); - // eslint-disable-next-line react-hooks/exhaustive-deps - useEffect(async () => { - if (!allNodes.length) return; - const researchersDoc = await firebase.db.collection("researchers").where("email", "==", email).get(); - if (researchersDoc.docs.length) { - const resData = researchersDoc.docs[0].data(); - setEditor(resData.hasOwnProperty("isEditor") && resData.isEditor); - } else { - setEditor(false); - } + useEffect(() => { + const checkEditor = async () => { + const researchersDoc = await firebase.db.collection("researchers").where("email", "==", email).get(); + if (researchersDoc.docs.length) { + const resData = researchersDoc.docs[0].data(); + setEditor(resData.hasOwnProperty("isEditor") && resData.isEditor); + } else { + setEditor(false); + } + }; + checkEditor(); + }, [firebase]); + useEffect(() => { var g = new dagreD3.graphlib.Graph({ compound: true }) .setGraph({ rankdir: "LR", isMultigraph: true }) .setDefaultEdgeLabel(function () { @@ -336,56 +323,55 @@ const OneCademyCollaborationModel = () => { }); d3.select("#graphGroup").selectAll("*").remove(); setNodesChanges([]); - for (let collabModelNode of allNodes) { - if ( - visibleNodes.includes(collabModelNode.id) && - !collabModelNode.deleted && - !g.nodes().includes(collabModelNode.id) - ) { - g.setNode(collabModelNode.id, { - label: collabModelNode.title, + for (let visibleNode of visibleNodes) { + if (allNodes[visibleNode] && !g.nodes().includes(visibleNode)) { + const nodeData = allNodes[visibleNode]; + console.log("visibleNode ==>", visibleNode, nodeData); + g.setNode(nodeData.id, { + label: nodeData.title, class: - selectedNode === collabModelNode.id + selectedNode === nodeData.id ? "type-ST" - : collabModelNode.type === "Negative Outcome" + : nodeData.type === "Negative Outcome" ? "type-NO" - : collabModelNode.type === "Positive Outcome" + : nodeData.type === "Positive Outcome" ? "type-PO" : "type-DF", - style: `fill: ${getColor(collabModelNode.type, nodeTypes)}` + style: `fill: ${getColor(nodeData.type, nodeTypes)}` }); } } let _maxDepth = 0; - for (let collabModelNode of allNodes) { - if (!collabModelNode.children || !collabModelNode.children.length) continue; - for (let elementChild of collabModelNode.children) { + for (let visibleNode of visibleNodes) { + const nodeData = allNodes[visibleNode]; + if (!nodeData?.children || nodeData.children.length === 0) continue; + for (let elementChild of nodeData.children) { if (_maxDepth < elementChild?.order) { _maxDepth = elementChild?.order; } if ( !elementChild.deleted && visibleNodes.includes(elementChild.id) && - visibleNodes.includes(collabModelNode.id) && - !collabModelNode.deleted + visibleNodes.includes(nodeData.id) && + !nodeData.deleted ) { let color = legends.find(legend => legend.text === elementChild.type)?.color || ""; let _arrowheadStyle = `fill: ${color}`; let _style = `stroke: ${color}; stroke-width: 2px;`; // if (parseInt(elementChild.order) === stepLink && stepLink !== 0) { - // _style = `stroke:${color}; stroke-width: 3px;filter: drop-shadow(3px 3px 5px ${color}); stroke-width: 2.7px;`; + // _style = stroke:${color}; stroke-width: 3px;filter: drop-shadow(3px 3px 5px ${color}); stroke-width: 2.7px;; // } - if (selectedLink.v === collabModelNode.id && selectedLink.w === elementChild.id) { + if (selectedLink.v === nodeData.id && selectedLink.w === elementChild.id) { _style = "stroke: #212121; stroke-width: 3px; filter: drop-shadow(3px 3px 5px #212121); stroke-width: 2.7px;"; _arrowheadStyle = "fill: #212121"; } if ( - ingnorOrder || + ignoreOrder || showAll || (parseInt(elementChild.order) > 0 && parseInt(elementChild.order) <= stepLink) ) { - g.setEdge(collabModelNode.id, elementChild.id, { + g.setEdge(nodeData.id, elementChild.id, { curve: d3.curveBasis, style: _style, arrowheadStyle: _arrowheadStyle, @@ -549,9 +535,9 @@ const OneCademyCollaborationModel = () => { if (editor) { edges.each(function (edgeData) { var edgeElement = d3.select(this); - const nodeIdx = allNodes.findIndex(node => node.id === edgeData.v); - const childIdx = allNodes[nodeIdx].children.findIndex(child => child.id === edgeData.w); - const order = allNodes[nodeIdx].children[childIdx].order; + const nodeData = allNodes[edgeData.v]; + const childIdx = nodeData.children.findIndex(child => child.id === edgeData.w); + const order = nodeData.children[childIdx].order; addPencilButton(edgeElement, edgeData, pencilButtonsGroup, order); }); } @@ -564,12 +550,12 @@ const OneCademyCollaborationModel = () => { }); } - setNodesLoded(false); + setNodesLoaded(false); return () => { d3.select("#graphGroup").selectAll("*").remove(); setZoomState(null); }; - }, [nodesLoded, allNodes, visibleNodes, darkMode, nodeTypes]); + }, [nodesLoaded, allNodes, visibleNodes, darkMode, nodeTypes]); const AddNewNode = second => { setTitle(""); @@ -706,12 +692,13 @@ const OneCademyCollaborationModel = () => { const deleteNode = async () => { if (!selectedNode) return; - const _allnodes = [...allNodes]; + const _allnodes = { ...allNodes }; const _listOfDiagrams = [...listOfDiagrams]; const _diagram = _listOfDiagrams.findIndex(diagram => diagram.id === selectedDiagram.id); const diagramRef = firebase.db.collection("collabModelDiagrams").doc(selectedDiagram.id); let _visibleNodes = [...visibleNodes]; - for (let node of _allnodes) { + for (let nodeId in _allnodes) { + const node = _allnodes[nodeId]; if (node.id === selectedNode) { node.deleted = true; } @@ -730,7 +717,8 @@ const OneCademyCollaborationModel = () => { } } await firebase.db.runTransaction(async t => { - for (let node of _allnodes) { + for (let nodeId in _allnodes) { + const node = _allnodes[nodeId]; const nodeRef = firebase.firestore().collection("collabModelNodes").doc(node.id); t.update(nodeRef, { children: node.children, deleted: node?.deleted || false }); } @@ -765,7 +753,7 @@ const OneCademyCollaborationModel = () => { const handleVisibileNodes = async node => { let _visibleNodes = visibleNodes; setShowAll(false); - setIngnorOrder(true); + setIgnoreOrder(true); const _listOfDiagrams = [...listOfDiagrams]; const _diagram = _listOfDiagrams.findIndex(diagram => diagram.id === selectedDiagram.id); const diagramRef = firebase.db.collection("collabModelDiagrams").doc(selectedDiagram.id); @@ -775,12 +763,14 @@ const OneCademyCollaborationModel = () => { } else { _visibleNodes.push(node.id); const childrens = node.children.filter(child => !child?.deleted); - const parents = allNodes.filter(_node => _node.children.some(child => child.id === node.id && !child?.deleted)); + const parents = Object.values(allNodes).filter(_node => + _node.children.some(child => child.id === node.id && !child?.deleted) + ); _visibleNodes = [..._visibleNodes, ...childrens.map(child => child.id), ...parents.map(parent => parent.id)]; } let _showall = true; - for (let node of allNodes) { + for (let node of Object.values(allNodes)) { if (!_visibleNodes.includes(node.id)) { _showall = false; break; @@ -835,7 +825,7 @@ const OneCademyCollaborationModel = () => { const child = children.find(child => child.id === childId); if (child.order !== linkOrder) { if (child.order === 0 || Number.isNaN(child.order)) { - for (let node of allNodes) { + for (let node of Object.values(allNodes)) { const _children = node.children; for (let _child of _children) { if (_child.order >= linkOrder) { @@ -852,7 +842,7 @@ const OneCademyCollaborationModel = () => { t.update(nodeRef, { children: _children }); } } else if (linkOrder === 0) { - for (let node of allNodes) { + for (let node of Object.values(allNodes)) { const _children = node.children; for (let _child of _children) { if (_child.order >= child.order) { @@ -869,7 +859,7 @@ const OneCademyCollaborationModel = () => { t.update(nodeRef, { children: _children }); } } else { - for (let node of allNodes) { + for (let node of Object.values(allNodes)) { const _children = node.children; if (child.order < linkOrder) { @@ -954,11 +944,7 @@ const OneCademyCollaborationModel = () => { _visibleNodes = []; setShowAll(false); } else { - for (let node of allNodes) { - if (!_visibleNodes.includes(node.id)) { - _visibleNodes.push(node.id); - } - } + _visibleNodes.push(...Object.keys(allNodes)); setShowAll(true); } _listOfDiagrams[_diagram].nodes = _visibleNodes; @@ -980,7 +966,7 @@ const OneCademyCollaborationModel = () => { const nextLink = () => { const _visibleNodes = []; - allNodes.forEach(node => { + Object.values(allNodes).forEach(node => { node.children.forEach(child => { if (stepLink + 1 >= child.order && child.order !== 0) { if (!_visibleNodes.includes(child.id)) { @@ -996,11 +982,11 @@ const OneCademyCollaborationModel = () => { setVisibleNodes(_visibleNodes); setLoadData(true); setShowAll(false); - setIngnorOrder(false); + setIgnoreOrder(false); }; const previousLink = () => { const _visibleNodes = []; - allNodes.forEach(node => { + Object.values(allNodes).forEach(node => { node.children.forEach(child => { if (stepLink - 1 >= child.order && child.order !== 0) { if (!_visibleNodes.includes(child.id)) { @@ -1016,7 +1002,7 @@ const OneCademyCollaborationModel = () => { setStepLink(prevActiveStep => (prevActiveStep - 1 > 0 ? prevActiveStep - 1 : 0)); setLoadData(true); setShowAll(false); - setIngnorOrder(false); + setIgnoreOrder(false); }; const deleteLink = async () => { @@ -1028,7 +1014,7 @@ const OneCademyCollaborationModel = () => { const nodeData = nodeDoc.data(); const childIdx = nodeData.children.findIndex(child => child.id === childId); const childp = nodeData.children[childIdx]; - for (let node of allNodes) { + for (let node of Object.values(allNodes)) { let _children = node.children; for (let _child of _children) { if (_child.order > childp.order) { @@ -1069,7 +1055,7 @@ const OneCademyCollaborationModel = () => { }; const resetOrder = () => { const _visibleNodes = []; - allNodes.forEach(node => { + Object.values(allNodes).forEach(node => { node.children.forEach(child => { if (1 >= child.order && child.order !== 0) { if (!_visibleNodes.includes(child.id)) { @@ -1085,7 +1071,7 @@ const OneCademyCollaborationModel = () => { setVisibleNodes(_visibleNodes); setLoadData(true); setShowAll(false); - setIngnorOrder(false); + setIgnoreOrder(false); }; const handleOpenSidBar = () => { setOpenSideBar(old => !old); @@ -1099,7 +1085,7 @@ const OneCademyCollaborationModel = () => { setSelectedDiagram(_diagram); setVisibleNodes(_diagram.nodes); setShowAll(false); - setNodesLoded(false); + setNodesLoaded(false); }; const handleEditDiagram = async () => { @@ -1149,6 +1135,40 @@ const OneCademyCollaborationModel = () => { setNewDiagramName(""); setOpenAddModal(false); }; + const downloadSvg = () => { + const svgElement = svgRef.current; + if (svgElement) { + const clone = svgElement.cloneNode(true); + const svgStyles = document.createElement("style"); + const cssRules = Array.from(document.styleSheets) + .reduce((acc, styleSheet) => { + try { + return acc.concat(Array.from(styleSheet.cssRules)); + } catch { + return acc; // Ignore CSS rules we can't access + } + }, []) + .map(rule => rule.cssText) + .join(" "); + + svgStyles.textContent = cssRules; + clone.insertBefore(svgStyles, clone.firstChild); + + const svgData = new XMLSerializer().serializeToString(clone); + const svgBlob = new Blob([svgData], { type: "image/svg+xml;charset=utf-8" }); + const url = URL.createObjectURL(svgBlob); + + const downloadLink = document.createElement("a"); + downloadLink.href = url; + downloadLink.download = "graph.svg"; + document.body.appendChild(downloadLink); + downloadLink.click(); + document.body.removeChild(downloadLink); + + URL.revokeObjectURL(url); + } + }; + return ( @@ -1230,7 +1250,7 @@ const OneCademyCollaborationModel = () => { Show All the Nodes - {allNodes.map((node, index) => ( + {Object.values(allNodes).map((node, index) => ( { }} sx={{ width: "100%", border: "1px", borderColor: "white" }} > - {allNodes.map(node => ( + {Object.values(allNodes).map(node => ( {node.title} @@ -1652,6 +1672,12 @@ const OneCademyCollaborationModel = () => { label={darkMode ? "Dark Mode" : "Light Mode"} sx={{ mb: "15px", color: darkMode ? "white" : "black" }} /> + + + + + + {editor && ( - - - - - - Add new diagram: - - - - - - - - - - - {" "} - - - - {" "} - + {diagrams.length > 0 ? ( + + + + - Choose nodes to show their causal relations. - {" "} - Show All the Nodes - - - {Object.values(allNodes).map((node, index) => ( - - { - handleVisibileNodes(node); - }} - /> - - - ))} - - - - - - {Object.values(nodeTypes).map((resource, index) => ( - + {Object.keys(nodes).length > 0 && } + {!openSideBar && ( + + + + )} - {resource.type} - - - ))} - {[ - { text: "Known Positive Effect", color: "#56E41B" }, - { text: "Hypothetical Positive Effect", color: "#1BBAE4" }, - { text: "Known Negative Effect", color: "#A91BE4" }, - { text: "Hypothetical Negative Effect", color: "#E4451B" } - ].map((resource, index) => ( - - - - {resource.text} - - - ))} - - - - - - - - - - - - - - - - - - - - - {visibleNodes.length > 0 ? ( - - ) : ( -
- - To show the nodes in the diagram, check them in the list. - -
- )} - {!openSideBar && ( - - )} - - {!openLegend && isMobile && ( - - )} - {visibleNodes.length > 0 && !isMobile && ( - - {Object.values(nodeTypes).map((resource, index) => ( - - ))} - {editor && ( - + {" "} + + {loadingResponse ? ( + + + + ) : ( + + + + )} + + {/* + {loadingResponse ? ( + { - setIsModalAddTypeOpen(true); + display: "flex", + justifyContent: "center" }} + > + + + ) : ( + - + )} - {[ - { text: "Known Positive Effect", color: "#56E41B" }, - { text: "Hypothetical Positive Effect", color: "#1BBAE4" }, - { text: "Known Negative Effect", color: "#A91BE4" }, - { text: "Hypothetical Negative Effect", color: "#E4451B" } - ].map((resource, index) => ( - - - - {resource.text} - - - ))} - - )} -
- - {openModifyLink && editor && ( - - - - - :not(style)": { m: 0.5, width: "25ch" } - }} - noValidate - autoComplete="off" - > - - Type - - - {/* */} + + {loadingResponse ? ( + */} - - - - + > + + + ) : ( { - setDeleteDialogLinkOpen(true); - }} + variant="contained" + onClick={AddNewNode} + sx={{ width: "35px", height: "35px", border: "1px solid gray", borderRadius: "10px" }} + disabled={newNode?.new} > - + - - - - )} - {openModifyLink && !editor && explanationLink !== "" && ( - {explanationLink} - )} - {openAddNode && ( - - { - setTitle(e.currentTarget.value); + )} + + + {diagrams.length > 0 && ( + + Diagram + + + )} + - - :not(style)": { m: 0.5, width: "25ch" } - }} - noValidate - autoComplete="off" - > - - Type - - - - children - - - - - - + > + { - setDeleteDialogOpen(true); - }} + variant="contained" + onClick={downloadSvg} + sx={{ width: "35px", height: "35px", border: "1px solid gray", borderRadius: "10px" }} > - + - + + + + {darkMode ? : } + + + } + /> - )} - - - - - + + + {!newNode?.new && ( + + )} + + + + + )} + {selectedLink && ( + - Reset - - } - label={darkMode ? "Dark Mode" : "Light Mode"} - sx={{ mb: "15px", color: darkMode ? "white" : "black" }} - /> - - - - - + + + Editing the link:{" "} + {nodes[selectedLink.source].label} + + + + {nodes[selectedLink.target].label} + + - {editor && ( - - )} - {editor && ( - - )} - {editor && Object.keys(selectedDiagram).length > 0 && !openModifyLink && !openAddNode && ( - - )} - - {!openModifyLink && - !openAddNode && - Object.keys(selectedDiagram).length > 0 && - listOfDiagrams.length > 0 && ( - + Certainty + - {[...listOfDiagrams].map(diagram => ( - - {diagram.name} - - ))} - - - )} + {["known", "hypothetical"].map((row, index) => ( + + {row} + + ))} + + + + Polarity + + + + {" "} + + + + + )} + + {Object.keys(nodes).length > 0 && !isMobile && ( + + {Object.values(nodeTypes).map((resource, index) => ( + + ))} + {editor && ( + + { + setIsModalAddTypeOpen(true); + }} + variant="contained" + > + + + + )} + + {Object.entries(LINKS_TYPES).map(resource => ( + + + {resource[0]} + + ))} + + + )} -
- - - {openSideBar && ( - - {openSideBar && !isMobile && ( - + + {openSideBar && ( + + - )} - - - {" "} - + - Choose nodes to show their causal relations. - {" "} - Show All the Nodes - - - {Object.values(allNodes) - .sort((a, b) => (a.title > b.title ? 1 : -1)) - .map((node, index) => ( - - { - handleVisibileNodes(node); - }} - /> - - - ))} - - - )} + + + Choose groups to show their causal relations: + + {openSideBar && !isMobile && ( + + + + )} + +
+ + + {/* */} + + + + )} + - - + + ) : ( + + + Generate a diagram + + + )} {editor && ( { editNodeType={editNodeType} /> )} + {ConfirmDialog} + {PromptDialog} ); }; diff --git a/src/hooks/useConfirmDialog.js b/src/hooks/useConfirmDialog.js new file mode 100644 index 00000000..cd7450fc --- /dev/null +++ b/src/hooks/useConfirmDialog.js @@ -0,0 +1,100 @@ +import { Button, Dialog, DialogActions, DialogContent, DialogContentText, TextField } from "@mui/material"; +import React, { useCallback, useState } from "react"; + +const useDialog = () => { + const [isOpen, setIsOpen] = useState(false); + const [dialogMessage, setDialogMessage] = useState(""); + const [isPrompt, setIsPrompt] = useState(false); + const [inputValue, setInputValue] = useState(""); + const resolveRef = React.useRef(null); + const [confirmation, setConfirmation] = useState(""); + const [cancel, setCancel] = useState(""); + + const showDialog = useCallback((message, prompt = false, confirmation, cancel) => { + setDialogMessage(message); + setIsOpen(true); + setIsPrompt(prompt); + setConfirmation(confirmation); + setCancel(cancel); + + return new Promise(resolve => { + resolveRef.current = resolve; + }); + }, []); + + const closeDialog = useCallback( + confirmed => { + setIsOpen(false); + setDialogMessage(""); + setInputValue(""); + + if (resolveRef.current) { + resolveRef.current(isPrompt ? inputValue : confirmed); + } + }, + [isPrompt, inputValue] + ); + + const handleInputChange = event => { + setInputValue(event.target.value); + }; + + const ConfirmDialog = ( + closeDialog(false)} sx={{ width: "100%" }}> + + {dialogMessage} + {isPrompt && ( + + )} + + + + {!isPrompt && cancel && ( + + )} + + + ); + + const promptIt = useCallback( + (message, confirmation, cancel) => showDialog(message, true, confirmation, cancel), + [showDialog] + ); + const confirmIt = useCallback( + (message, confirmation, cancel) => showDialog(message, false, confirmation, cancel), + [showDialog] + ); + + return { promptIt, confirmIt, ConfirmDialog }; +}; + +export default useDialog; diff --git a/src/hooks/usePromptDialog.js b/src/hooks/usePromptDialog.js new file mode 100644 index 00000000..11ad54d8 --- /dev/null +++ b/src/hooks/usePromptDialog.js @@ -0,0 +1,150 @@ +import { + Button, + Dialog, + DialogActions, + DialogContent, + DialogContentText, + TextField, + Grid, + Typography +} from "@mui/material"; +import React, { useCallback, useEffect, useState } from "react"; +import { useRecoilValue } from "recoil"; +import { firebaseState } from "../store/AuthAtoms"; +import Box from "@mui/material/Box"; + +const useDialog = () => { + const [isOpen, setIsOpen] = useState(false); + const [dialogMessage, setDialogMessage] = useState(""); + const [inputValue, setInputValue] = useState(""); + const resolveRef = React.useRef(null); + const [confirmation, setConfirmation] = useState(""); + const [cancel, setCancel] = useState(""); + const firebase = useRecoilValue(firebaseState); + const [llmPrompt, setLlmPrompt] = useState(""); + + const getPrompt = async type => { + const promptDoc = await firebase.db.collection("diagramPrompts").doc(type).get(); + const promptData = promptDoc.data(); + setLlmPrompt(promptData?.prompt || ""); + }; + + const showDialog = useCallback((message, confirmation, cancel) => { + getPrompt(confirmation.toLowerCase()); + setDialogMessage(message); + setIsOpen(true); + setConfirmation(confirmation); + setCancel(cancel); + + return new Promise(resolve => { + resolveRef.current = resolve; + }); + }, []); + + const closeDialog = useCallback(() => { + setIsOpen(false); + setDialogMessage(""); + setInputValue(""); + setLlmPrompt(""); + + if (resolveRef.current) { + savePrompt(); + resolveRef.current(inputValue || ""); + } + }, [inputValue, llmPrompt]); + + const handleUserInputChange = event => { + setInputValue(event.target.value); + }; + + const handleLlmPromptChange = event => { + setLlmPrompt(event.target.value); + }; + const savePrompt = () => { + const promptRef = firebase.db.collection("diagramPrompts").doc(confirmation.toLowerCase()); + promptRef.set({ + prompt: llmPrompt + }); + }; + + const PromptDialog = ( + + + {dialogMessage} + + + + {confirmation.toLowerCase() === "generate" ? "Enter your document bellow:" : "Your input:"} + + + + + System Prompt: + + + + + + + {cancel && ( + + )} + + + ); + + const promptItDiagram = useCallback( + (message, confirmation, cancel, type) => showDialog(message, confirmation, cancel), + [showDialog] + ); + + return { promptItDiagram, PromptDialog }; +}; + +export default useDialog;