mirror of
https://github.com/viewflow/viewflow.git
synced 2025-07-28 07:43:10 +08:00
Changes sync
This commit is contained in:
@ -2,10 +2,13 @@
|
|||||||
Changelog
|
Changelog
|
||||||
=========
|
=========
|
||||||
|
|
||||||
GIT VERSION
|
2.0.0.b5 2023-07-10
|
||||||
-----------
|
-------------------
|
||||||
|
|
||||||
- Alow attach layout to forms in default form rendering template
|
- Alow attach layout to forms in default form rendering template
|
||||||
|
- Fix subprocess node activation
|
||||||
|
- Added db indexes for workflow models
|
||||||
|
- Improve workflow REST API support
|
||||||
|
|
||||||
2.0.0.b4 2023-06-05
|
2.0.0.b4 2023-06-05
|
||||||
-------------------
|
-------------------
|
||||||
|
14
README.md
14
README.md
@ -179,17 +179,13 @@ modifications of Viewflow. You can find the commercial license terms in
|
|||||||
|
|
||||||
## Changelog
|
## Changelog
|
||||||
|
|
||||||
2.0.0.b4 2023-06-05
|
2.0.0.b5 2023-07-10
|
||||||
-------------------
|
-------------------
|
||||||
|
|
||||||
- New flow.SplitFirst Node
|
- Alow attach layout to forms in default form rendering template
|
||||||
- New celery.Timer Node
|
- Fix subprocess node activation
|
||||||
- Expose REST API with drf-spectacular
|
- Added db indexes for workflow models
|
||||||
- Expose list_ordering_fields in a ModelViewset
|
- Improve workflow REST API support
|
||||||
- Retain history and return to the Inbox/Queue list views after completing a flow task
|
|
||||||
- Enable smooth page transitions in Chrome/Safari
|
|
||||||
- Hotwire/Turbo integration for Django Admin with viewflow.contrib.admin app
|
|
||||||
- Resolved issue with viewflow.fsm reporting unmet condition messages
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
2
setup.py
2
setup.py
@ -4,7 +4,7 @@ README = open("README.md", "r", encoding="utf-8").read()
|
|||||||
|
|
||||||
setuptools.setup(
|
setuptools.setup(
|
||||||
name="django-viewflow",
|
name="django-viewflow",
|
||||||
version="2.0.0b4",
|
version="2.0.0b5",
|
||||||
author_email="kmmbvnr@gmail.com",
|
author_email="kmmbvnr@gmail.com",
|
||||||
author="Mikhail Podgurskiy",
|
author="Mikhail Podgurskiy",
|
||||||
description="Reusable library to build business applications fast",
|
description="Reusable library to build business applications fast",
|
||||||
|
@ -34,7 +34,11 @@ class DashboardView(
|
|||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
sorted_nodes, _ = chart.topsort(self.flow_class)
|
sorted_nodes, _ = chart.topsort(self.flow_class)
|
||||||
nodes = [node for node in sorted_nodes if node.task_type in ["HUMAN", "JOB"]]
|
nodes = [
|
||||||
|
node
|
||||||
|
for node in sorted_nodes
|
||||||
|
if node.task_type in ["HUMAN", "JOB", "SUBPROCESS"]
|
||||||
|
]
|
||||||
|
|
||||||
start_nodes = [
|
start_nodes = [
|
||||||
{"node": node, "can_execute": node.can_execute(self.request.user)}
|
{"node": node, "can_execute": node.can_execute(self.request.user)}
|
||||||
|
@ -8,6 +8,7 @@ from django.db.models.constants import LOOKUP_SEP
|
|||||||
from django.db.models.query import ModelIterable
|
from django.db.models.query import ModelIterable
|
||||||
|
|
||||||
from .status import STATUS
|
from .status import STATUS
|
||||||
|
from .utils import get_next_process_task
|
||||||
|
|
||||||
|
|
||||||
def _available_flows(flow_classes, user):
|
def _available_flows(flow_classes, user):
|
||||||
@ -257,22 +258,28 @@ class TaskQuerySet(QuerySet):
|
|||||||
Prefer assigned tasks first, if not, return first task from user queue
|
Prefer assigned tasks first, if not, return first task from user queue
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# first try to find an assigned task
|
# task inside a same process
|
||||||
task = self.filter(process=process, owner=user, status=STATUS.ASSIGNED).first()
|
task = get_next_process_task(self, process, user)
|
||||||
|
|
||||||
# lookup for a task in a queue
|
# task inside subprocess
|
||||||
if task is None:
|
if task is None:
|
||||||
task = (
|
subprocess_task = self.filter(process__parent_task__process=process).first()
|
||||||
self.user_queue(user).filter(process=process, status=STATUS.NEW).first()
|
if subprocess_task:
|
||||||
)
|
task = get_next_process_task(self, subprocess_task.process, user)
|
||||||
|
|
||||||
# lookup for a job
|
# task inside parent process
|
||||||
if task is None:
|
if task is None and process.parent_task_id:
|
||||||
task = (
|
task = get_next_process_task(self, process.parent_task.process, user)
|
||||||
self.filter(process=process, flow_task_type='JOB', status__in=[
|
|
||||||
STATUS.NEW, STATUS.SCHEDULED, STATUS.STARTED
|
# task inside other subprocesses of parent task
|
||||||
]).first()
|
if task is None and process.parent_task_id:
|
||||||
)
|
processes = process.__class__._default_manager.filter(
|
||||||
|
parent_task__process=process.parent_task.process
|
||||||
|
).exclude(pk=process.pk)
|
||||||
|
for sub_process in processes:
|
||||||
|
task = get_next_process_task(self, sub_process, user)
|
||||||
|
if task:
|
||||||
|
break
|
||||||
|
|
||||||
return task
|
return task
|
||||||
|
|
||||||
|
@ -1,20 +1,48 @@
|
|||||||
|
from .status import STATUS
|
||||||
|
|
||||||
|
|
||||||
class Act(object):
|
class Act(object):
|
||||||
"""Shortcut to access activation data."""
|
"""Shortcut to access activation data."""
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def process(self):
|
def process(self):
|
||||||
"""Shortcut for lambda activation: activation.process...)"""
|
"""Shortcut for lambda activation: activation.process...)"""
|
||||||
|
|
||||||
class Lookup(object):
|
class Lookup(object):
|
||||||
def __getattribute__(self, name):
|
def __getattribute__(self, name):
|
||||||
return lambda activation: getattr(activation.process, name)
|
return lambda activation: getattr(activation.process, name)
|
||||||
|
|
||||||
return Lookup()
|
return Lookup()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def task(self):
|
def task(self):
|
||||||
"""Shortcut for lambda activation: activation.task...)"""
|
"""Shortcut for lambda activation: activation.task...)"""
|
||||||
|
|
||||||
class Lookup(object):
|
class Lookup(object):
|
||||||
def __getattribute__(self, name):
|
def __getattribute__(self, name):
|
||||||
return lambda activation: getattr(activation.task, name)
|
return lambda activation: getattr(activation.task, name)
|
||||||
|
|
||||||
return Lookup()
|
return Lookup()
|
||||||
|
|
||||||
|
|
||||||
act = Act()
|
act = Act()
|
||||||
|
|
||||||
|
|
||||||
|
def get_next_process_task(manager, process, user):
|
||||||
|
task = manager.filter(process=process, owner=user, status=STATUS.ASSIGNED).first()
|
||||||
|
|
||||||
|
# lookup for a task in a queue
|
||||||
|
if task is None:
|
||||||
|
task = (
|
||||||
|
manager.user_queue(user).filter(process=process, status=STATUS.NEW).first()
|
||||||
|
)
|
||||||
|
|
||||||
|
# lookup for a job
|
||||||
|
if task is None:
|
||||||
|
task = manager.filter(
|
||||||
|
process=process,
|
||||||
|
flow_task_type="JOB",
|
||||||
|
status__in=[STATUS.NEW, STATUS.SCHEDULED, STATUS.STARTED],
|
||||||
|
).first()
|
||||||
|
|
||||||
|
return task
|
||||||
|
Reference in New Issue
Block a user