diff --git a/src/CanvasContext.tsx b/src/CanvasContext.tsx index bf45a9c7..f96db479 100644 --- a/src/CanvasContext.tsx +++ b/src/CanvasContext.tsx @@ -1,7 +1,6 @@ import { InterpreterFrom } from 'xstate'; import { canvasMachine } from './canvasMachine'; -import { createRequiredContext } from './utils'; +import { createInterpreterContext, createRequiredContext } from './utils'; -export const [CanvasProvider, useCanvas] = createRequiredContext< - InterpreterFrom ->('Canvas'); +export const [CanvasProvider, useCanvas, createCanvasMachineSelector] = + createInterpreterContext>('Canvas'); diff --git a/src/pages/graph-only.tsx b/src/pages/graph-only.tsx new file mode 100644 index 00000000..52299f7f --- /dev/null +++ b/src/pages/graph-only.tsx @@ -0,0 +1,164 @@ +import { AddIcon, MinusIcon, RepeatIcon } from '@chakra-ui/icons'; +import { Box, ButtonGroup, ChakraProvider, IconButton } from '@chakra-ui/react'; +import { useInterpret, useSelector } from '@xstate/react'; +import { useRouter } from 'next/router'; +import React, { useEffect, useMemo } from 'react'; +import { createMachine, StateFrom } from 'xstate'; +import { AppHead } from '../AppHead'; +import { CanvasContainer } from '../CanvasContainer'; +import { CanvasProvider, createCanvasMachineSelector } from '../CanvasContext'; +import { + canvasMachine, + getShouldEnableZoomInButton, + getShouldEnableZoomOutButton, +} from '../canvasMachine'; +import { toDirectedGraph } from '../directedGraph'; +import { Graph } from '../Graph'; +import { isOnClientSide } from '../isOnClientSide'; +import { SimulationProvider } from '../SimulationContext'; +import { simulationMachine } from '../simulationMachine'; +import { theme } from '../theme'; +import { CompressIcon } from '../Icons'; + +const getCurrentSimService = (state: StateFrom) => { + if (!state.context.currentSessionId) return; + return state.context.serviceDataMap[state.context.currentSessionId]; +}; + +const getIsVisualizing = (state: StateFrom) => { + return state.matches('visualizing.ready'); +}; + +const getIsReadyForFitToScreen = (state: StateFrom) => { + return Boolean(state.context.elkGraph); +}; + +const GraphOnly = () => { + const router = useRouter(); + + const parseResult = useMemo(() => { + if (!router.query.config) return undefined; + const config = JSON.parse((router.query.config as string) || '{}'); + const machine = createMachine(config || {}); + + return { + machine, + digraph: toDirectedGraph(machine), + }; + }, [Boolean(router.query.config)]); + + const canvasService = useInterpret(canvasMachine); + const simService = useInterpret(simulationMachine); + + useEffect(() => { + if (parseResult?.machine) { + simService.send({ + type: 'MACHINES.REGISTER', + machines: [parseResult?.machine], + }); + } + }, [Boolean(parseResult?.machine)]); + + const shouldEnableZoomOutButton = useSelector( + canvasService, + getShouldEnableZoomOutButton, + ); + + const shouldEnableZoomInButton = useSelector( + canvasService, + getShouldEnableZoomInButton, + ); + + const currentSimService = useSelector(simService, getCurrentSimService); + + const isReadyForFitToScreen = useSelector( + canvasService, + getIsReadyForFitToScreen, + ); + + useEffect(() => { + if (isReadyForFitToScreen) { + canvasService.send('FIT_TO_VIEW'); + } + }, [isReadyForFitToScreen]); + + return ( + <> + + {isOnClientSide() && parseResult && ( + + + + + + + + {parseResult?.digraph && currentSimService && ( + + )} + + + + + } + disabled={!shouldEnableZoomOutButton} + onClick={() => canvasService.send('ZOOM.OUT')} + variant="secondary" + /> + } + disabled={!shouldEnableZoomInButton} + onClick={() => canvasService.send('ZOOM.IN')} + variant="secondary" + /> + } + onClick={() => canvasService.send('FIT_TO_VIEW')} + variant="secondary" + /> + } + onClick={() => canvasService.send('POSITION.RESET')} + variant="secondary" + /> + + + + + + + + )} + + ); +}; + +export default GraphOnly;