diff --git a/CHANGELOG.md b/CHANGELOG.md index 9ab91809..a287d6ad 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Change Log +## v2.0.4 (2021/01/09) + +Patch Update + +- Fixed bug causing workflow graph to break on deleting nodes. +- Added new warnings when using start from scratch button to avoid accidental deletion of work. ## v2.0.3 (2020/11/27) Patch Update diff --git a/backend/setup.py b/backend/setup.py index bca712b0..eb23e344 100644 --- a/backend/setup.py +++ b/backend/setup.py @@ -2,7 +2,7 @@ setup( name='qresp', - version='2.0.3', + version='2.0.4', url='https://qresp.org/', entry_points = { 'console_scripts': ['qresp=project.__main__:main'], diff --git a/frontend/Context/Curator/curatorReducer.js b/frontend/Context/Curator/curatorReducer.js index 11d3a6fc..66304b35 100644 --- a/frontend/Context/Curator/curatorReducer.js +++ b/frontend/Context/Curator/curatorReducer.js @@ -17,6 +17,8 @@ import { SET_DOCUMENTATION, } from "../types"; +import { getNodeNumber, reduceEdgeNodeId } from "../../Utils/graph"; + export default (state, action) => { switch (action.type) { case SET_CURATORINFO: @@ -54,10 +56,19 @@ export default (state, action) => { case DELETE: const prefix = action.payload.type.charAt(0); + const node_number_to_delete = getNodeNumber(action.payload.id); - const newEdges = state.workflow.edges.filter( - (edge) => edge.to != action.payload.id && edge.from != action.payload.id - ); + /* + 1st filter removes the edges corresponding to the deleted node. + 2nd filter fixes the node and id mapping, deleting a node causes the node with higher id having incorrect edges + */ + + const newEdges = state.workflow.edges + .filter( + (edge) => + edge.to != action.payload.id && edge.from != action.payload.id + ) + .map((edge) => reduceEdgeNodeId(node_number_to_delete, prefix, edge)); return { ...state, diff --git a/frontend/Utils/graph.js b/frontend/Utils/graph.js index 65d93d4f..94c5a3b1 100644 --- a/frontend/Utils/graph.js +++ b/frontend/Utils/graph.js @@ -20,6 +20,27 @@ const createGraph = ({ nodes, edges }) => { return graph; }; +// Returns the number of record in the corresponding section +const getNodeNumber = (id) => parseInt(id.substring(1)); + +/* +When a node is deleted, we rempa their ids to the lower number. +So we also have to rempa the edges, this is what reduce means in this context. +*/ +const reduceEdgeNodeId = (node_number_to_delete, prefix, edge) => { + if (edge.to.charAt(0) == prefix) { + if (getNodeNumber(edge.to) > node_number_to_delete) { + edge.to = prefix + (getNodeNumber(edge.to) - 1).toString(); + } + } + if (edge.from.charAt(0) == prefix) { + if (getNodeNumber(edge.from) > node_number_to_delete) { + edge.from = prefix + (getNodeNumber(edge.from) - 1).toString(); + } + } + return edge; +}; + const isGraphCyclicUtil = (node, graph, visited, stack) => { if (!visited[node]) { visited[node] = true; @@ -61,4 +82,4 @@ const isGraph = { }, }; -export { isGraph }; +export { isGraph, getNodeNumber, reduceEdgeNodeId }; diff --git a/frontend/components/CuratorElements/TopActions.js b/frontend/components/CuratorElements/TopActions.js index ae65b64a..42d1314b 100644 --- a/frontend/components/CuratorElements/TopActions.js +++ b/frontend/components/CuratorElements/TopActions.js @@ -48,7 +48,7 @@ const preview = (metadata, setAlert, router) => { const TopActions = () => { const { metadata, setAll, resetAll } = useContext(CuratorContext); - const { setAlert } = useContext(AlertContext); + const { setAlert, unsetAlert } = useContext(AlertContext); const { setSelectedHttp, selectedHttp } = useContext(ServerContext); const [mdata, setMdata] = useState(""); const [resumeDialogOpen, setResumeDialogOpen] = useState(false); @@ -59,6 +59,31 @@ const TopActions = () => { resume: () => { setResumeDialogOpen(true); }, + scratch: () => { + setAlert( + "Warning", + "This is an irreversible operation, please download your work if you plan to use it in the future. Do you still wish to continue ?", + + } + href={`data:text/json;charset=utf-8,${encodeURIComponent( + JSON.stringify(onClicks.download(metadata), null, 2) + )}`} + download="metadata.json" + > + Download Metadata + + { + resetAll(); + unsetAlert(); + }} + > + Yes, start from Scratch + + + ); + }, download: (metadata) => { return { ...metadata, selectedHttp: selectedHttp }; }, @@ -78,7 +103,7 @@ const TopActions = () => { ), scratch: (fullWidth = false) => ( - + Start from Scratch diff --git a/frontend/package.json b/frontend/package.json index 8009085c..9d5c82be 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,6 +1,6 @@ { "name": "qresp", - "version": "2.0.3", + "version": "2.0.4", "private": true, "scripts": { "dev": "next dev",