Skip to content

Commit

Permalink
added state management for hiding and showing children nodes
Browse files Browse the repository at this point in the history
  • Loading branch information
AbbyB97 committed Jul 12, 2024
1 parent 9a9af1a commit 699e4bc
Show file tree
Hide file tree
Showing 4 changed files with 97 additions and 107 deletions.
137 changes: 61 additions & 76 deletions src/components/FlowChart/CustomFlowNode/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,90 +13,70 @@ import style from './customFlowNode.module.scss';
export default function CustomFlowNode({ data, dragging, selected, xPos, yPos, id }: EntityNodeProps) {
const [collapse, setCollapse] = useState(data.expandedByDefault ?? false);
const [addNodeContentCollapse, setAddNodeContentCollapse] = useState(false);
const reactFlowUI = useSelector(userInterfaceSelectors.selectReactFlowUI);
const [showHiddenNodes, setShowHiddenNodes] = useState(false);

const currentnodes = reactFlowUI?.flowChartNodes;
const thisNodeState = currentnodes?.find((node) => node?.id === id);
const flowChartNoedesState = useSelector(userInterfaceSelectors.flowChartNodes);
const expandedHiddenNodeId = useSelector(userInterfaceSelectors.expandedHiddenNodeId);

const thisNodeState = useMemo(() => {
return flowChartNoedesState?.find((node) => node?.id === id);
}, [flowChartNoedesState, id]);

const hasHiddenChildren = useMemo(() => {
return currentnodes?.some((node) => node?.parentId === id && node.hidden !== undefined);
}, [currentnodes, id]);
return flowChartNoedesState?.some((node) => node?.parentId === id && node.hidden !== undefined);
}, [flowChartNoedesState, id]);
const dispatch = useDispatch();

const toggleHiddenNodes = useCallback(
(showHiddenNodes: boolean) => {
// const
if (showHiddenNodes) {
const updatedNodes = currentnodes?.map((node, i) => {
const totalNodes = currentnodes?.filter((node) => node.parentId === id).length || 1; // Total child nodes
const toggleHiddenNodes = useCallback(() => {
if (expandedHiddenNodeId !== id) {
const updatedNodes = flowChartNoedesState?.map((node, i) => {
const totalNodes = flowChartNoedesState?.filter((node) => node.parentId === id).length || 1; // Total child nodes

const multiplier = totalNodes < 3 ? 300 : 200;
const nodeRadius = multiplier * (totalNodes * 0.3); // Smaller radius for nodes within a group
const nodeAngle = ((2 * Math.PI) / totalNodes) * i;
const multiplier = totalNodes < 3 ? 300 : 200;
const nodeRadius = multiplier * (totalNodes * 0.3); // Smaller radius for nodes within a group
const nodeAngle = ((2 * Math.PI) / totalNodes) * i;

if (node?.parentId !== id && node.hidden === false) {
return {
...node,
hidden: true,
};
}
if (node?.parentId !== id && node.hidden === false) {
return {
...node,
hidden: true,
};
}

if (node?.parentId === id && node.hidden !== undefined) {
const positionMultiplier = totalNodes < 2 ? 3.5 : 1.75;
const position = {
x: nodeRadius * positionMultiplier * Math.cos(nodeAngle),
y: nodeRadius * positionMultiplier * Math.sin(nodeAngle),
};
if (node?.parentId === id && node.hidden !== undefined) {
const positionMultiplier = totalNodes < 2 ? 3.5 : 1.75;
const position = {
x: nodeRadius * positionMultiplier * Math.cos(nodeAngle),
y: nodeRadius * positionMultiplier * Math.sin(nodeAngle),
};

return {
...node,
position: position,
// position: {
// x: xPos + 100,
// y: yPos + 100,
// },
hidden: false,
};
}
return node;
});
return {
...node,
position: position,
hidden: false,
};
}
return node;
});

dispatch(
userInterfaceActions.setReactFlowUI({
flowChartNodes: updatedNodes || [],
flowChartEdges: reactFlowUI?.flowChartEdges || [],
flowDirection: reactFlowUI?.flowDirection,
legends: reactFlowUI?.legends,
}),
);
} else {
const updatedNodes = currentnodes?.map((node) => {
if (node?.parentId === id && node.hidden !== undefined) {
return {
...node,
// position: {
// x: xPos + 100,
// y: yPos + 100,
// },
hidden: true,
};
}
return node;
});
if (updatedNodes) dispatch(userInterfaceActions.updateReactFlowNodes(updatedNodes));

dispatch(
userInterfaceActions.setReactFlowUI({
flowChartNodes: updatedNodes || [],
flowChartEdges: reactFlowUI?.flowChartEdges || [],
flowDirection: reactFlowUI?.flowDirection,
legends: reactFlowUI?.legends,
}),
);
}
},
[currentnodes, reactFlowUI, dispatch, id],
);
dispatch(userInterfaceActions.setShowHiddenNodes(id));
} else {
const updatedNodes = flowChartNoedesState?.map((node) => {
if (node?.parentId === id && node.hidden !== undefined) {
return {
...node,
hidden: true,
};
}
return node;
});

if (updatedNodes) dispatch(userInterfaceActions.updateReactFlowNodes(updatedNodes));

dispatch(userInterfaceActions.setShowHiddenNodes(undefined));
}
}, [flowChartNoedesState, dispatch, id, expandedHiddenNodeId]);

const toggle = () => setCollapse(!collapse);
const copyToClipboard = useCopyToClipboard();
Expand Down Expand Up @@ -197,13 +177,18 @@ export default function CustomFlowNode({ data, dragging, selected, xPos, yPos, i
<Button
color="primary"
onClick={() => {
setShowHiddenNodes(!showHiddenNodes);
toggleHiddenNodes(!showHiddenNodes);
// setShowHiddenNodes(!expandedHiddenNodeId);
toggleHiddenNodes();
}}
className={cx('mt-1', style.nodeButton, getExpandButtonStatusClasses())}
>
{/* <span className="mx-auto">{status}</span> */}
<i className={cx('fa ', { 'fa-eye': !showHiddenNodes, 'fa-eye-slash': showHiddenNodes })} />
<i
className={cx('fa ', {
'fa-eye': expandedHiddenNodeId !== id,
'fa-eye-slash': expandedHiddenNodeId === id,
})}
/>
</Button>
) : null}
{/*
Expand Down
38 changes: 12 additions & 26 deletions src/components/FlowChart/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -185,37 +185,26 @@ const FlowChartContent = ({
legends,
}: FlowChartProps) => {
const defaultEdgeOptions = { animated: true };
const reactFlowUI = useSelector(userInterfaceSelectors.selectReactFlowUI);
const flowChartNodesState = useSelector(userInterfaceSelectors.flowChartNodes);
const flowChartEdgesState = useSelector(userInterfaceSelectors.flowChartEdges);

const dispatch = useDispatch();

const onNodesChange = useCallback(
(changes: NodeChange[]) => {
const newNodes = applyNodeChanges(changes, reactFlowUI?.flowChartNodes ?? []);
dispatch(
userInterfaceActions.setReactFlowUI({
flowChartNodes: newNodes,
flowChartEdges: reactFlowUI?.flowChartEdges || [],
flowDirection: reactFlowUI?.flowDirection,
legends: reactFlowUI?.legends,
}),
);
const newNodes = applyNodeChanges(changes, flowChartNodesState ?? []);

dispatch(userInterfaceActions.updateReactFlowNodes(newNodes));
},
[dispatch, reactFlowUI],
[dispatch, flowChartNodesState],
);

const onEdgesChange = useCallback(
(changes: EdgeChange[]) => {
const newEdges = applyEdgeChanges(changes, reactFlowUI?.flowChartEdges ?? []);
dispatch(
userInterfaceActions.setReactFlowUI({
flowChartNodes: reactFlowUI?.flowChartNodes || [],
flowChartEdges: newEdges,
flowDirection: reactFlowUI?.flowDirection,
legends: reactFlowUI?.legends,
}),
);
const newEdges = applyEdgeChanges(changes, flowChartEdgesState ?? []);
dispatch(userInterfaceActions.updateReactFlowEdges(newEdges));
},
[dispatch, reactFlowUI],
[dispatch, flowChartEdgesState],
);

// // TODO: Implement onConnect in future if needed
Expand All @@ -224,8 +213,6 @@ const FlowChartContent = ({
useEffect(() => {
// initial placement of nodes and edges
const { nodes, edges } = getLayoutedElements(flowChartNodes, flowChartEdges, flowDirection);
// setNodes(nodes);
// setEdges(edges);

dispatch(
userInterfaceActions.setReactFlowUI({
Expand All @@ -241,17 +228,16 @@ const FlowChartContent = ({
{flowChartTitle && <h5 className="text-muted">{flowChartTitle}</h5>}
<div className={cx(style.flowChartContainer, style.floatingedges)}>
<ReactFlow
nodes={reactFlowUI?.flowChartNodes}
nodes={flowChartNodesState}
proOptions={{ hideAttribution: true }}
edges={reactFlowUI?.flowChartEdges}
edges={flowChartEdgesState}
onNodesChange={onNodesChange}
onEdgesChange={onEdgesChange}
nodeTypes={nodeTypes}
fitView={!defaultViewport}
defaultViewport={defaultViewport}
defaultEdgeOptions={defaultEdgeOptions}
edgeTypes={edgeTypes}
// connectionLineComponent={FloatingConnectionLine}
>
<Controls />
<Background variant={BackgroundVariant.Dots} gap={16} size={1} />
Expand Down
27 changes: 23 additions & 4 deletions src/ducks/user-interface.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { createSlice, PayloadAction } from '@reduxjs/toolkit';
import { CustomNode } from 'components/FlowChart';
import { Edge } from 'reactflow';
import { createSelector } from 'reselect';
import { AjaxError } from 'rxjs/ajax';
import { GlobalModalModel, LockWidgetNameEnum, ReactFlowUI, WidgetLockErrorModel, WidgetLockModel } from 'types/user-interface';
Expand Down Expand Up @@ -124,9 +125,21 @@ export const slice = createSlice({
state.reactFlowUI = undefined;
},

setShowHiddenNodes: (state, action: PayloadAction<boolean>) => {
updateReactFlowNodes: (state, action: PayloadAction<CustomNode[]>) => {
if (state.reactFlowUI) {
state.reactFlowUI.showHiddenNodes = action.payload;
state.reactFlowUI.flowChartNodes = action.payload;
}
},

updateReactFlowEdges: (state, action: PayloadAction<Edge[]>) => {
if (state.reactFlowUI) {
state.reactFlowUI.flowChartEdges = action.payload;
}
},

setShowHiddenNodes: (state, action: PayloadAction<string | undefined>) => {
if (state.reactFlowUI) {
state.reactFlowUI.expandedHiddenNodeId = action.payload;
}
},

Expand All @@ -147,7 +160,10 @@ const selectInitiateAttributeCallback = createSelector(selectState, (state) => s
const selectAttributeCallbackValue = createSelector(selectState, (state) => state.attributeCallbackValue);
const selectCallbackValue = createSelector(selectState, (state) => state.formCallbackValue);
const selectInitiateFormCallback = createSelector(selectState, (state) => state.initiateFormCallback);
const selectReactFlowUI = createSelector(selectState, (state) => state.reactFlowUI);
const reactFlowUI = createSelector(selectState, (state) => state.reactFlowUI);
const flowChartNodes = createSelector(reactFlowUI, (state) => state?.flowChartNodes);
const flowChartEdges = createSelector(reactFlowUI, (state) => state?.flowChartEdges);
const expandedHiddenNodeId = createSelector(reactFlowUI, (state) => state?.expandedHiddenNodeId);

export const selectors = {
selectState,
Expand All @@ -157,7 +173,10 @@ export const selectors = {
selectAttributeCallbackValue,
selectCallbackValue,
selectInitiateFormCallback,
selectReactFlowUI,
reactFlowUI,
flowChartNodes,
flowChartEdges,
expandedHiddenNodeId,
};

export const actions = slice.actions;
Expand Down
2 changes: 1 addition & 1 deletion src/types/user-interface.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ export interface ReactFlowUI {
flowChartEdges: Edge[];
flowDirection?: 'TB' | 'BT' | 'LR' | 'RL' | 'STAR';
legends?: LegendItem[];
showHiddenNodes?: boolean;
expandedHiddenNodeId?: string;
}

export const AddNewAttributeList: AddNewAttributeType[] = [
Expand Down

0 comments on commit 699e4bc

Please sign in to comment.