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",