diff --git a/src/js/component/ongoing.jsx b/src/js/component/ongoing.jsx index 547a2600..2764c67b 100644 --- a/src/js/component/ongoing.jsx +++ b/src/js/component/ongoing.jsx @@ -1,4 +1,5 @@ -import { memo } from 'react'; +import cx from 'classnames'; +import { memo, useCallback, useEffect, useState } from 'react'; import { useSelector } from 'react-redux'; import { pluralize } from '../common/format'; import { Spinner } from 'web-common/components'; @@ -14,9 +15,37 @@ const getMessage = ongoing => { const Ongoing = () => { const processes = useSelector(state => state.ongoing); + const [flash, setFlash] = useState(false); + + const handleOnBeforeUnload = useCallback((ev) => { + if (processes.length > 0) { + // If user cancelled the unload, flash the ongoing pane to + // indicate that there are ongoing operations + setTimeout(() => setFlash(true), 0); + ev.preventDefault(); + } + }, [processes.length]); + + useEffect(() => { + window.addEventListener("beforeunload", handleOnBeforeUnload); + return () => { + window.removeEventListener("beforeunload", handleOnBeforeUnload); + } + }, [handleOnBeforeUnload]); + + useEffect(() => { + if (flash) { + const timer = setTimeout(() => { + setFlash(false); + }, 700); // animation takes 2x330ms + return () => { + clearTimeout(timer); + } + } + }, [flash]); return ( -