All Downloads are FREE. Search and download functionalities are using the official Maven repository.

components.common.TaskBackButton.tsx Maven / Gradle / Ivy

There is a newer version: 0.80.3
Show newest version
import { CircularProgressWithLabel } from 'components/common/TimedLoader';
import { AUTOCANCEL_TIME } from 'helpers/environment';
import Report from 'helpers/report';
import { TraitHelper } from 'helpers/traits';
import useCountDown from 'hooks/counter';
import { useFormInfo } from 'hooks/form';
import { useNotifier } from 'hooks/notification';
import { useTaskEndHandler } from 'hooks/submit';
import { useSubmitting } from 'hooks/submitting';
import { useTranslator } from 'hooks/translator';
import { ABORT_TASK, CANCEL_TASK } from 'queries/task';
import React, { useEffect, useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useLocation } from 'react-router-dom';
import { bannerQueries } from 'utils/banner-utils';

import { useMutation } from '@apollo/client';
import ArrowBackIcon from '@mui/icons-material/ArrowBack';
import LoadingButton from '@mui/lab/LoadingButton';
import { Box, Tooltip } from '@mui/material';

const TaskBackButton = () => {
  const { t }        = useTranslation()
  const {submitting} = useSubmitting()

  const {activateAutoCancel, isCancellable, onClick: onCancel, loading: loadingCancel} = useTaskCancel()
  const {activateAutoAbort, onClick: onAbort, loading: loadingAbort}                   = useTaskAbort()

  if (activateAutoAbort && activateAutoCancel)
    console.error("Traits #autoabort and #autocancel are present simultaniously. #autocancel currently has precedence.")

  const activate    = activateAutoAbort || activateAutoCancel
  const autoOnClick = (activateAutoCancel && onCancel) || (activateAutoAbort && onAbort) || (() => {})
  const loading     = loadingCancel || loadingAbort

  return (
    
      
      
        
          }
            onClick={onCancel}
            color="primary"
            size="small"
            disabled={loading || submitting || !isCancellable}
            //variant="contained"
          >
            {t("explorer.backward")}
          
        
      
      {!loading && activate ?  : null}
       theme.palette.grey[500]}} />
    
  )
}
const useTaskCancel = () => {
  const formInfo              = useFormInfo()
  const [loading, setLoading] = useState(false)
  const [doCancel]            = useMutation(CANCEL_TASK, { refetchQueries: bannerQueries })
  const notifier              = useNotifier()
  const { translator }        = useTranslator()
  const isCancellable         = formInfo.documentation.cancellable || formInfo.isStartForm
  const hasAutoCancel         = useMemo(() => TraitHelper.hasTrait(formInfo.form.fields, "autocancel"),[formInfo])
  const taskEndHandler        = useTaskEndHandler()
  const {setSubmitting}       = useSubmitting()

  const onClick = () => {
    if (formInfo.isStartForm)
      taskEndHandler()
    else {
      setSubmitting(true)
      setLoading(true)
      doCancel( { variables: { deploymentId: formInfo.processDefinition?.deploymentId, id: formInfo.taskId }})
        .then(
          result => {
            const tasks = result.data?.cancelTask?.assignedTasks
            taskEndHandler(tasks)
          }, (error: any)  => {
            const report = Report.from(error, translator, {category: Report.backend})
            report.addToNotifier(notifier)
            console.error("Cancel error: %s", report.verboseMessage)
          }
        )
        .finally(() => { setLoading(false); setSubmitting(false) })
    }
  }

  if (hasAutoCancel && !isCancellable)
    notifier.error("This task has an #autocancel trait, but its task is not cancellable.")

  return {onClick, loading, isCancellable, hasAutoCancel, activateAutoCancel: isCancellable && hasAutoCancel}
}

const useTaskAbort = () => {
  const formInfo              = useFormInfo()
  const [loading, setLoading] = useState(false)
  const [doAbort]             = useMutation(ABORT_TASK, { refetchQueries: bannerQueries })
  const notifier              = useNotifier()
  const { translator }        = useTranslator()
  const traits                = formInfo?.processDefinition?.traits || []
  const isAbortable           = TraitHelper.containsTrait(traits, "cancellable") || formInfo.isStartForm
  const hasAutoAbort          = useMemo(() => TraitHelper.hasTrait(formInfo.form.fields, "autoabort"),[formInfo])
  const taskEndHandler        = useTaskEndHandler()
  const {setSubmitting}       = useSubmitting()

  const onClick = () => {
    if (formInfo.isStartForm)
      taskEndHandler()
    else {
      setLoading(true)
      setSubmitting(true)
      doAbort( { variables: { id: formInfo.processInstanceId }})
        .then(
          result => {
            const tasks = result.data?.cancelTask?.assignedTasks
            taskEndHandler(tasks)
          }, (error: any)  => {
            const report = Report.from(error, translator, { category: Report.backend})
            report.addToNotifier(notifier)
            console.error("Cancel error: %s", report.verboseMessage)
          }
        )
        .finally(() => { setLoading(false); setSubmitting(false) })
    }
  }

  if (hasAutoAbort && !isAbortable)
    notifier.error("This task has an #autoabort trait, but its process is not cancellable. Current process traits: " + JSON.stringify(traits.map(trait => trait.name)))

  return {onClick, loading, isAbortable, hasAutoAbort, activateAutoAbort: isAbortable && hasAutoAbort}
}

const AutoCanceller = ({onClick}: {onClick: () => void}) => {
  const { ref, counter }        = useCountDown(AUTOCANCEL_TIME, () => { onClick() })
  const [disabled, setDisabled] = useState(false)
  
  const removeTimer = () => {
    ref.current.stop()
    setDisabled(true)
  }

  useEffect(()=>{
    // @ts-ignore
    document.addEventListener('click', removeTimer)
    document.addEventListener('keyup', removeTimer)

    // @ts-ignore
    return () => {
      document.removeEventListener('keyup', removeTimer)
      document.removeEventListener('click', removeTimer)
    }
  }, [])

  if (!disabled)
    return ;
  else
    return 
}

const CancelEventHandler = ({onClick}: {onClick: (e: React.SyntheticEvent) => void}) => {
  const [finishStatus, setfinishStatus] = useState(false);
  const formInfo                        = useFormInfo()
  const cancellable                     = formInfo.documentation.cancellable
  const { t }                           = useTranslation()
  const location                        = useLocation()
  const taskEndHandler                  = useTaskEndHandler()

  const onBackButtonEvent = (e: React.SyntheticEvent) => {
    if (formInfo.isStartForm){
      taskEndHandler()
      return null
    }

    if (!finishStatus) {
      e.preventDefault()
      e.stopPropagation()

      if (cancellable) {
        setfinishStatus(true)
        onClick(e)
      } else {
        window.history.pushState(null, "", "#" + location.pathname)
        setfinishStatus(false)
        window.alert(t("cannot_cancel_task"))
      }
    }
  }

  useEffect(() => {
    window.history.pushState(null, "", "#" + location.pathname);
    // @ts-ignore
    window.addEventListener('popstate', onBackButtonEvent);
    return () => {
      // @ts-ignore
      window.removeEventListener('popstate', onBackButtonEvent);
    };
  }, []);

  return null
}


export default TaskBackButton




© 2015 - 2024 Weber Informatics LLC | Privacy Policy