Merge remote-tracking branch 'origin/main' into feature/carbon_ui
This commit is contained in:
commit
eede34b564
|
@ -27,8 +27,10 @@ from SpiffWorkflow.bpmn.specs.events.event_definitions import NoneEventDefinitio
|
|||
|
||||
from .ValidationException import ValidationException
|
||||
from ..specs.BpmnProcessSpec import BpmnProcessSpec
|
||||
from ..specs.events import StartEvent, EndEvent, BoundaryEvent, IntermediateCatchEvent, IntermediateThrowEvent
|
||||
from ..specs.events import SendTask, ReceiveTask
|
||||
from ..specs.events.EndEvent import EndEvent
|
||||
from ..specs.events.StartEvent import StartEvent
|
||||
from ..specs.events.IntermediateEvent import BoundaryEvent, IntermediateCatchEvent, IntermediateThrowEvent
|
||||
from ..specs.events.IntermediateEvent import SendTask, ReceiveTask
|
||||
from ..specs.SubWorkflowTask import CallActivity, SubWorkflowTask, TransactionSubprocess
|
||||
from ..specs.ExclusiveGateway import ExclusiveGateway
|
||||
from ..specs.InclusiveGateway import InclusiveGateway
|
||||
|
|
|
@ -23,7 +23,8 @@ from .ValidationException import ValidationException
|
|||
from ..specs.NoneTask import NoneTask
|
||||
from ..specs.ScriptTask import ScriptTask
|
||||
from ..specs.UserTask import UserTask
|
||||
from ..specs.events import _BoundaryEventParent, CancelEventDefinition
|
||||
from ..specs.events.IntermediateEvent import _BoundaryEventParent
|
||||
from ..specs.events.event_definitions import CancelEventDefinition
|
||||
from ..specs.MultiInstanceTask import getDynamicMIClass
|
||||
from ..specs.SubWorkflowTask import CallActivity, TransactionSubprocess, SubWorkflowTask
|
||||
from ..specs.ExclusiveGateway import ExclusiveGateway
|
||||
|
|
|
@ -5,7 +5,7 @@ from SpiffWorkflow.bpmn.specs.events.event_definitions import CorrelationPropert
|
|||
from .ValidationException import ValidationException
|
||||
from .TaskParser import TaskParser
|
||||
from .util import first, one
|
||||
from ..specs.events import (TimerEventDefinition, MessageEventDefinition,
|
||||
from ..specs.events.event_definitions import (TimerEventDefinition, MessageEventDefinition,
|
||||
ErrorEventDefinition, EscalationEventDefinition,
|
||||
SignalEventDefinition,
|
||||
CancelEventDefinition, CycleTimerEventDefinition,
|
||||
|
|
|
@ -35,7 +35,8 @@ class NodeParser:
|
|||
return expression.text if expression is not None else None
|
||||
|
||||
def parse_documentation(self, sequence_flow=None):
|
||||
documentation_node = first(self._xpath(sequence_flow or self.node, './/bpmn:documentation'))
|
||||
node = sequence_flow if sequence_flow is not None else self.node
|
||||
documentation_node = first(self._xpath(node, './/bpmn:documentation'))
|
||||
return None if documentation_node is None else documentation_node.text
|
||||
|
||||
def parse_incoming_data_references(self):
|
||||
|
|
|
@ -23,7 +23,7 @@ from builtins import object
|
|||
from collections import deque
|
||||
import json
|
||||
from ...task import TaskState
|
||||
from ...specs import SubWorkflow
|
||||
from ...specs.Subworkflow import SubWorkflow
|
||||
from ...serializer.base import Serializer
|
||||
from ..workflow import BpmnWorkflow
|
||||
|
||||
|
|
|
@ -15,6 +15,3 @@
|
|||
# License along with this library; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
# 02110-1301 USA
|
||||
|
||||
from .workflow import BpmnWorkflowSerializer
|
||||
from .bpmn_converters import BpmnDataConverter
|
|
@ -7,9 +7,9 @@ from SpiffWorkflow.bpmn.specs.BpmnProcessSpec import BpmnDataSpecification
|
|||
|
||||
from .dictionary import DictionaryConverter
|
||||
|
||||
from ..specs.events import SignalEventDefinition, MessageEventDefinition, NoneEventDefinition
|
||||
from ..specs.events import TimerEventDefinition, CycleTimerEventDefinition, TerminateEventDefinition
|
||||
from ..specs.events import ErrorEventDefinition, EscalationEventDefinition, CancelEventDefinition
|
||||
from ..specs.events.event_definitions import SignalEventDefinition, MessageEventDefinition, NoneEventDefinition
|
||||
from ..specs.events.event_definitions import TimerEventDefinition, CycleTimerEventDefinition, TerminateEventDefinition
|
||||
from ..specs.events.event_definitions import ErrorEventDefinition, EscalationEventDefinition, CancelEventDefinition
|
||||
from ..specs.events.event_definitions import CorrelationProperty, NamedEventDefinition
|
||||
|
||||
from ..specs.BpmnSpecMixin import BpmnSpecMixin, SequenceFlow
|
||||
|
|
|
@ -2,7 +2,7 @@ from uuid import UUID
|
|||
|
||||
from .bpmn_converters import BpmnTaskSpecConverter
|
||||
|
||||
from ...specs import StartTask
|
||||
from ...specs.StartTask import StartTask
|
||||
from ...specs.Simple import Simple
|
||||
from ...specs.LoopResetTask import LoopResetTask
|
||||
|
||||
|
@ -19,7 +19,9 @@ from ..specs.ExclusiveGateway import ExclusiveGateway
|
|||
from ..specs.InclusiveGateway import InclusiveGateway
|
||||
from ..specs.ParallelGateway import ParallelGateway
|
||||
|
||||
from ..specs.events import StartEvent, EndEvent, BoundaryEvent, IntermediateCatchEvent, IntermediateThrowEvent
|
||||
from ..specs.events.StartEvent import StartEvent
|
||||
from ..specs.events.EndEvent import EndEvent
|
||||
from ..specs.events.IntermediateEvent import BoundaryEvent, IntermediateCatchEvent, IntermediateThrowEvent
|
||||
from ..specs.events.IntermediateEvent import _BoundaryEventParent, SendTask, ReceiveTask
|
||||
|
||||
from ..workflow import BpmnWorkflow
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
|
||||
from ...task import TaskState
|
||||
from ...operators import Operator
|
||||
from ...specs import TaskSpec
|
||||
from ...specs.base import TaskSpec
|
||||
|
||||
|
||||
class _BpmnCondition(Operator):
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
from ...exceptions import WorkflowException
|
||||
|
||||
from .BpmnSpecMixin import BpmnSpecMixin
|
||||
from ...specs import TaskSpec
|
||||
from ...specs.base import TaskSpec
|
||||
from ...specs.ExclusiveChoice import ExclusiveChoice
|
||||
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
# 02110-1301 USA
|
||||
from ...bpmn.specs.BpmnSpecMixin import BpmnSpecMixin
|
||||
|
||||
from ...specs import Simple
|
||||
from ...specs.Simple import Simple
|
||||
|
||||
|
||||
class ManualTask(Simple, BpmnSpecMixin):
|
||||
|
@ -32,4 +32,4 @@ class ManualTask(Simple, BpmnSpecMixin):
|
|||
|
||||
@property
|
||||
def spec_type(self):
|
||||
return 'Manual Task'
|
||||
return 'Manual Task'
|
||||
|
|
|
@ -29,7 +29,7 @@ from .ScriptTask import ScriptTask
|
|||
from .ExclusiveGateway import ExclusiveGateway
|
||||
from ...dmn.specs.BusinessRuleTask import BusinessRuleTask
|
||||
from ...operators import valueof, is_number
|
||||
from ...specs import SubWorkflow
|
||||
from ...specs.SubWorkflow import SubWorkflow
|
||||
from ...specs.base import TaskSpec
|
||||
from ...util.impl import get_class
|
||||
from ...task import Task, TaskState
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
# License along with this library; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
# 02110-1301 USA
|
||||
from ...specs import Simple
|
||||
from ...specs.Simple import Simple
|
||||
|
||||
from ...bpmn.specs.BpmnSpecMixin import BpmnSpecMixin
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ from copy import deepcopy
|
|||
|
||||
from SpiffWorkflow.task import TaskState
|
||||
from .BpmnSpecMixin import BpmnSpecMixin
|
||||
from ...specs import TaskSpec
|
||||
from ...specs.base import TaskSpec
|
||||
|
||||
|
||||
class SubWorkflowTask(BpmnSpecMixin):
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
from .StartEvent import StartEvent
|
||||
from .EndEvent import EndEvent
|
||||
from .IntermediateEvent import IntermediateCatchEvent, IntermediateThrowEvent, BoundaryEvent, _BoundaryEventParent, SendTask, ReceiveTask
|
||||
from .event_definitions import (NoneEventDefinition, CancelEventDefinition, ErrorEventDefinition, EscalationEventDefinition, MessageEventDefinition,
|
||||
SignalEventDefinition, TimerEventDefinition, CycleTimerEventDefinition, TerminateEventDefinition)
|
|
@ -161,7 +161,9 @@ class BpmnWorkflow(Workflow):
|
|||
event_definition.payload = payload
|
||||
self.catch(event_definition, correlations=correlations)
|
||||
|
||||
def do_engine_steps(self, exit_at = None):
|
||||
def do_engine_steps(self, exit_at = None,
|
||||
will_complete_task=None,
|
||||
did_complete_task=None):
|
||||
"""
|
||||
Execute any READY tasks that are engine specific (for example, gateways
|
||||
or script tasks). This is done in a loop, so it will keep completing
|
||||
|
@ -169,6 +171,8 @@ class BpmnWorkflow(Workflow):
|
|||
left.
|
||||
|
||||
:param exit_at: After executing a task with a name matching this param return the task object
|
||||
:param will_complete_task: Callback that will be called prior to completing a task
|
||||
:param did_complete_task: Callback that will be called after completing a task
|
||||
"""
|
||||
assert not self.read_only
|
||||
engine_steps = list(
|
||||
|
@ -176,21 +180,34 @@ class BpmnWorkflow(Workflow):
|
|||
if self._is_engine_task(t.task_spec)])
|
||||
while engine_steps:
|
||||
for task in engine_steps:
|
||||
if will_complete_task is not None:
|
||||
will_complete_task(task)
|
||||
task.complete()
|
||||
if did_complete_task is not None:
|
||||
did_complete_task(task)
|
||||
if task.task_spec.name == exit_at:
|
||||
return task
|
||||
engine_steps = list(
|
||||
[t for t in self.get_tasks(TaskState.READY)
|
||||
if self._is_engine_task(t.task_spec)])
|
||||
|
||||
def refresh_waiting_tasks(self):
|
||||
def refresh_waiting_tasks(self,
|
||||
will_refresh_task=None,
|
||||
did_refresh_task=None):
|
||||
"""
|
||||
Refresh the state of all WAITING tasks. This will, for example, update
|
||||
Catching Timer Events whose waiting time has passed.
|
||||
|
||||
:param will_refresh_task: Callback that will be called prior to refreshing a task
|
||||
:param did_refresh_task: Callback that will be called after refreshing a task
|
||||
"""
|
||||
assert not self.read_only
|
||||
for my_task in self.get_tasks(TaskState.WAITING):
|
||||
if will_refresh_task is not None:
|
||||
will_refresh_task(my_task)
|
||||
my_task.task_spec._update(my_task)
|
||||
if did_refresh_task is not None:
|
||||
did_refresh_task(my_task)
|
||||
|
||||
def get_tasks_from_spec_name(self, name, workflow=None):
|
||||
return [t for t in self.get_tasks(workflow=workflow) if t.task_spec.name == name]
|
||||
|
|
|
@ -6,7 +6,9 @@ from SpiffWorkflow.dmn.parser.BpmnDmnParser import BpmnDmnParser
|
|||
from SpiffWorkflow.dmn.specs.BusinessRuleTask import BusinessRuleTask
|
||||
from SpiffWorkflow.camunda.parser.task_spec import BusinessRuleTaskParser
|
||||
|
||||
from SpiffWorkflow.bpmn.specs.events import EndEvent, IntermediateThrowEvent, StartEvent, IntermediateCatchEvent, BoundaryEvent
|
||||
from SpiffWorkflow.bpmn.specs.events.StartEvent import StartEvent
|
||||
from SpiffWorkflow.bpmn.specs.events.EndEvent import EndEvent
|
||||
from SpiffWorkflow.bpmn.specs.events.IntermediateEvent import IntermediateThrowEvent, IntermediateCatchEvent, BoundaryEvent
|
||||
from .event_parsers import CamundaStartEventParser, CamundaEndEventParser, \
|
||||
CamundaIntermediateCatchEventParser, CamundaIntermediateThrowEventParser, CamundaBoundaryEventParser
|
||||
|
||||
|
|
|
@ -1,2 +0,0 @@
|
|||
from .task_spec_converters import UserTaskConverter, StartEventConverter, EndEventConverter, \
|
||||
BoundaryEventConverter, IntermediateCatchEventConverter, IntermediateThrowEventConverter
|
|
@ -1,6 +1,8 @@
|
|||
from functools import partial
|
||||
|
||||
from SpiffWorkflow.bpmn.specs.events import EndEvent, IntermediateThrowEvent, StartEvent, IntermediateCatchEvent, BoundaryEvent
|
||||
from SpiffWorkflow.bpmn.specs.events.StartEvent import StartEvent
|
||||
from SpiffWorkflow.bpmn.specs.events.EndEvent import EndEvent
|
||||
from SpiffWorkflow.bpmn.specs.events.IntermediateEvent import IntermediateThrowEvent, IntermediateCatchEvent, BoundaryEvent
|
||||
from ..specs.events.event_definitions import MessageEventDefinition
|
||||
from ...bpmn.serializer.bpmn_converters import BpmnTaskSpecConverter
|
||||
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
from .task_spec_converters import BusinessRuleTaskConverter
|
|
@ -1,6 +1,6 @@
|
|||
from SpiffWorkflow.bpmn.exceptions import WorkflowTaskExecException
|
||||
|
||||
from ...specs import Simple
|
||||
from ...specs.Simple import Simple
|
||||
|
||||
from ...bpmn.specs.BpmnSpecMixin import BpmnSpecMixin
|
||||
from ...util.deep_merge import DeepMerge
|
||||
|
|
|
@ -16,6 +16,71 @@ from builtins import object
|
|||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
# 02110-1301 USA
|
||||
|
||||
import re
|
||||
from .. import operators
|
||||
from .. import specs
|
||||
from ..specs.AcquireMutex import AcquireMutex
|
||||
from ..specs.Cancel import Cancel
|
||||
from ..specs.CancelTask import CancelTask
|
||||
from ..specs.Celery import Celery
|
||||
from ..specs.Choose import Choose
|
||||
from ..specs.ExclusiveChoice import ExclusiveChoice
|
||||
from ..specs.Execute import Execute
|
||||
from ..specs.Gate import Gate
|
||||
from ..specs.Join import Join
|
||||
from ..specs.Merge import Merge
|
||||
from ..specs.MultiChoice import MultiChoice
|
||||
from ..specs.MultiInstance import MultiInstance
|
||||
from ..specs.ReleaseMutex import ReleaseMutex
|
||||
from ..specs.Simple import Simple
|
||||
from ..specs.StartTask import StartTask
|
||||
from ..specs.SubWorkflow import SubWorkflow
|
||||
from ..specs.ThreadStart import ThreadStart
|
||||
from ..specs.ThreadMerge import ThreadMerge
|
||||
from ..specs.ThreadSplit import ThreadSplit
|
||||
from ..specs.Transform import Transform
|
||||
from ..specs.Trigger import Trigger
|
||||
from ..specs.WorkflowSpec import WorkflowSpec
|
||||
from ..specs.LoopResetTask import LoopResetTask
|
||||
|
||||
# Create a list of tag names out of the spec names.
|
||||
def spec_map():
|
||||
return {
|
||||
'acquire-mutex': AcquireMutex,
|
||||
'cancel': Cancel,
|
||||
'cancel-task': CancelTask,
|
||||
'celery': Celery,
|
||||
'choose': Choose,
|
||||
'exclusive-choice': ExclusiveChoice,
|
||||
'execute': Execute,
|
||||
'gate': Gate,
|
||||
'join': Join,
|
||||
'merge': Merge,
|
||||
'multi-choice': MultiChoice,
|
||||
'multi-instance': MultiInstance,
|
||||
'release-mutex': ReleaseMutex,
|
||||
'simple': Simple,
|
||||
'start-task': StartTask,
|
||||
'sub-workflow': SubWorkflow,
|
||||
'thread-start': ThreadStart,
|
||||
'thread-merge': ThreadMerge,
|
||||
'thread-split': ThreadSplit,
|
||||
'transform': Transform,
|
||||
'trigger': Trigger,
|
||||
'workflow-spec': WorkflowSpec,
|
||||
'loop-reset-task': LoopResetTask,
|
||||
'task': Simple,
|
||||
}
|
||||
|
||||
def op_map():
|
||||
return {
|
||||
'equals': operators.Equal,
|
||||
'not-equals': operators.NotEqual,
|
||||
'less-than': operators.LessThan,
|
||||
'greater-than': operators.GreaterThan,
|
||||
'matches': operators.Match
|
||||
}
|
||||
|
||||
|
||||
class Serializer(object):
|
||||
|
||||
|
|
|
@ -24,11 +24,30 @@ from ..util.impl import get_class
|
|||
from ..task import Task
|
||||
from ..operators import (Attrib, PathAttrib, Equal, NotEqual,
|
||||
Operator, GreaterThan, LessThan, Match)
|
||||
from ..specs import (Cancel, AcquireMutex, CancelTask, Celery, Choose,
|
||||
ExclusiveChoice, Execute, Gate, Join, MultiChoice,
|
||||
MultiInstance, ReleaseMutex, Simple, WorkflowSpec,
|
||||
TaskSpec, SubWorkflow, StartTask, ThreadMerge,
|
||||
ThreadSplit, ThreadStart, Merge, Trigger, LoopResetTask)
|
||||
from ..specs.base import TaskSpec
|
||||
from ..specs.AcquireMutex import AcquireMutex
|
||||
from ..specs.Cancel import Cancel
|
||||
from ..specs.CancelTask import CancelTask
|
||||
from ..specs.Celery import Celery
|
||||
from ..specs.Choose import Choose
|
||||
from ..specs.ExclusiveChoice import ExclusiveChoice
|
||||
from ..specs.Execute import Execute
|
||||
from ..specs.Gate import Gate
|
||||
from ..specs.Join import Join
|
||||
from ..specs.Merge import Merge
|
||||
from ..specs.MultiChoice import MultiChoice
|
||||
from ..specs.MultiInstance import MultiInstance
|
||||
from ..specs.ReleaseMutex import ReleaseMutex
|
||||
from ..specs.Simple import Simple
|
||||
from ..specs.StartTask import StartTask
|
||||
from ..specs.SubWorkflow import SubWorkflow
|
||||
from ..specs.ThreadStart import ThreadStart
|
||||
from ..specs.ThreadMerge import ThreadMerge
|
||||
from ..specs.ThreadSplit import ThreadSplit
|
||||
from ..specs.Transform import Transform
|
||||
from ..specs.Trigger import Trigger
|
||||
from ..specs.WorkflowSpec import WorkflowSpec
|
||||
from ..specs.LoopResetTask import LoopResetTask
|
||||
from .base import Serializer
|
||||
from .exceptions import TaskNotSupportedError, MissingSpecError
|
||||
import warnings
|
||||
|
|
|
@ -18,25 +18,15 @@
|
|||
# 02110-1301 USA
|
||||
import re
|
||||
import xml.dom.minidom as minidom
|
||||
from .. import operators, specs
|
||||
from .. import operators
|
||||
from ..specs.Simple import Simple
|
||||
from ..specs.WorkflowSpec import WorkflowSpec
|
||||
from ..exceptions import StorageException
|
||||
from .base import Serializer
|
||||
from .base import Serializer, spec_map, op_map
|
||||
|
||||
# Create a list of tag names out of the spec names.
|
||||
_spec_map = dict()
|
||||
for name in dir(specs):
|
||||
if name.startswith('_'):
|
||||
continue
|
||||
module = specs.__dict__[name]
|
||||
name = re.sub(r'(.)([A-Z])', r'\1-\2', name).lower()
|
||||
_spec_map[name] = module
|
||||
_spec_map['task'] = specs.Simple
|
||||
|
||||
_op_map = {'equals': operators.Equal,
|
||||
'not-equals': operators.NotEqual,
|
||||
'less-than': operators.LessThan,
|
||||
'greater-than': operators.GreaterThan,
|
||||
'matches': operators.Match}
|
||||
_spec_map = spec_map()
|
||||
_op_map = op_map()
|
||||
|
||||
_exc = StorageException
|
||||
|
||||
|
@ -299,9 +289,9 @@ class XmlSerializer(Serializer):
|
|||
_exc('%s without a name attribute' % node.nodeName)
|
||||
|
||||
# Read all task specs and create a list of successors.
|
||||
workflow_spec = specs.WorkflowSpec(name, filename)
|
||||
workflow_spec = WorkflowSpec(name, filename)
|
||||
del workflow_spec.task_specs['Start']
|
||||
end = specs.Simple(workflow_spec, 'End'), []
|
||||
end = Simple(workflow_spec, 'End'), []
|
||||
read_specs = dict(end=end)
|
||||
for child_node in node.childNodes:
|
||||
if child_node.nodeType != minidom.Node.ELEMENT_NODE:
|
||||
|
|
|
@ -24,29 +24,35 @@ from .. import specs, operators
|
|||
from ..task import Task, TaskStateNames
|
||||
from ..operators import (Attrib, Assign, PathAttrib, Equal, NotEqual,
|
||||
GreaterThan, LessThan, Match)
|
||||
from ..specs import (Cancel, AcquireMutex, CancelTask, Celery, Choose,
|
||||
ExclusiveChoice, Execute, Gate, Join, MultiChoice,
|
||||
MultiInstance, ReleaseMutex, Simple, WorkflowSpec,
|
||||
SubWorkflow, StartTask, ThreadMerge,
|
||||
ThreadSplit, ThreadStart, Merge, Trigger, LoopResetTask)
|
||||
from .base import Serializer
|
||||
from ..specs.AcquireMutex import AcquireMutex
|
||||
from ..specs.Cancel import Cancel
|
||||
from ..specs.CancelTask import CancelTask
|
||||
from ..specs.Celery import Celery
|
||||
from ..specs.Choose import Choose
|
||||
from ..specs.ExclusiveChoice import ExclusiveChoice
|
||||
from ..specs.Execute import Execute
|
||||
from ..specs.Gate import Gate
|
||||
from ..specs.Join import Join
|
||||
from ..specs.Merge import Merge
|
||||
from ..specs.MultiChoice import MultiChoice
|
||||
from ..specs.MultiInstance import MultiInstance
|
||||
from ..specs.ReleaseMutex import ReleaseMutex
|
||||
from ..specs.Simple import Simple
|
||||
from ..specs.StartTask import StartTask
|
||||
from ..specs.SubWorkflow import SubWorkflow
|
||||
from ..specs.ThreadStart import ThreadStart
|
||||
from ..specs.ThreadMerge import ThreadMerge
|
||||
from ..specs.ThreadSplit import ThreadSplit
|
||||
from ..specs.Transform import Transform
|
||||
from ..specs.Trigger import Trigger
|
||||
from ..specs.WorkflowSpec import WorkflowSpec
|
||||
from ..specs.LoopResetTask import LoopResetTask
|
||||
from .base import Serializer, spec_map, op_map
|
||||
from .exceptions import TaskNotSupportedError
|
||||
|
||||
# Create a list of tag names out of the spec names.
|
||||
_spec_map = dict()
|
||||
for name in dir(specs):
|
||||
if name.startswith('_'):
|
||||
continue
|
||||
module = specs.__dict__[name]
|
||||
name = re.sub(r'(.)([A-Z])', r'\1-\2', name).lower()
|
||||
_spec_map[name] = module
|
||||
_spec_map['task'] = specs.Simple
|
||||
|
||||
_op_map = {'equals': operators.Equal,
|
||||
'not-equals': operators.NotEqual,
|
||||
'less-than': operators.LessThan,
|
||||
'greater-than': operators.GreaterThan,
|
||||
'matches': operators.Match}
|
||||
_spec_map = spec_map()
|
||||
_op_map = op_map()
|
||||
|
||||
|
||||
class XmlSerializer(Serializer):
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
from .tasks import CallActivityParser
|
|
@ -18,7 +18,7 @@
|
|||
# 02110-1301 USA
|
||||
import os
|
||||
|
||||
from . import StartTask
|
||||
from .StartTask import StartTask
|
||||
from .base import TaskSpec
|
||||
from ..task import TaskState
|
||||
from ..exceptions import WorkflowException
|
||||
|
@ -87,7 +87,7 @@ class SubWorkflow(TaskSpec):
|
|||
|
||||
def _create_subworkflow(self, my_task):
|
||||
from ..serializer.prettyxml import XmlSerializer
|
||||
from ..specs import WorkflowSpec
|
||||
from ..specs.WorkflowSpec import WorkflowSpec
|
||||
from ..workflow import Workflow
|
||||
file_name = valueof(my_task, self.file)
|
||||
serializer = XmlSerializer()
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
from ..task import TaskState
|
||||
from ..exceptions import WorkflowException
|
||||
from ..operators import valueof
|
||||
from ..specs import Join
|
||||
from ..specs.Join import Join
|
||||
|
||||
|
||||
class ThreadMerge(Join):
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
# 02110-1301 USA
|
||||
|
||||
from ..specs import StartTask
|
||||
from ..specs.StartTask import StartTask
|
||||
|
||||
|
||||
class WorkflowSpec(object):
|
||||
|
@ -82,7 +82,7 @@ class WorkflowSpec(object):
|
|||
:returns: empty list if valid, a list of errors if not
|
||||
"""
|
||||
results = []
|
||||
from ..specs import Join
|
||||
from ..specs.Join import Join
|
||||
|
||||
def recursive_find_loop(task, history):
|
||||
current = history[:]
|
||||
|
|
|
@ -1,31 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# flake8: noqa
|
||||
|
||||
from .base import TaskSpec
|
||||
from .AcquireMutex import AcquireMutex
|
||||
from .Cancel import Cancel
|
||||
from .CancelTask import CancelTask
|
||||
from .Celery import Celery
|
||||
from .Choose import Choose
|
||||
from .ExclusiveChoice import ExclusiveChoice
|
||||
from .Execute import Execute
|
||||
from .Gate import Gate
|
||||
from .Join import Join
|
||||
from .Merge import Merge
|
||||
from .MultiChoice import MultiChoice
|
||||
from .MultiInstance import MultiInstance
|
||||
from .ReleaseMutex import ReleaseMutex
|
||||
from .Simple import Simple
|
||||
from .StartTask import StartTask
|
||||
from .SubWorkflow import SubWorkflow
|
||||
from .ThreadStart import ThreadStart
|
||||
from .ThreadMerge import ThreadMerge
|
||||
from .ThreadSplit import ThreadSplit
|
||||
from .Transform import Transform
|
||||
from .Trigger import Trigger
|
||||
from .WorkflowSpec import WorkflowSpec
|
||||
from .LoopResetTask import LoopResetTask
|
||||
|
||||
import inspect
|
||||
__all__ = [name for name, obj in list(locals().items())
|
||||
if not (name.startswith('_') or inspect.ismodule(obj))]
|
|
@ -1 +0,0 @@
|
|||
from .process import SpiffBpmnParser, VALIDATOR
|
|
@ -3,8 +3,15 @@ import os
|
|||
from SpiffWorkflow.dmn.parser.BpmnDmnParser import BpmnDmnParser
|
||||
from SpiffWorkflow.bpmn.parser.BpmnParser import BpmnValidator, full_tag
|
||||
|
||||
from SpiffWorkflow.bpmn.specs.events import StartEvent, EndEvent, IntermediateThrowEvent, BoundaryEvent, IntermediateCatchEvent
|
||||
from SpiffWorkflow.spiff.specs import NoneTask, ManualTask, UserTask, ScriptTask, SubWorkflowTask, TransactionSubprocess, CallActivity, ServiceTask
|
||||
from SpiffWorkflow.bpmn.specs.events.EndEvent import EndEvent
|
||||
from SpiffWorkflow.bpmn.specs.events.StartEvent import StartEvent
|
||||
from SpiffWorkflow.bpmn.specs.events.IntermediateEvent import IntermediateThrowEvent, BoundaryEvent, IntermediateCatchEvent
|
||||
from SpiffWorkflow.spiff.specs.none_task import NoneTask
|
||||
from SpiffWorkflow.spiff.specs.manual_task import ManualTask
|
||||
from SpiffWorkflow.spiff.specs.user_task import UserTask
|
||||
from SpiffWorkflow.spiff.specs.script_task import ScriptTask
|
||||
from SpiffWorkflow.spiff.specs.subworkflow_task import SubWorkflowTask, TransactionSubprocess, CallActivity
|
||||
from SpiffWorkflow.spiff.specs.service_task import ServiceTask
|
||||
from SpiffWorkflow.spiff.specs.events.event_types import SendTask, ReceiveTask
|
||||
from SpiffWorkflow.spiff.parser.task_spec import SpiffTaskParser, SubWorkflowParser, CallActivityParser, ServiceTaskParser, ScriptTaskParser
|
||||
from SpiffWorkflow.spiff.parser.event_parsers import (SpiffStartEventParser, SpiffEndEventParser, SpiffBoundaryEventParser,
|
||||
|
|
|
@ -1,4 +0,0 @@
|
|||
from .task_spec_converters import NoneTaskConverter, ManualTaskConverter, UserTaskConverter, ScriptTaskConverter
|
||||
from .task_spec_converters import TransactionSubprocessConverter, CallActivityTaskConverter, SubWorkflowTaskConverter
|
||||
from .task_spec_converters import StartEventConverter, EndEventConverter, IntermediateCatchEventConverter, IntermediateThrowEventConverter, \
|
||||
BoundaryEventConverter, SendTaskConverter, ReceiveTaskConverter, ServiceTaskConverter
|
|
@ -1,9 +1,16 @@
|
|||
from functools import partial
|
||||
|
||||
from SpiffWorkflow.bpmn.serializer.bpmn_converters import BpmnTaskSpecConverter
|
||||
from SpiffWorkflow.bpmn.specs.events import EndEvent, StartEvent, IntermediateThrowEvent, IntermediateCatchEvent, BoundaryEvent
|
||||
from SpiffWorkflow.spiff.specs import NoneTask, ManualTask, UserTask, ScriptTask, ServiceTask, SubWorkflowTask, TransactionSubprocess, CallActivity
|
||||
from SpiffWorkflow.spiff.specs.events import SendTask, ReceiveTask
|
||||
from SpiffWorkflow.bpmn.specs.events.StartEvent import StartEvent
|
||||
from SpiffWorkflow.bpmn.specs.events.EndEvent import EndEvent
|
||||
from SpiffWorkflow.bpmn.specs.events.IntermediateEvent import IntermediateThrowEvent, IntermediateCatchEvent, BoundaryEvent
|
||||
from SpiffWorkflow.spiff.specs.none_task import NoneTask
|
||||
from SpiffWorkflow.spiff.specs.manual_task import ManualTask
|
||||
from SpiffWorkflow.spiff.specs.user_task import UserTask
|
||||
from SpiffWorkflow.spiff.specs.script_task import ScriptTask
|
||||
from SpiffWorkflow.spiff.specs.service_task import ServiceTask
|
||||
from SpiffWorkflow.spiff.specs.subworkflow_task import SubWorkflowTask, TransactionSubprocess, CallActivity
|
||||
from SpiffWorkflow.spiff.specs.events.event_types import SendTask, ReceiveTask
|
||||
from SpiffWorkflow.spiff.specs.events.event_definitions import MessageEventDefinition
|
||||
|
||||
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
from .manual_task import ManualTask
|
||||
from .none_task import NoneTask
|
||||
from .subworkflow_task import SubWorkflowTask, TransactionSubprocess, CallActivity
|
||||
from .user_task import UserTask
|
||||
from .script_task import ScriptTask
|
||||
from .service_task import ServiceTask
|
|
@ -1 +0,0 @@
|
|||
from .event_types import SendTask, ReceiveTask
|
|
@ -19,7 +19,7 @@
|
|||
|
||||
import logging
|
||||
|
||||
from . import specs
|
||||
from .specs.Simple import Simple
|
||||
from .specs.LoopResetTask import LoopResetTask
|
||||
from .task import Task, TaskState
|
||||
from .util.compat import mutex
|
||||
|
@ -61,7 +61,7 @@ class Workflow(object):
|
|||
if 'Root' in workflow_spec.task_specs:
|
||||
root = workflow_spec.task_specs['Root']
|
||||
else:
|
||||
root = specs.Simple(workflow_spec, 'Root')
|
||||
root = Simple(workflow_spec, 'Root')
|
||||
logger.info('Initialize', extra=self.log_info())
|
||||
|
||||
# Setting TaskState.COMPLETED prevents the root task from being executed.
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import json
|
||||
from SpiffWorkflow.workflow import Workflow
|
||||
from SpiffWorkflow.specs import WorkflowSpec
|
||||
from SpiffWorkflow.specs.WorkflowSpec import WorkflowSpec
|
||||
from SpiffWorkflow.serializer.json import JSONSerializer
|
||||
|
||||
# Load from JSON
|
||||
|
|
|
@ -6,7 +6,7 @@ import unittest
|
|||
import os
|
||||
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..'))
|
||||
|
||||
from SpiffWorkflow.specs import WorkflowSpec
|
||||
from SpiffWorkflow.specs.WorkflowSpec import WorkflowSpec
|
||||
from SpiffWorkflow.task import Task
|
||||
from SpiffWorkflow.serializer.prettyxml import XmlSerializer
|
||||
from tests.SpiffWorkflow.util import run_workflow
|
||||
|
|
|
@ -6,7 +6,9 @@ import os.path
|
|||
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..'))
|
||||
|
||||
from SpiffWorkflow.workflow import Workflow
|
||||
from SpiffWorkflow.specs import Join, MultiChoice, WorkflowSpec
|
||||
from SpiffWorkflow.specs.Join import Join
|
||||
from SpiffWorkflow.specs.MultiChoice import MultiChoice
|
||||
from SpiffWorkflow.specs.WorkflowSpec import WorkflowSpec
|
||||
from SpiffWorkflow.operators import Attrib, Equal, PathAttrib
|
||||
from SpiffWorkflow.task import TaskState
|
||||
from SpiffWorkflow.specs.Simple import Simple
|
||||
|
|
|
@ -7,7 +7,8 @@ import os.path
|
|||
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..'))
|
||||
|
||||
from SpiffWorkflow.task import Task, TaskState, updateDotDict
|
||||
from SpiffWorkflow.specs import WorkflowSpec, Simple
|
||||
from SpiffWorkflow.specs.WorkflowSpec import WorkflowSpec
|
||||
from SpiffWorkflow.specs.Simple import Simple
|
||||
|
||||
|
||||
class MockWorkflow(object):
|
||||
|
|
|
@ -7,7 +7,9 @@ data_dir = os.path.join(os.path.dirname(__file__), 'data')
|
|||
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..'))
|
||||
|
||||
from SpiffWorkflow.workflow import Workflow
|
||||
from SpiffWorkflow.specs import Cancel, Simple, WorkflowSpec
|
||||
from SpiffWorkflow.specs.Cancel import Cancel
|
||||
from SpiffWorkflow.specs.Simple import Simple
|
||||
from SpiffWorkflow.specs.WorkflowSpec import WorkflowSpec
|
||||
from SpiffWorkflow.task import TaskState
|
||||
from SpiffWorkflow.serializer.prettyxml import XmlSerializer
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
import unittest
|
||||
from SpiffWorkflow.bpmn.workflow import BpmnWorkflow
|
||||
from SpiffWorkflow.bpmn.specs.events import MessageEventDefinition
|
||||
from SpiffWorkflow.bpmn.specs.events.event_definitions import MessageEventDefinition
|
||||
from tests.SpiffWorkflow.bpmn.BpmnWorkflowTestCase import BpmnWorkflowTestCase
|
||||
|
||||
__author__ = 'matth'
|
||||
|
|
|
@ -10,7 +10,7 @@ from SpiffWorkflow.bpmn.serializer.bpmn_converters import BpmnTaskSpecConverter
|
|||
|
||||
# Many of our tests relied on the Packager to set the calledElement attribute on
|
||||
# Call Activities. I've moved that code to a customized parser.
|
||||
from SpiffWorkflow.signavio.parser import CallActivityParser
|
||||
from SpiffWorkflow.signavio.parser.tasks import CallActivityParser
|
||||
from SpiffWorkflow.bpmn.specs.SubWorkflowTask import CallActivity
|
||||
|
||||
__author__ = 'matth'
|
||||
|
|
|
@ -6,7 +6,7 @@ from uuid import uuid4
|
|||
from SpiffWorkflow.task import TaskState
|
||||
from SpiffWorkflow.bpmn.PythonScriptEngine import PythonScriptEngine
|
||||
from SpiffWorkflow.bpmn.parser.BpmnParser import BpmnParser
|
||||
from SpiffWorkflow.bpmn.serializer import BpmnWorkflowSerializer
|
||||
from SpiffWorkflow.bpmn.serializer.workflow import BpmnWorkflowSerializer
|
||||
from SpiffWorkflow.bpmn.serializer.BpmnSerializer import BpmnSerializer
|
||||
from SpiffWorkflow.bpmn.workflow import BpmnWorkflow
|
||||
from tests.SpiffWorkflow.bpmn.BpmnLoaderForTests import TestUserTaskConverter
|
||||
|
|
|
@ -7,7 +7,7 @@ from SpiffWorkflow.bpmn.parser.BpmnParser import BpmnValidator
|
|||
|
||||
from SpiffWorkflow.task import TaskState
|
||||
|
||||
from SpiffWorkflow.bpmn.serializer import BpmnWorkflowSerializer
|
||||
from SpiffWorkflow.bpmn.serializer.workflow import BpmnWorkflowSerializer
|
||||
from .BpmnLoaderForTests import TestUserTaskConverter, TestBpmnParser
|
||||
|
||||
__author__ = 'matth'
|
||||
|
|
|
@ -3,7 +3,7 @@ import os
|
|||
import unittest
|
||||
|
||||
from SpiffWorkflow.camunda.parser.CamundaParser import CamundaParser
|
||||
from SpiffWorkflow.spiff.parser import SpiffBpmnParser
|
||||
from SpiffWorkflow.spiff.parser.process import SpiffBpmnParser
|
||||
|
||||
from tests.SpiffWorkflow.bpmn.BpmnWorkflowTestCase import BpmnWorkflowTestCase
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
import unittest
|
||||
|
||||
from SpiffWorkflow.bpmn.specs.events import CancelEventDefinition, SignalEventDefinition
|
||||
from SpiffWorkflow.bpmn.specs.events.event_definitions import CancelEventDefinition, SignalEventDefinition
|
||||
from SpiffWorkflow.task import TaskState
|
||||
from SpiffWorkflow.bpmn.workflow import BpmnWorkflow
|
||||
from tests.SpiffWorkflow.bpmn.BpmnWorkflowTestCase import BpmnWorkflowTestCase
|
||||
|
|
|
@ -5,7 +5,7 @@ import datetime
|
|||
import time
|
||||
from datetime import timedelta
|
||||
|
||||
from SpiffWorkflow.bpmn.specs.events import EndEvent
|
||||
from SpiffWorkflow.bpmn.specs.events.EndEvent import EndEvent
|
||||
from SpiffWorkflow.task import TaskState
|
||||
from SpiffWorkflow.bpmn.workflow import BpmnWorkflow
|
||||
from SpiffWorkflow.bpmn.PythonScriptEngine import PythonScriptEngine
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
import os
|
||||
|
||||
from SpiffWorkflow.bpmn.serializer import BpmnWorkflowSerializer
|
||||
from SpiffWorkflow.bpmn.serializer.workflow import BpmnWorkflowSerializer
|
||||
from SpiffWorkflow.camunda.parser.CamundaParser import CamundaParser
|
||||
from SpiffWorkflow.camunda.serializer import UserTaskConverter, StartEventConverter, EndEventConverter, \
|
||||
from SpiffWorkflow.camunda.serializer.task_spec_converters import UserTaskConverter, StartEventConverter, EndEventConverter, \
|
||||
IntermediateCatchEventConverter, IntermediateThrowEventConverter, BoundaryEventConverter
|
||||
|
||||
from SpiffWorkflow.dmn.serializer import BusinessRuleTaskConverter
|
||||
from SpiffWorkflow.dmn.serializer.task_spec_converters import BusinessRuleTaskConverter
|
||||
|
||||
from tests.SpiffWorkflow.bpmn.BpmnWorkflowTestCase import BpmnWorkflowTestCase
|
||||
|
||||
|
|
|
@ -3,7 +3,8 @@ import unittest
|
|||
|
||||
from SpiffWorkflow.camunda.specs.UserTask import FormField, UserTask, Form, \
|
||||
EnumFormField
|
||||
from SpiffWorkflow.specs import WorkflowSpec, TaskSpec
|
||||
from SpiffWorkflow.specs.base import TaskSpec
|
||||
from SpiffWorkflow.specs.WorkflowSpec import WorkflowSpec
|
||||
|
||||
|
||||
class UserTaskSpecTest(unittest.TestCase):
|
||||
|
|
|
@ -1,6 +1,11 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
from SpiffWorkflow.specs import ExclusiveChoice, Join, MultiChoice, MultiInstance, Simple, WorkflowSpec
|
||||
from SpiffWorkflow.specs.ExclusiveChoice import ExclusiveChoice
|
||||
from SpiffWorkflow.specs.Join import Join
|
||||
from SpiffWorkflow.specs.MultiChoice import MultiChoice
|
||||
from SpiffWorkflow.specs.MultiInstance import MultiInstance
|
||||
from SpiffWorkflow.specs.Simple import Simple
|
||||
from SpiffWorkflow.specs.WorkflowSpec import WorkflowSpec
|
||||
from SpiffWorkflow.operators import Attrib, Equal, NotEqual
|
||||
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ sys.path.insert(0, os.path.join(dirname, '..'))
|
|||
|
||||
from PatternTest import run_workflow, PatternTest
|
||||
from SpiffWorkflow.serializer.base import Serializer
|
||||
from SpiffWorkflow.specs import WorkflowSpec
|
||||
from SpiffWorkflow.specs.WorkflowSpec import WorkflowSpec
|
||||
from SpiffWorkflow.workflow import Workflow
|
||||
from SpiffWorkflow.serializer.exceptions import TaskNotSupportedError
|
||||
|
||||
|
|
|
@ -6,7 +6,8 @@ import unittest
|
|||
import pickle
|
||||
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..', '..'))
|
||||
from .TaskSpecTest import TaskSpecTest
|
||||
from SpiffWorkflow.specs import Celery, WorkflowSpec
|
||||
from SpiffWorkflow.specs.Celery import Celery
|
||||
from SpiffWorkflow.specs.WorkflowSpec import WorkflowSpec
|
||||
from SpiffWorkflow.operators import Attrib
|
||||
from SpiffWorkflow.serializer.dict import DictionarySerializer
|
||||
from base64 import b64encode
|
||||
|
|
|
@ -10,7 +10,7 @@ sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..', '..'))
|
|||
from tests.SpiffWorkflow.util import run_workflow
|
||||
from .TaskSpecTest import TaskSpecTest
|
||||
from SpiffWorkflow.task import TaskState
|
||||
from SpiffWorkflow.specs import Execute
|
||||
from SpiffWorkflow.specs.Execute import Execute
|
||||
|
||||
|
||||
class ExecuteTest(TaskSpecTest):
|
||||
|
|
|
@ -8,7 +8,7 @@ import unittest
|
|||
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..', '..'))
|
||||
|
||||
from .TaskSpecTest import TaskSpecTest
|
||||
from SpiffWorkflow.specs import Join
|
||||
from SpiffWorkflow.specs.Join import Join
|
||||
|
||||
|
||||
class JoinTest(TaskSpecTest):
|
||||
|
|
|
@ -8,7 +8,9 @@ import unittest
|
|||
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..', '..'))
|
||||
|
||||
from .JoinTest import JoinTest
|
||||
from SpiffWorkflow.specs import Merge, WorkflowSpec, Simple
|
||||
from SpiffWorkflow.specs.Merge import Merge
|
||||
from SpiffWorkflow.specs.WorkflowSpec import WorkflowSpec
|
||||
from SpiffWorkflow.specs.Simple import Simple
|
||||
from SpiffWorkflow.workflow import Workflow
|
||||
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ import os
|
|||
|
||||
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..', '..'))
|
||||
|
||||
from SpiffWorkflow.specs import WorkflowSpec
|
||||
from SpiffWorkflow.specs.WorkflowSpec import WorkflowSpec
|
||||
from SpiffWorkflow.specs.SubWorkflow import SubWorkflow
|
||||
from SpiffWorkflow.serializer.prettyxml import XmlSerializer
|
||||
from SpiffWorkflow.task import TaskState
|
||||
|
|
|
@ -5,9 +5,11 @@ import unittest
|
|||
import os
|
||||
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..', '..'))
|
||||
|
||||
from SpiffWorkflow.specs import WorkflowSpec, Simple, Join
|
||||
from SpiffWorkflow.specs.Join import Join
|
||||
from SpiffWorkflow.specs.Simple import Simple
|
||||
from SpiffWorkflow.specs.WorkflowSpec import WorkflowSpec
|
||||
from SpiffWorkflow.exceptions import WorkflowException
|
||||
from SpiffWorkflow.specs import TaskSpec
|
||||
from SpiffWorkflow.specs.base import TaskSpec
|
||||
from SpiffWorkflow.serializer.dict import DictionarySerializer
|
||||
|
||||
|
||||
|
|
|
@ -9,7 +9,8 @@ sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..', '..'))
|
|||
|
||||
from tests.SpiffWorkflow.util import run_workflow
|
||||
from .TaskSpecTest import TaskSpecTest
|
||||
from SpiffWorkflow.specs import Transform, Simple
|
||||
from SpiffWorkflow.specs.Transform import Transform
|
||||
from SpiffWorkflow.specs.Simple import Simple
|
||||
|
||||
|
||||
class TransformTest(TaskSpecTest):
|
||||
|
|
|
@ -15,7 +15,8 @@ try:
|
|||
except ImportError as e:
|
||||
from tests.SpiffWorkflow.util import track_workflow
|
||||
from SpiffWorkflow.workflow import Workflow
|
||||
from SpiffWorkflow.specs import Join, WorkflowSpec
|
||||
from SpiffWorkflow.specs.Join import Join
|
||||
from SpiffWorkflow.specs.WorkflowSpec import WorkflowSpec
|
||||
from SpiffWorkflow.serializer.prettyxml import XmlSerializer
|
||||
|
||||
serializer = XmlSerializer()
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
import os
|
||||
|
||||
from SpiffWorkflow.spiff.parser import SpiffBpmnParser, VALIDATOR
|
||||
from SpiffWorkflow.spiff.serializer import NoneTaskConverter, \
|
||||
from SpiffWorkflow.spiff.parser.process import SpiffBpmnParser, VALIDATOR
|
||||
from SpiffWorkflow.spiff.serializer.task_spec_converters import NoneTaskConverter, \
|
||||
ManualTaskConverter, UserTaskConverter, ScriptTaskConverter, \
|
||||
SubWorkflowTaskConverter, TransactionSubprocessConverter, \
|
||||
CallActivityTaskConverter, \
|
||||
|
@ -11,7 +11,7 @@ from SpiffWorkflow.spiff.serializer import NoneTaskConverter, \
|
|||
IntermediateCatchEventConverter, IntermediateThrowEventConverter, \
|
||||
ServiceTaskConverter
|
||||
from SpiffWorkflow.dmn.serializer.task_spec_converters import BusinessRuleTaskConverter
|
||||
from SpiffWorkflow.bpmn.serializer import BpmnWorkflowSerializer
|
||||
from SpiffWorkflow.bpmn.serializer.workflow import BpmnWorkflowSerializer
|
||||
|
||||
from tests.SpiffWorkflow.bpmn.BpmnWorkflowTestCase import BpmnWorkflowTestCase
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
"""empty message
|
||||
|
||||
Revision ID: bdd1d64689db
|
||||
Revision ID: b1647eff45c9
|
||||
Revises:
|
||||
Create Date: 2022-11-02 11:31:50.606843
|
||||
Create Date: 2022-11-02 14:25:09.992800
|
||||
|
||||
"""
|
||||
from alembic import op
|
||||
|
@ -10,7 +10,7 @@ import sqlalchemy as sa
|
|||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = 'bdd1d64689db'
|
||||
revision = 'b1647eff45c9'
|
||||
down_revision = None
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
@ -106,6 +106,7 @@ def upgrade():
|
|||
sa.Column('status', sa.String(length=50), nullable=True),
|
||||
sa.Column('bpmn_version_control_type', sa.String(length=50), nullable=True),
|
||||
sa.Column('bpmn_version_control_identifier', sa.String(length=255), nullable=True),
|
||||
sa.Column('spiff_step', sa.Integer(), nullable=True),
|
||||
sa.ForeignKeyConstraint(['process_initiator_id'], ['user.id'], ),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
|
@ -229,10 +230,22 @@ def upgrade():
|
|||
sa.Column('timestamp', sa.DECIMAL(precision=17, scale=6), nullable=False),
|
||||
sa.Column('message', sa.String(length=255), nullable=True),
|
||||
sa.Column('current_user_id', sa.Integer(), nullable=True),
|
||||
sa.Column('spiff_step', sa.Integer(), nullable=False),
|
||||
sa.ForeignKeyConstraint(['current_user_id'], ['user.id'], ),
|
||||
sa.ForeignKeyConstraint(['process_instance_id'], ['process_instance.id'], ),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
op.create_table('spiff_step_details',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('process_instance_id', sa.Integer(), nullable=False),
|
||||
sa.Column('spiff_step', sa.Integer(), nullable=False),
|
||||
sa.Column('task_json', sa.JSON(), nullable=False),
|
||||
sa.Column('timestamp', sa.DECIMAL(precision=17, scale=6), nullable=False),
|
||||
sa.Column('completed_by_user_id', sa.Integer(), nullable=True),
|
||||
sa.ForeignKeyConstraint(['completed_by_user_id'], ['user.id'], ),
|
||||
sa.ForeignKeyConstraint(['process_instance_id'], ['process_instance.id'], ),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
op.create_table('active_task_user',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('active_task_id', sa.Integer(), nullable=False),
|
||||
|
@ -266,6 +279,7 @@ def downgrade():
|
|||
op.drop_index(op.f('ix_active_task_user_user_id'), table_name='active_task_user')
|
||||
op.drop_index(op.f('ix_active_task_user_active_task_id'), table_name='active_task_user')
|
||||
op.drop_table('active_task_user')
|
||||
op.drop_table('spiff_step_details')
|
||||
op.drop_table('spiff_logging')
|
||||
op.drop_table('permission_assignment')
|
||||
op.drop_table('message_instance')
|
|
@ -95,7 +95,7 @@ python-versions = ">=3.5"
|
|||
dev = ["cloudpickle", "coverage[toml] (>=5.0.2)", "furo", "hypothesis", "mypy (>=0.900,!=0.940)", "pre-commit", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "sphinx", "sphinx-notfound-page", "zope.interface"]
|
||||
docs = ["furo", "sphinx", "sphinx-notfound-page", "zope.interface"]
|
||||
tests = ["cloudpickle", "coverage[toml] (>=5.0.2)", "hypothesis", "mypy (>=0.900,!=0.940)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "zope.interface"]
|
||||
tests-no-zope = ["cloudpickle", "coverage[toml] (>=5.0.2)", "hypothesis", "mypy (>=0.900,!=0.940)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins"]
|
||||
tests_no_zope = ["cloudpickle", "coverage[toml] (>=5.0.2)", "hypothesis", "mypy (>=0.900,!=0.940)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins"]
|
||||
|
||||
[[package]]
|
||||
name = "Babel"
|
||||
|
@ -268,7 +268,7 @@ optional = false
|
|||
python-versions = ">=3.6.0"
|
||||
|
||||
[package.extras]
|
||||
unicode-backport = ["unicodedata2"]
|
||||
unicode_backport = ["unicodedata2"]
|
||||
|
||||
[[package]]
|
||||
name = "classify-imports"
|
||||
|
@ -1512,7 +1512,7 @@ urllib3 = ">=1.21.1,<1.27"
|
|||
|
||||
[package.extras]
|
||||
socks = ["PySocks (>=1.5.6,!=1.5.7)"]
|
||||
use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"]
|
||||
use_chardet_on_py3 = ["chardet (>=3.0.2,<6)"]
|
||||
|
||||
[[package]]
|
||||
name = "requests-toolbelt"
|
||||
|
@ -1625,7 +1625,7 @@ falcon = ["falcon (>=1.4)"]
|
|||
fastapi = ["fastapi (>=0.79.0)"]
|
||||
flask = ["blinker (>=1.1)", "flask (>=0.11)"]
|
||||
httpx = ["httpx (>=0.16.0)"]
|
||||
pure-eval = ["asttokens", "executing", "pure-eval"]
|
||||
pure_eval = ["asttokens", "executing", "pure-eval"]
|
||||
pyspark = ["pyspark (>=2.4.4)"]
|
||||
quart = ["blinker (>=1.1)", "quart (>=0.16.1)"]
|
||||
rq = ["rq (>=0.6)"]
|
||||
|
@ -1865,15 +1865,13 @@ develop = false
|
|||
[package.dependencies]
|
||||
celery = "*"
|
||||
configparser = "*"
|
||||
dateparser = "*"
|
||||
lxml = "*"
|
||||
pytz = "*"
|
||||
|
||||
[package.source]
|
||||
type = "git"
|
||||
url = "https://github.com/sartography/SpiffWorkflow"
|
||||
reference = "main"
|
||||
resolved_reference = "a6392d19061f623394f5705fb78af23673d3940d"
|
||||
resolved_reference = "8d820dce1f439bb76bc07e39629832d998d6f634"
|
||||
|
||||
[[package]]
|
||||
name = "SQLAlchemy"
|
||||
|
@ -1891,19 +1889,19 @@ aiomysql = ["aiomysql", "greenlet (!=0.4.17)"]
|
|||
aiosqlite = ["aiosqlite", "greenlet (!=0.4.17)", "typing_extensions (!=3.10.0.1)"]
|
||||
asyncio = ["greenlet (!=0.4.17)"]
|
||||
asyncmy = ["asyncmy (>=0.2.3,!=0.2.4)", "greenlet (!=0.4.17)"]
|
||||
mariadb-connector = ["mariadb (>=1.0.1,!=1.1.2)"]
|
||||
mariadb_connector = ["mariadb (>=1.0.1,!=1.1.2)"]
|
||||
mssql = ["pyodbc"]
|
||||
mssql-pymssql = ["pymssql"]
|
||||
mssql-pyodbc = ["pyodbc"]
|
||||
mssql_pymssql = ["pymssql"]
|
||||
mssql_pyodbc = ["pyodbc"]
|
||||
mypy = ["mypy (>=0.910)", "sqlalchemy2-stubs"]
|
||||
mysql = ["mysqlclient (>=1.4.0)", "mysqlclient (>=1.4.0,<2)"]
|
||||
mysql-connector = ["mysql-connector-python"]
|
||||
mysql_connector = ["mysql-connector-python"]
|
||||
oracle = ["cx_oracle (>=7)", "cx_oracle (>=7,<8)"]
|
||||
postgresql = ["psycopg2 (>=2.7)"]
|
||||
postgresql-asyncpg = ["asyncpg", "greenlet (!=0.4.17)"]
|
||||
postgresql-pg8000 = ["pg8000 (>=1.16.6,!=1.29.0)"]
|
||||
postgresql-psycopg2binary = ["psycopg2-binary"]
|
||||
postgresql-psycopg2cffi = ["psycopg2cffi"]
|
||||
postgresql_asyncpg = ["asyncpg", "greenlet (!=0.4.17)"]
|
||||
postgresql_pg8000 = ["pg8000 (>=1.16.6,!=1.29.0)"]
|
||||
postgresql_psycopg2binary = ["psycopg2-binary"]
|
||||
postgresql_psycopg2cffi = ["psycopg2cffi"]
|
||||
pymysql = ["pymysql", "pymysql (<1)"]
|
||||
sqlcipher = ["sqlcipher3_binary"]
|
||||
|
||||
|
@ -2621,7 +2619,6 @@ greenlet = [
|
|||
{file = "greenlet-1.1.3.post0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:0a954002064ee919b444b19c1185e8cce307a1f20600f47d6f4b6d336972c809"},
|
||||
{file = "greenlet-1.1.3.post0-cp39-cp39-win32.whl", hash = "sha256:2ccdc818cc106cc238ff7eba0d71b9c77be868fdca31d6c3b1347a54c9b187b2"},
|
||||
{file = "greenlet-1.1.3.post0-cp39-cp39-win_amd64.whl", hash = "sha256:91a84faf718e6f8b888ca63d0b2d6d185c8e2a198d2a7322d75c303e7097c8b7"},
|
||||
{file = "greenlet-1.1.3.post0.tar.gz", hash = "sha256:f5e09dc5c6e1796969fd4b775ea1417d70e49a5df29aaa8e5d10675d9e11872c"},
|
||||
]
|
||||
gunicorn = [
|
||||
{file = "gunicorn-20.1.0-py3-none-any.whl", hash = "sha256:9dcc4547dbb1cb284accfb15ab5667a0e5d1881cc443e0677b4882a4067a807e"},
|
||||
|
@ -2946,10 +2943,7 @@ orjson = [
|
|||
{file = "orjson-3.8.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:b68a42a31f8429728183c21fb440c21de1b62e5378d0d73f280e2d894ef8942e"},
|
||||
{file = "orjson-3.8.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:ff13410ddbdda5d4197a4a4c09969cb78c722a67550f0a63c02c07aadc624833"},
|
||||
{file = "orjson-3.8.0-cp310-none-win_amd64.whl", hash = "sha256:2d81e6e56bbea44be0222fb53f7b255b4e7426290516771592738ca01dbd053b"},
|
||||
{file = "orjson-3.8.0-cp311-cp311-macosx_10_7_x86_64.whl", hash = "sha256:200eae21c33f1f8b02a11f5d88d76950cd6fd986d88f1afe497a8ae2627c49aa"},
|
||||
{file = "orjson-3.8.0-cp311-cp311-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:9529990f3eab54b976d327360aa1ff244a4b12cb5e4c5b3712fcdd96e8fe56d4"},
|
||||
{file = "orjson-3.8.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:e2defd9527651ad39ec20ae03c812adf47ef7662bdd6bc07dabb10888d70dc62"},
|
||||
{file = "orjson-3.8.0-cp311-none-win_amd64.whl", hash = "sha256:b21c7af0ff6228ca7105f54f0800636eb49201133e15ddb80ac20c1ce973ef07"},
|
||||
{file = "orjson-3.8.0-cp37-cp37m-macosx_10_7_x86_64.whl", hash = "sha256:9e6ac22cec72d5b39035b566e4b86c74b84866f12b5b0b6541506a080fb67d6d"},
|
||||
{file = "orjson-3.8.0-cp37-cp37m-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:e2f4a5542f50e3d336a18cb224fc757245ca66b1fd0b70b5dd4471b8ff5f2b0e"},
|
||||
{file = "orjson-3.8.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e1418feeb8b698b9224b1f024555895169d481604d5d884498c1838d7412794c"},
|
||||
|
@ -3062,7 +3056,18 @@ py = [
|
|||
{file = "py-1.11.0.tar.gz", hash = "sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719"},
|
||||
]
|
||||
pyasn1 = [
|
||||
{file = "pyasn1-0.4.8-py2.4.egg", hash = "sha256:fec3e9d8e36808a28efb59b489e4528c10ad0f480e57dcc32b4de5c9d8c9fdf3"},
|
||||
{file = "pyasn1-0.4.8-py2.5.egg", hash = "sha256:0458773cfe65b153891ac249bcf1b5f8f320b7c2ce462151f8fa74de8934becf"},
|
||||
{file = "pyasn1-0.4.8-py2.6.egg", hash = "sha256:5c9414dcfede6e441f7e8f81b43b34e834731003427e5b09e4e00e3172a10f00"},
|
||||
{file = "pyasn1-0.4.8-py2.7.egg", hash = "sha256:6e7545f1a61025a4e58bb336952c5061697da694db1cae97b116e9c46abcf7c8"},
|
||||
{file = "pyasn1-0.4.8-py2.py3-none-any.whl", hash = "sha256:39c7e2ec30515947ff4e87fb6f456dfc6e84857d34be479c9d4a4ba4bf46aa5d"},
|
||||
{file = "pyasn1-0.4.8-py3.1.egg", hash = "sha256:78fa6da68ed2727915c4767bb386ab32cdba863caa7dbe473eaae45f9959da86"},
|
||||
{file = "pyasn1-0.4.8-py3.2.egg", hash = "sha256:08c3c53b75eaa48d71cf8c710312316392ed40899cb34710d092e96745a358b7"},
|
||||
{file = "pyasn1-0.4.8-py3.3.egg", hash = "sha256:03840c999ba71680a131cfaee6fab142e1ed9bbd9c693e285cc6aca0d555e576"},
|
||||
{file = "pyasn1-0.4.8-py3.4.egg", hash = "sha256:7ab8a544af125fb704feadb008c99a88805126fb525280b2270bb25cc1d78a12"},
|
||||
{file = "pyasn1-0.4.8-py3.5.egg", hash = "sha256:e89bf84b5437b532b0803ba5c9a5e054d21fec423a89952a74f87fa2c9b7bce2"},
|
||||
{file = "pyasn1-0.4.8-py3.6.egg", hash = "sha256:014c0e9976956a08139dc0712ae195324a75e142284d5f87f1a87ee1b068a359"},
|
||||
{file = "pyasn1-0.4.8-py3.7.egg", hash = "sha256:99fcc3c8d804d1bc6d9a099921e39d827026409a58f2a720dcdb89374ea0c776"},
|
||||
{file = "pyasn1-0.4.8.tar.gz", hash = "sha256:aef77c9fb94a3ac588e87841208bdec464471d9871bd5050a287cc9a475cd0ba"},
|
||||
]
|
||||
pycodestyle = [
|
||||
|
|
|
@ -998,6 +998,12 @@ paths:
|
|||
description: If true, this wil return all tasks associated with the process instance and not just user tasks.
|
||||
schema:
|
||||
type: boolean
|
||||
- name: spiff_step
|
||||
in: query
|
||||
required: false
|
||||
description: If set will return the tasks as they were during a specific step of execution.
|
||||
schema:
|
||||
type: integer
|
||||
get:
|
||||
tags:
|
||||
- Process Instances
|
||||
|
|
|
@ -46,6 +46,9 @@ from spiffworkflow_backend.models.process_instance_report import (
|
|||
from spiffworkflow_backend.models.refresh_token import RefreshTokenModel # noqa: F401
|
||||
from spiffworkflow_backend.models.secret_model import SecretModel # noqa: F401
|
||||
from spiffworkflow_backend.models.spiff_logging import SpiffLoggingModel # noqa: F401
|
||||
from spiffworkflow_backend.models.spiff_step_details import (
|
||||
SpiffStepDetailsModel,
|
||||
) # noqa: F401
|
||||
from spiffworkflow_backend.models.user import UserModel # noqa: F401
|
||||
from spiffworkflow_backend.models.group import GroupModel # noqa: F401
|
||||
|
||||
|
|
|
@ -81,6 +81,7 @@ class ProcessInstanceModel(SpiffworkflowBaseDBModel):
|
|||
spiff_logs = relationship("SpiffLoggingModel", cascade="delete") # type: ignore
|
||||
message_instances = relationship("MessageInstanceModel", cascade="delete") # type: ignore
|
||||
message_correlations = relationship("MessageCorrelationModel", cascade="delete") # type: ignore
|
||||
spiff_step_details = relationship("SpiffStepDetailsModel", cascade="delete") # type: ignore
|
||||
|
||||
bpmn_json: str | None = deferred(db.Column(db.JSON)) # type: ignore
|
||||
start_in_seconds: int | None = db.Column(db.Integer)
|
||||
|
@ -92,6 +93,7 @@ class ProcessInstanceModel(SpiffworkflowBaseDBModel):
|
|||
bpmn_xml_file_contents: bytes | None = None
|
||||
bpmn_version_control_type: str = db.Column(db.String(50))
|
||||
bpmn_version_control_identifier: str = db.Column(db.String(255))
|
||||
spiff_step: int = db.Column(db.Integer)
|
||||
|
||||
@property
|
||||
def serialized(self) -> dict[str, Any]:
|
||||
|
@ -110,6 +112,7 @@ class ProcessInstanceModel(SpiffworkflowBaseDBModel):
|
|||
"end_in_seconds": self.end_in_seconds,
|
||||
"process_initiator_id": self.process_initiator_id,
|
||||
"bpmn_xml_file_contents": local_bpmn_xml_file_contents,
|
||||
"spiff_step": self.spiff_step,
|
||||
}
|
||||
|
||||
@property
|
||||
|
|
|
@ -25,3 +25,4 @@ class SpiffLoggingModel(SpiffworkflowBaseDBModel):
|
|||
timestamp: float = db.Column(db.DECIMAL(17, 6), nullable=False)
|
||||
message: Optional[str] = db.Column(db.String(255), nullable=True)
|
||||
current_user_id: int = db.Column(ForeignKey(UserModel.id), nullable=True)
|
||||
spiff_step: int = db.Column(db.Integer, nullable=False)
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
"""Spiff_step_details."""
|
||||
from dataclasses import dataclass
|
||||
|
||||
from flask_bpmn.models.db import db
|
||||
from flask_bpmn.models.db import SpiffworkflowBaseDBModel
|
||||
from sqlalchemy import ForeignKey
|
||||
from sqlalchemy.orm import deferred
|
||||
|
||||
from spiffworkflow_backend.models.process_instance import ProcessInstanceModel
|
||||
from spiffworkflow_backend.models.user import UserModel
|
||||
|
||||
|
||||
@dataclass
|
||||
class SpiffStepDetailsModel(SpiffworkflowBaseDBModel):
|
||||
"""SpiffStepDetailsModel."""
|
||||
|
||||
__tablename__ = "spiff_step_details"
|
||||
id: int = db.Column(db.Integer, primary_key=True)
|
||||
process_instance_id: int = db.Column(ForeignKey(ProcessInstanceModel.id), nullable=False) # type: ignore
|
||||
spiff_step: int = db.Column(db.Integer, nullable=False)
|
||||
task_json: str | None = deferred(db.Column(db.JSON, nullable=False)) # type: ignore
|
||||
timestamp: float = db.Column(db.DECIMAL(17, 6), nullable=False)
|
||||
completed_by_user_id: int = db.Column(ForeignKey(UserModel.id), nullable=True)
|
|
@ -57,6 +57,7 @@ from spiffworkflow_backend.models.process_model import ProcessModelInfoSchema
|
|||
from spiffworkflow_backend.models.secret_model import SecretModel
|
||||
from spiffworkflow_backend.models.secret_model import SecretModelSchema
|
||||
from spiffworkflow_backend.models.spiff_logging import SpiffLoggingModel
|
||||
from spiffworkflow_backend.models.spiff_step_details import SpiffStepDetailsModel
|
||||
from spiffworkflow_backend.models.user import UserModel
|
||||
from spiffworkflow_backend.routes.user import verify_token
|
||||
from spiffworkflow_backend.services.authorization_service import AuthorizationService
|
||||
|
@ -954,10 +955,23 @@ def task_list_my_tasks(page: int = 1, per_page: int = 100) -> flask.wrappers.Res
|
|||
|
||||
|
||||
def process_instance_task_list(
|
||||
process_instance_id: int, all_tasks: bool = False
|
||||
process_instance_id: int, all_tasks: bool = False, spiff_step: int = 0
|
||||
) -> flask.wrappers.Response:
|
||||
"""Process_instance_task_list."""
|
||||
process_instance = find_process_instance_by_id_or_raise(process_instance_id)
|
||||
|
||||
if spiff_step > 0:
|
||||
step_detail = (
|
||||
db.session.query(SpiffStepDetailsModel)
|
||||
.filter(
|
||||
SpiffStepDetailsModel.process_instance_id == process_instance.id,
|
||||
SpiffStepDetailsModel.spiff_step == spiff_step,
|
||||
)
|
||||
.first()
|
||||
)
|
||||
if step_detail is not None:
|
||||
process_instance.bpmn_json = json.dumps(step_detail.task_json)
|
||||
|
||||
processor = ProcessInstanceProcessor(process_instance)
|
||||
|
||||
spiff_tasks = None
|
||||
|
@ -1233,6 +1247,7 @@ def script_unit_test_run(
|
|||
"""Script_unit_test_run."""
|
||||
# FIXME: We should probably clear this somewhere else but this works
|
||||
current_app.config["THREAD_LOCAL_DATA"].process_instance_id = None
|
||||
current_app.config["THREAD_LOCAL_DATA"].spiff_step = None
|
||||
|
||||
python_script = _get_required_parameter_or_raise("python_script", body)
|
||||
input_json = _get_required_parameter_or_raise("input_json", body)
|
||||
|
|
|
@ -9,8 +9,8 @@ from spiffworkflow_backend.models.script_attributes_context import (
|
|||
from spiffworkflow_backend.scripts.script import Script
|
||||
|
||||
|
||||
class GetUser(Script):
|
||||
"""GetUser."""
|
||||
class GetCurrentUser(Script):
|
||||
"""GetCurrentUser."""
|
||||
|
||||
def get_description(self) -> str:
|
||||
"""Get_description."""
|
||||
|
|
|
@ -8,7 +8,7 @@ from spiffworkflow_backend.scripts.script import Script
|
|||
|
||||
|
||||
class GetProcessInfo(Script):
|
||||
"""GetUser."""
|
||||
"""GetProcessInfo."""
|
||||
|
||||
def get_description(self) -> str:
|
||||
"""Get_description."""
|
||||
|
|
|
@ -108,6 +108,8 @@ class SpiffFilter(logging.Filter):
|
|||
if hasattr(tld, "process_instance_id"):
|
||||
process_instance_id = tld.process_instance_id
|
||||
setattr(record, "process_instance_id", process_instance_id) # noqa: B010
|
||||
if hasattr(tld, "spiff_step"):
|
||||
setattr(record, "spiff_step", tld.spiff_step) # noqa: 8010
|
||||
if hasattr(g, "user") and g.user:
|
||||
setattr(record, "current_user_id", g.user.id) # noqa: B010
|
||||
return True
|
||||
|
@ -204,6 +206,11 @@ class DBHandler(logging.Handler):
|
|||
timestamp = record.created
|
||||
message = record.msg if hasattr(record, "msg") else None
|
||||
current_user_id = record.current_user_id if hasattr(record, "current_user_id") else None # type: ignore
|
||||
spiff_step = (
|
||||
record.spiff_step # type: ignore
|
||||
if hasattr(record, "spiff_step") and record.spiff_step is not None # type: ignore
|
||||
else 1
|
||||
)
|
||||
spiff_log = SpiffLoggingModel(
|
||||
process_instance_id=record.process_instance_id, # type: ignore
|
||||
bpmn_process_identifier=bpmn_process_identifier,
|
||||
|
@ -214,6 +221,7 @@ class DBHandler(logging.Handler):
|
|||
message=message,
|
||||
timestamp=timestamp,
|
||||
current_user_id=current_user_id,
|
||||
spiff_step=spiff_step,
|
||||
)
|
||||
db.session.add(spiff_log)
|
||||
db.session.commit()
|
||||
|
|
|
@ -29,31 +29,39 @@ from SpiffWorkflow.bpmn.exceptions import WorkflowTaskExecException # type: ign
|
|||
from SpiffWorkflow.bpmn.parser.ValidationException import ValidationException # type: ignore
|
||||
from SpiffWorkflow.bpmn.PythonScriptEngine import Box # type: ignore
|
||||
from SpiffWorkflow.bpmn.PythonScriptEngine import PythonScriptEngine
|
||||
from SpiffWorkflow.bpmn.serializer import BpmnWorkflowSerializer # type: ignore
|
||||
from SpiffWorkflow.bpmn.serializer.workflow import BpmnWorkflowSerializer # type: ignore
|
||||
from SpiffWorkflow.bpmn.specs.BpmnProcessSpec import BpmnProcessSpec # type: ignore
|
||||
from SpiffWorkflow.bpmn.specs.events import CancelEventDefinition # type: ignore
|
||||
from SpiffWorkflow.bpmn.specs.events import EndEvent
|
||||
from SpiffWorkflow.bpmn.specs.events.EndEvent import EndEvent # type: ignore
|
||||
from SpiffWorkflow.bpmn.specs.events.event_definitions import CancelEventDefinition # type: ignore
|
||||
from SpiffWorkflow.bpmn.workflow import BpmnWorkflow # type: ignore
|
||||
from SpiffWorkflow.dmn.parser.BpmnDmnParser import BpmnDmnParser # type: ignore
|
||||
from SpiffWorkflow.dmn.serializer import BusinessRuleTaskConverter # type: ignore
|
||||
from SpiffWorkflow.dmn.serializer.task_spec_converters import BusinessRuleTaskConverter # type: ignore
|
||||
from SpiffWorkflow.exceptions import WorkflowException # type: ignore
|
||||
from SpiffWorkflow.serializer.exceptions import MissingSpecError # type: ignore
|
||||
from SpiffWorkflow.spiff.parser.process import SpiffBpmnParser # type: ignore
|
||||
from SpiffWorkflow.spiff.serializer import BoundaryEventConverter # type: ignore
|
||||
from SpiffWorkflow.spiff.serializer import CallActivityTaskConverter
|
||||
from SpiffWorkflow.spiff.serializer import EndEventConverter
|
||||
from SpiffWorkflow.spiff.serializer import IntermediateCatchEventConverter
|
||||
from SpiffWorkflow.spiff.serializer import IntermediateThrowEventConverter
|
||||
from SpiffWorkflow.spiff.serializer import ManualTaskConverter
|
||||
from SpiffWorkflow.spiff.serializer import NoneTaskConverter
|
||||
from SpiffWorkflow.spiff.serializer import ReceiveTaskConverter
|
||||
from SpiffWorkflow.spiff.serializer import ScriptTaskConverter
|
||||
from SpiffWorkflow.spiff.serializer import SendTaskConverter
|
||||
from SpiffWorkflow.spiff.serializer import ServiceTaskConverter
|
||||
from SpiffWorkflow.spiff.serializer import StartEventConverter
|
||||
from SpiffWorkflow.spiff.serializer import SubWorkflowTaskConverter
|
||||
from SpiffWorkflow.spiff.serializer import TransactionSubprocessConverter
|
||||
from SpiffWorkflow.spiff.serializer import UserTaskConverter
|
||||
from SpiffWorkflow.spiff.serializer.task_spec_converters import BoundaryEventConverter # type: ignore
|
||||
from SpiffWorkflow.spiff.serializer.task_spec_converters import (
|
||||
CallActivityTaskConverter,
|
||||
)
|
||||
from SpiffWorkflow.spiff.serializer.task_spec_converters import EndEventConverter
|
||||
from SpiffWorkflow.spiff.serializer.task_spec_converters import (
|
||||
IntermediateCatchEventConverter,
|
||||
)
|
||||
from SpiffWorkflow.spiff.serializer.task_spec_converters import (
|
||||
IntermediateThrowEventConverter,
|
||||
)
|
||||
from SpiffWorkflow.spiff.serializer.task_spec_converters import ManualTaskConverter
|
||||
from SpiffWorkflow.spiff.serializer.task_spec_converters import NoneTaskConverter
|
||||
from SpiffWorkflow.spiff.serializer.task_spec_converters import ReceiveTaskConverter
|
||||
from SpiffWorkflow.spiff.serializer.task_spec_converters import ScriptTaskConverter
|
||||
from SpiffWorkflow.spiff.serializer.task_spec_converters import SendTaskConverter
|
||||
from SpiffWorkflow.spiff.serializer.task_spec_converters import ServiceTaskConverter
|
||||
from SpiffWorkflow.spiff.serializer.task_spec_converters import StartEventConverter
|
||||
from SpiffWorkflow.spiff.serializer.task_spec_converters import SubWorkflowTaskConverter
|
||||
from SpiffWorkflow.spiff.serializer.task_spec_converters import (
|
||||
TransactionSubprocessConverter,
|
||||
)
|
||||
from SpiffWorkflow.spiff.serializer.task_spec_converters import UserTaskConverter
|
||||
from SpiffWorkflow.task import Task as SpiffTask # type: ignore
|
||||
from SpiffWorkflow.task import TaskState
|
||||
from SpiffWorkflow.util.deep_merge import DeepMerge # type: ignore
|
||||
|
@ -79,12 +87,16 @@ from spiffworkflow_backend.models.process_model import ProcessModelInfo
|
|||
from spiffworkflow_backend.models.script_attributes_context import (
|
||||
ScriptAttributesContext,
|
||||
)
|
||||
from spiffworkflow_backend.models.spiff_step_details import SpiffStepDetailsModel
|
||||
from spiffworkflow_backend.models.user import UserModel
|
||||
from spiffworkflow_backend.models.user import UserModelSchema
|
||||
from spiffworkflow_backend.scripts.script import Script
|
||||
from spiffworkflow_backend.services.file_system_service import FileSystemService
|
||||
from spiffworkflow_backend.services.process_model_service import ProcessModelService
|
||||
from spiffworkflow_backend.services.service_task_service import ServiceTaskDelegate
|
||||
from spiffworkflow_backend.services.spec_file_service import (
|
||||
ProcessModelFileNotFoundError,
|
||||
)
|
||||
from spiffworkflow_backend.services.spec_file_service import SpecFileService
|
||||
from spiffworkflow_backend.services.user_service import UserService
|
||||
|
||||
|
@ -276,9 +288,9 @@ class ProcessInstanceProcessor:
|
|||
self, process_instance_model: ProcessInstanceModel, validate_only: bool = False
|
||||
) -> None:
|
||||
"""Create a Workflow Processor based on the serialized information available in the process_instance model."""
|
||||
current_app.config[
|
||||
"THREAD_LOCAL_DATA"
|
||||
].process_instance_id = process_instance_model.id
|
||||
tld = current_app.config["THREAD_LOCAL_DATA"]
|
||||
tld.process_instance_id = process_instance_model.id
|
||||
tld.spiff_step = process_instance_model.spiff_step
|
||||
|
||||
# we want this to be the fully qualified path to the process model including all group subcomponents
|
||||
current_app.config["THREAD_LOCAL_DATA"].process_model_identifier = (
|
||||
|
@ -411,10 +423,8 @@ class ProcessInstanceProcessor:
|
|||
bpmn_process_spec, subprocesses
|
||||
)
|
||||
|
||||
def add_user_info_to_process_instance(
|
||||
self, bpmn_process_instance: BpmnWorkflow
|
||||
) -> None:
|
||||
"""Add_user_info_to_process_instance."""
|
||||
def current_user(self) -> Any:
|
||||
"""Current_user."""
|
||||
current_user = None
|
||||
if UserService.has_user():
|
||||
current_user = UserService.current_user()
|
||||
|
@ -425,6 +435,14 @@ class ProcessInstanceProcessor:
|
|||
elif self.process_instance_model.process_initiator_id:
|
||||
current_user = self.process_instance_model.process_initiator
|
||||
|
||||
return current_user
|
||||
|
||||
def add_user_info_to_process_instance(
|
||||
self, bpmn_process_instance: BpmnWorkflow
|
||||
) -> None:
|
||||
"""Add_user_info_to_process_instance."""
|
||||
current_user = self.current_user()
|
||||
|
||||
if current_user:
|
||||
current_user_data = UserModelSchema().dump(current_user)
|
||||
tasks = bpmn_process_instance.get_tasks(TaskState.READY)
|
||||
|
@ -542,9 +560,31 @@ class ProcessInstanceProcessor:
|
|||
"lane_assignment_id": lane_assignment_id,
|
||||
}
|
||||
|
||||
def save_spiff_step_details(self) -> None:
|
||||
"""SaveSpiffStepDetails."""
|
||||
bpmn_json = self.serialize()
|
||||
wf_json = json.loads(bpmn_json)
|
||||
task_json = "{}"
|
||||
if "tasks" in wf_json:
|
||||
task_json = json.dumps(wf_json["tasks"])
|
||||
|
||||
# TODO want to just save the tasks, something wasn't immediately working
|
||||
# so after the flow works with the full wf_json revisit this
|
||||
task_json = wf_json
|
||||
details_model = SpiffStepDetailsModel(
|
||||
process_instance_id=self.process_instance_model.id,
|
||||
spiff_step=self.process_instance_model.spiff_step or 1,
|
||||
task_json=task_json,
|
||||
timestamp=round(time.time()),
|
||||
completed_by_user_id=self.current_user().id,
|
||||
)
|
||||
db.session.add(details_model)
|
||||
db.session.commit()
|
||||
|
||||
def save(self) -> None:
|
||||
"""Saves the current state of this processor to the database."""
|
||||
self.process_instance_model.bpmn_json = self.serialize()
|
||||
|
||||
complete_states = [TaskState.CANCELLED, TaskState.COMPLETED]
|
||||
user_tasks = list(self.get_all_user_tasks())
|
||||
self.process_instance_model.status = self.get_status().value
|
||||
|
@ -632,10 +672,14 @@ class ProcessInstanceProcessor:
|
|||
process_models = ProcessModelService().get_process_models()
|
||||
for process_model in process_models:
|
||||
if process_model.primary_file_name:
|
||||
etree_element = SpecFileService.get_etree_element_from_file_name(
|
||||
process_model, process_model.primary_file_name
|
||||
)
|
||||
bpmn_process_identifiers = []
|
||||
try:
|
||||
etree_element = SpecFileService.get_etree_element_from_file_name(
|
||||
process_model, process_model.primary_file_name
|
||||
)
|
||||
bpmn_process_identifiers = []
|
||||
except ProcessModelFileNotFoundError:
|
||||
# if primary_file_name doesn't actually exist on disk, then just go on to the next process_model
|
||||
continue
|
||||
|
||||
try:
|
||||
bpmn_process_identifiers = (
|
||||
|
@ -663,6 +707,11 @@ class ProcessInstanceProcessor:
|
|||
bpmn_process_identifier: str,
|
||||
) -> str:
|
||||
"""Bpmn_file_full_path_from_bpmn_process_identifier."""
|
||||
if bpmn_process_identifier is None:
|
||||
raise ValueError(
|
||||
"bpmn_file_full_path_from_bpmn_process_identifier: bpmn_process_identifier is unexpectedly None"
|
||||
)
|
||||
|
||||
bpmn_process_id_lookup = BpmnProcessIdLookup.query.filter_by(
|
||||
bpmn_process_identifier=bpmn_process_identifier
|
||||
).first()
|
||||
|
@ -695,6 +744,10 @@ class ProcessInstanceProcessor:
|
|||
if processed_identifiers is None:
|
||||
processed_identifiers = set()
|
||||
processor_dependencies = parser.get_process_dependencies()
|
||||
|
||||
# since get_process_dependencies() returns a set with None sometimes, we need to remove it
|
||||
processor_dependencies = processor_dependencies - {None}
|
||||
|
||||
processor_dependencies_new = processor_dependencies - processed_identifiers
|
||||
bpmn_process_identifiers_in_parser = parser.get_process_ids()
|
||||
|
||||
|
@ -930,11 +983,29 @@ class ProcessInstanceProcessor:
|
|||
|
||||
db.session.commit()
|
||||
|
||||
def increment_spiff_step(self) -> None:
|
||||
"""Spiff_step++."""
|
||||
spiff_step = self.process_instance_model.spiff_step or 0
|
||||
spiff_step += 1
|
||||
self.process_instance_model.spiff_step = spiff_step
|
||||
current_app.config["THREAD_LOCAL_DATA"].spiff_step = spiff_step
|
||||
db.session.add(self.process_instance_model)
|
||||
db.session.commit()
|
||||
|
||||
def do_engine_steps(self, exit_at: None = None, save: bool = False) -> None:
|
||||
"""Do_engine_steps."""
|
||||
try:
|
||||
self.bpmn_process_instance.refresh_waiting_tasks()
|
||||
self.bpmn_process_instance.do_engine_steps(exit_at=exit_at)
|
||||
self.bpmn_process_instance.refresh_waiting_tasks(
|
||||
will_refresh_task=lambda t: self.increment_spiff_step(),
|
||||
did_refresh_task=lambda t: self.save_spiff_step_details(),
|
||||
)
|
||||
|
||||
self.bpmn_process_instance.do_engine_steps(
|
||||
exit_at=exit_at,
|
||||
will_complete_task=lambda t: self.increment_spiff_step(),
|
||||
did_complete_task=lambda t: self.save_spiff_step_details(),
|
||||
)
|
||||
|
||||
self.process_bpmn_messages()
|
||||
self.queue_waiting_receive_messages()
|
||||
|
||||
|
@ -956,6 +1027,7 @@ class ProcessInstanceProcessor:
|
|||
# A little hackly, but make the bpmn_process_instance catch a cancel event.
|
||||
bpmn_process_instance.signal("cancel") # generate a cancel signal.
|
||||
bpmn_process_instance.catch(CancelEventDefinition())
|
||||
# Due to this being static, can't save granular step details in this case
|
||||
bpmn_process_instance.do_engine_steps()
|
||||
except WorkflowTaskExecException as we:
|
||||
raise ApiError.from_workflow_exception("task_error", str(we), we) from we
|
||||
|
@ -1054,7 +1126,9 @@ class ProcessInstanceProcessor:
|
|||
|
||||
def complete_task(self, task: SpiffTask) -> None:
|
||||
"""Complete_task."""
|
||||
self.increment_spiff_step()
|
||||
self.bpmn_process_instance.complete_task_from_id(task.id)
|
||||
self.save_spiff_step_details()
|
||||
|
||||
def get_data(self) -> dict[str, Any]:
|
||||
"""Get_data."""
|
||||
|
|
|
@ -27,6 +27,10 @@ from spiffworkflow_backend.services.file_system_service import FileSystemService
|
|||
from spiffworkflow_backend.services.process_model_service import ProcessModelService
|
||||
|
||||
|
||||
class ProcessModelFileNotFoundError(Exception):
|
||||
"""ProcessModelFileNotFoundError."""
|
||||
|
||||
|
||||
class SpecFileService(FileSystemService):
|
||||
"""SpecFileService."""
|
||||
|
||||
|
@ -90,9 +94,8 @@ class SpecFileService(FileSystemService):
|
|||
"""Get_data."""
|
||||
file_path = SpecFileService.file_path(process_model_info, file_name)
|
||||
if not os.path.exists(file_path):
|
||||
raise ApiError(
|
||||
"unknown_file",
|
||||
f"No file found with name {file_name} in {process_model_info.display_name}",
|
||||
raise ProcessModelFileNotFoundError(
|
||||
f"No file found with name {file_name} in {process_model_info.display_name}"
|
||||
)
|
||||
with open(file_path, "rb") as f_handle:
|
||||
spec_file_data = f_handle.read()
|
||||
|
|
|
@ -1123,6 +1123,8 @@ class TestProcessApi(BaseTest):
|
|||
)
|
||||
|
||||
assert response.json is not None
|
||||
# assert response.json['next_task'] is not None
|
||||
|
||||
active_tasks = (
|
||||
db.session.query(ActiveTaskModel)
|
||||
.filter(ActiveTaskModel.process_instance_id == process_instance_id)
|
||||
|
|
|
@ -36,6 +36,7 @@ class TestSpiffLogging(BaseTest):
|
|||
bpmn_task_identifier=bpmn_task_identifier,
|
||||
message=message,
|
||||
timestamp=timestamp,
|
||||
spiff_step=1,
|
||||
)
|
||||
assert spiff_log.timestamp == timestamp
|
||||
|
||||
|
|
|
@ -76,6 +76,10 @@ export default function AdminRoutes() {
|
|||
path="process-models/:process_group_id/:process_model_id/process-instances/:process_instance_id"
|
||||
element={<ProcessInstanceShow />}
|
||||
/>
|
||||
<Route
|
||||
path="process-models/:process_group_id/:process_model_id/process-instances/:process_instance_id/:spiff_step"
|
||||
element={<ProcessInstanceShow />}
|
||||
/>
|
||||
<Route
|
||||
path="process-models/:process_group_id/:process_model_id/process-instances/reports"
|
||||
element={<ProcessInstanceReportList />}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { useEffect, useState } from 'react';
|
||||
// @ts-ignore
|
||||
import { Table } from '@carbon/react';
|
||||
import { useParams, useSearchParams } from 'react-router-dom';
|
||||
import { useParams, useSearchParams, Link } from 'react-router-dom';
|
||||
import PaginationForTable from '../components/PaginationForTable';
|
||||
import ProcessBreadcrumb from '../components/ProcessBreadcrumb';
|
||||
import {
|
||||
|
@ -40,7 +40,14 @@ export default function ProcessInstanceLogList() {
|
|||
<td>{rowToUse.bpmn_task_name}</td>
|
||||
<td>{rowToUse.bpmn_task_type}</td>
|
||||
<td>{rowToUse.username}</td>
|
||||
<td>{convertSecondsToFormattedDate(rowToUse.timestamp)}</td>
|
||||
<td>
|
||||
<Link
|
||||
data-qa="process-instance-show-link"
|
||||
to={`/admin/process-models/${params.process_group_id}/${params.process_model_id}/process-instances/${rowToUse.process_instance_id}/${rowToUse.spiff_step}`}
|
||||
>
|
||||
{convertSecondsToFormattedDate(rowToUse.timestamp)}
|
||||
</Link>
|
||||
</td>
|
||||
</tr>
|
||||
);
|
||||
});
|
||||
|
|
|
@ -33,10 +33,16 @@ export default function ProcessInstanceShow() {
|
|||
path: `/process-models/${params.process_group_id}/${params.process_model_id}/process-instances/${params.process_instance_id}`,
|
||||
successCallback: setProcessInstance,
|
||||
});
|
||||
HttpService.makeCallToBackend({
|
||||
path: `/process-instance/${params.process_instance_id}/tasks?all_tasks=true`,
|
||||
successCallback: setTasks,
|
||||
});
|
||||
if (typeof params.spiff_step === 'undefined')
|
||||
HttpService.makeCallToBackend({
|
||||
path: `/process-instance/${params.process_instance_id}/tasks?all_tasks=true`,
|
||||
successCallback: setTasks,
|
||||
});
|
||||
else
|
||||
HttpService.makeCallToBackend({
|
||||
path: `/process-instance/${params.process_instance_id}/tasks?all_tasks=true&spiff_step=${params.spiff_step}`,
|
||||
successCallback: setTasks,
|
||||
});
|
||||
}, [params]);
|
||||
|
||||
const deleteProcessInstance = () => {
|
||||
|
@ -91,6 +97,62 @@ export default function ProcessInstanceShow() {
|
|||
return taskIds;
|
||||
};
|
||||
|
||||
const currentSpiffStep = (processInstanceToUse: any) => {
|
||||
if (typeof params.spiff_step === 'undefined') {
|
||||
return processInstanceToUse.spiff_step;
|
||||
}
|
||||
|
||||
return Number(params.spiff_step);
|
||||
};
|
||||
|
||||
const showingFirstSpiffStep = (processInstanceToUse: any) => {
|
||||
return currentSpiffStep(processInstanceToUse) === 1;
|
||||
};
|
||||
|
||||
const showingLastSpiffStep = (processInstanceToUse: any) => {
|
||||
return (
|
||||
currentSpiffStep(processInstanceToUse) === processInstanceToUse.spiff_step
|
||||
);
|
||||
};
|
||||
|
||||
const spiffStepLink = (
|
||||
processInstanceToUse: any,
|
||||
label: string,
|
||||
distance: number
|
||||
) => {
|
||||
return (
|
||||
<li>
|
||||
<Link
|
||||
reloadDocument
|
||||
data-qa="process-instance-step-link"
|
||||
to={`/admin/process-models/${params.process_group_id}/${
|
||||
params.process_model_id
|
||||
}/process-instances/${params.process_instance_id}/${
|
||||
currentSpiffStep(processInstanceToUse) + distance
|
||||
}`}
|
||||
>
|
||||
{label}
|
||||
</Link>
|
||||
</li>
|
||||
);
|
||||
};
|
||||
|
||||
const previousStepLink = (processInstanceToUse: any) => {
|
||||
if (showingFirstSpiffStep(processInstanceToUse)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return spiffStepLink(processInstanceToUse, 'Previous Step', -1);
|
||||
};
|
||||
|
||||
const nextStepLink = (processInstanceToUse: any) => {
|
||||
if (showingLastSpiffStep(processInstanceToUse)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return spiffStepLink(processInstanceToUse, 'Next Step', 1);
|
||||
};
|
||||
|
||||
const getInfoTag = (processInstanceToUse: any) => {
|
||||
const currentEndDate = convertSecondsToFormattedDate(
|
||||
processInstanceToUse.end_in_seconds
|
||||
|
@ -130,6 +192,12 @@ export default function ProcessInstanceShow() {
|
|||
Messages
|
||||
</Link>
|
||||
</li>
|
||||
<li>
|
||||
Step {currentSpiffStep(processInstanceToUse)} of{' '}
|
||||
{processInstanceToUse.spiff_step}
|
||||
</li>
|
||||
{previousStepLink(processInstanceToUse)}
|
||||
{nextStepLink(processInstanceToUse)}
|
||||
</ul>
|
||||
);
|
||||
};
|
||||
|
@ -229,7 +297,9 @@ export default function ProcessInstanceShow() {
|
|||
};
|
||||
|
||||
const canEditTaskData = (task: any) => {
|
||||
return task.state === 'READY';
|
||||
return (
|
||||
task.state === 'READY' && showingLastSpiffStep(processInstance as any)
|
||||
);
|
||||
};
|
||||
|
||||
const cancelEditingTaskData = () => {
|
||||
|
|
Loading…
Reference in New Issue