the big message improvements branch (#1549)
* imported patch from old message_improvements branch w/ burnettk * wip. * merging in changes from message_improvements * remove patch files that were accidendetally added. * Added a modal for editing a correlation. Added ability to delete whole correlation keys. A little css cleanup. * * Removing migration - will add back in at the end. * The Message models API should not require page and per_age parameters, it will return all. * The Message model list should return a full json description of all messages/correlations for all containing groups. * * wip * Add import, fix class name * Getting ./bin/pyl to pass * Getting ./bin/pyl to pass * Some fe lint fixes * Some ruff fixes * Commands to nuke poetry dirs * Temp skipping of a couple tests * Getting ./bin/pyl to pass * This needs to be back in * Revert back to main * Factored out data store handling * Working on factoring out collecting messages, has test failure * Formatting * Fixed up test failures * Remove commentted out lines * Adding fields * Fix merge issue * Re-enable modal * WIP * Untested relationships * Remove correlation key table * Remove retrieval expression from uniqueness * Remove commentted out lines * WIP * WIP * WIP * WIP * WIP * Make mypy pass * Getting formatters to pass * Add migration * WIP fixing tests * WIP fixing tests * WIP fixing tests * WIP fixing tests * WIP fixing tests * Getting ./bin/pyl to pass * Fix skipped test * Fix skipped test * Getting ./bin/pyl to pass * Remove unused method * Remove unused methods * Clean up unused code * Refactor to support creating single messages from the UI * Untested support for processing one process_group * WIP test * WIP test * Filled out test * Getting ./bin/pyl to pass * Message Editor Modal Work * Change migration and add in schemas. * Swtich to using the associated branch of the process BPMN.io mods * Get the backend returning messages created from the frontend to the drop down list in the BPMN.io editor. * Merge main, fix up test * Getting ./bin/pyl to pass * Show path in location * Rename var * install packages from bpmn-js-spiffworkflow as well for local development * process group api can add and update message models now w/ burnettk * backend tests are passing now w/ burnettk * the launch message edit button is loading the editor w/ burnettk * updated bpmn-js-spiffworkflow * pyl is passing w/ burnettk * updated bpmn-js-spiffworkflow w/ burnettk * updated bpmn-js-spiffworkflow w/ burnettk * fixed console errors w/ burnettk * a couple tweaks w/ burnettk * save the message json in the new format from the mform w/ burnettk * display the correlation props in the form w/ burnettk * default to empty schema so the format is obvious * allow removing correlation props from web ui w/ burnettk * added save notification when saving a message on a process model w/ burnettk * fixed broken test w/ burnettk * Updating test cases to new message format, tests are failing * support schema from messages in frontend * Fixing tests * Fixing tests * Fixing tests * removed references to correlation keys and removed unused components w/ burnettk * removed temp mesasge model edit button w/ burnettk * Make mypy pass * Fixing tests * Fixing tests * Getting ./bin/pyl to pass * save deleted messages before attempting to add new ones w/ burnettk * set state for the message id so it can be changed w/ burnettk * do not wait for the message id to be set since it is not necessary w/ burnettk * updated bpmn-js-spiffworkflow w/ burnettk * build images for this branch w/ burnettk * put location in path of message-models so we can control permissions on it w/ burnettk * fix black * some coderabbit suggestions * pull in spiff fix * Default schema to {} * Temp fix for invalid schema * updated bpmn-js-spiffworkflow * some updates for issue 1626 * minor name tweaks and attempts to update message dropdown in panel when message changes - does not work yet w/ burnettk * updated bpmn-js-spiffworkflow w/ burnettk * attempt to call add_message.returned event when message updates w/ burnettk * treat formData as a state in the MesasgeEditor so it can be updated when the form contents is modified w/ burnettk * updated bpmn-js-spiffworkflow w/ burnettk * Feature/merge correlation properties (#1693) * Merge XML Correlation properties with Process group properties * updates for messages w/ burnettk --------- Co-authored-by: theaubmov <ayoubaitlachgar98@gmail.com> Co-authored-by: jasquat <jasquat@users.noreply.github.com> * do not wait for message id state to be set to better support new messages w/ burnettk * updated SpiffWorkflow w/ burnettk * some cleanup from coderabbit and linting * added index to message tables, run typecheck in ci, and other updates while code reviewing w/ burnettk * updated bpmn-js-spiffworkflow w/ burnettk * remove branch to build --------- Co-authored-by: jasquat <jasquat@users.noreply.github.com> Co-authored-by: danfunk <daniel.h.funk@gmail.com> Co-authored-by: Jon Herron <jon.herron@yahoo.com> Co-authored-by: burnettk <burnettk@users.noreply.github.com> Co-authored-by: jasquat <2487833+jasquat@users.noreply.github.com> Co-authored-by: theaubmov <ayoubaitlachgar98@gmail.com>
This commit is contained in:
parent
a63e8a34a1
commit
eae5f7dd2d
|
@ -0,0 +1,85 @@
|
|||
"""empty message
|
||||
|
||||
Revision ID: 43afc70a7016
|
||||
Revises: d4b900e71852
|
||||
Create Date: 2024-06-10 11:17:19.060779
|
||||
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
from sqlalchemy.dialects import mysql
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = '43afc70a7016'
|
||||
down_revision = 'd4b900e71852'
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.create_table('message',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('identifier', sa.String(length=255), nullable=False),
|
||||
sa.Column('location', sa.String(length=255), nullable=False),
|
||||
sa.Column('schema', sa.JSON(), nullable=False),
|
||||
sa.Column('updated_at_in_seconds', sa.Integer(), nullable=False),
|
||||
sa.Column('created_at_in_seconds', sa.Integer(), nullable=False),
|
||||
sa.PrimaryKeyConstraint('id'),
|
||||
sa.UniqueConstraint('identifier', 'location', name='message_identifier_location_unique')
|
||||
)
|
||||
with op.batch_alter_table('message', schema=None) as batch_op:
|
||||
batch_op.create_index(batch_op.f('ix_message_identifier'), ['identifier'], unique=False)
|
||||
batch_op.create_index(batch_op.f('ix_message_location'), ['location'], unique=False)
|
||||
|
||||
op.create_table('message_correlation_property',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('message_id', sa.Integer(), nullable=False),
|
||||
sa.Column('identifier', sa.String(length=255), nullable=False),
|
||||
sa.Column('retrieval_expression', sa.String(length=255), nullable=False),
|
||||
sa.Column('updated_at_in_seconds', sa.Integer(), nullable=False),
|
||||
sa.Column('created_at_in_seconds', sa.Integer(), nullable=False),
|
||||
sa.ForeignKeyConstraint(['message_id'], ['message.id'], name='message_correlation_property_message_id_fk'),
|
||||
sa.PrimaryKeyConstraint('id'),
|
||||
sa.UniqueConstraint('message_id', 'identifier', name='message_correlation_property_unique')
|
||||
)
|
||||
with op.batch_alter_table('message_correlation_property', schema=None) as batch_op:
|
||||
batch_op.create_index(batch_op.f('ix_message_correlation_property_identifier'), ['identifier'], unique=False)
|
||||
batch_op.create_index(batch_op.f('ix_message_correlation_property_message_id'), ['message_id'], unique=False)
|
||||
|
||||
with op.batch_alter_table('correlation_property_cache', schema=None) as batch_op:
|
||||
batch_op.drop_index('ix_correlation_property_cache_message_name')
|
||||
batch_op.drop_index('ix_correlation_property_cache_name')
|
||||
|
||||
op.drop_table('correlation_property_cache')
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
def downgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.create_table('correlation_property_cache',
|
||||
sa.Column('id', mysql.INTEGER(), autoincrement=True, nullable=False),
|
||||
sa.Column('name', mysql.VARCHAR(collation='utf8mb4_0900_as_cs', length=50), nullable=False),
|
||||
sa.Column('message_name', mysql.VARCHAR(collation='utf8mb4_0900_as_cs', length=50), nullable=False),
|
||||
sa.Column('process_model_id', mysql.VARCHAR(collation='utf8mb4_0900_as_cs', length=255), nullable=False),
|
||||
sa.Column('retrieval_expression', mysql.VARCHAR(collation='utf8mb4_0900_as_cs', length=255), nullable=True),
|
||||
sa.PrimaryKeyConstraint('id'),
|
||||
mysql_collate='utf8mb4_0900_as_cs',
|
||||
mysql_default_charset='utf8mb4',
|
||||
mysql_engine='InnoDB'
|
||||
)
|
||||
with op.batch_alter_table('correlation_property_cache', schema=None) as batch_op:
|
||||
batch_op.create_index('ix_correlation_property_cache_name', ['name'], unique=False)
|
||||
batch_op.create_index('ix_correlation_property_cache_message_name', ['message_name'], unique=False)
|
||||
|
||||
with op.batch_alter_table('message_correlation_property', schema=None) as batch_op:
|
||||
batch_op.drop_index(batch_op.f('ix_message_correlation_property_message_id'))
|
||||
batch_op.drop_index(batch_op.f('ix_message_correlation_property_identifier'))
|
||||
|
||||
op.drop_table('message_correlation_property')
|
||||
with op.batch_alter_table('message', schema=None) as batch_op:
|
||||
batch_op.drop_index(batch_op.f('ix_message_location'))
|
||||
batch_op.drop_index(batch_op.f('ix_message_identifier'))
|
||||
|
||||
op.drop_table('message')
|
||||
# ### end Alembic commands ###
|
|
@ -2959,7 +2959,7 @@ doc = ["sphinx", "sphinx_rtd_theme"]
|
|||
type = "git"
|
||||
url = "https://github.com/sartography/SpiffWorkflow"
|
||||
reference = "main"
|
||||
resolved_reference = "faf859fefcb21eecd6038f32efb48eb19d09ae28"
|
||||
resolved_reference = "6cf13eb18cd77f17b6c06e99c6756c0dce26675b"
|
||||
|
||||
[[package]]
|
||||
name = "spiffworkflow-connector-command"
|
||||
|
|
|
@ -2580,6 +2580,41 @@ paths:
|
|||
schema:
|
||||
$ref: "#/components/schemas/Workflow"
|
||||
|
||||
/message-models:
|
||||
get:
|
||||
tags:
|
||||
- Messages
|
||||
operationId: spiffworkflow_backend.routes.messages_controller.message_model_list_from_root
|
||||
summary: Get a list of message models
|
||||
responses:
|
||||
"200":
|
||||
description: A list of message models
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/Workflow"
|
||||
|
||||
/message-models/{relative_location}:
|
||||
parameters:
|
||||
- name: relative_location
|
||||
in: path
|
||||
required: true
|
||||
description: The location of the message model relative to the root of the project, defaults to /
|
||||
schema:
|
||||
type: string
|
||||
get:
|
||||
tags:
|
||||
- Messages
|
||||
operationId: spiffworkflow_backend.routes.messages_controller.message_model_list
|
||||
summary: Get a list of message models
|
||||
responses:
|
||||
"200":
|
||||
description: A list of message models
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/Workflow"
|
||||
|
||||
/messages:
|
||||
parameters:
|
||||
- name: process_instance_id
|
||||
|
|
|
@ -106,6 +106,10 @@ from spiffworkflow_backend.models.user_property import (
|
|||
from spiffworkflow_backend.models.service_account import (
|
||||
ServiceAccountModel,
|
||||
) # noqa: F401
|
||||
from spiffworkflow_backend.models.message_model import (
|
||||
MessageModel,
|
||||
MessageCorrelationPropertyModel,
|
||||
) # noqa: F401
|
||||
from spiffworkflow_backend.models.future_task import (
|
||||
FutureTaskModel,
|
||||
) # noqa: F401
|
||||
|
|
|
@ -1,23 +0,0 @@
|
|||
from dataclasses import dataclass
|
||||
|
||||
from spiffworkflow_backend.models.db import SpiffworkflowBaseDBModel
|
||||
from spiffworkflow_backend.models.db import db
|
||||
|
||||
|
||||
@dataclass
|
||||
class CorrelationPropertyCache(SpiffworkflowBaseDBModel):
|
||||
"""A list of known correlation properties as read from BPMN files.
|
||||
|
||||
This correlation properties are not directly linked to anything
|
||||
but it provides a way to know what processes are talking about
|
||||
what messages and correlation keys. And could be useful as an
|
||||
api endpoint if you wanted to know what another process model
|
||||
is using.
|
||||
"""
|
||||
|
||||
__tablename__ = "correlation_property_cache"
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
name: str = db.Column(db.String(50), nullable=False, index=True)
|
||||
message_name: str = db.Column(db.String(50), nullable=False, index=True)
|
||||
process_model_id: str = db.Column(db.String(255), nullable=False)
|
||||
retrieval_expression: str = db.Column(db.String(255))
|
|
@ -0,0 +1,44 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass
|
||||
|
||||
from sqlalchemy import ForeignKey
|
||||
from sqlalchemy import UniqueConstraint
|
||||
from sqlalchemy.orm import relationship
|
||||
|
||||
from spiffworkflow_backend.models.db import SpiffworkflowBaseDBModel
|
||||
from spiffworkflow_backend.models.db import db
|
||||
|
||||
|
||||
@dataclass
|
||||
class MessageModel(SpiffworkflowBaseDBModel):
|
||||
__tablename__ = "message"
|
||||
__table_args__ = (UniqueConstraint("identifier", "location", name="message_identifier_location_unique"),)
|
||||
|
||||
id: int = db.Column(db.Integer, primary_key=True)
|
||||
identifier: str = db.Column(db.String(255), index=True, nullable=False)
|
||||
location: str = db.Column(db.String(255), index=True, nullable=False)
|
||||
schema: dict = db.Column(db.JSON, nullable=False)
|
||||
updated_at_in_seconds: int = db.Column(db.Integer, nullable=False)
|
||||
created_at_in_seconds: int = db.Column(db.Integer, nullable=False)
|
||||
|
||||
correlation_properties = relationship("MessageCorrelationPropertyModel", cascade="delete")
|
||||
|
||||
|
||||
@dataclass
|
||||
class MessageCorrelationPropertyModel(SpiffworkflowBaseDBModel):
|
||||
__tablename__ = "message_correlation_property"
|
||||
__table_args__ = (UniqueConstraint("message_id", "identifier", name="message_correlation_property_unique"),)
|
||||
|
||||
id: int = db.Column(db.Integer, primary_key=True)
|
||||
message_id: int = db.Column(
|
||||
ForeignKey(MessageModel.id, name="message_correlation_property_message_id_fk"), # type: ignore
|
||||
nullable=False,
|
||||
index=True,
|
||||
)
|
||||
identifier: str = db.Column(db.String(255), index=True, nullable=False)
|
||||
retrieval_expression: str = db.Column(db.String(255), nullable=False)
|
||||
updated_at_in_seconds: int = db.Column(db.Integer, nullable=False)
|
||||
created_at_in_seconds: int = db.Column(db.Integer, nullable=False)
|
||||
|
||||
message = relationship("MessageModel", back_populates="correlation_properties")
|
|
@ -18,6 +18,19 @@ PROCESS_GROUP_SUPPORTED_KEYS_FOR_DISK_SERIALIZATION = [
|
|||
"display_name",
|
||||
"description",
|
||||
"data_store_specifications",
|
||||
"messages",
|
||||
"correlation_keys",
|
||||
"correlation_properties",
|
||||
]
|
||||
|
||||
|
||||
PROCESS_GROUP_KEYS_TO_UPDATE_FROM_API = [
|
||||
"display_name",
|
||||
"description",
|
||||
"messages",
|
||||
"data_store_specifications",
|
||||
"correlation_keys",
|
||||
"correlation_properties",
|
||||
]
|
||||
|
||||
|
||||
|
@ -32,6 +45,9 @@ class ProcessGroup:
|
|||
process_groups: list[ProcessGroup] = field(default_factory=list["ProcessGroup"])
|
||||
data_store_specifications: dict[str, Any] = field(default_factory=dict)
|
||||
parent_groups: list[ProcessGroupLite] | None = None
|
||||
messages: dict[str, Any] | None = None
|
||||
correlation_keys: list[dict[str, Any]] | None = None
|
||||
correlation_properties: list[dict[str, Any]] | None = None
|
||||
|
||||
# TODO: delete these once they no no longer mentioned in current
|
||||
# process_group.json files
|
||||
|
@ -62,6 +78,23 @@ class ProcessGroup:
|
|||
return list(dict_keys)
|
||||
|
||||
|
||||
class MessageSchema(Schema):
|
||||
class Meta:
|
||||
fields = ["id", "schema"]
|
||||
|
||||
|
||||
class RetrievalExpressionSchema(Schema):
|
||||
class Meta:
|
||||
fields = ["message_ref", "formal_expression"]
|
||||
|
||||
|
||||
class CorrelationPropertySchema(Schema):
|
||||
class Meta:
|
||||
fields = ["id", "retrieval_expression"]
|
||||
|
||||
retrieval_expression = marshmallow.fields.Nested(RetrievalExpressionSchema, required=False)
|
||||
|
||||
|
||||
class ProcessGroupSchema(Schema):
|
||||
class Meta:
|
||||
model = ProcessGroup
|
||||
|
@ -71,10 +104,16 @@ class ProcessGroupSchema(Schema):
|
|||
"process_models",
|
||||
"description",
|
||||
"process_groups",
|
||||
"messages",
|
||||
"correlation_properties",
|
||||
]
|
||||
|
||||
process_models = marshmallow.fields.List(marshmallow.fields.Nested("ProcessModelInfoSchema", dump_only=True, required=False))
|
||||
process_groups = marshmallow.fields.List(marshmallow.fields.Nested("ProcessGroupSchema", dump_only=True, required=False))
|
||||
messages = marshmallow.fields.List(marshmallow.fields.Nested(MessageSchema, dump_only=True, required=False))
|
||||
correlation_properties = marshmallow.fields.List(
|
||||
marshmallow.fields.Nested(CorrelationPropertySchema, dump_only=True, required=False)
|
||||
)
|
||||
|
||||
@post_load
|
||||
def make_process_group(self, data: dict[str, str | bool | int], **kwargs: dict) -> ProcessGroup:
|
||||
|
|
|
@ -6,10 +6,43 @@ from flask import jsonify
|
|||
from flask import make_response
|
||||
from flask.wrappers import Response
|
||||
|
||||
from spiffworkflow_backend.models.db import db
|
||||
from spiffworkflow_backend.models.message_instance import MessageInstanceModel
|
||||
from spiffworkflow_backend.models.message_model import MessageCorrelationPropertyModel
|
||||
from spiffworkflow_backend.models.message_model import MessageModel
|
||||
from spiffworkflow_backend.models.process_instance import ProcessInstanceModel
|
||||
from spiffworkflow_backend.models.process_instance import ProcessInstanceModelSchema
|
||||
from spiffworkflow_backend.services.message_service import MessageService
|
||||
from spiffworkflow_backend.services.upsearch_service import UpsearchService
|
||||
|
||||
|
||||
def message_model_list_from_root() -> flask.wrappers.Response:
|
||||
return message_model_list()
|
||||
|
||||
|
||||
def message_model_list(relative_location: str | None = None) -> flask.wrappers.Response:
|
||||
# Returns all the messages and correlation properties that exist at the given
|
||||
# relative location or higher in the directory tree.
|
||||
|
||||
loc = relative_location.replace(":", "/") if relative_location else ""
|
||||
locations = UpsearchService.upsearch_locations(loc)
|
||||
messages = db.session.query(MessageModel).filter(MessageModel.location.in_(locations)).order_by(MessageModel.identifier).all() # type: ignore
|
||||
|
||||
def correlation_property_response(correlation_property: MessageCorrelationPropertyModel) -> dict[str, str]:
|
||||
return {
|
||||
"identifier": correlation_property.identifier,
|
||||
"retrieval_expression": correlation_property.retrieval_expression,
|
||||
}
|
||||
|
||||
def message_response(message: MessageModel) -> dict[str, Any]:
|
||||
return {
|
||||
"identifier": message.identifier,
|
||||
"location": message.location,
|
||||
"schema": message.schema,
|
||||
"correlation_properties": [correlation_property_response(cp) for cp in message.correlation_properties],
|
||||
}
|
||||
|
||||
return make_response(jsonify({"messages": [message_response(m) for m in messages]}), 200)
|
||||
|
||||
|
||||
def message_instance_list(
|
||||
|
|
|
@ -13,11 +13,14 @@ from spiffworkflow_backend.exceptions.api_error import ApiError
|
|||
from spiffworkflow_backend.exceptions.error import NotAuthorizedError
|
||||
from spiffworkflow_backend.exceptions.process_entity_not_found_error import ProcessEntityNotFoundError
|
||||
from spiffworkflow_backend.models.db import db
|
||||
from spiffworkflow_backend.models.message_model import MessageModel
|
||||
from spiffworkflow_backend.models.process_group import PROCESS_GROUP_KEYS_TO_UPDATE_FROM_API
|
||||
from spiffworkflow_backend.models.process_group import ProcessGroup
|
||||
from spiffworkflow_backend.models.process_group import ProcessGroupSchema
|
||||
from spiffworkflow_backend.routes.process_api_blueprint import _commit_and_push_to_git
|
||||
from spiffworkflow_backend.routes.process_api_blueprint import _un_modify_modified_process_model_id
|
||||
from spiffworkflow_backend.services.authorization_service import AuthorizationService
|
||||
from spiffworkflow_backend.services.message_definition_service import MessageDefinitionService
|
||||
from spiffworkflow_backend.services.process_model_service import ProcessModelService
|
||||
from spiffworkflow_backend.services.process_model_service import ProcessModelWithInstancesNotDeletableError
|
||||
from spiffworkflow_backend.services.spec_file_service import SpecFileService
|
||||
|
@ -68,9 +71,9 @@ def process_group_delete(modified_process_group_id: str) -> flask.wrappers.Respo
|
|||
|
||||
|
||||
def process_group_update(modified_process_group_id: str, body: dict) -> flask.wrappers.Response:
|
||||
"""Process Group Update."""
|
||||
body_include_list = ["display_name", "description"]
|
||||
body_filtered = {include_item: body[include_item] for include_item in body_include_list if include_item in body}
|
||||
body_filtered = {
|
||||
include_item: body[include_item] for include_item in PROCESS_GROUP_KEYS_TO_UPDATE_FROM_API if include_item in body
|
||||
}
|
||||
|
||||
process_group_id = _un_modify_modified_process_model_id(modified_process_group_id)
|
||||
if not ProcessModelService.is_process_group_identifier(process_group_id):
|
||||
|
@ -82,6 +85,14 @@ def process_group_update(modified_process_group_id: str, body: dict) -> flask.wr
|
|||
|
||||
process_group = ProcessGroup(id=process_group_id, **body_filtered)
|
||||
ProcessModelService.update_process_group(process_group)
|
||||
|
||||
all_message_models: dict[tuple[str, str], MessageModel] = {}
|
||||
MessageDefinitionService.collect_message_models(process_group, process_group_id, all_message_models)
|
||||
MessageDefinitionService.delete_message_models_at_location(process_group_id)
|
||||
db.session.commit()
|
||||
MessageDefinitionService.save_all_message_models(all_message_models)
|
||||
db.session.commit()
|
||||
|
||||
_commit_and_push_to_git(f"User: {g.user.username} updated process group {process_group_id}")
|
||||
return make_response(jsonify(process_group), 200)
|
||||
|
||||
|
|
|
@ -59,6 +59,7 @@ PATH_SEGMENTS_FOR_PERMISSION_ALL = [
|
|||
{"path": "/event-error-details", "relevant_permissions": ["read"]},
|
||||
{"path": "/logs", "relevant_permissions": ["read"]},
|
||||
{"path": "/logs/typeahead-filter-values", "relevant_permissions": ["read"]},
|
||||
{"path": "/message-models", "relevant_permissions": ["read"]},
|
||||
{
|
||||
"path": "/process-instances",
|
||||
"relevant_permissions": ["create", "read", "delete"],
|
||||
|
|
|
@ -8,8 +8,11 @@ from spiffworkflow_backend.data_stores.kkv import KKVDataStore
|
|||
from spiffworkflow_backend.models.db import db
|
||||
from spiffworkflow_backend.models.json_data_store import JSONDataStoreModel
|
||||
from spiffworkflow_backend.models.kkv_data_store import KKVDataStoreModel
|
||||
from spiffworkflow_backend.models.message_model import MessageModel
|
||||
from spiffworkflow_backend.models.process_group import ProcessGroup
|
||||
from spiffworkflow_backend.models.reference_cache import ReferenceCacheModel
|
||||
from spiffworkflow_backend.services.file_system_service import FileSystemService
|
||||
from spiffworkflow_backend.services.message_definition_service import MessageDefinitionService
|
||||
from spiffworkflow_backend.services.process_model_service import ProcessModelService
|
||||
from spiffworkflow_backend.services.reference_cache_service import ReferenceCacheService
|
||||
from spiffworkflow_backend.services.spec_file_service import SpecFileService
|
||||
|
@ -33,6 +36,7 @@ class DataSetupService:
|
|||
files = FileSystemService.walk_files_from_root_path(True, None)
|
||||
reference_objects: dict[str, ReferenceCacheModel] = {}
|
||||
all_data_store_specifications: dict[tuple[str, str, str], Any] = {}
|
||||
all_message_models: dict[tuple[str, str], MessageModel] = {}
|
||||
references = []
|
||||
|
||||
for file in files:
|
||||
|
@ -42,7 +46,6 @@ class DataSetupService:
|
|||
try:
|
||||
# FIXME: get_references_for_file_contents is erroring out for elements in the list
|
||||
refs = SpecFileService.get_references_for_process(process_model)
|
||||
|
||||
for ref in refs:
|
||||
try:
|
||||
reference_cache = ReferenceCacheModel.from_spec_reference(ref)
|
||||
|
@ -80,29 +83,19 @@ class DataSetupService:
|
|||
elif FileSystemService.is_process_group_json_file(file):
|
||||
try:
|
||||
process_group = ProcessModelService.find_or_create_process_group(os.path.dirname(file))
|
||||
cls._collect_data_store_specifications(process_group, file, all_data_store_specifications)
|
||||
MessageDefinitionService.collect_message_models(process_group, process_group.id, all_message_models)
|
||||
except Exception:
|
||||
current_app.logger.debug(f"Failed to load process group from file @ '{file}'")
|
||||
continue
|
||||
|
||||
for data_store_type, specs_by_id in process_group.data_store_specifications.items():
|
||||
if not isinstance(specs_by_id, dict):
|
||||
current_app.logger.debug(f"Expected dictionary as value for key '{data_store_type}' in file @ '{file}'")
|
||||
continue
|
||||
|
||||
for identifier, specification in specs_by_id.items():
|
||||
location = specification.get("location")
|
||||
if location is None:
|
||||
current_app.logger.debug(
|
||||
f"Location missing from data store specification '{identifier}' in file @ '{file}'"
|
||||
)
|
||||
continue
|
||||
|
||||
all_data_store_specifications[(data_store_type, location, identifier)] = specification
|
||||
|
||||
current_app.logger.debug("DataSetupService.save_all_process_models() end")
|
||||
|
||||
ReferenceCacheService.add_new_generation(reference_objects)
|
||||
cls._sync_data_store_models_with_specifications(all_data_store_specifications)
|
||||
MessageDefinitionService.delete_all_message_models()
|
||||
db.session.commit()
|
||||
MessageDefinitionService.save_all_message_models(all_message_models)
|
||||
db.session.commit()
|
||||
|
||||
for ref in references:
|
||||
try:
|
||||
|
@ -118,6 +111,25 @@ class DataSetupService:
|
|||
|
||||
return failing_process_models
|
||||
|
||||
@classmethod
|
||||
def _collect_data_store_specifications(
|
||||
cls, process_group: ProcessGroup, file_name: str, all_data_store_specifications: dict[tuple[str, str, str], Any]
|
||||
) -> None:
|
||||
for data_store_type, specs_by_id in process_group.data_store_specifications.items():
|
||||
if not isinstance(specs_by_id, dict):
|
||||
current_app.logger.debug(f"Expected dictionary as value for key '{data_store_type}' in file @ '{file_name}'")
|
||||
continue
|
||||
|
||||
for identifier, specification in specs_by_id.items():
|
||||
location = specification.get("location")
|
||||
if location is None:
|
||||
current_app.logger.debug(
|
||||
f"Location missing from data store specification '{identifier}' in file @ '{file_name}'"
|
||||
)
|
||||
continue
|
||||
|
||||
all_data_store_specifications[(data_store_type, location, identifier)] = specification
|
||||
|
||||
@classmethod
|
||||
def _sync_data_store_models_with_specifications(cls, all_data_store_specifications: dict[tuple[str, str, str], Any]) -> None:
|
||||
all_data_store_models: dict[tuple[str, str, str], Any] = {}
|
||||
|
@ -208,5 +220,3 @@ class DataSetupService:
|
|||
current_app.logger.debug(f"DataSetupService: was expecting key '{key}' to point to a data store model to delete.")
|
||||
continue
|
||||
db.session.delete(model)
|
||||
|
||||
db.session.commit()
|
||||
|
|
|
@ -0,0 +1,74 @@
|
|||
from typing import Any
|
||||
|
||||
from flask import current_app
|
||||
|
||||
from spiffworkflow_backend.models.db import db
|
||||
from spiffworkflow_backend.models.message_model import MessageCorrelationPropertyModel
|
||||
from spiffworkflow_backend.models.message_model import MessageModel
|
||||
from spiffworkflow_backend.models.process_group import ProcessGroup
|
||||
|
||||
|
||||
class MessageDefinitionService:
|
||||
@classmethod
|
||||
def _message_model_from_message(
|
||||
cls, identifier: str, message_definition: dict[str, Any], process_group: ProcessGroup
|
||||
) -> MessageModel | None:
|
||||
schema = message_definition.get("schema", "{}")
|
||||
|
||||
return MessageModel(identifier=identifier, location=process_group.id, schema=schema)
|
||||
|
||||
@classmethod
|
||||
def _correlation_property_models_from_message_definition(
|
||||
cls, correlation_property_group: dict[str, Any], location: str
|
||||
) -> list[MessageCorrelationPropertyModel]:
|
||||
models: list[MessageCorrelationPropertyModel] = []
|
||||
|
||||
for identifier, definition in correlation_property_group.items():
|
||||
retrieval_expressions = definition.get("retrieval_expressions")
|
||||
|
||||
if not retrieval_expressions:
|
||||
current_app.logger.debug(f"Malformed correlation property: '{identifier}' in file @ '{location}'")
|
||||
continue
|
||||
|
||||
for retrieval_expression in retrieval_expressions:
|
||||
models.append(MessageCorrelationPropertyModel(identifier=identifier, retrieval_expression=retrieval_expression))
|
||||
|
||||
return models
|
||||
|
||||
@classmethod
|
||||
def collect_message_models(
|
||||
cls, process_group: ProcessGroup, location: str, all_message_models: dict[tuple[str, str], MessageModel]
|
||||
) -> None:
|
||||
messages: dict[str, Any] = process_group.messages or {}
|
||||
|
||||
for message_identifier, message_definition in messages.items():
|
||||
message_model = cls._message_model_from_message(message_identifier, message_definition, process_group)
|
||||
if message_model is None:
|
||||
continue
|
||||
all_message_models[(message_model.identifier, message_model.location)] = message_model
|
||||
|
||||
correlation_property_models = cls._correlation_property_models_from_message_definition(
|
||||
message_definition.get("correlation_properties", {}), location
|
||||
)
|
||||
|
||||
message_model.correlation_properties = correlation_property_models # type: ignore
|
||||
|
||||
@classmethod
|
||||
def delete_all_message_models(cls) -> None:
|
||||
messages = MessageModel.query.all()
|
||||
for message in messages:
|
||||
db.session.delete(message)
|
||||
|
||||
@classmethod
|
||||
def delete_message_models_at_location(cls, location: str) -> None:
|
||||
messages = MessageModel.query.filter_by(location=location).all()
|
||||
for message in messages:
|
||||
db.session.delete(message)
|
||||
|
||||
@classmethod
|
||||
def save_all_message_models(cls, all_message_models: dict[tuple[str, str], MessageModel]) -> None:
|
||||
for message_model in all_message_models.values():
|
||||
db.session.add(message_model)
|
||||
|
||||
for correlation_property_model in message_model.correlation_properties:
|
||||
db.session.add(correlation_property_model)
|
|
@ -9,7 +9,6 @@ from lxml import etree # type: ignore
|
|||
from SpiffWorkflow.bpmn.parser.BpmnParser import BpmnValidator # type: ignore
|
||||
|
||||
from spiffworkflow_backend.exceptions.error import NotAuthorizedError
|
||||
from spiffworkflow_backend.models.correlation_property_cache import CorrelationPropertyCache
|
||||
from spiffworkflow_backend.models.db import db
|
||||
from spiffworkflow_backend.models.file import File
|
||||
from spiffworkflow_backend.models.file import FileType
|
||||
|
@ -255,7 +254,6 @@ class SpecFileService(FileSystemService):
|
|||
def update_caches_except_process(ref: Reference) -> None:
|
||||
SpecFileService.update_process_caller_cache(ref)
|
||||
SpecFileService.update_message_trigger_cache(ref)
|
||||
SpecFileService.update_correlation_cache(ref)
|
||||
|
||||
@staticmethod
|
||||
def clear_caches_for_item(
|
||||
|
@ -336,28 +334,3 @@ class SpecFileService(FileSystemService):
|
|||
current_triggerable_processes.remove(message_triggerable_process_model)
|
||||
for trigger_pm in current_triggerable_processes:
|
||||
db.session.delete(trigger_pm)
|
||||
|
||||
@staticmethod
|
||||
def update_correlation_cache(ref: Reference) -> None:
|
||||
for name in ref.correlations.keys():
|
||||
correlation_property_retrieval_expressions = ref.correlations[name]["retrieval_expressions"]
|
||||
|
||||
for cpre in correlation_property_retrieval_expressions:
|
||||
message_name = ref.messages.get(cpre["messageRef"], None)
|
||||
retrieval_expression = cpre["expression"]
|
||||
process_model_id = ref.relative_location
|
||||
|
||||
existing = CorrelationPropertyCache.query.filter_by(
|
||||
name=name,
|
||||
message_name=message_name,
|
||||
process_model_id=process_model_id,
|
||||
retrieval_expression=retrieval_expression,
|
||||
).first()
|
||||
if existing is None:
|
||||
new_cache = CorrelationPropertyCache(
|
||||
name=name,
|
||||
message_name=message_name,
|
||||
process_model_id=process_model_id,
|
||||
retrieval_expression=retrieval_expression,
|
||||
)
|
||||
db.session.add(new_cache)
|
||||
|
|
|
@ -2,9 +2,6 @@
|
|||
<bpmn:definitions xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:spiffworkflow="http://spiffworkflow.org/bpmn/schema/1.0/core" id="Definitions_96f6665" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="3.0.0-dev">
|
||||
<bpmn:collaboration id="Collaboration_0oye1os">
|
||||
<bpmn:participant id="message_receiver" name="Message Receiver (invoice approver)" processRef="message_receiver_process" />
|
||||
<bpmn:participant id="message_sender" name="Message Sender" />
|
||||
<bpmn:messageFlow id="message_send_flow" name="Message Send Flow" sourceRef="message_sender" targetRef="receive_message" />
|
||||
<bpmn:messageFlow id="Flow_0ds946g" sourceRef="send_message_response" targetRef="message_sender" />
|
||||
<bpmn:correlationKey name="invoice">
|
||||
<bpmn:correlationPropertyRef>customer_id</bpmn:correlationPropertyRef>
|
||||
<bpmn:correlationPropertyRef>po_number</bpmn:correlationPropertyRef>
|
||||
|
|
|
@ -2,15 +2,6 @@
|
|||
<bpmn:definitions xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:spiffworkflow="http://spiffworkflow.org/bpmn/schema/1.0/core" id="Definitions_96f6665" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="3.0.0-dev">
|
||||
<bpmn:collaboration id="Collaboration_0oye1os">
|
||||
<bpmn:participant id="message_initiator" name="Message Initiator" processRef="message_send_process" />
|
||||
<bpmn:participant id="message-receiver" name="Message Receiver" />
|
||||
<bpmn:messageFlow id="message_send_flow" name="Message Send Flow" sourceRef="send_message" targetRef="message-receiver" />
|
||||
<bpmn:messageFlow id="message_response_flow" name="Message Response Flow" sourceRef="message-receiver" targetRef="receive_message_response" />
|
||||
<bpmn:textAnnotation id="TextAnnotation_0oxbpew">
|
||||
<bpmn:text>The messages sent here are about an Invoice that can be uniquely identified by the customer_id ("sartography") and a purchase order number (1001)
|
||||
|
||||
It will fire a message connected to the invoice keys above, starting another process, which can communicate back to this specific process instance using the correct key.</bpmn:text>
|
||||
</bpmn:textAnnotation>
|
||||
<bpmn:association id="Association_1d6q7zd" sourceRef="message_initiator" targetRef="TextAnnotation_0oxbpew" />
|
||||
<bpmn:correlationKey name="invoice">
|
||||
<bpmn:correlationPropertyRef>po_number</bpmn:correlationPropertyRef>
|
||||
<bpmn:correlationPropertyRef>customer_id</bpmn:correlationPropertyRef>
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
# Creating Content
|
||||
This section will explain how we combine **Markdown** and **Jinja** to make it easy to display content to participants in a workflow.
|
|
@ -0,0 +1,41 @@
|
|||
{
|
||||
"title": "A Simple Form",
|
||||
"description": "Provide a little information, and we will display it back to you in a second",
|
||||
"properties": {
|
||||
"first_name": {
|
||||
"type": "string",
|
||||
"title": "First Name"
|
||||
},
|
||||
"is_joke": {
|
||||
"type": "boolean",
|
||||
"title": "Would you like to hear a Chuck Norris joke?"
|
||||
},
|
||||
"color": {
|
||||
"type": "string",
|
||||
"title": "What is your favorite color?",
|
||||
"enum": [
|
||||
"Midnight Blue",
|
||||
"Crimson Red",
|
||||
"Emerald Green",
|
||||
"Sunflower Yellow",
|
||||
"Mauve Mist",
|
||||
"Mint Ice",
|
||||
"Burnt Sienna",
|
||||
"Powder Pink",
|
||||
"Royal Purple",
|
||||
"Peach Fuzz",
|
||||
"Goldenrod",
|
||||
"Turquoise Splash",
|
||||
"Tangerine Tango",
|
||||
"Cerulean Sky",
|
||||
"Sagebrush Green",
|
||||
"Lavender Blush",
|
||||
"Cocoa Bean Brown",
|
||||
"Teal Lagoon",
|
||||
"Electric Indigo",
|
||||
"Antique Brass"
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["first_name","is_joke","color"]
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"is_joke": {
|
||||
"ui:widget": "radio",
|
||||
"ui:options": {
|
||||
"inline": true
|
||||
}
|
||||
},
|
||||
"ui:order": [
|
||||
"first_name",
|
||||
"is_joke",
|
||||
"color"
|
||||
]
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"description": "This process demonstrates how you can display content to the user.",
|
||||
"display_name": "Displaying Content",
|
||||
"exception_notification_addresses": [],
|
||||
"fault_or_suspend_on_exception": "fault",
|
||||
"metadata_extraction_paths": null,
|
||||
"primary_file_name": "show-content.bpmn",
|
||||
"primary_process_id": "Process_puxk39c"
|
||||
}
|
|
@ -0,0 +1,220 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<bpmn:definitions xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:spiffworkflow="http://spiffworkflow.org/bpmn/schema/1.0/core" id="Definitions_96f6665" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="3.0.0-dev">
|
||||
<bpmn:process id="Process_puxk39c" isExecutable="true">
|
||||
<bpmn:startEvent id="StartEvent_1">
|
||||
<bpmn:outgoing>Flow_1wvtd9f</bpmn:outgoing>
|
||||
</bpmn:startEvent>
|
||||
<bpmn:sequenceFlow id="Flow_1wvtd9f" sourceRef="StartEvent_1" targetRef="Activity_1f9v5wa" />
|
||||
<bpmn:endEvent id="Event_1wckt3w">
|
||||
<bpmn:extensionElements>
|
||||
<spiffworkflow:instructionsForEndUser>### Checkout the BPMN!
|
||||
|
||||
Open up this diagram in edit mode where you can move things around and view task properties, but you won't be able to save these demos. To do this, click on "Displaying Content" in the Breadcrumbs above, then open the file "show-content.bpmn". Click on the manual tasks and will see they each have content in their "Instructions" in the properties panel on the right. You can open these instructions in the markdown editor by clicking on the "Launch Editor" button which provides a great way to see how Markdown and Jinja can be used to create content.
|
||||
|
||||
### Build a BPMN process yourself!
|
||||
Complete the [Request a Playground](/process-models/examples:0-4-request-permissions) task to get access to your own private area of this Demo SpiffWorkflow instance. There you can build your own documentation!
|
||||
|
||||
### Get Involved!
|
||||
Please get in touch with us! We would love to help you build beautiful documentation into your workflows. There is no end to what we can accomplish if we work together. Please reach out to Dan at [dan@sartography.com](mailto:dan@sartography.com) to get started.
|
||||
|
||||
### What's Next?
|
||||
Check out the some of the other [basic examples](/process-groups/examples:1-basic-concepts) to learn more.
|
||||
|
||||
</spiffworkflow:instructionsForEndUser>
|
||||
</bpmn:extensionElements>
|
||||
<bpmn:incoming>Flow_1thoqro</bpmn:incoming>
|
||||
</bpmn:endEvent>
|
||||
<bpmn:sequenceFlow id="Flow_0r9coud" sourceRef="Activity_1f9v5wa" targetRef="Activity_1r4u2ny" />
|
||||
<bpmn:manualTask id="Activity_1f9v5wa" name="Introduction">
|
||||
<bpmn:extensionElements>
|
||||
<spiffworkflow:instructionsForEndUser>We use two open standards for displaying content.
|
||||
|
||||
### 1. Markdown
|
||||
Markdown provides some minimal tools for formatting text. It can handle basic formatting from **bold text** to headings, tables, lists, etc... It is not the most expressive possible way of writing content, but it does help standardize your documentation and assure it can be easily updated by anyone else. The [Markdown Guilde](https://www.markdownguide.org/getting-started/) provides excellent information on the standard, how to use it, and why it is useful.
|
||||
|
||||
### 2. Jinja
|
||||
As a workflow process runs, it collects information from many sources. User Tasks collect information from Web Forms, Service Tasks can pull information from other applications - these are just two examples of many. This data is collected and can be used in later tasks in the process. One way to use the information is to display it, which is where Jinja comes into play. While there is a lot that can be done in Jinja, you can go a very long way knowing one simple rule:
|
||||
|
||||
> Wrap variables you want to display in double curly brackets like this \{\{my_variable\}\}
|
||||
|
||||
This will allow you to take any information you have available and present it back to the end user. You can learn more about the Jinja syntax in the [official documentation](https://jinja.palletsprojects.com/en/3.1.x/templates/). It isn't just variable replacement. You can use it to hide information under certain circumstances, or display lots of data in a list or table. It is very powerful.
|
||||
|
||||
## Whats Next:
|
||||
Let's complete a simple form so you can enter some information. We'll also run a script in the background that will generate some additional variables. We'll take this data, and present it in another manual task.</spiffworkflow:instructionsForEndUser>
|
||||
</bpmn:extensionElements>
|
||||
<bpmn:incoming>Flow_1wvtd9f</bpmn:incoming>
|
||||
<bpmn:outgoing>Flow_0r9coud</bpmn:outgoing>
|
||||
</bpmn:manualTask>
|
||||
<bpmn:sequenceFlow id="Flow_0796xeb" sourceRef="Activity_1r4u2ny" targetRef="Activity_0pdnphi" />
|
||||
<bpmn:userTask id="Activity_1r4u2ny" name="A Simple Form">
|
||||
<bpmn:extensionElements>
|
||||
<spiffworkflow:instructionsForEndUser>Please complete the simple form below. We'll show you these values in the next manual task.</spiffworkflow:instructionsForEndUser>
|
||||
<spiffworkflow:properties>
|
||||
<spiffworkflow:property name="formJsonSchemaFilename" value="a-simple-form-schema.json" />
|
||||
<spiffworkflow:property name="formUiSchemaFilename" value="a-simple-form-uischema.json" />
|
||||
</spiffworkflow:properties>
|
||||
</bpmn:extensionElements>
|
||||
<bpmn:incoming>Flow_0r9coud</bpmn:incoming>
|
||||
<bpmn:outgoing>Flow_0796xeb</bpmn:outgoing>
|
||||
</bpmn:userTask>
|
||||
<bpmn:sequenceFlow id="Flow_0wr8gfr" sourceRef="Activity_0pdnphi" targetRef="Activity_0l7raxy" />
|
||||
<bpmn:sequenceFlow id="Flow_1thoqro" sourceRef="Activity_1jr7x9o" targetRef="Event_1wckt3w" />
|
||||
<bpmn:scriptTask id="Activity_0pdnphi" name="Create more content">
|
||||
<bpmn:extensionElements>
|
||||
<spiffworkflow:instructionsForEndUser>Generating some colors for you, give us just a second ....</spiffworkflow:instructionsForEndUser>
|
||||
</bpmn:extensionElements>
|
||||
<bpmn:incoming>Flow_0796xeb</bpmn:incoming>
|
||||
<bpmn:outgoing>Flow_0wr8gfr</bpmn:outgoing>
|
||||
<bpmn:script>time.sleep(3)
|
||||
colors = {
|
||||
"Ninja Black": "#1E1E1E",
|
||||
"Zombie Green": "#6ACD58",
|
||||
"Toasted Marshmallow": "#F9E5C6",
|
||||
"Alien Armpit": "#84D314",
|
||||
"Granny Smith Apple Accident": "#A8E4A0",
|
||||
"Teleportation Blue": "#7FDBFF",
|
||||
"Invisible Pink Unicorn": "#FF77A9",
|
||||
"Flamingo Fandango": "#F6A8D6",
|
||||
"Laser Lemon": "#FFFF66",
|
||||
"Yeti Frostbite": "#D5F2E3"
|
||||
}</bpmn:script>
|
||||
</bpmn:scriptTask>
|
||||
<bpmn:manualTask id="Activity_1jr7x9o" name="Displaying Data">
|
||||
<bpmn:extensionElements>
|
||||
<spiffworkflow:instructionsForEndUser>We just did two things:
|
||||
|
||||
1. Completed a form, which allowed us to collect some information from you.
|
||||
2. We ran a script, that created a list of colors for us to display.
|
||||
|
||||
Now we can present that information back to you using Markdown and Jinja .....
|
||||
|
||||
### Form Data
|
||||
You provided the following information the form:
|
||||
|
||||
**Your Name**: {{first_name}}
|
||||
|
||||
**Favorite Color**: {{color}}
|
||||
|
||||
{% if is_joke %}
|
||||
You said you would like to hear a joke about Chuck Norris, so here you go:
|
||||
|
||||
> When Chuck Norris falls into the water, Chuck Norris doesn’t get wet. Water gets Chuck Norris.
|
||||
|
||||
{% else %}
|
||||
You said you didn't want to year a joke about Chuck Norris, so here is a joke that does not include old Chuck.
|
||||
|
||||
> What is an astronaut's favorite part on a computer? The space bar.
|
||||
{% endif %}
|
||||
|
||||
### Automatic Task Messages
|
||||
We also created a list of silly color names in a script task. You should have seen that flash by as it was happening. We intentionally made it slow (we ask Python to sleep for 2 seconds), so you could see that even automatic tasks (if they take a long time) can be configured to display a message as they run in the background. Here is the list of colors we created rendered as a table :
|
||||
|
||||
| Color Name | Color Hex Value | Color |
|
||||
|----------|-----------|-----|
|
||||
| Blue | #0000ff | <div style="background-color:blue; color:blue"> blue </div> |
|
||||
{%- for name, hex in colors.items() %}
|
||||
|
||||
| {{name}} | {{hex}} | <div style="background-color:{{hex}}; color:{{hex}}"> {{name}} </div> |
|
||||
{%- endfor %}
|
||||
|
||||
|
||||
|
||||
</spiffworkflow:instructionsForEndUser>
|
||||
</bpmn:extensionElements>
|
||||
<bpmn:incoming>Flow_0fdwa26</bpmn:incoming>
|
||||
<bpmn:outgoing>Flow_1thoqro</bpmn:outgoing>
|
||||
</bpmn:manualTask>
|
||||
<bpmn:sequenceFlow id="Flow_1rgip89" sourceRef="Activity_0l7raxy" targetRef="Activity_0jfo38l" />
|
||||
<bpmn:sequenceFlow id="Flow_0fdwa26" sourceRef="Activity_0jfo38l" targetRef="Activity_1jr7x9o" />
|
||||
<bpmn:scriptTask id="Activity_0l7raxy" name="More processing">
|
||||
<bpmn:extensionElements>
|
||||
<spiffworkflow:instructionsForEndUser>Making the colors more silly ...</spiffworkflow:instructionsForEndUser>
|
||||
</bpmn:extensionElements>
|
||||
<bpmn:incoming>Flow_0wr8gfr</bpmn:incoming>
|
||||
<bpmn:outgoing>Flow_1rgip89</bpmn:outgoing>
|
||||
<bpmn:script>time.sleep(1)</bpmn:script>
|
||||
</bpmn:scriptTask>
|
||||
<bpmn:scriptTask id="Activity_0jfo38l" name="Even More Processing">
|
||||
<bpmn:extensionElements>
|
||||
<spiffworkflow:instructionsForEndUser>Turning the silly level all the way up to 11, almost done ....</spiffworkflow:instructionsForEndUser>
|
||||
</bpmn:extensionElements>
|
||||
<bpmn:incoming>Flow_1rgip89</bpmn:incoming>
|
||||
<bpmn:outgoing>Flow_0fdwa26</bpmn:outgoing>
|
||||
<bpmn:script>time.sleep(2)</bpmn:script>
|
||||
</bpmn:scriptTask>
|
||||
<bpmn:textAnnotation id="TextAnnotation_05wkdje">
|
||||
<bpmn:text>These three script tasks would execute nearly instantly, we are forcing them to run slowly (asking python to go to sleep for a few seconds) to demonstrate long running background tasks, so you can see how to let your end users know what is going on when you are doing complex things in the background.</bpmn:text>
|
||||
</bpmn:textAnnotation>
|
||||
<bpmn:association id="Association_1cnnzc4" sourceRef="Activity_0l7raxy" targetRef="TextAnnotation_05wkdje" />
|
||||
</bpmn:process>
|
||||
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
|
||||
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_puxk39c">
|
||||
<bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent_1">
|
||||
<dc:Bounds x="-38" y="159" width="36" height="36" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="Event_1wckt3w_di" bpmnElement="Event_1wckt3w">
|
||||
<dc:Bounds x="932" y="159" width="36" height="36" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="Activity_0rez9jv_di" bpmnElement="Activity_1f9v5wa">
|
||||
<dc:Bounds x="50" y="137" width="100" height="80" />
|
||||
<bpmndi:BPMNLabel />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="Activity_0i1lx1p_di" bpmnElement="Activity_1r4u2ny">
|
||||
<dc:Bounds x="200" y="137" width="100" height="80" />
|
||||
<bpmndi:BPMNLabel />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="Activity_0atremz_di" bpmnElement="Activity_0pdnphi">
|
||||
<dc:Bounds x="360" y="137" width="100" height="80" />
|
||||
<bpmndi:BPMNLabel />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="Activity_0q99tkd_di" bpmnElement="Activity_1jr7x9o">
|
||||
<dc:Bounds x="800" y="137" width="100" height="80" />
|
||||
<bpmndi:BPMNLabel />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="Activity_0e1jkdk_di" bpmnElement="Activity_0l7raxy">
|
||||
<dc:Bounds x="500" y="137" width="100" height="80" />
|
||||
<bpmndi:BPMNLabel />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="Activity_072c998_di" bpmnElement="Activity_0jfo38l">
|
||||
<dc:Bounds x="650" y="137" width="100" height="80" />
|
||||
<bpmndi:BPMNLabel />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="TextAnnotation_05wkdje_di" bpmnElement="TextAnnotation_05wkdje">
|
||||
<dc:Bounds x="420" y="0" width="320" height="98" />
|
||||
<bpmndi:BPMNLabel />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNEdge id="Flow_1wvtd9f_di" bpmnElement="Flow_1wvtd9f">
|
||||
<di:waypoint x="-2" y="177" />
|
||||
<di:waypoint x="50" y="177" />
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge id="Flow_0r9coud_di" bpmnElement="Flow_0r9coud">
|
||||
<di:waypoint x="150" y="177" />
|
||||
<di:waypoint x="200" y="177" />
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge id="Flow_0796xeb_di" bpmnElement="Flow_0796xeb">
|
||||
<di:waypoint x="300" y="177" />
|
||||
<di:waypoint x="360" y="177" />
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge id="Flow_0wr8gfr_di" bpmnElement="Flow_0wr8gfr">
|
||||
<di:waypoint x="460" y="177" />
|
||||
<di:waypoint x="500" y="177" />
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge id="Flow_1thoqro_di" bpmnElement="Flow_1thoqro">
|
||||
<di:waypoint x="900" y="177" />
|
||||
<di:waypoint x="932" y="177" />
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge id="Flow_1rgip89_di" bpmnElement="Flow_1rgip89">
|
||||
<di:waypoint x="600" y="177" />
|
||||
<di:waypoint x="650" y="177" />
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge id="Flow_0fdwa26_di" bpmnElement="Flow_0fdwa26">
|
||||
<di:waypoint x="750" y="177" />
|
||||
<di:waypoint x="800" y="177" />
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge id="Association_1cnnzc4_di" bpmnElement="Association_1cnnzc4">
|
||||
<di:waypoint x="530" y="137" />
|
||||
<di:waypoint x="511" y="98" />
|
||||
</bpmndi:BPMNEdge>
|
||||
</bpmndi:BPMNPlane>
|
||||
</bpmndi:BPMNDiagram>
|
||||
</bpmn:definitions>
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"description": "These process models are the basic building blocks of our system. Understand these individually, then put them together anyway you can imagine.",
|
||||
"display_name": "1. Basics",
|
||||
"messages": {"basic_message": { "schema": {} } }
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
{
|
||||
"admin": false,
|
||||
"description": "These examples are provided to help you understand how SpiffWorkflow functions.",
|
||||
"display_name": "Examples",
|
||||
"display_order": 40,
|
||||
"parent_groups": null,
|
||||
|
||||
|
||||
"messages": {
|
||||
"table_seated": {
|
||||
"correlation_properties": {
|
||||
"table_number": {
|
||||
"retrieval_expressions": ["table_number"]
|
||||
},
|
||||
"franchise_id": {
|
||||
"retrieval_expressions": ["franchise_id"]
|
||||
}
|
||||
},
|
||||
"schema": {}
|
||||
},
|
||||
"order_ready": {
|
||||
"correlation_properties": {
|
||||
"table_number": {
|
||||
"retrieval_expressions": ["table_number"]
|
||||
},
|
||||
"franchise_id": {
|
||||
"retrieval_expressions": ["franchise_id"]
|
||||
}
|
||||
},
|
||||
"schema": {}
|
||||
},
|
||||
"end_of_day_receipts": {
|
||||
"schema": {}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
import io
|
||||
import json
|
||||
import os
|
||||
import shutil
|
||||
import time
|
||||
from collections.abc import Generator
|
||||
from contextlib import contextmanager
|
||||
|
@ -578,6 +579,12 @@ class BaseTest:
|
|||
finally:
|
||||
app.config[config_identifier] = initial_value
|
||||
|
||||
@staticmethod
|
||||
def copy_example_process_models() -> None:
|
||||
source = os.path.abspath(os.path.join(FileSystemService.root_path(), "..", "..", "..", "process_models_example_dir"))
|
||||
destination = current_app.config["SPIFFWORKFLOW_BACKEND_BPMN_SPEC_ABSOLUTE_DIR"]
|
||||
shutil.copytree(source, destination)
|
||||
|
||||
def round_last_state_change(self, bpmn_process_dict: dict | list) -> None:
|
||||
"""Round last state change to the nearest 4 significant digits.
|
||||
|
||||
|
|
|
@ -1,10 +1,14 @@
|
|||
import json
|
||||
|
||||
import pytest
|
||||
from flask import Flask
|
||||
from flask import g
|
||||
from flask.testing import FlaskClient
|
||||
from spiffworkflow_backend.exceptions.api_error import ApiError
|
||||
from spiffworkflow_backend.models.message_instance import MessageInstanceModel
|
||||
from spiffworkflow_backend.models.user import UserModel
|
||||
from spiffworkflow_backend.routes.messages_controller import message_send
|
||||
from spiffworkflow_backend.services.data_setup_service import DataSetupService
|
||||
|
||||
from tests.spiffworkflow_backend.helpers.base_test import BaseTest
|
||||
|
||||
|
@ -66,3 +70,118 @@ class TestMessages(BaseTest):
|
|||
assert len(waiting_messages) == 0
|
||||
# The process has completed
|
||||
assert process_instance.status == "complete"
|
||||
|
||||
def test_message_model_list_up_search(
|
||||
self,
|
||||
app: Flask,
|
||||
client: FlaskClient,
|
||||
with_db_and_bpmn_file_cleanup: None,
|
||||
with_super_admin_user: UserModel,
|
||||
) -> None:
|
||||
self.copy_example_process_models()
|
||||
DataSetupService.save_all_process_models()
|
||||
response = client.get(
|
||||
"/v1.0/message-models/examples:1-basic-concepts",
|
||||
headers=self.logged_in_headers(with_super_admin_user),
|
||||
content_type="application/json",
|
||||
)
|
||||
assert response.status_code == 200
|
||||
assert response.json is not None
|
||||
assert len(response.json["messages"]) == 4
|
||||
|
||||
response = client.get(
|
||||
"/v1.0/message-models",
|
||||
headers=self.logged_in_headers(with_super_admin_user),
|
||||
content_type="application/json",
|
||||
)
|
||||
assert response.status_code == 200
|
||||
assert response.json is not None
|
||||
assert len(response.json["messages"]) == 0, "should not have access to messages defined in a sub directory"
|
||||
|
||||
def test_process_group_update_syncs_message_models(
|
||||
self,
|
||||
app: Flask,
|
||||
client: FlaskClient,
|
||||
with_db_and_bpmn_file_cleanup: None,
|
||||
with_super_admin_user: UserModel,
|
||||
) -> None:
|
||||
self.create_process_group("bob")
|
||||
|
||||
response = client.get(
|
||||
"/v1.0/message-models/bob",
|
||||
headers=self.logged_in_headers(with_super_admin_user),
|
||||
content_type="application/json",
|
||||
)
|
||||
assert response.status_code == 200
|
||||
assert response.json is not None
|
||||
assert len(response.json["messages"]) == 0
|
||||
|
||||
process_group = {
|
||||
"admin": False,
|
||||
"description": "Bob's Group",
|
||||
"display_name": "Bob",
|
||||
"display_order": 40,
|
||||
"parent_groups": None,
|
||||
"messages": {
|
||||
"table_seated": {
|
||||
"correlation_properties": {
|
||||
"table_number": {
|
||||
"retrieval_expressions": ["table_number"],
|
||||
},
|
||||
"franchise_id": {
|
||||
"retrieval_expressions": ["franchise_id"],
|
||||
},
|
||||
},
|
||||
"schema": {},
|
||||
},
|
||||
"order_ready": {
|
||||
"correlation_properties": {
|
||||
"table_number": {
|
||||
"retrieval_expressions": ["table_number"],
|
||||
},
|
||||
"franchise_id": {
|
||||
"retrieval_expressions": ["franchise_id"],
|
||||
},
|
||||
},
|
||||
"schema": {},
|
||||
},
|
||||
"end_of_day_receipts": {
|
||||
"schema": {},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
response = client.put(
|
||||
"/v1.0/process-groups/bob",
|
||||
headers=self.logged_in_headers(with_super_admin_user),
|
||||
content_type="application/json",
|
||||
data=json.dumps(process_group),
|
||||
)
|
||||
assert response.status_code == 200
|
||||
|
||||
response = client.get(
|
||||
"/v1.0/message-models/bob",
|
||||
headers=self.logged_in_headers(with_super_admin_user),
|
||||
content_type="application/json",
|
||||
)
|
||||
assert response.status_code == 200
|
||||
assert response.json is not None
|
||||
assert "messages" in response.json
|
||||
|
||||
messages = response.json["messages"]
|
||||
expected_message_identifiers = {"table_seated", "order_ready", "end_of_day_receipts"}
|
||||
assert len(messages) == len(expected_message_identifiers)
|
||||
|
||||
expected_correlation_properties = {
|
||||
"table_seated": {"table_number": "table_number", "franchise_id": "franchise_id"},
|
||||
"order_ready": {"table_number": "table_number", "franchise_id": "franchise_id"},
|
||||
"end_of_day_receipts": {},
|
||||
}
|
||||
|
||||
for message in messages:
|
||||
assert message["identifier"] in expected_message_identifiers
|
||||
assert message["location"] == "bob"
|
||||
assert message["schema"] == {}
|
||||
|
||||
cp = {p["identifier"]: p["retrieval_expression"] for p in message["correlation_properties"]}
|
||||
assert cp == expected_correlation_properties[message["identifier"]]
|
||||
|
|
|
@ -98,6 +98,7 @@ class TestAuthorizationService(BaseTest):
|
|||
("/event-error-details/some-process-group:some-process-model:*", "read"),
|
||||
("/logs/some-process-group:some-process-model:*", "read"),
|
||||
("/logs/typeahead-filter-values/some-process-group:some-process-model:*", "read"),
|
||||
("/message-models/some-process-group:some-process-model:*", "read"),
|
||||
("/process-data/some-process-group:some-process-model:*", "read"),
|
||||
(
|
||||
"/process-data-file-download/some-process-group:some-process-model:*",
|
||||
|
@ -189,6 +190,7 @@ class TestAuthorizationService(BaseTest):
|
|||
"read",
|
||||
),
|
||||
("/logs/typeahead-filter-values/some-process-group:some-process-model/*", "read"),
|
||||
("/message-models/some-process-group:some-process-model/*", "read"),
|
||||
("/process-data/some-process-group:some-process-model/*", "read"),
|
||||
(
|
||||
"/process-instance-suspend/some-process-group:some-process-model/*",
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
from flask.app import Flask
|
||||
from flask.testing import FlaskClient
|
||||
from spiffworkflow_backend.models.message_model import MessageModel
|
||||
from spiffworkflow_backend.models.reference_cache import ReferenceCacheModel
|
||||
from spiffworkflow_backend.services.data_setup_service import DataSetupService
|
||||
|
||||
from tests.spiffworkflow_backend.helpers.base_test import BaseTest
|
||||
|
||||
|
||||
class TestDataSetupService(BaseTest):
|
||||
def test_data_setup_service_finds_models(
|
||||
self,
|
||||
app: Flask,
|
||||
client: FlaskClient,
|
||||
with_db_and_bpmn_file_cleanup: None,
|
||||
) -> None:
|
||||
self.copy_example_process_models()
|
||||
DataSetupService.save_all_process_models()
|
||||
cache = ReferenceCacheModel.query.filter(ReferenceCacheModel.type == "process").all()
|
||||
assert len(cache) == 1
|
||||
|
||||
def test_data_setup_service_finds_messages(
|
||||
self,
|
||||
app: Flask,
|
||||
client: FlaskClient,
|
||||
with_db_and_bpmn_file_cleanup: None,
|
||||
) -> None:
|
||||
self.copy_example_process_models()
|
||||
DataSetupService.save_all_process_models()
|
||||
message_models = MessageModel.query.all()
|
||||
assert len(message_models) == 4
|
||||
message_map = {model.identifier: model for model in message_models}
|
||||
|
||||
assert "table_seated" in message_map
|
||||
assert "order_ready" in message_map
|
||||
assert "end_of_day_receipts" in message_map
|
||||
assert "basic_message" in message_map
|
||||
|
||||
assert message_map["order_ready"].location == "examples"
|
||||
|
||||
correlations = {cp.identifier: cp.retrieval_expression for cp in message_map["order_ready"].correlation_properties}
|
||||
assert correlations == {"table_number": "table_number", "franchise_id": "franchise_id"}
|
||||
|
||||
assert message_map["basic_message"].location == "examples/1-basic-concepts"
|
||||
assert message_map["basic_message"].correlation_properties == []
|
|
@ -98,6 +98,7 @@
|
|||
"eslint-plugin-unused-imports": "^3.2.0",
|
||||
"inherits-browser": "^0.0.1",
|
||||
"jsdom": "^24.0.0",
|
||||
"nice-select2": "^2.1.0",
|
||||
"prettier": "^3.3.0",
|
||||
"safe-regex": "^2.1.1",
|
||||
"tiny-svg": "^2.2.3",
|
||||
|
@ -7668,7 +7669,7 @@
|
|||
},
|
||||
"node_modules/bpmn-js-spiffworkflow": {
|
||||
"version": "0.0.8",
|
||||
"resolved": "git+ssh://git@github.com/sartography/bpmn-js-spiffworkflow.git#38f5b5d7563f24608e7b3b177547e273f7cc94a0",
|
||||
"resolved": "git+ssh://git@github.com/sartography/bpmn-js-spiffworkflow.git#ee86b31cd7fc6f42f92f56171a9945a8ff22773a",
|
||||
"license": "LGPL",
|
||||
"dependencies": {
|
||||
"inherits": "^2.0.4",
|
||||
|
@ -7676,6 +7677,7 @@
|
|||
"min-dash": "^3.8.1",
|
||||
"min-dom": "^3.2.1",
|
||||
"moddle": "^5.0.3",
|
||||
"nice-select2": "^2.1.0",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "18.2.0",
|
||||
"tiny-svg": "^2.2.3"
|
||||
|
@ -9129,6 +9131,23 @@
|
|||
"resolved": "https://registry.npmjs.org/crelt/-/crelt-1.0.5.tgz",
|
||||
"integrity": "sha512-+BO9wPPi+DWTDcNYhr/W90myha8ptzftZT+LwcmUbbok0rcP/fequmFYCw8NMoH7pkAZQzU78b3kYrlua5a9eA=="
|
||||
},
|
||||
"node_modules/cross-env": {
|
||||
"version": "7.0.3",
|
||||
"resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz",
|
||||
"integrity": "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==",
|
||||
"dependencies": {
|
||||
"cross-spawn": "^7.0.1"
|
||||
},
|
||||
"bin": {
|
||||
"cross-env": "src/bin/cross-env.js",
|
||||
"cross-env-shell": "src/bin/cross-env-shell.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.14",
|
||||
"npm": ">=6",
|
||||
"yarn": ">=1"
|
||||
}
|
||||
},
|
||||
"node_modules/cross-spawn": {
|
||||
"version": "7.0.3",
|
||||
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
|
||||
|
@ -9150,6 +9169,70 @@
|
|||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/css-loader": {
|
||||
"version": "6.11.0",
|
||||
"resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.11.0.tgz",
|
||||
"integrity": "sha512-CTJ+AEQJjq5NzLga5pE39qdiSV56F8ywCIsqNIRF0r7BDgWsN25aazToqAFg7ZrtA/U016xudB3ffgweORxX7g==",
|
||||
"dependencies": {
|
||||
"icss-utils": "^5.1.0",
|
||||
"postcss": "^8.4.33",
|
||||
"postcss-modules-extract-imports": "^3.1.0",
|
||||
"postcss-modules-local-by-default": "^4.0.5",
|
||||
"postcss-modules-scope": "^3.2.0",
|
||||
"postcss-modules-values": "^4.0.0",
|
||||
"postcss-value-parser": "^4.2.0",
|
||||
"semver": "^7.5.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 12.13.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/webpack"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@rspack/core": "0.x || 1.x",
|
||||
"webpack": "^5.0.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@rspack/core": {
|
||||
"optional": true
|
||||
},
|
||||
"webpack": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/css-loader/node_modules/lru-cache": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
|
||||
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
|
||||
"dependencies": {
|
||||
"yallist": "^4.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/css-loader/node_modules/semver": {
|
||||
"version": "7.6.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz",
|
||||
"integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==",
|
||||
"dependencies": {
|
||||
"lru-cache": "^6.0.0"
|
||||
},
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/css-loader/node_modules/yallist": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
||||
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
|
||||
},
|
||||
"node_modules/css-selector-parser": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/css-selector-parser/-/css-selector-parser-1.4.1.tgz",
|
||||
|
@ -9172,6 +9255,17 @@
|
|||
"resolved": "https://registry.npmjs.org/css.escape/-/css.escape-1.5.1.tgz",
|
||||
"integrity": "sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg=="
|
||||
},
|
||||
"node_modules/cssesc": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
|
||||
"integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==",
|
||||
"bin": {
|
||||
"cssesc": "bin/cssesc"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/cssstyle": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-4.0.1.tgz",
|
||||
|
@ -12045,8 +12139,7 @@
|
|||
"node_modules/fs.realpath": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
|
||||
"integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
|
||||
"devOptional": true
|
||||
"integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw=="
|
||||
},
|
||||
"node_modules/fsevents": {
|
||||
"version": "2.3.3",
|
||||
|
@ -12224,7 +12317,6 @@
|
|||
"version": "7.2.3",
|
||||
"resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
|
||||
"integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
|
||||
"devOptional": true,
|
||||
"dependencies": {
|
||||
"fs.realpath": "^1.0.0",
|
||||
"inflight": "^1.0.4",
|
||||
|
@ -12890,6 +12982,17 @@
|
|||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/icss-utils": {
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz",
|
||||
"integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==",
|
||||
"engines": {
|
||||
"node": "^10 || ^12 || >= 14"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"postcss": "^8.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/ids": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/ids/-/ids-1.0.5.tgz",
|
||||
|
@ -13027,7 +13130,6 @@
|
|||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
|
||||
"integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
|
||||
"devOptional": true,
|
||||
"dependencies": {
|
||||
"once": "^1.3.0",
|
||||
"wrappy": "1"
|
||||
|
@ -13071,6 +13173,14 @@
|
|||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/interpret": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz",
|
||||
"integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==",
|
||||
"engines": {
|
||||
"node": ">= 0.10"
|
||||
}
|
||||
},
|
||||
"node_modules/invariant": {
|
||||
"version": "2.2.4",
|
||||
"resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz",
|
||||
|
@ -19119,6 +19229,16 @@
|
|||
"integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/nice-select2": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/nice-select2/-/nice-select2-2.2.0.tgz",
|
||||
"integrity": "sha512-UVlqc/ReJPFnQhESbbJrFHCjVe74OWrewh/8w2A+zLlJ98BI4FVDVALV1tOfYCmhNcZtH4L1lQispCUIWX11nQ==",
|
||||
"dependencies": {
|
||||
"cross-env": "^7.0.3",
|
||||
"css-loader": "^6.7.3",
|
||||
"shx": "^0.3.4"
|
||||
}
|
||||
},
|
||||
"node_modules/node-dir": {
|
||||
"version": "0.1.17",
|
||||
"resolved": "https://registry.npmjs.org/node-dir/-/node-dir-0.1.17.tgz",
|
||||
|
@ -19810,7 +19930,6 @@
|
|||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
|
||||
"integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
|
||||
"devOptional": true,
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
|
@ -19975,6 +20094,73 @@
|
|||
"node": "^10 || ^12 || >=14"
|
||||
}
|
||||
},
|
||||
"node_modules/postcss-modules-extract-imports": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.1.0.tgz",
|
||||
"integrity": "sha512-k3kNe0aNFQDAZGbin48pL2VNidTF0w4/eASDsxlyspobzU3wZQLOGj7L9gfRe0Jo9/4uud09DsjFNH7winGv8Q==",
|
||||
"engines": {
|
||||
"node": "^10 || ^12 || >= 14"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"postcss": "^8.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/postcss-modules-local-by-default": {
|
||||
"version": "4.0.5",
|
||||
"resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.5.tgz",
|
||||
"integrity": "sha512-6MieY7sIfTK0hYfafw1OMEG+2bg8Q1ocHCpoWLqOKj3JXlKu4G7btkmM/B7lFubYkYWmRSPLZi5chid63ZaZYw==",
|
||||
"dependencies": {
|
||||
"icss-utils": "^5.0.0",
|
||||
"postcss-selector-parser": "^6.0.2",
|
||||
"postcss-value-parser": "^4.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^10 || ^12 || >= 14"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"postcss": "^8.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/postcss-modules-scope": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.2.0.tgz",
|
||||
"integrity": "sha512-oq+g1ssrsZOsx9M96c5w8laRmvEu9C3adDSjI8oTcbfkrTE8hx/zfyobUoWIxaKPO8bt6S62kxpw5GqypEw1QQ==",
|
||||
"dependencies": {
|
||||
"postcss-selector-parser": "^6.0.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^10 || ^12 || >= 14"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"postcss": "^8.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/postcss-modules-values": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz",
|
||||
"integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==",
|
||||
"dependencies": {
|
||||
"icss-utils": "^5.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^10 || ^12 || >= 14"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"postcss": "^8.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/postcss-selector-parser": {
|
||||
"version": "6.0.16",
|
||||
"resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.16.tgz",
|
||||
"integrity": "sha512-A0RVJrX+IUkVZbW3ClroRWurercFhieevHB38sr2+l9eUClMqome3LmEmnhlNy+5Mr2EYN6B2Kaw9wYdd+VHiw==",
|
||||
"dependencies": {
|
||||
"cssesc": "^3.0.0",
|
||||
"util-deprecate": "^1.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/postcss-value-parser": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz",
|
||||
|
@ -20657,6 +20843,17 @@
|
|||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/rechoir": {
|
||||
"version": "0.6.2",
|
||||
"resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz",
|
||||
"integrity": "sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==",
|
||||
"dependencies": {
|
||||
"resolve": "^1.1.6"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.10"
|
||||
}
|
||||
},
|
||||
"node_modules/redent": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz",
|
||||
|
@ -21683,6 +21880,22 @@
|
|||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/shelljs": {
|
||||
"version": "0.8.5",
|
||||
"resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.5.tgz",
|
||||
"integrity": "sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==",
|
||||
"dependencies": {
|
||||
"glob": "^7.0.0",
|
||||
"interpret": "^1.0.0",
|
||||
"rechoir": "^0.6.2"
|
||||
},
|
||||
"bin": {
|
||||
"shjs": "bin/shjs"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/shortid": {
|
||||
"version": "2.2.16",
|
||||
"resolved": "https://registry.npmjs.org/shortid/-/shortid-2.2.16.tgz",
|
||||
|
@ -21696,6 +21909,21 @@
|
|||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-2.1.11.tgz",
|
||||
"integrity": "sha512-s/snB+WGm6uwi0WjsZdaVcuf3KJXlfGl2LcxgwkEwJF0D/BWzVWAZW/XY4bFaiR7s0Jk3FPvlnepg1H1b1UwlA=="
|
||||
},
|
||||
"node_modules/shx": {
|
||||
"version": "0.3.4",
|
||||
"resolved": "https://registry.npmjs.org/shx/-/shx-0.3.4.tgz",
|
||||
"integrity": "sha512-N6A9MLVqjxZYcVn8hLmtneQWIJtp8IKzMP4eMnx+nqkvXoqinUPCbUFLp2UcWTEIUONhlk0ewxr/jaVGlc+J+g==",
|
||||
"dependencies": {
|
||||
"minimist": "^1.2.3",
|
||||
"shelljs": "^0.8.5"
|
||||
},
|
||||
"bin": {
|
||||
"shx": "lib/cli.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/side-channel": {
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz",
|
||||
|
@ -24617,6 +24845,11 @@
|
|||
"react-dom": ">=16.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/util-deprecate": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
|
||||
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
|
||||
},
|
||||
"node_modules/uuid": {
|
||||
"version": "8.3.2",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
|
||||
|
@ -30983,7 +31216,7 @@
|
|||
}
|
||||
},
|
||||
"bpmn-js-spiffworkflow": {
|
||||
"version": "git+ssh://git@github.com/sartography/bpmn-js-spiffworkflow.git#38f5b5d7563f24608e7b3b177547e273f7cc94a0",
|
||||
"version": "git+ssh://git@github.com/sartography/bpmn-js-spiffworkflow.git#ee86b31cd7fc6f42f92f56171a9945a8ff22773a",
|
||||
"from": "bpmn-js-spiffworkflow@github:sartography/bpmn-js-spiffworkflow#main",
|
||||
"requires": {
|
||||
"inherits": "^2.0.4",
|
||||
|
@ -30991,6 +31224,7 @@
|
|||
"min-dash": "^3.8.1",
|
||||
"min-dom": "^3.2.1",
|
||||
"moddle": "^5.0.3",
|
||||
"nice-select2": "^2.1.0",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "18.2.0",
|
||||
"tiny-svg": "^2.2.3"
|
||||
|
@ -32056,6 +32290,14 @@
|
|||
"resolved": "https://registry.npmjs.org/crelt/-/crelt-1.0.5.tgz",
|
||||
"integrity": "sha512-+BO9wPPi+DWTDcNYhr/W90myha8ptzftZT+LwcmUbbok0rcP/fequmFYCw8NMoH7pkAZQzU78b3kYrlua5a9eA=="
|
||||
},
|
||||
"cross-env": {
|
||||
"version": "7.0.3",
|
||||
"resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz",
|
||||
"integrity": "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==",
|
||||
"requires": {
|
||||
"cross-spawn": "^7.0.1"
|
||||
}
|
||||
},
|
||||
"cross-spawn": {
|
||||
"version": "7.0.3",
|
||||
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
|
||||
|
@ -32071,6 +32313,44 @@
|
|||
"resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-1.0.0.tgz",
|
||||
"integrity": "sha512-GsVpkFPlycH7/fRR7Dhcmnoii54gV1nz7y4CWyeFS14N+JVBBhY+r8amRHE4BwSYal7BPTDp8isvAlCxyFt3Hg=="
|
||||
},
|
||||
"css-loader": {
|
||||
"version": "6.11.0",
|
||||
"resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.11.0.tgz",
|
||||
"integrity": "sha512-CTJ+AEQJjq5NzLga5pE39qdiSV56F8ywCIsqNIRF0r7BDgWsN25aazToqAFg7ZrtA/U016xudB3ffgweORxX7g==",
|
||||
"requires": {
|
||||
"icss-utils": "^5.1.0",
|
||||
"postcss": "^8.4.33",
|
||||
"postcss-modules-extract-imports": "^3.1.0",
|
||||
"postcss-modules-local-by-default": "^4.0.5",
|
||||
"postcss-modules-scope": "^3.2.0",
|
||||
"postcss-modules-values": "^4.0.0",
|
||||
"postcss-value-parser": "^4.2.0",
|
||||
"semver": "^7.5.4"
|
||||
},
|
||||
"dependencies": {
|
||||
"lru-cache": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
|
||||
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
|
||||
"requires": {
|
||||
"yallist": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"semver": {
|
||||
"version": "7.6.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz",
|
||||
"integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==",
|
||||
"requires": {
|
||||
"lru-cache": "^6.0.0"
|
||||
}
|
||||
},
|
||||
"yallist": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
||||
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"css-selector-parser": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/css-selector-parser/-/css-selector-parser-1.4.1.tgz",
|
||||
|
@ -32087,6 +32367,11 @@
|
|||
"resolved": "https://registry.npmjs.org/css.escape/-/css.escape-1.5.1.tgz",
|
||||
"integrity": "sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg=="
|
||||
},
|
||||
"cssesc": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
|
||||
"integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg=="
|
||||
},
|
||||
"cssstyle": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-4.0.1.tgz",
|
||||
|
@ -34286,8 +34571,7 @@
|
|||
"fs.realpath": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
|
||||
"integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
|
||||
"devOptional": true
|
||||
"integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw=="
|
||||
},
|
||||
"fsevents": {
|
||||
"version": "2.3.3",
|
||||
|
@ -34413,7 +34697,6 @@
|
|||
"version": "7.2.3",
|
||||
"resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
|
||||
"integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
|
||||
"devOptional": true,
|
||||
"requires": {
|
||||
"fs.realpath": "^1.0.0",
|
||||
"inflight": "^1.0.4",
|
||||
|
@ -34912,6 +35195,12 @@
|
|||
"safer-buffer": ">= 2.1.2 < 3.0.0"
|
||||
}
|
||||
},
|
||||
"icss-utils": {
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz",
|
||||
"integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==",
|
||||
"requires": {}
|
||||
},
|
||||
"ids": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/ids/-/ids-1.0.5.tgz",
|
||||
|
@ -35006,7 +35295,6 @@
|
|||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
|
||||
"integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
|
||||
"devOptional": true,
|
||||
"requires": {
|
||||
"once": "^1.3.0",
|
||||
"wrappy": "1"
|
||||
|
@ -35044,6 +35332,11 @@
|
|||
"side-channel": "^1.0.4"
|
||||
}
|
||||
},
|
||||
"interpret": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz",
|
||||
"integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA=="
|
||||
},
|
||||
"invariant": {
|
||||
"version": "2.2.4",
|
||||
"resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz",
|
||||
|
@ -39520,6 +39813,16 @@
|
|||
"integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==",
|
||||
"dev": true
|
||||
},
|
||||
"nice-select2": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/nice-select2/-/nice-select2-2.2.0.tgz",
|
||||
"integrity": "sha512-UVlqc/ReJPFnQhESbbJrFHCjVe74OWrewh/8w2A+zLlJ98BI4FVDVALV1tOfYCmhNcZtH4L1lQispCUIWX11nQ==",
|
||||
"requires": {
|
||||
"cross-env": "^7.0.3",
|
||||
"css-loader": "^6.7.3",
|
||||
"shx": "^0.3.4"
|
||||
}
|
||||
},
|
||||
"node-dir": {
|
||||
"version": "0.1.17",
|
||||
"resolved": "https://registry.npmjs.org/node-dir/-/node-dir-0.1.17.tgz",
|
||||
|
@ -40040,8 +40343,7 @@
|
|||
"path-is-absolute": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
|
||||
"integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
|
||||
"devOptional": true
|
||||
"integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg=="
|
||||
},
|
||||
"path-is-inside": {
|
||||
"version": "1.0.2",
|
||||
|
@ -40156,6 +40458,47 @@
|
|||
"source-map-js": "^1.2.0"
|
||||
}
|
||||
},
|
||||
"postcss-modules-extract-imports": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.1.0.tgz",
|
||||
"integrity": "sha512-k3kNe0aNFQDAZGbin48pL2VNidTF0w4/eASDsxlyspobzU3wZQLOGj7L9gfRe0Jo9/4uud09DsjFNH7winGv8Q==",
|
||||
"requires": {}
|
||||
},
|
||||
"postcss-modules-local-by-default": {
|
||||
"version": "4.0.5",
|
||||
"resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.5.tgz",
|
||||
"integrity": "sha512-6MieY7sIfTK0hYfafw1OMEG+2bg8Q1ocHCpoWLqOKj3JXlKu4G7btkmM/B7lFubYkYWmRSPLZi5chid63ZaZYw==",
|
||||
"requires": {
|
||||
"icss-utils": "^5.0.0",
|
||||
"postcss-selector-parser": "^6.0.2",
|
||||
"postcss-value-parser": "^4.1.0"
|
||||
}
|
||||
},
|
||||
"postcss-modules-scope": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.2.0.tgz",
|
||||
"integrity": "sha512-oq+g1ssrsZOsx9M96c5w8laRmvEu9C3adDSjI8oTcbfkrTE8hx/zfyobUoWIxaKPO8bt6S62kxpw5GqypEw1QQ==",
|
||||
"requires": {
|
||||
"postcss-selector-parser": "^6.0.4"
|
||||
}
|
||||
},
|
||||
"postcss-modules-values": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz",
|
||||
"integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==",
|
||||
"requires": {
|
||||
"icss-utils": "^5.0.0"
|
||||
}
|
||||
},
|
||||
"postcss-selector-parser": {
|
||||
"version": "6.0.16",
|
||||
"resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.16.tgz",
|
||||
"integrity": "sha512-A0RVJrX+IUkVZbW3ClroRWurercFhieevHB38sr2+l9eUClMqome3LmEmnhlNy+5Mr2EYN6B2Kaw9wYdd+VHiw==",
|
||||
"requires": {
|
||||
"cssesc": "^3.0.0",
|
||||
"util-deprecate": "^1.0.2"
|
||||
}
|
||||
},
|
||||
"postcss-value-parser": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz",
|
||||
|
@ -40651,6 +40994,14 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"rechoir": {
|
||||
"version": "0.6.2",
|
||||
"resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz",
|
||||
"integrity": "sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==",
|
||||
"requires": {
|
||||
"resolve": "^1.1.6"
|
||||
}
|
||||
},
|
||||
"redent": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz",
|
||||
|
@ -41430,6 +41781,16 @@
|
|||
"resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.1.tgz",
|
||||
"integrity": "sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA=="
|
||||
},
|
||||
"shelljs": {
|
||||
"version": "0.8.5",
|
||||
"resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.5.tgz",
|
||||
"integrity": "sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==",
|
||||
"requires": {
|
||||
"glob": "^7.0.0",
|
||||
"interpret": "^1.0.0",
|
||||
"rechoir": "^0.6.2"
|
||||
}
|
||||
},
|
||||
"shortid": {
|
||||
"version": "2.2.16",
|
||||
"resolved": "https://registry.npmjs.org/shortid/-/shortid-2.2.16.tgz",
|
||||
|
@ -41445,6 +41806,15 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"shx": {
|
||||
"version": "0.3.4",
|
||||
"resolved": "https://registry.npmjs.org/shx/-/shx-0.3.4.tgz",
|
||||
"integrity": "sha512-N6A9MLVqjxZYcVn8hLmtneQWIJtp8IKzMP4eMnx+nqkvXoqinUPCbUFLp2UcWTEIUONhlk0ewxr/jaVGlc+J+g==",
|
||||
"requires": {
|
||||
"minimist": "^1.2.3",
|
||||
"shelljs": "^0.8.5"
|
||||
}
|
||||
},
|
||||
"side-channel": {
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz",
|
||||
|
@ -43725,6 +44095,11 @@
|
|||
"resize-observer-polyfill": "^1.5.1"
|
||||
}
|
||||
},
|
||||
"util-deprecate": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
|
||||
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
|
||||
},
|
||||
"uuid": {
|
||||
"version": "8.3.2",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
|
||||
|
|
|
@ -76,8 +76,10 @@
|
|||
"serve": "vite preview",
|
||||
"test": "vitest run --coverage",
|
||||
"format": "prettier --write src/**/*.[tj]s{,x}",
|
||||
"lint": "./node_modules/.bin/eslint src",
|
||||
"lint:fix": "./node_modules/.bin/eslint --fix src"
|
||||
"eslint": "./node_modules/.bin/eslint src",
|
||||
"lint": "npm run eslint && npm run typecheck",
|
||||
"lint:fix": "./node_modules/.bin/eslint --fix src",
|
||||
"typecheck": "./node_modules/.bin/tsc --noEmit"
|
||||
},
|
||||
"eslintConfig": {
|
||||
"extends": [
|
||||
|
@ -113,7 +115,6 @@
|
|||
"cypress-slow-down": "^1.3.1",
|
||||
"cypress-vite": "^1.5.0",
|
||||
"eslint": "^8.56.0",
|
||||
"eslint_d": "^12.2.0",
|
||||
"eslint-config-airbnb": "^19.0.4",
|
||||
"eslint-config-prettier": "^9.1.0",
|
||||
"eslint-plugin-cypress": "^2.15.1",
|
||||
|
@ -124,8 +125,10 @@
|
|||
"eslint-plugin-react-hooks": "^4.6.2",
|
||||
"eslint-plugin-sonarjs": "^1.0.3",
|
||||
"eslint-plugin-unused-imports": "^3.2.0",
|
||||
"eslint_d": "^12.2.0",
|
||||
"inherits-browser": "^0.0.1",
|
||||
"jsdom": "^24.0.0",
|
||||
"nice-select2": "^2.1.0",
|
||||
"prettier": "^3.3.0",
|
||||
"safe-regex": "^2.1.1",
|
||||
"tiny-svg": "^2.2.3",
|
||||
|
|
|
@ -264,6 +264,22 @@ export default function CustomForm({
|
|||
}
|
||||
};
|
||||
|
||||
const checkJsonField = (
|
||||
formDataToCheck: any,
|
||||
propertyKey: string,
|
||||
errors: any,
|
||||
_jsonSchema: any,
|
||||
_uiSchemaPassedIn?: any
|
||||
) => {
|
||||
if (propertyKey in formDataToCheck) {
|
||||
try {
|
||||
JSON.parse(formDataToCheck[propertyKey]);
|
||||
} catch (e) {
|
||||
errors[propertyKey].addError(`has invalid JSON: ${e}`);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const checkNumericRange = (
|
||||
formDataToCheck: any,
|
||||
propertyKey: string,
|
||||
|
@ -407,6 +423,19 @@ export default function CustomForm({
|
|||
currentUiSchema,
|
||||
);
|
||||
}
|
||||
if (
|
||||
currentUiSchema &&
|
||||
'ui:options' in currentUiSchema &&
|
||||
currentUiSchema['ui:options']['validateJson'] === true
|
||||
) {
|
||||
checkJsonField(
|
||||
formDataToCheck,
|
||||
propertyKey,
|
||||
errors,
|
||||
jsonSchemaToUse,
|
||||
currentUiSchema
|
||||
);
|
||||
}
|
||||
|
||||
if (
|
||||
currentUiSchema &&
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import { ReactElement } from 'react';
|
||||
import { UiSchemaUxElement } from '../extension_ui_schema_interfaces';
|
||||
|
||||
type OwnProps = {
|
||||
|
@ -30,10 +31,12 @@ export function ExtensionUxElementMap({
|
|||
return mainElement();
|
||||
}
|
||||
|
||||
export default function ExtensionUxElementForDisplay(args: OwnProps) {
|
||||
export default function ExtensionUxElementForDisplay(
|
||||
args: OwnProps,
|
||||
): ReactElement | null {
|
||||
const result = ExtensionUxElementMap(args);
|
||||
if (result === null) {
|
||||
return null;
|
||||
}
|
||||
return result;
|
||||
return <>{result}</>;
|
||||
}
|
||||
|
|
|
@ -19,7 +19,6 @@ import {
|
|||
import { Logout } from '@carbon/icons-react';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useLocation, Link, LinkProps } from 'react-router-dom';
|
||||
// @ts-expect-error TS(2307) FIXME: Cannot find module '../logo.svg' or its correspond... Remove this comment to see the full error message
|
||||
import logo from '../logo.svg';
|
||||
import UserService from '../services/UserService';
|
||||
import { UiSchemaUxElement } from '../extension_ui_schema_interfaces';
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import { useState } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
// @ts-ignore
|
||||
import { Button, Form, Stack, TextInput, TextArea } from '@carbon/react';
|
||||
import { modifyProcessIdentifierForPathParam, slugifyString } from '../helpers';
|
||||
import HttpService from '../services/HttpService';
|
||||
import { ProcessGroup } from '../interfaces';
|
||||
|
||||
import useProcessGroupFetcher from '../hooks/useProcessGroupFetcher';
|
||||
|
||||
type OwnProps = {
|
||||
|
@ -72,6 +72,7 @@ export default function ProcessGroupForm({
|
|||
const postBody = {
|
||||
display_name: processGroup.display_name,
|
||||
description: processGroup.description,
|
||||
messages: processGroup.messages,
|
||||
};
|
||||
if (mode === 'new') {
|
||||
if (parentGroupId) {
|
||||
|
@ -155,7 +156,6 @@ export default function ProcessGroupForm({
|
|||
}
|
||||
/>,
|
||||
);
|
||||
|
||||
return textInputs;
|
||||
};
|
||||
|
||||
|
|
|
@ -70,60 +70,64 @@ import { usePermissionFetcher } from '../hooks/PermissionService';
|
|||
type OwnProps = {
|
||||
processModelId: string;
|
||||
diagramType: string;
|
||||
tasks?: Task[] | null;
|
||||
saveDiagram?: (..._args: any[]) => any;
|
||||
onDeleteFile?: (..._args: any[]) => any;
|
||||
isPrimaryFile?: boolean;
|
||||
onSetPrimaryFile?: (..._args: any[]) => any;
|
||||
diagramXML?: string | null;
|
||||
fileName?: string;
|
||||
onLaunchScriptEditor?: (..._args: any[]) => any;
|
||||
onLaunchMarkdownEditor?: (..._args: any[]) => any;
|
||||
onLaunchBpmnEditor?: (..._args: any[]) => any;
|
||||
onLaunchJsonSchemaEditor?: (..._args: any[]) => any;
|
||||
onLaunchDmnEditor?: (..._args: any[]) => any;
|
||||
onElementClick?: (..._args: any[]) => any;
|
||||
onServiceTasksRequested?: (..._args: any[]) => any;
|
||||
onDataStoresRequested?: (..._args: any[]) => any;
|
||||
onJsonSchemaFilesRequested?: (..._args: any[]) => any;
|
||||
onDmnFilesRequested?: (..._args: any[]) => any;
|
||||
onSearchProcessModels?: (..._args: any[]) => any;
|
||||
onElementsChanged?: (..._args: any[]) => any;
|
||||
url?: string;
|
||||
callers?: ProcessReference[];
|
||||
activeUserElement?: React.ReactElement;
|
||||
callers?: ProcessReference[];
|
||||
diagramXML?: string | null;
|
||||
disableSaveButton?: boolean;
|
||||
fileName?: string;
|
||||
isPrimaryFile?: boolean;
|
||||
onDataStoresRequested?: (..._args: any[]) => any;
|
||||
onDeleteFile?: (..._args: any[]) => any;
|
||||
onDmnFilesRequested?: (..._args: any[]) => any;
|
||||
onElementClick?: (..._args: any[]) => any;
|
||||
onElementsChanged?: (..._args: any[]) => any;
|
||||
onJsonSchemaFilesRequested?: (..._args: any[]) => any;
|
||||
onLaunchBpmnEditor?: (..._args: any[]) => any;
|
||||
onLaunchDmnEditor?: (..._args: any[]) => any;
|
||||
onLaunchJsonSchemaEditor?: (..._args: any[]) => any;
|
||||
onLaunchMarkdownEditor?: (..._args: any[]) => any;
|
||||
onLaunchScriptEditor?: (..._args: any[]) => any;
|
||||
onLaunchMessageEditor?: (..._args: any[]) => any;
|
||||
onMessagesRequested?: (..._args: any[]) => any;
|
||||
onSearchProcessModels?: (..._args: any[]) => any;
|
||||
onServiceTasksRequested?: (..._args: any[]) => any;
|
||||
onSetPrimaryFile?: (..._args: any[]) => any;
|
||||
saveDiagram?: (..._args: any[]) => any;
|
||||
tasks?: Task[] | null;
|
||||
url?: string;
|
||||
};
|
||||
|
||||
const FitViewport = 'fit-viewport';
|
||||
|
||||
// https://codesandbox.io/s/quizzical-lake-szfyo?file=/src/App.js was a handy reference
|
||||
export default function ReactDiagramEditor({
|
||||
processModelId,
|
||||
diagramType,
|
||||
tasks,
|
||||
saveDiagram,
|
||||
onDeleteFile,
|
||||
isPrimaryFile,
|
||||
onSetPrimaryFile,
|
||||
diagramXML,
|
||||
fileName,
|
||||
onLaunchScriptEditor,
|
||||
onLaunchMarkdownEditor,
|
||||
onLaunchBpmnEditor,
|
||||
onLaunchJsonSchemaEditor,
|
||||
onLaunchDmnEditor,
|
||||
onElementClick,
|
||||
onServiceTasksRequested,
|
||||
onDataStoresRequested,
|
||||
onJsonSchemaFilesRequested,
|
||||
onDmnFilesRequested,
|
||||
onSearchProcessModels,
|
||||
onElementsChanged,
|
||||
url,
|
||||
callers,
|
||||
activeUserElement,
|
||||
callers,
|
||||
diagramType,
|
||||
diagramXML,
|
||||
disableSaveButton,
|
||||
fileName,
|
||||
isPrimaryFile,
|
||||
onDataStoresRequested,
|
||||
onDeleteFile,
|
||||
onDmnFilesRequested,
|
||||
onElementClick,
|
||||
onElementsChanged,
|
||||
onJsonSchemaFilesRequested,
|
||||
onLaunchBpmnEditor,
|
||||
onLaunchDmnEditor,
|
||||
onLaunchJsonSchemaEditor,
|
||||
onLaunchMarkdownEditor,
|
||||
onLaunchScriptEditor,
|
||||
onLaunchMessageEditor,
|
||||
onMessagesRequested,
|
||||
onSearchProcessModels,
|
||||
onServiceTasksRequested,
|
||||
onSetPrimaryFile,
|
||||
processModelId,
|
||||
saveDiagram,
|
||||
tasks,
|
||||
url,
|
||||
}: OwnProps) {
|
||||
const [diagramXMLString, setDiagramXMLString] = useState('');
|
||||
const [diagramModelerState, setDiagramModelerState] = useState(null);
|
||||
|
@ -409,6 +413,12 @@ export default function ReactDiagramEditor({
|
|||
}
|
||||
});
|
||||
|
||||
diagramModeler.on('spiff.messages.requested', (event: any) => {
|
||||
if (onMessagesRequested) {
|
||||
onMessagesRequested(event);
|
||||
}
|
||||
});
|
||||
|
||||
diagramModeler.on('spiff.json_schema_files.requested', (event: any) => {
|
||||
handleServiceTasksRequested(event);
|
||||
});
|
||||
|
@ -418,21 +428,29 @@ export default function ReactDiagramEditor({
|
|||
onSearchProcessModels(event.value, event.eventBus, event.element);
|
||||
}
|
||||
});
|
||||
|
||||
diagramModeler.on('spiff.message.edit', (event: any) => {
|
||||
if (onLaunchMessageEditor) {
|
||||
onLaunchMessageEditor(event);
|
||||
}
|
||||
});
|
||||
}, [
|
||||
diagramModelerState,
|
||||
diagramType,
|
||||
onLaunchScriptEditor,
|
||||
onLaunchMarkdownEditor,
|
||||
onDataStoresRequested,
|
||||
onDmnFilesRequested,
|
||||
onElementClick,
|
||||
onElementsChanged,
|
||||
onJsonSchemaFilesRequested,
|
||||
onLaunchBpmnEditor,
|
||||
onLaunchDmnEditor,
|
||||
onLaunchJsonSchemaEditor,
|
||||
onElementClick,
|
||||
onServiceTasksRequested,
|
||||
onDataStoresRequested,
|
||||
onJsonSchemaFilesRequested,
|
||||
onDmnFilesRequested,
|
||||
onLaunchMarkdownEditor,
|
||||
onLaunchScriptEditor,
|
||||
onLaunchMessageEditor,
|
||||
onMessagesRequested,
|
||||
onSearchProcessModels,
|
||||
onElementsChanged,
|
||||
onServiceTasksRequested,
|
||||
]);
|
||||
|
||||
useEffect(() => {
|
||||
|
@ -549,13 +567,13 @@ export default function ReactDiagramEditor({
|
|||
alreadyImportedXmlRef.current = true;
|
||||
}
|
||||
|
||||
function dmnTextHandler(text: str) {
|
||||
function dmnTextHandler(text: string) {
|
||||
const decisionId = `decision_${makeid(7)}`;
|
||||
const newText = text.replaceAll('{{DECISION_ID}}', decisionId);
|
||||
setDiagramXMLString(newText);
|
||||
}
|
||||
|
||||
function bpmnTextHandler(text: str) {
|
||||
function bpmnTextHandler(text: string) {
|
||||
const processId = `Process_${makeid(7)}`;
|
||||
const newText = text.replaceAll('{{PROCESS_ID}}', processId);
|
||||
setDiagramXMLString(newText);
|
||||
|
@ -563,7 +581,7 @@ export default function ReactDiagramEditor({
|
|||
|
||||
function fetchDiagramFromURL(
|
||||
urlToUse: any,
|
||||
textHandler?: (text: str) => void,
|
||||
textHandler?: (text: string) => void,
|
||||
) {
|
||||
fetch(urlToUse)
|
||||
.then((response) => response.text())
|
||||
|
@ -603,7 +621,7 @@ export default function ReactDiagramEditor({
|
|||
return undefined;
|
||||
}
|
||||
let newDiagramFileName = 'new_bpmn_diagram.bpmn';
|
||||
let textHandler = null;
|
||||
let textHandler = undefined;
|
||||
if (diagramType === 'dmn') {
|
||||
newDiagramFileName = 'new_dmn_diagram.dmn';
|
||||
textHandler = dmnTextHandler;
|
||||
|
|
|
@ -0,0 +1,279 @@
|
|||
import { useEffect, useState } from 'react';
|
||||
import CustomForm from '../CustomForm';
|
||||
import {
|
||||
ProcessGroup,
|
||||
RJSFFormObject,
|
||||
MessageDefinition,
|
||||
CorrelationProperties,
|
||||
} from '../../interfaces';
|
||||
import {
|
||||
unModifyProcessIdentifierForPathParam,
|
||||
setPageTitle,
|
||||
} from '../../helpers';
|
||||
import HttpService from '../../services/HttpService';
|
||||
import {
|
||||
convertCorrelationPropertiesToRJSF,
|
||||
mergeCorrelationProperties,
|
||||
} from './MessageHelper';
|
||||
import { Notification } from '../Notification';
|
||||
|
||||
type OwnProps = {
|
||||
modifiedProcessGroupIdentifier: string;
|
||||
messageId: string;
|
||||
messageEvent: any;
|
||||
correlationProperties: any;
|
||||
};
|
||||
|
||||
export function MessageEditor({
|
||||
modifiedProcessGroupIdentifier,
|
||||
messageId,
|
||||
messageEvent,
|
||||
correlationProperties,
|
||||
}: OwnProps) {
|
||||
const [processGroup, setProcessGroup] = useState<ProcessGroup | null>(null);
|
||||
const [currentFormData, setCurrentFormData] = useState<any>(null);
|
||||
const [displaySaveMessageMessage, setDisplaySaveMessageMessage] =
|
||||
useState<boolean>(false);
|
||||
const [currentMessageId, setCurrentMessageId] = useState<string | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
const setInitialFormData = (newProcessGroup: ProcessGroup) => {
|
||||
let newCorrelationProperties = convertCorrelationPropertiesToRJSF(
|
||||
messageId,
|
||||
newProcessGroup,
|
||||
);
|
||||
newCorrelationProperties = mergeCorrelationProperties(
|
||||
correlationProperties,
|
||||
newCorrelationProperties,
|
||||
);
|
||||
|
||||
const jsonSchema =
|
||||
(newProcessGroup.messages || {})[messageId]?.schema || {};
|
||||
const newFormData = {
|
||||
processGroupIdentifier: unModifyProcessIdentifierForPathParam(
|
||||
modifiedProcessGroupIdentifier,
|
||||
),
|
||||
messageId: messageId,
|
||||
correlation_properties: newCorrelationProperties,
|
||||
schema: JSON.stringify(jsonSchema, null, 2),
|
||||
};
|
||||
setCurrentFormData(newFormData);
|
||||
};
|
||||
const processResult = (result: ProcessGroup) => {
|
||||
setProcessGroup(result);
|
||||
setCurrentMessageId(messageId);
|
||||
setPageTitle([result.display_name]);
|
||||
setInitialFormData(result);
|
||||
};
|
||||
HttpService.makeCallToBackend({
|
||||
path: `/process-groups/${modifiedProcessGroupIdentifier}`,
|
||||
successCallback: processResult,
|
||||
});
|
||||
}, [modifiedProcessGroupIdentifier]);
|
||||
|
||||
const handleProcessGroupUpdateResponse = (
|
||||
response: ProcessGroup,
|
||||
messageIdentifier: string,
|
||||
updatedMessagesForId: MessageDefinition,
|
||||
) => {
|
||||
setProcessGroup(response);
|
||||
setDisplaySaveMessageMessage(true);
|
||||
messageEvent.eventBus.fire('spiff.add_message.returned', {
|
||||
name: messageIdentifier,
|
||||
correlation_properties: updatedMessagesForId.correlation_properties,
|
||||
});
|
||||
};
|
||||
|
||||
const updateCorrelationPropertiesOnProcessGroup = (
|
||||
currentMessagesForId: MessageDefinition,
|
||||
formData: any,
|
||||
) => {
|
||||
const newCorrelationProperties: CorrelationProperties = {
|
||||
...currentMessagesForId.correlation_properties,
|
||||
};
|
||||
(formData.correlation_properties || []).forEach((formProp: any) => {
|
||||
if (!(formProp.id in newCorrelationProperties)) {
|
||||
newCorrelationProperties[formProp.id] = {
|
||||
retrieval_expressions: [],
|
||||
};
|
||||
}
|
||||
if (
|
||||
!newCorrelationProperties[formProp.id].retrieval_expressions.includes(
|
||||
formProp.retrievalExpression,
|
||||
)
|
||||
) {
|
||||
newCorrelationProperties[formProp.id].retrieval_expressions.push(
|
||||
formProp.retrievalExpression,
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
Object.keys(currentMessagesForId.correlation_properties || []).forEach(
|
||||
(propId: string) => {
|
||||
const foundProp = (formData.correlation_properties || []).find(
|
||||
(formProp: any) => {
|
||||
return propId === formProp.id;
|
||||
},
|
||||
);
|
||||
if (!foundProp) {
|
||||
delete newCorrelationProperties[propId];
|
||||
}
|
||||
},
|
||||
);
|
||||
return newCorrelationProperties;
|
||||
};
|
||||
|
||||
const updateProcessGroupWithMessages = (formObject: RJSFFormObject) => {
|
||||
const { formData } = formObject;
|
||||
|
||||
if (!processGroup) {
|
||||
return;
|
||||
}
|
||||
|
||||
// keep track of new and old message ids so we can handle renaming a message
|
||||
const newMessageId = formData.messageId;
|
||||
const oldMessageId = currentMessageId || newMessageId;
|
||||
|
||||
const processGroupForUpdate = { ...processGroup };
|
||||
if (!processGroupForUpdate.messages) {
|
||||
processGroupForUpdate.messages = {};
|
||||
}
|
||||
const currentMessagesForId: MessageDefinition =
|
||||
(processGroupForUpdate.messages || {})[oldMessageId] || {};
|
||||
const updatedMessagesForId = { ...currentMessagesForId };
|
||||
|
||||
const newCorrelationProperties = updateCorrelationPropertiesOnProcessGroup(
|
||||
currentMessagesForId,
|
||||
formData,
|
||||
);
|
||||
|
||||
updatedMessagesForId.correlation_properties = newCorrelationProperties;
|
||||
|
||||
try {
|
||||
updatedMessagesForId.schema = JSON.parse(formData.schema || '{}');
|
||||
} catch (e) {
|
||||
alert(`Invalid schema: ${e}`);
|
||||
return;
|
||||
}
|
||||
|
||||
processGroupForUpdate.messages[newMessageId] = updatedMessagesForId;
|
||||
setCurrentMessageId(newMessageId);
|
||||
const path = `/process-groups/${modifiedProcessGroupIdentifier}`;
|
||||
HttpService.makeCallToBackend({
|
||||
path,
|
||||
successCallback: (response: ProcessGroup) =>
|
||||
handleProcessGroupUpdateResponse(
|
||||
response,
|
||||
newMessageId,
|
||||
updatedMessagesForId,
|
||||
),
|
||||
httpMethod: 'PUT',
|
||||
postBody: processGroupForUpdate,
|
||||
});
|
||||
};
|
||||
|
||||
const schema = {
|
||||
type: 'object',
|
||||
required: ['processGroupIdentifier', 'messageId'],
|
||||
properties: {
|
||||
processGroupIdentifier: {
|
||||
type: 'string',
|
||||
title: 'Location',
|
||||
default: '/',
|
||||
pattern: '^[\\/\\w-]+$',
|
||||
validationErrorMessage:
|
||||
'must contain only alphanumeric characters, "/", underscores, or hyphens',
|
||||
description:
|
||||
'Only process models within this path will have access to this message.',
|
||||
},
|
||||
messageId: {
|
||||
type: 'string',
|
||||
title: 'Message Name',
|
||||
pattern: '^[\\w -]+$',
|
||||
validationErrorMessage:
|
||||
'must contain only alphanumeric characters, underscores, or hyphens',
|
||||
description:
|
||||
'The mesage name should contain no spaces or special characters',
|
||||
},
|
||||
correlation_properties: {
|
||||
type: 'array',
|
||||
title: 'Correlation Properties',
|
||||
items: {
|
||||
type: 'object',
|
||||
required: ['id', 'retrievalExpression'],
|
||||
properties: {
|
||||
id: {
|
||||
type: 'string',
|
||||
title: 'Property Name',
|
||||
description: '',
|
||||
},
|
||||
retrievalExpression: {
|
||||
type: 'string',
|
||||
title: 'Retrieval Expression',
|
||||
description:
|
||||
'This is how to extract the property from the body of the message',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
schema: {
|
||||
type: 'string',
|
||||
title: 'Json Schema',
|
||||
default: '{}',
|
||||
description: 'The payload must conform to this schema if defined.',
|
||||
},
|
||||
},
|
||||
};
|
||||
const uischema = {
|
||||
schema: {
|
||||
'ui:widget': 'textarea',
|
||||
'ui:rows': 5,
|
||||
'ui:options': { validateJson: true },
|
||||
},
|
||||
'ui:layout': [
|
||||
{
|
||||
processGroupIdentifier: { sm: 2, md: 4, lg: 8 },
|
||||
messageId: { sm: 2, md: 4, lg: 8 },
|
||||
schema: { sm: 4, md: 4, lg: 8 },
|
||||
correlation_properties: {
|
||||
sm: 4,
|
||||
md: 4,
|
||||
lg: 8,
|
||||
id: { sm: 2, md: 4, lg: 8 },
|
||||
extractionExpression: { sm: 2, md: 4, lg: 8 },
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const updateFormData = (formObject: any) => {
|
||||
setCurrentFormData(formObject.formData);
|
||||
};
|
||||
|
||||
if (processGroup && currentFormData) {
|
||||
return (
|
||||
<>
|
||||
{displaySaveMessageMessage ? (
|
||||
<Notification
|
||||
title="Save successful"
|
||||
hideCloseButton
|
||||
timeout={4000}
|
||||
onClose={() => setDisplaySaveMessageMessage(false)}
|
||||
>
|
||||
Message has been saved
|
||||
</Notification>
|
||||
) : null}
|
||||
<CustomForm
|
||||
id={currentMessageId || ''}
|
||||
schema={schema}
|
||||
uiSchema={uischema}
|
||||
formData={currentFormData}
|
||||
onSubmit={updateProcessGroupWithMessages}
|
||||
submitButtonText="Save"
|
||||
onChange={updateFormData}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
import { ProcessGroup } from '../../interfaces';
|
||||
|
||||
const arrayCompare = (array1: string[], array2: string[]) => {
|
||||
return (
|
||||
array1.length === array2.length &&
|
||||
array1.every((value, index) => value === array2[index])
|
||||
);
|
||||
};
|
||||
|
||||
export const getPropertiesForMessage = (
|
||||
messageId: string,
|
||||
processGroup: ProcessGroup,
|
||||
) => {
|
||||
const message = (processGroup.messages || {})[messageId];
|
||||
if (message) {
|
||||
return message.correlation_properties;
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
export const convertCorrelationPropertiesToRJSF = (
|
||||
messageId: string,
|
||||
processGroup: ProcessGroup,
|
||||
) => {
|
||||
const correlationProperties = getPropertiesForMessage(
|
||||
messageId,
|
||||
processGroup,
|
||||
);
|
||||
const correlationPropertiesToUse = correlationProperties || {};
|
||||
const returnArray: any = [];
|
||||
Object.keys(correlationPropertiesToUse).forEach((propIdentifier: string) => {
|
||||
const property = correlationPropertiesToUse[propIdentifier];
|
||||
return property.retrieval_expressions.forEach((retExp: string) => {
|
||||
returnArray.push({
|
||||
id: propIdentifier,
|
||||
retrievalExpression: retExp,
|
||||
});
|
||||
});
|
||||
});
|
||||
return returnArray;
|
||||
};
|
||||
|
||||
export const mergeCorrelationProperties = (
|
||||
xmlProperties: any,
|
||||
apiProperties: any,
|
||||
) => {
|
||||
const mergedProperties = xmlProperties ? [...xmlProperties] : [];
|
||||
|
||||
apiProperties.forEach((apiProperty: any) => {
|
||||
const existingProperty = mergedProperties.find(
|
||||
(prop) => prop.id === apiProperty.id,
|
||||
);
|
||||
|
||||
if (existingProperty) {
|
||||
existingProperty.retrievalExpression = apiProperty.retrievalExpression;
|
||||
} else {
|
||||
mergedProperties.push(apiProperty);
|
||||
}
|
||||
});
|
||||
|
||||
return mergedProperties;
|
||||
};
|
|
@ -4,16 +4,16 @@ import { ErrorOutline } from '@carbon/icons-react';
|
|||
// @ts-ignore
|
||||
import { Table, Modal, Button } from '@carbon/react';
|
||||
import { Link, useSearchParams } from 'react-router-dom';
|
||||
import PaginationForTable from './PaginationForTable';
|
||||
import ProcessBreadcrumb from './ProcessBreadcrumb';
|
||||
import PaginationForTable from '../PaginationForTable';
|
||||
import ProcessBreadcrumb from '../ProcessBreadcrumb';
|
||||
import {
|
||||
getPageInfoFromSearchParams,
|
||||
modifyProcessIdentifierForPathParam,
|
||||
} from '../helpers';
|
||||
import HttpService from '../services/HttpService';
|
||||
import { FormatProcessModelDisplayName } from './MiniComponents';
|
||||
import { MessageInstance } from '../interfaces';
|
||||
import DateAndTimeService from '../services/DateAndTimeService';
|
||||
} from '../../helpers';
|
||||
import HttpService from '../../services/HttpService';
|
||||
import { FormatProcessModelDisplayName } from '../MiniComponents';
|
||||
import { MessageInstance } from '../../interfaces';
|
||||
import DateAndTimeService from '../../services/DateAndTimeService';
|
||||
|
||||
type OwnProps = {
|
||||
processInstanceId?: number;
|
||||
|
@ -122,6 +122,7 @@ export default function MessageInstanceList({ processInstanceId }: OwnProps) {
|
|||
<td>{instanceLink}</td>
|
||||
<td>{row.name}</td>
|
||||
<td>{row.message_type}</td>
|
||||
<td>{row.counterpart_id}</td>
|
||||
<td>
|
||||
<Button
|
||||
kind="ghost"
|
||||
|
@ -151,6 +152,7 @@ export default function MessageInstanceList({ processInstanceId }: OwnProps) {
|
|||
<th>Process instance</th>
|
||||
<th>Name</th>
|
||||
<th>Type</th>
|
||||
<th>Corresponding Message Instance</th>
|
||||
<th>Details</th>
|
||||
<th>Status</th>
|
||||
<th>Created at</th>
|
|
@ -0,0 +1,103 @@
|
|||
import React, { useEffect, useState } from 'react';
|
||||
import { Table } from '@carbon/react';
|
||||
import { useSearchParams } from 'react-router-dom';
|
||||
import PaginationForTable from '../PaginationForTable';
|
||||
import {
|
||||
getPageInfoFromSearchParams,
|
||||
modifyProcessIdentifierForPathParam,
|
||||
} from '../../helpers';
|
||||
import HttpService from '../../services/HttpService';
|
||||
import { PaginationObject, ReferenceCache } from '../../interfaces';
|
||||
|
||||
// TODO: update to work with current message-models api
|
||||
type OwnProps = {
|
||||
processGroupId?: string;
|
||||
};
|
||||
|
||||
export default function MessageModelList({ processGroupId }: OwnProps) {
|
||||
const [messageModels, setMessageModels] = useState<ReferenceCache[]>([]);
|
||||
const [pagination, setPagination] = useState<PaginationObject | null>(null);
|
||||
const [searchParams] = useSearchParams();
|
||||
|
||||
useEffect(() => {
|
||||
const setMessageInstanceListFromResult = (result: any) => {
|
||||
setMessageModels(result.results);
|
||||
setPagination(result.pagination);
|
||||
};
|
||||
const { page, perPage } = getPageInfoFromSearchParams(searchParams);
|
||||
const queryParamString = `per_page=${perPage}&page=${page}`;
|
||||
let modifiedProcessIdentifierForPathParam = '';
|
||||
if (processGroupId) {
|
||||
modifiedProcessIdentifierForPathParam = `/${modifyProcessIdentifierForPathParam(
|
||||
processGroupId
|
||||
)}`;
|
||||
}
|
||||
|
||||
HttpService.makeCallToBackend({
|
||||
path: `/message-models${modifiedProcessIdentifierForPathParam}?${queryParamString}`,
|
||||
successCallback: setMessageInstanceListFromResult,
|
||||
});
|
||||
}, [processGroupId, searchParams]);
|
||||
|
||||
const correlation = (row: ReferenceCache): string => {
|
||||
let keys = '';
|
||||
const cProps: string[] = [];
|
||||
if ('correlation_keys' in row.properties) {
|
||||
keys = row.properties.correlation_keys;
|
||||
}
|
||||
if ('correlations' in row.properties) {
|
||||
row.properties.correlations.forEach((cor: any) => {
|
||||
cProps.push(cor.correlation_property);
|
||||
});
|
||||
}
|
||||
if (cProps.length > 0) {
|
||||
keys += ` (${cProps.join(', ')})`;
|
||||
}
|
||||
return keys;
|
||||
};
|
||||
|
||||
const buildTable = () => {
|
||||
const rows = messageModels.map((row: ReferenceCache) => {
|
||||
return (
|
||||
<tr key={row.identifier}>
|
||||
<td>{row.identifier}</td>
|
||||
<td>
|
||||
<a
|
||||
href={`/process-groups/${modifyProcessIdentifierForPathParam(
|
||||
row.relative_location
|
||||
)}`}
|
||||
>
|
||||
{row.relative_location}
|
||||
</a>
|
||||
</td>
|
||||
<td>{correlation(row)}</td>
|
||||
</tr>
|
||||
);
|
||||
});
|
||||
return (
|
||||
<Table striped bordered>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Id</th>
|
||||
<th>Location</th>
|
||||
<th>Correlation</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>{rows}</tbody>
|
||||
</Table>
|
||||
);
|
||||
};
|
||||
if (pagination) {
|
||||
const { page, perPage } = getPageInfoFromSearchParams(searchParams);
|
||||
return (
|
||||
<PaginationForTable
|
||||
page={page}
|
||||
perPage={perPage}
|
||||
pagination={pagination}
|
||||
tableToDisplay={buildTable()}
|
||||
paginationQueryParamPrefix="message-model-list"
|
||||
/>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}
|
|
@ -314,3 +314,4 @@ export const renderElementsForArray = (elements: ElementForArray[]) => {
|
|||
<div key={element.key}>{element.component}</div>
|
||||
));
|
||||
};
|
||||
|
||||
|
|
|
@ -276,6 +276,10 @@ h1.with-icons {
|
|||
margin-top: 5px;
|
||||
}
|
||||
|
||||
h3.with-icons {
|
||||
margin-top: 12px;
|
||||
}
|
||||
|
||||
.with-icons {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
@ -1004,9 +1008,18 @@ div.onboarding {
|
|||
text-align: right; /* Aligns text to the right within the container */
|
||||
}
|
||||
|
||||
div.retrievalExpressionsForm {
|
||||
border: 1px solid #999;
|
||||
border-radius: 15px;
|
||||
background: #ddd;
|
||||
padding: 20px;
|
||||
margin: 20px;
|
||||
}
|
||||
|
||||
.task-info-modal-accordion .cds--accordion__content {
|
||||
padding-right: 1rem;
|
||||
}
|
||||
|
||||
.task-instance-modal-row-item {
|
||||
height: 48px;
|
||||
line-height: 48px;
|
||||
|
|
|
@ -212,26 +212,46 @@ export interface ProcessInstance {
|
|||
process_model_uses_queued_execution?: boolean;
|
||||
}
|
||||
|
||||
export interface MessageCorrelationProperties {
|
||||
[key: string]: string;
|
||||
export interface CorrelationProperty {
|
||||
retrieval_expressions: string[];
|
||||
}
|
||||
|
||||
export interface MessageCorrelations {
|
||||
[key: string]: MessageCorrelationProperties;
|
||||
export interface CorrelationProperties {
|
||||
[key: string]: CorrelationProperty;
|
||||
}
|
||||
|
||||
export interface MessageDefinition {
|
||||
correlation_properties: CorrelationProperties;
|
||||
schema: any;
|
||||
}
|
||||
|
||||
export interface Messages {
|
||||
[key: string]: MessageDefinition;
|
||||
}
|
||||
|
||||
type ReferenceCacheType = 'decision' | 'process' | 'data_store' | 'message';
|
||||
|
||||
export interface ReferenceCache {
|
||||
identifier: string;
|
||||
display_name: string;
|
||||
relative_location: string;
|
||||
type: ReferenceCacheType;
|
||||
file_name: string;
|
||||
properties: any;
|
||||
}
|
||||
|
||||
export interface MessageInstance {
|
||||
id: number;
|
||||
process_model_identifier: string;
|
||||
process_model_display_name: string;
|
||||
process_instance_id: number;
|
||||
name: string;
|
||||
message_type: string;
|
||||
failure_cause: string;
|
||||
status: string;
|
||||
created_at_in_seconds: number;
|
||||
message_correlations?: MessageCorrelations;
|
||||
correlation_keys: any;
|
||||
counterpart_id: number;
|
||||
created_at_in_seconds: number;
|
||||
failure_cause: string;
|
||||
id: number;
|
||||
message_type: string;
|
||||
name: string;
|
||||
process_instance_id: number;
|
||||
process_model_display_name: string;
|
||||
process_model_identifier: string;
|
||||
status: string;
|
||||
}
|
||||
|
||||
export interface ReportFilter {
|
||||
|
@ -299,6 +319,7 @@ export interface ProcessGroup {
|
|||
process_models?: ProcessModel[];
|
||||
process_groups?: ProcessGroup[];
|
||||
parent_groups?: ProcessGroupLite[];
|
||||
messages?: Messages;
|
||||
}
|
||||
|
||||
export interface HotCrumbItemObject {
|
||||
|
@ -523,3 +544,7 @@ export interface PublicTask {
|
|||
process_instance_id: number;
|
||||
confirmation_message_markdown: string;
|
||||
}
|
||||
|
||||
export interface RJSFFormObject {
|
||||
formData: any;
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ export default function DataStoreNew() {
|
|||
id: '',
|
||||
name: '',
|
||||
type: '',
|
||||
schema: '',
|
||||
schema: '{}',
|
||||
description: '',
|
||||
});
|
||||
useEffect(() => {
|
||||
|
|
|
@ -1,8 +1,31 @@
|
|||
import MessageInstanceList from '../components/MessageInstanceList';
|
||||
import MessageInstanceList from '../components/messages/MessageInstanceList';
|
||||
import { setPageTitle } from '../helpers';
|
||||
|
||||
export default function MessageListPage() {
|
||||
setPageTitle(['Messages']);
|
||||
|
||||
// TODO: add tabs back in when MessageModelList is working again
|
||||
// TODO: only load the component for the tab we are currently on
|
||||
// return (
|
||||
// <>
|
||||
// <h1>Messages</h1>
|
||||
// <Tabs>
|
||||
// <TabList aria-label="List of tabs">
|
||||
// <Tab>Message Instances</Tab>
|
||||
// <Tab>Message Models</Tab>
|
||||
// </TabList>
|
||||
// <TabPanels>
|
||||
// <TabPanel>
|
||||
// <MessageInstanceList />
|
||||
// </TabPanel>
|
||||
// <TabPanel>
|
||||
// <MessageModelList />
|
||||
// </TabPanel>
|
||||
// </TabPanels>
|
||||
// </Tabs>
|
||||
// </>
|
||||
// );
|
||||
|
||||
return (
|
||||
<>
|
||||
<h1>Messages</h1>
|
||||
|
|
|
@ -76,7 +76,7 @@ import TaskListTable from '../components/TaskListTable';
|
|||
import useAPIError from '../hooks/UseApiError';
|
||||
import UserSearch from '../components/UserSearch';
|
||||
import ProcessInstanceLogList from '../components/ProcessInstanceLogList';
|
||||
import MessageInstanceList from '../components/MessageInstanceList';
|
||||
import MessageInstanceList from '../components/messages/MessageInstanceList';
|
||||
import {
|
||||
childrenForErrorObject,
|
||||
errorForDisplayFromString,
|
||||
|
@ -1800,11 +1800,7 @@ export default function ProcessInstanceShow({ variant }: OwnProps) {
|
|||
<Tab>Tasks</Tab>
|
||||
</TabList>
|
||||
<TabPanels>
|
||||
<TabPanel>
|
||||
{selectedTabIndex === 0 ? (
|
||||
<TabPanel>{diagramArea()}</TabPanel>
|
||||
) : null}
|
||||
</TabPanel>
|
||||
<TabPanel>{selectedTabIndex === 0 ? diagramArea() : null}</TabPanel>
|
||||
<TabPanel>
|
||||
{selectedTabIndex === 1 ? (
|
||||
<ProcessInstanceLogList
|
||||
|
|
|
@ -39,6 +39,7 @@ import ReactFormBuilder from '../components/ReactFormBuilder/ReactFormBuilder';
|
|||
import ProcessBreadcrumb from '../components/ProcessBreadcrumb';
|
||||
import useAPIError from '../hooks/UseApiError';
|
||||
import {
|
||||
getGroupFromModifiedModelId,
|
||||
makeid,
|
||||
modifyProcessIdentifierForPathParam,
|
||||
setPageTitle,
|
||||
|
@ -56,6 +57,7 @@ import { useFocusedTabStatus } from '../hooks/useFocusedTabStatus';
|
|||
import useScriptAssistEnabled from '../hooks/useScriptAssistEnabled';
|
||||
import useProcessScriptAssistMessage from '../hooks/useProcessScriptAssistQuery';
|
||||
import SpiffTooltip from '../components/SpiffTooltip';
|
||||
import { MessageEditor } from '../components/messages/MessageEditor';
|
||||
|
||||
export default function ProcessModelEditDiagram() {
|
||||
const [showFileNameEditor, setShowFileNameEditor] = useState(false);
|
||||
|
@ -79,6 +81,9 @@ export default function ProcessModelEditDiagram() {
|
|||
const [markdownText, setMarkdownText] = useState<string | undefined>('');
|
||||
const [markdownEventBus, setMarkdownEventBus] = useState<any>(null);
|
||||
const [showMarkdownEditor, setShowMarkdownEditor] = useState(false);
|
||||
const [showMessageEditor, setShowMessageEditor] = useState(false);
|
||||
const [messageId, setMessageId] = useState<string>('');
|
||||
const [correlationProperties, setCorrelationProperties] = useState<any>([]);
|
||||
const [showProcessSearch, setShowProcessSearch] = useState(false);
|
||||
const [processSearchEventBus, setProcessSearchEventBus] = useState<any>(null);
|
||||
const [processSearchElement, setProcessSearchElement] = useState<any>(null);
|
||||
|
@ -88,8 +93,12 @@ export default function ProcessModelEditDiagram() {
|
|||
const [processModelFileInvalidText, setProcessModelFileInvalidText] =
|
||||
useState<string>('');
|
||||
|
||||
const [messageEvent, setMessageEvent] = useState<any>(null);
|
||||
|
||||
const handleShowMarkdownEditor = () => setShowMarkdownEditor(true);
|
||||
|
||||
const handleShowMessageEditor = () => setShowMessageEditor(true);
|
||||
|
||||
const editorRef = useRef(null);
|
||||
const monacoRef = useRef(null);
|
||||
|
||||
|
@ -435,6 +444,20 @@ export default function ProcessModelEditDiagram() {
|
|||
}
|
||||
};
|
||||
|
||||
const makeMessagesRequestedHandler = (event: any) => {
|
||||
return function fireEvent(results: any) {
|
||||
event.eventBus.fire('spiff.messages.returned', {
|
||||
configuration: results,
|
||||
});
|
||||
};
|
||||
};
|
||||
const onMessagesRequested = (event: any) => {
|
||||
HttpService.makeCallToBackend({
|
||||
path: `/message-models/${modifiedProcessModelId}`,
|
||||
successCallback: makeMessagesRequestedHandler(event),
|
||||
});
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const updateDiagramFiles = (pm: ProcessModel) => {
|
||||
setProcessModel(pm);
|
||||
|
@ -1036,6 +1059,46 @@ export default function ProcessModelEditDiagram() {
|
|||
);
|
||||
};
|
||||
|
||||
const onLaunchMessageEditor = (event: any) => {
|
||||
setMessageEvent(event);
|
||||
setMessageId(event.value.messageId);
|
||||
setCorrelationProperties(event.value.correlation_properties);
|
||||
handleShowMessageEditor();
|
||||
};
|
||||
const handleMessageEditorClose = () => {
|
||||
setShowMessageEditor(false);
|
||||
onMessagesRequested(messageEvent);
|
||||
};
|
||||
|
||||
const messageEditor = () => {
|
||||
// do not render this component until we actually want to display it
|
||||
if (!showMessageEditor) {
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<Modal
|
||||
open={showMessageEditor}
|
||||
modalHeading="Create/Edit Message"
|
||||
primaryButtonText="Close (this does not save)"
|
||||
onRequestSubmit={handleMessageEditorClose}
|
||||
onRequestClose={handleMessageEditorClose}
|
||||
size="lg"
|
||||
preventCloseOnClickOutside
|
||||
>
|
||||
<div data-color-mode="light">
|
||||
<MessageEditor
|
||||
modifiedProcessGroupIdentifier={getGroupFromModifiedModelId(
|
||||
modifiedProcessModelId,
|
||||
)}
|
||||
messageId={messageId}
|
||||
correlationProperties={correlationProperties}
|
||||
messageEvent={messageEvent}
|
||||
/>
|
||||
</div>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
|
||||
const onSearchProcessModels = (
|
||||
_processId: string,
|
||||
eventBus: any,
|
||||
|
@ -1141,7 +1204,7 @@ export default function ProcessModelEditDiagram() {
|
|||
};
|
||||
|
||||
const onLaunchJsonSchemaEditor = (
|
||||
element: any,
|
||||
_element: any,
|
||||
fileName: string,
|
||||
eventBus: any,
|
||||
) => {
|
||||
|
@ -1232,28 +1295,30 @@ export default function ProcessModelEditDiagram() {
|
|||
}
|
||||
return (
|
||||
<ReactDiagramEditor
|
||||
activeUserElement={<ActiveUsers />}
|
||||
callers={callers}
|
||||
diagramType="bpmn"
|
||||
diagramXML={bpmnXmlForDiagramRendering}
|
||||
disableSaveButton={!diagramHasChanges}
|
||||
fileName={params.file_name}
|
||||
isPrimaryFile={params.file_name === processModel?.primary_file_name}
|
||||
onDataStoresRequested={onDataStoresRequested}
|
||||
onDeleteFile={onDeleteFile}
|
||||
onDmnFilesRequested={onDmnFilesRequested}
|
||||
onElementsChanged={onElementsChanged}
|
||||
onJsonSchemaFilesRequested={onJsonSchemaFilesRequested}
|
||||
onLaunchBpmnEditor={onLaunchBpmnEditor}
|
||||
onLaunchDmnEditor={onLaunchDmnEditor}
|
||||
onLaunchJsonSchemaEditor={onLaunchJsonSchemaEditor}
|
||||
onLaunchMarkdownEditor={onLaunchMarkdownEditor}
|
||||
onLaunchScriptEditor={onLaunchScriptEditor}
|
||||
onLaunchMessageEditor={onLaunchMessageEditor}
|
||||
onMessagesRequested={onMessagesRequested}
|
||||
onSearchProcessModels={onSearchProcessModels}
|
||||
onServiceTasksRequested={onServiceTasksRequested}
|
||||
onSetPrimaryFile={onSetPrimaryFileCallback}
|
||||
processModelId={params.process_model_id || ''}
|
||||
saveDiagram={saveDiagram}
|
||||
onDeleteFile={onDeleteFile}
|
||||
isPrimaryFile={params.file_name === processModel?.primary_file_name}
|
||||
onSetPrimaryFile={onSetPrimaryFileCallback}
|
||||
diagramXML={bpmnXmlForDiagramRendering}
|
||||
fileName={params.file_name}
|
||||
diagramType="bpmn"
|
||||
onLaunchScriptEditor={onLaunchScriptEditor}
|
||||
onServiceTasksRequested={onServiceTasksRequested}
|
||||
onDataStoresRequested={onDataStoresRequested}
|
||||
onLaunchMarkdownEditor={onLaunchMarkdownEditor}
|
||||
onLaunchBpmnEditor={onLaunchBpmnEditor}
|
||||
onLaunchJsonSchemaEditor={onLaunchJsonSchemaEditor}
|
||||
onJsonSchemaFilesRequested={onJsonSchemaFilesRequested}
|
||||
onLaunchDmnEditor={onLaunchDmnEditor}
|
||||
onDmnFilesRequested={onDmnFilesRequested}
|
||||
onSearchProcessModels={onSearchProcessModels}
|
||||
onElementsChanged={onElementsChanged}
|
||||
callers={callers}
|
||||
activeUserElement={<ActiveUsers />}
|
||||
disableSaveButton={!diagramHasChanges}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
@ -1298,6 +1363,7 @@ export default function ProcessModelEditDiagram() {
|
|||
{markdownEditor()}
|
||||
{jsonSchemaEditor()}
|
||||
{processModelSelector()}
|
||||
{messageEditor()}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
@ -1327,7 +1393,6 @@ export default function ProcessModelEditDiagram() {
|
|||
|
||||
{unsavedChangesMessage()}
|
||||
{saveFileMessage()}
|
||||
|
||||
{appropriateEditor()}
|
||||
<div id="diagram-container" />
|
||||
</>
|
||||
|
|
Loading…
Reference in New Issue