Skip to content

Commit

Permalink
SF-04 Refactor flow slice (#26)
Browse files Browse the repository at this point in the history
* Start SF-04

* Rewrite flow.slice to split entities into three separate entity adapters

* Update builder.slice with new flowActions and proper selector creation

* Rename node/node.slice to palette/node.slice and add extra actions

* Update spell check dictionary

* Update flow.slice selectors

* Update flow.logic with flow.slice api changes

* Split flow.logic up into four different logic files

* Update node.logic with node.slice api changes

* Update node.api with palette/node.slice api changes

* Correctly type flow.slice actions

* Don't open directories when first rendered in tree (Default closed)

* Update components with new redux slice APIs

* Change ports of flow-client

* Correct bug in tree.logic, correctly handle empty string directory values

* Remove remaining template code

* Update red/ with redux API changes

* Finish SF-04
  • Loading branch information
JoshuaCWebDeveloper authored May 22, 2024
1 parent 3d7f16c commit 142c177
Show file tree
Hide file tree
Showing 42 changed files with 3,665 additions and 3,313 deletions.
2 changes: 2 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
"oneditprepare",
"oneditresize",
"oneditsave",
"onpaletteadd",
"onpaletteremove",
"projectstorm",
"ptype",
"PWRD"
Expand Down
11 changes: 5 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -208,12 +208,11 @@ The backlog is organized by epic, with each task having a unique ID, description

### Scrum Board

| To Do | In Progress | In Review | Done |
| ----- | ----------- | --------- | ---- |
| SF-01 | | | |
| SF-02 | | | |
| SF-03 | | | |
| SF-04 | | | |
| To Do | In Progress | In Review | Done |
| ----- | ----------- | --------- | ----- |
| SF-01 | | | SF-04 |
| SF-02 | | | |
| SF-03 | | | |

### Progress Tracking

Expand Down
12 changes: 6 additions & 6 deletions packages/flow-client/src/app/components/builder/node-editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@ import redTypedInputCssUrl from '../../red/red-typed-input.css?url';
import {
FlowNodeEntity,
flowActions,
selectEntityById,
selectFlowNodeById,
} from '../../redux/modules/flow/flow.slice';
import { selectNodeById } from '../../redux/modules/node/node.slice';
import { selectPaletteNodeById } from '../../redux/modules/palette/node.slice';
import environment from '../../../environment';

const StyledEditor = styled.div`
Expand Down Expand Up @@ -187,10 +187,10 @@ export const NodeEditor = () => {
);
const editing = useAppSelector(selectEditing);
const editingNode = useAppSelector(state =>
selectEntityById(state, editing ?? '')
selectFlowNodeById(state, editing ?? '')
) as FlowNodeEntity;
const editingNodeEntity = useAppSelector(state =>
selectNodeById(state, editingNode?.type)
selectPaletteNodeById(state, editingNode?.type)
);

const propertiesFormRefCallback = useCallback(
Expand Down Expand Up @@ -251,7 +251,7 @@ export const NodeEditor = () => {
(propertiesForm?.getRootNode() as ShadowRoot) ?? undefined
);
// TODO: Implement logic method for removing any old input links (if necessary)
dispatch(flowActions.removeEntity(editingNode.id));
dispatch(flowActions.removeFlowNode(editingNode.id));
closeEditor();
}, [
closeEditor,
Expand Down Expand Up @@ -321,7 +321,7 @@ export const NodeEditor = () => {
});
}
// update node
dispatch(flowLogic.updateFlowNode(editingNode.id, nodeUpdates));
dispatch(flowLogic.node.updateFlowNode(editingNode.id, nodeUpdates));
// close editor
closeEditor();
}, [
Expand Down
43 changes: 16 additions & 27 deletions packages/flow-client/src/app/components/builder/tab-manager.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,8 @@ import {
selectOpenFlows,
} from '../../redux/modules/builder/builder.slice';
import {
FlowEntity,
SubflowEntity,
flowActions,
selectFlows,
selectSubflows,
selectFlowEntities,
} from '../../redux/modules/flow/flow.slice';
import { FlowCanvas } from '../flow-canvas/flow-canvas';

Expand Down Expand Up @@ -126,8 +123,7 @@ const StyledTabManager = styled.div`

export const TabManager = () => {
const dispatch = useDispatch();
const flows = useAppSelector(selectFlows);
const subflows = useAppSelector(selectSubflows);
const flowEntities = useAppSelector(selectFlowEntities);
const openFlows = useAppSelector(selectOpenFlows);
const activeFlow = useAppSelector(selectActiveFlow);
const flowCounter = useAppSelector(selectNewFlowCounter);
Expand All @@ -151,17 +147,16 @@ export const TabManager = () => {
const createNewTab = useCallback(() => {
const flowId = uuidv4();
dispatch(
flowActions.addEntity({
flowActions.addFlowEntity({
id: flowId,
type: 'tab',
label: `New Flow${flowCounter ? ` ${flowCounter}` : ''}`,
type: 'flow',
name: `New Flow${flowCounter ? ` ${flowCounter}` : ''}`,
disabled: false,
info: '',
env: [],
})
);
dispatch(builderActions.addNewFlow(flowId));
dispatch(builderActions.openFlow(flowId));
dispatch(builderActions.setActiveFlow(flowId));
}, [dispatch, flowCounter]);

Expand All @@ -187,38 +182,32 @@ export const TabManager = () => {
ref={tabContentRef}
>
<div className="tab-list">
{openFlows.map(flowId => {
const flowOrSubflow = [...flows, ...subflows].find(
it => it.id === flowId
);
const name =
(flowOrSubflow as SubflowEntity)?.name ??
(flowOrSubflow as FlowEntity)?.label ??
'...';
return (
{openFlows
.map(flowId => flowEntities[flowId])
.filter(it => it)
.map(flowEntity => (
<div
key={flowId}
id={`tab-${flowId}`}
key={flowEntity.id}
id={`tab-${flowEntity.id}`}
className={`tab-item ${
flowId === activeFlow
flowEntity.id === activeFlow
? 'active-tab'
: ''
}`}
onClick={() => switchTab(flowId)}
onClick={() => switchTab(flowEntity.id)}
>
<p>{name}</p>
<p>{flowEntity.name}</p>
<span
className="close-btn"
onClick={e => {
e.stopPropagation(); // Prevent tab switch when closing
closeTab(flowId);
closeTab(flowEntity.id);
}}
>
<i className="fa fa-times"></i>
</span>
</div>
);
})}
))}
</div>
</div>

Expand Down
4 changes: 2 additions & 2 deletions packages/flow-client/src/app/components/flow-canvas/engine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ import {
} from '@projectstorm/react-diagrams';
import { DropTargetMonitor } from 'react-dnd';

import { SerializedGraph } from '../../redux/modules/flow/graph.logic';
import { CustomDiagramModel } from './model';
import { CustomNodeFactory } from './node';
import { SerializedGraph } from '../../redux/modules/flow/flow.logic';

export class CustomEngine extends DiagramEngine {
constructor(options?: CanvasEngineOptions) {
Expand Down Expand Up @@ -201,7 +201,7 @@ export const createEngine = (options = {}) => {
engine.getLinkFactories().registerFactory(new DefaultLinkFactory());
engine.getLinkFactories().registerFactory(new PathFindingLinkFactory());
engine.getPortFactories().registerFactory(new DefaultPortFactory());
// register the default interaction behaviours
// register the default interaction behaviors
engine.getStateMachine().pushState(new DefaultDiagramState());
return engine;
};
31 changes: 21 additions & 10 deletions packages/flow-client/src/app/components/flow-canvas/flow-canvas.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,13 @@ import styled from 'styled-components';
import { v4 as uuidv4 } from 'uuid';

import { useAppDispatch, useAppLogic, useAppSelector } from '../../redux/hooks';
import { SerializedGraph } from '../../redux/modules/flow/flow.logic';
import { selectAllEntities } from '../../redux/modules/flow/flow.slice';
import { NodeEntity } from '../../redux/modules/node/node.slice';
import {
selectAllDirectories,
selectAllFlowEntities,
selectAllFlowNodes,
} from '../../redux/modules/flow/flow.slice';
import { SerializedGraph } from '../../redux/modules/flow/graph.logic';
import { PaletteNodeEntity } from '../../redux/modules/palette/node.slice';
import { ItemTypes } from '../node/draggable-item-types'; // Assuming ItemTypes is defined elsewhere
import { createEngine } from './engine';
import { CustomDiagramModel } from './model';
Expand Down Expand Up @@ -98,11 +102,13 @@ const debounce = (func: (...args: unknown[]) => void, wait: number) => {
};

const LogFlowSlice = () => {
const flowSlice = useAppSelector(selectAllEntities);
const flowEntities = useAppSelector(selectAllFlowEntities);
const flowNodes = useAppSelector(selectAllFlowNodes);
const directories = useAppSelector(selectAllDirectories);

useEffect(() => {
console.log('Flow state: ', flowSlice);
}, [flowSlice]);
console.log('Flow state: ', { flowEntities, flowNodes, directories });
}, [flowEntities, flowNodes, directories]);

return null; // This component does not render anything
};
Expand Down Expand Up @@ -145,7 +151,10 @@ export const FlowCanvas: React.FC<FlowCanvasProps> = ({ flowId }) => {
}, [flowId, engine]);

const serializedGraph = useAppSelector(state =>
flowLogic.selectSerializedGraphByFlowId(state, model?.getID() ?? '')
flowLogic.graph.selectSerializedGraphByFlowId(
state,
model?.getID() ?? ''
)
);

const registerModelChangeListener = useCallback(() => {
Expand All @@ -160,7 +169,9 @@ export const FlowCanvas: React.FC<FlowCanvasProps> = ({ flowId }) => {
const serializedModel =
model.serialize() as unknown as SerializedGraph;
// Dispatch an action to update the Redux state with the serialized model
dispatch(flowLogic.updateFlowFromSerializedGraph(serializedModel));
dispatch(
flowLogic.graph.updateFlowFromSerializedGraph(serializedModel)
);
}, 500);

// Register event listeners and store the handle in the ref
Expand Down Expand Up @@ -250,7 +261,7 @@ export const FlowCanvas: React.FC<FlowCanvasProps> = ({ flowId }) => {

const [, drop] = useDrop(() => ({
accept: ItemTypes.NODE,
drop: (entity: NodeEntity, monitor) => {
drop: (entity: PaletteNodeEntity, monitor) => {
// Find the canvas widget element
const canvasElement = document.querySelector(
'.flow-canvas > svg'
Expand Down Expand Up @@ -302,7 +313,7 @@ export const FlowCanvas: React.FC<FlowCanvasProps> = ({ flowId }) => {

node.setPosition(nodePosition);

const ports = flowLogic.getNodeInputsOutputs(config, entity);
const ports = flowLogic.node.getNodeInputsOutputs(config, entity);
ports.inputs.forEach(input => {
node.addPort(
new DefaultPortModel({
Expand Down
8 changes: 4 additions & 4 deletions packages/flow-client/src/app/components/flow-canvas/node.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ import styled from 'styled-components';

import { useAppDispatch } from '../../redux/hooks';
import { builderActions } from '../../redux/modules/builder/builder.slice';
import { NodeEntity } from '../../redux/modules/node/node.slice';
import NodeRedNode from '../node/node-red-node';
import { CustomEngine } from './engine';
import { FlowNodeEntity } from '../../redux/modules/flow/flow.slice';
import { PaletteNodeEntity } from '../../redux/modules/palette/node.slice';

// Styled components for the node and its elements
const StyledNode = styled.div<{
Expand Down Expand Up @@ -198,7 +198,7 @@ export const Node: React.FC<NodeProps> = ({ node, engine }) => {
dispatch(builderActions.setEditing(node.getID()));
};

const entity = node.entity ?? ({} as NodeEntity);
const entity = node.entity ?? ({} as PaletteNodeEntity);

return (
<StyledNode
Expand Down Expand Up @@ -240,12 +240,12 @@ export const Node: React.FC<NodeProps> = ({ node, engine }) => {

// Assuming createCustomNodeModel exists, and you're adding to this file
export class CustomNodeModel extends DefaultNodeModel {
public entity?: NodeEntity;
public entity?: PaletteNodeEntity;
public config?: FlowNodeEntity;

constructor(options: {
extras: {
entity: NodeEntity;
entity: PaletteNodeEntity;
config: FlowNodeEntity;
[index: string]: unknown;
};
Expand Down
13 changes: 6 additions & 7 deletions packages/flow-client/src/app/components/flow-tree/flow-tree.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ import {
selectNewFlowCounter,
selectNewFolderCounter,
} from '../../redux/modules/builder/builder.slice';
import { TreeItemData } from '../../redux/modules/flow/flow.logic';
import { flowActions } from '../../redux/modules/flow/flow.slice';
import { TreeItemData } from '../../redux/modules/flow/tree.logic';
import { TreeItem } from './tree-item';

const StyledFlowTree = styled.div`
Expand Down Expand Up @@ -49,7 +49,7 @@ const StyledFlowTree = styled.div`
export const FlowTree = () => {
const dispatch = useAppDispatch();
const flowLogic = useAppLogic().flow;
const { tree, items } = useAppSelector(flowLogic.selectFlowTree);
const { tree, items } = useAppSelector(flowLogic.tree.selectFlowTree);
const activeFlow = useAppSelector(selectActiveFlow);
const flowCounter = useAppSelector(selectNewFlowCounter);
const folderCounter = useAppSelector(selectNewFolderCounter);
Expand All @@ -74,7 +74,7 @@ export const FlowTree = () => {
const handleNewFolder = useCallback(() => {
const folderId = uuidv4();
dispatch(
flowActions.addEntity({
flowActions.addDirectory({
id: folderId,
type: 'directory',
name: `New Folder ${folderCounter}`,
Expand All @@ -89,18 +89,17 @@ export const FlowTree = () => {
const flowId = uuidv4();

dispatch(
flowActions.addEntity({
flowActions.addFlowEntity({
id: flowId,
type: 'tab',
label: `New Flow${flowCounter ? ` ${flowCounter}` : ''}`,
type: 'flow',
name: `New Flow${flowCounter ? ` ${flowCounter}` : ''}`,
disabled: false,
info: '',
env: [],
directory: getSelectedDirectory(),
})
);
dispatch(builderActions.addNewFlow(flowId));
dispatch(builderActions.openFlow(flowId));
dispatch(builderActions.setActiveFlow(flowId));
}, [dispatch, flowCounter, getSelectedDirectory]);

Expand Down
Loading

0 comments on commit 142c177

Please sign in to comment.