diff --git a/src/components/molecules/InterpretationButtons.tsx b/src/components/molecules/InterpretationButtons.tsx new file mode 100644 index 00000000..bedb85af --- /dev/null +++ b/src/components/molecules/InterpretationButtons.tsx @@ -0,0 +1,178 @@ +import { Box, Button, IconButton, Stack, Typography } from "@mui/material"; +import { PauseCircle, PlayCircle, StopCircle } from "@mui/icons-material"; +import React, { useCallback, useEffect, useState } from "react"; +import { interpretCurrentRecording, stopCurrentInterpretation } from "../../api/recording"; +import { useSocketStore } from "../../context/socket"; +import { useGlobalInfoStore } from "../../context/globalInfo"; +import { GenericModal } from "../atoms/GenericModal"; +import { WhereWhatPair } from "@wbr-project/wbr-interpret"; +import HelpIcon from '@mui/icons-material/Help'; + +interface InterpretationButtonsProps { + enableStepping: (isPaused: boolean) => void; +} + +interface InterpretationInfo { + running: boolean; + isPaused: boolean; +} + +const interpretationInfo: InterpretationInfo = { + running: false, + isPaused: false, +} + +export const InterpretationButtons = ({ enableStepping }: InterpretationButtonsProps) => { + const [info, setInfo] = React.useState(interpretationInfo); + const [decisionModal, setDecisionModal] = useState<{ + pair: WhereWhatPair | null, + actionType: string, + selector: string, + action: string, + open:boolean + }>({ pair: null, actionType: '', selector: '', action: '', open: false} ); + + const { socket } = useSocketStore(); + const { notify } = useGlobalInfoStore(); + + const finishedHandler = useCallback(() => { + setInfo({...info, isPaused: false}); + enableStepping(false); + }, [info, enableStepping]); + + const breakpointHitHandler = useCallback(() => { + setInfo({running: false, isPaused: true}); + notify('warning', 'Please restart the interpretation, after updating the recording'); + enableStepping(true); + }, [info, enableStepping]); + + const decisionHandler = useCallback( + ({pair, actionType, lastData} + : {pair: WhereWhatPair | null, actionType: string, lastData: { selector: string, action: string }}) => { + const {selector, action} = lastData; + setDecisionModal((prevState) => { + return { + pair, + actionType, + selector, + action, + open: true, + } + }) + }, [decisionModal]); + + const handleDecision = (decision: boolean) => { + const {pair, actionType} = decisionModal; + socket?.emit('decision', {pair, actionType, decision}); + setDecisionModal({pair: null, actionType: '', selector: '', action: '', open: false}); + } + + const handleDescription = () => { + switch (decisionModal.actionType){ + case 'customAction': + return ( + + + Do you want to use the previously recorded selector + as a where condition for matching the action? + + + [previous action: {decisionModal.action}] +
{decisionModal.selector}
+
+
); + default: return null;} + } + + useEffect(() => { + if (socket) { + socket.on('finished', finishedHandler); + socket.on('breakpointHit', breakpointHitHandler); + socket.on('decision', decisionHandler); + } + return () => { + socket?.off('finished', finishedHandler); + socket?.off('breakpointHit', breakpointHitHandler); + socket?.off('decision', decisionHandler); + } + }, [socket, finishedHandler, breakpointHitHandler]); + + const handlePlay = async () => { + if (info.isPaused) { + socket?.emit("resume"); + setInfo({running: true, isPaused: false}); + enableStepping(false); + } else { + setInfo({...info, running: true}); + const finished = await interpretCurrentRecording(); + setInfo({...info, running: false}); + if (finished) { + notify('info', 'Interpretation finished'); + } else { + notify('error', 'Interpretation failed to start'); + } + } + }; + + const handleStop = async () => { + setInfo({ running: false, isPaused: false }); + enableStepping(false); + await stopCurrentInterpretation(); + }; + + const handlePause = async () => { + if (info.running) { + socket?.emit("pause"); + setInfo({ running: false, isPaused: true }); + notify('warning', 'Please restart the interpretation, after updating the recording'); + enableStepping(true); + } + }; + + return ( + + + + Pause + + + + {info.isPaused ? 'Resume' : 'Start'} + + + + Stop + + {}} isOpen={decisionModal.open} canBeClosed={false} + modalStyle={{ + position: 'absolute', + top: '50%', + left: '50%', + transform: 'translate(-50%, -50%)', + width: 500, + background: 'white', + border: '2px solid #000', + boxShadow: '24', + height:'fit-content', + display:'block', + overflow:'scroll', + padding: '5px 25px 10px 25px', + }}> +
+ + { + handleDescription() + } +
+ + +
+
+
+
+ ); +};