diff --git a/src/components/Nodes/DefaultNode/default.module.css b/src/components/Tree/Nodes/DefaultNode/default.module.css
similarity index 100%
rename from src/components/Nodes/DefaultNode/default.module.css
rename to src/components/Tree/Nodes/DefaultNode/default.module.css
diff --git a/src/components/Tree/Tree.tsx b/src/components/Tree/Tree.tsx
index 12e757a..a9a5e51 100644
--- a/src/components/Tree/Tree.tsx
+++ b/src/components/Tree/Tree.tsx
@@ -1,6 +1,7 @@
-import { BoolNode } from 'components/Nodes/BoolNode/BoolNode';
-import { DefaultNode } from 'components/Nodes/DefaultNode/DefaultNode';
import { ControlCenter } from 'components/Tree/ControlCenter';
+import { DecisionEdge } from 'components/Tree/Edges/DecisionEdge/DecisionEdge';
+import { BoolNode } from 'components/Tree/Nodes/BoolNode/BoolNode';
+import { DefaultNode } from 'components/Tree/Nodes/DefaultNode/DefaultNode';
import { useDecisionTree, useTreeDirection } from 'hooks';
import React, { useMemo, useState } from 'react';
import ReactFlow, { Edge, MiniMap, Node, useReactFlow, useViewport, XYPosition } from 'reactflow';
@@ -11,6 +12,10 @@ export interface TreeProps {
mapVisible?: boolean;
}
+const edgeTypes = {
+ decision: DecisionEdge,
+};
+
/**
* Tree - responsible for rendering the decision tree
*/
@@ -27,6 +32,7 @@ export const Tree = ({ nodes, edges }: TreeProps) => {
{
onEdgesChange,
markDecisionMade,
markDecisionFocused,
+ updatePath,
} = useDecTreeStore((state) => state);
/** show a node's direct children and the edges leading to them */
@@ -64,6 +65,10 @@ export const useDecisionTree = (initialTree?: PositionUnawareDecisionTree) => {
}
}, [initialTree, setStoreTree, showStoreNode]);
+ const addToPath = (source: string, target: string) => {
+ updatePath(source, target);
+ };
+
return {
tree,
showNode,
@@ -77,5 +82,6 @@ export const useDecisionTree = (initialTree?: PositionUnawareDecisionTree) => {
onNodesChange,
markDecisionMade,
markDecisionFocused,
+ addToPath,
} as const;
};
diff --git a/src/hooks/useFetchConfig/useFetchConfig.tsx b/src/hooks/useFetchConfig/useFetchConfig.tsx
index 0fb508a..f80154d 100644
--- a/src/hooks/useFetchConfig/useFetchConfig.tsx
+++ b/src/hooks/useFetchConfig/useFetchConfig.tsx
@@ -1,4 +1,4 @@
-import { BoolNodeData } from 'components/Nodes/BoolNode/BoolNode';
+import { BoolNodeData } from 'components/Tree';
import { useEffect, useState } from 'react';
import { PositionUnawareDecisionTree, TreeNode } from 'store';
import { BooleanNodeData, NodeData } from 'store/DecisionSlice/decisionSlice';
diff --git a/src/store/DagEdgeSlice/dagEdgeSlice.ts b/src/store/DagEdgeSlice/dagEdgeSlice.ts
index 4dfbee8..726c363 100644
--- a/src/store/DagEdgeSlice/dagEdgeSlice.ts
+++ b/src/store/DagEdgeSlice/dagEdgeSlice.ts
@@ -1,9 +1,10 @@
+import { DecisionEdgeData } from 'components/Tree/Edges/DecisionEdge/DecisionEdge';
import { applyEdgeChanges, Edge, EdgeChange, OnEdgesChange } from 'reactflow';
import { addDagEdge } from 'store/DagEdgeSlice/dagEdgeUtils';
import { StateCreator } from 'zustand';
interface DagEdgeSliceState {
- dagEdges: Edge[];
+ dagEdges: Edge[];
}
interface DagEdgeSliceActions {
@@ -13,6 +14,10 @@ interface DagEdgeSliceActions {
removeEdgesByTarget: (nodeIds: string[]) => void;
/** Create an edge */
createEdge: (sourceId?: string, targetId?: string) => void;
+ /** Mark an edge as decision made by source */
+ addEdgeToPath: (source: string, target: string) => void;
+ /** Remove an edge from the path by source */
+ removeEdgeFromPathBySource: (source: string) => void;
}
export interface DagEdgeSlice extends DagEdgeSliceState, DagEdgeSliceActions {}
@@ -54,4 +59,35 @@ export const createDagEdgeSlice: StateCreator<
'createEdge'
);
},
+ removeEdgeFromPathBySource: (source: string) => {
+ const newEdges = get().dagEdges.map((edge) => {
+ if (edge.source === source) {
+ edge.data = { decisionMade: false };
+ }
+ return edge;
+ });
+ set(
+ {
+ dagEdges: newEdges,
+ },
+ false,
+ 'removeEdgeFromPathBySource'
+ );
+ },
+ addEdgeToPath: (source: string, target: string) => {
+ const newEdges = get().dagEdges.map((edge) => {
+ if (edge.source === source && edge.target === target) {
+ edge.style = { stroke: '#05b485', strokeWidth: '3px' };
+ edge.data = { decisionMade: true };
+ }
+ return edge;
+ });
+ set(
+ {
+ dagEdges: newEdges,
+ },
+ false,
+ 'markEdgeAsDecisionMade'
+ );
+ },
});
diff --git a/src/store/DagEdgeSlice/dagEdgeUtils.ts b/src/store/DagEdgeSlice/dagEdgeUtils.ts
index f3b440e..610e4ee 100644
--- a/src/store/DagEdgeSlice/dagEdgeUtils.ts
+++ b/src/store/DagEdgeSlice/dagEdgeUtils.ts
@@ -20,7 +20,7 @@ export const createDagEdge = (source: string, target: string): Edge => {
hidden: false,
source,
target,
- type: 'smoothstep',
+ type: 'decision',
markerEnd: { type: MarkerType.ArrowClosed },
};
};
diff --git a/src/store/TreeSlice/treeSlice.ts b/src/store/TreeSlice/treeSlice.ts
index a7f5870..72df625 100644
--- a/src/store/TreeSlice/treeSlice.ts
+++ b/src/store/TreeSlice/treeSlice.ts
@@ -19,6 +19,7 @@ export interface TreeSlice {
removeNiblings: (nodeId: string) => void;
markDecisionMade: (nodeId: string) => void;
markDecisionFocused: (nodeId: string) => void;
+ updatePath: (source: string, target: string) => void;
}
/** The state of the tree, implemented as a shared slice that builds on concrete slices
@@ -75,7 +76,6 @@ export const createTreeSlice: StateCreator<
const siblingDescendantIds = siblings.flatMap((id) => getDescendantIds(get().tree, id));
get().setStatus([nodeId], 'chosen');
get().setStatus([...siblingDescendantIds, ...siblings], undefined);
- get().updateDagNodes(get().tree);
},
markDecisionFocused: (nodeId: string) => {
const siblings = getSiblingIds(get().tree, nodeId);
@@ -84,4 +84,8 @@ export const createTreeSlice: StateCreator<
get().setStatus([...siblingDescendantIds, ...siblings], undefined);
get().updateDagNodes(get().tree);
},
+ updatePath: (source: string, target: string) => {
+ get().removeEdgeFromPathBySource(source);
+ get().addEdgeToPath(source, target);
+ },
});