Skip to content

Commit

Permalink
Temp: Last state
Browse files Browse the repository at this point in the history
  • Loading branch information
lordrip committed Aug 7, 2024
1 parent fe03804 commit d4e6292
Show file tree
Hide file tree
Showing 31 changed files with 5,503 additions and 423 deletions.
70 changes: 36 additions & 34 deletions packages/ui/src/components/Visualization/Canvas/Canvas.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,14 @@ import { CanvasSideBar } from './CanvasSideBar';
import { CanvasDefaults } from './canvas.defaults';
import { CanvasEdge, CanvasNode, LayoutType } from './canvas.models';
import { CanvasService } from './canvas.service';
import { TopologyControllerScheduler } from './topology-controller.scheduler';

interface CanvasProps {
contextToolbar?: ReactNode;
entities: BaseVisualCamelEntity[];
}

export const Canvas: FunctionComponent<PropsWithChildren<CanvasProps>> = (props) => {
export const Canvas: FunctionComponent<PropsWithChildren<CanvasProps>> = ({ entities, contextToolbar }) => {
/** State for @patternfly/react-topology */
const [selectedIds, setSelectedIds] = useState<string[]>([]);
const [selectedNode, setSelectedNode] = useState<CanvasNode | undefined>(undefined);
Expand All @@ -51,13 +52,13 @@ export const Canvas: FunctionComponent<PropsWithChildren<CanvasProps>> = (props)
/** Context to interact with the Canvas catalog */
const catalogModalContext = useContext(CatalogModalContext);

const controller = useMemo(() => CanvasService.createController(), []);
const controllerScheduler = useMemo(() => new TopologyControllerScheduler(CanvasService.createController()), []);
const { visibleFlows } = useContext(VisibleFlowsContext)!;
const shouldShowEmptyState = useMemo(() => {
const areNoFlows = props.entities.length === 0;
const areNoFlows = entities.length === 0;
const areAllFlowsHidden = Object.values(visibleFlows).every((visible) => !visible);
return areNoFlows || areAllFlowsHidden;
}, [props.entities.length, visibleFlows]);
}, [entities.length, visibleFlows]);

const controlButtons = useMemo(() => {
const customButtons: TopologyControlButton[] = catalogModalContext
Expand All @@ -72,9 +73,9 @@ export const Canvas: FunctionComponent<PropsWithChildren<CanvasProps>> = (props)
tooltip: 'Horizontal Layout',
callback: action(() => {
setActiveLayout(LayoutType.DagreHorizontal);
controller.getGraph().setLayout(LayoutType.DagreHorizontal);
controller.getGraph().reset();
controller.getGraph().layout();
controllerScheduler.getGraph().setLayout(LayoutType.DagreHorizontal);
controllerScheduler.getGraph().reset();
controllerScheduler.getGraph().layout();
}),
},
{
Expand All @@ -87,9 +88,9 @@ export const Canvas: FunctionComponent<PropsWithChildren<CanvasProps>> = (props)
tooltip: 'Vertical Layout',
callback: action(() => {
setActiveLayout(LayoutType.DagreVertical);
controller.getGraph().setLayout(LayoutType.DagreVertical);
controller.getGraph().reset();
controller.getGraph().layout();
controllerScheduler.getGraph().setLayout(LayoutType.DagreVertical);
controllerScheduler.getGraph().reset();
controllerScheduler.getGraph().layout();
}),
},
{
Expand All @@ -106,22 +107,22 @@ export const Canvas: FunctionComponent<PropsWithChildren<CanvasProps>> = (props)
return createTopologyControlButtons({
...defaultControlButtonsOptions,
zoomInCallback: action(() => {
controller.getGraph().scaleBy(4 / 3);
controllerScheduler.getGraph().scaleBy(4 / 3);
}),
zoomOutCallback: action(() => {
controller.getGraph().scaleBy(3 / 4);
controllerScheduler.getGraph().scaleBy(3 / 4);
}),
fitToScreenCallback: action(() => {
controller.getGraph().fit(80);
controllerScheduler.getGraph().fit(80);
}),
resetViewCallback: action(() => {
controller.getGraph().reset();
controller.getGraph().layout();
controllerScheduler.getGraph().reset();
controllerScheduler.getGraph().layout();
}),
legend: false,
customButtons,
});
}, [catalogModalContext, controller]);
}, [catalogModalContext, controllerScheduler, setActiveLayout]);

const handleSelection = useCallback(
(selectedIds: string[]) => {
Expand All @@ -136,31 +137,31 @@ export const Canvas: FunctionComponent<PropsWithChildren<CanvasProps>> = (props)

/** Set up the controller one time */
useEffect(() => {
const localController = controller;
const graphLayoutEndFn = () => {
localController.getGraph().fit(80);
const localController = controllerScheduler;
const graphLayoutEndFn = async () => {
await localController.fit(80);
};

localController.addEventListener(SELECTION_EVENT, handleSelection);
localController.addEventListener(GRAPH_LAYOUT_END_EVENT, graphLayoutEndFn);
localController.getController().addEventListener(SELECTION_EVENT, handleSelection);
localController.getController().addEventListener(GRAPH_LAYOUT_END_EVENT, graphLayoutEndFn);

return () => {
localController.removeEventListener(SELECTION_EVENT, handleSelection);
localController.removeEventListener(GRAPH_LAYOUT_END_EVENT, graphLayoutEndFn);
localController.getController().removeEventListener(SELECTION_EVENT, handleSelection);
localController.getController().removeEventListener(GRAPH_LAYOUT_END_EVENT, graphLayoutEndFn);
};

// eslint-disable-next-line react-hooks/exhaustive-deps
}, [handleSelection]);

/** Draw graph */
useEffect(() => {
if (!Array.isArray(props.entities)) return;
if (!Array.isArray(entities)) return;
setSelectedNode(undefined);

const nodes: CanvasNode[] = [];
const edges: CanvasEdge[] = [];

props.entities.forEach((entity) => {
entities.forEach((entity) => {
if (visibleFlows[entity.id]) {
const { nodes: childNodes, edges: childEdges } = CanvasService.getFlowDiagram(entity.toVizNode());
nodes.push(...childNodes);
Expand All @@ -180,17 +181,18 @@ export const Canvas: FunctionComponent<PropsWithChildren<CanvasProps>> = (props)
},
};

controller.fromModel(model, false);
}, [controller, props.entities, visibleFlows]);
controllerScheduler.getController().fromModel(model, false);
}, [activeLayout, controllerScheduler, entities, visibleFlows]);

useEffect(() => {
const timeoutId = setTimeout(() => {
controller.getGraph().fit(80);
const timeoutId = setTimeout(async () => {
await controllerScheduler.fit(80);
}, 500);

return () => {
clearTimeout(timeoutId);
};
}, [controller, selectedIds]);
}, [controllerScheduler, selectedIds]);

const handleCloseSideBar = useCallback(() => {
setSelectedIds([]);
Expand All @@ -201,15 +203,15 @@ export const Canvas: FunctionComponent<PropsWithChildren<CanvasProps>> = (props)

return (
<TopologyView
sideBarResizable={true}
sideBarResizable
sideBarOpen={isSidebarOpen}
sideBar={<CanvasSideBar selectedNode={selectedNode} onClose={handleCloseSideBar} />}
contextToolbar={props.contextToolbar}
contextToolbar={contextToolbar}
controlBar={<TopologyControlBar controlButtons={controlButtons} />}
>
<VisualizationProvider controller={controller}>
<VisualizationProvider controller={controllerScheduler.getController()}>
{shouldShowEmptyState ? (
<VisualizationEmptyState data-testid="visualization-empty-state" entitiesNumber={props.entities.length} />
<VisualizationEmptyState data-testid="visualization-empty-state" entitiesNumber={entities.length} />
) : (
<VisualizationSurface state={{ selectedIds }} />
)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,14 @@ describe('CanvasService', () => {
it('should allow consumers to create a new controller and register its factories', () => {
const layoutFactorySpy = jest.spyOn(Visualization.prototype, 'registerLayoutFactory');
const componentFactorySpy = jest.spyOn(Visualization.prototype, 'registerComponentFactory');
const baselineElementFactorySpy = jest.spyOn(Visualization.prototype, 'registerElementFactory');

const controller = CanvasService.createController();

expect(controller).toBeInstanceOf(Visualization);
expect(layoutFactorySpy).toHaveBeenCalledWith(CanvasService.baselineLayoutFactory);
expect(componentFactorySpy).toHaveBeenCalledWith(CanvasService.baselineComponentFactory);
expect(baselineElementFactorySpy).toHaveBeenCalledWith(CanvasService.baselineElementFactory);
});

describe('baselineComponentFactory', () => {
Expand Down
Loading

0 comments on commit d4e6292

Please sign in to comment.