merged in main and resolved conflicts w/ burnettk
This commit is contained in:
commit
9a1a8a4fbe
|
@ -3,7 +3,7 @@ import {
|
|||
BpmnPropertiesPanelModule,
|
||||
BpmnPropertiesProviderModule,
|
||||
} from 'bpmn-js-properties-panel';
|
||||
import diagramXML from '../test/spec/bpmn/basic_message.bpmn';
|
||||
import diagramXML from '../test/spec/bpmn/empty_diagram.bpmn';
|
||||
import spiffworkflow from './spiffworkflow';
|
||||
import setupFileOperations from './fileOperations';
|
||||
|
||||
|
|
|
@ -4,9 +4,9 @@
|
|||
* @param container
|
||||
*/
|
||||
|
||||
|
||||
export function findDataObjects(parent) {
|
||||
let dataObjects = [];
|
||||
export function findDataObjects(parent, dataObjects) {
|
||||
if (typeof(dataObjects) === 'undefined')
|
||||
dataObjects = [];
|
||||
let process;
|
||||
if (!parent) {
|
||||
return [];
|
||||
|
@ -15,16 +15,13 @@ export function findDataObjects(parent) {
|
|||
process = parent.processRef;
|
||||
} else {
|
||||
process = parent;
|
||||
if (process.$type === 'bpmn:SubProcess')
|
||||
findDataObjects(process.$parent, dataObjects);
|
||||
}
|
||||
if (!process.flowElements) {
|
||||
return [];
|
||||
}
|
||||
for (const element of process.flowElements) {
|
||||
if (
|
||||
element.$type === 'bpmn:DataObject' &&
|
||||
dataObjects.indexOf(element) < 0
|
||||
) {
|
||||
dataObjects.push(element);
|
||||
if (typeof(process.flowElements) !== 'undefined') {
|
||||
for (const element of process.flowElements) {
|
||||
if (element.$type === 'bpmn:DataObject')
|
||||
dataObjects.push(element);
|
||||
}
|
||||
}
|
||||
return dataObjects;
|
||||
|
@ -38,16 +35,26 @@ export function findDataObject(process, id) {
|
|||
}
|
||||
}
|
||||
|
||||
export function findDataReferenceShapes(processShape, id) {
|
||||
let refs = [];
|
||||
for (const shape of processShape.children) {
|
||||
if (shape.type === 'bpmn:DataObjectReference') {
|
||||
if (shape.businessObject.dataObjectRef && shape.businessObject.dataObjectRef.id === id) {
|
||||
refs.push(shape);
|
||||
}
|
||||
}
|
||||
}
|
||||
return refs;
|
||||
export function findDataObjectReferences(children, dataObjectId) {
|
||||
return children.flatMap((child) => {
|
||||
if (child.$type == 'bpmn:DataObjectReference' && child.dataObjectRef.id == dataObjectId)
|
||||
return [child];
|
||||
else if (child.$type == 'bpmn:SubProcess')
|
||||
return findDataObjectReferences(child.get('flowElements'), dataObjectId);
|
||||
else
|
||||
return [];
|
||||
});
|
||||
}
|
||||
|
||||
export function findDataObjectReferenceShapes(children, dataObjectId) {
|
||||
return children.flatMap((child) => {
|
||||
if (child.type == 'bpmn:DataObjectReference' && child.businessObject.dataObjectRef.id == dataObjectId)
|
||||
return [child];
|
||||
else if (child.type == 'bpmn:SubProcess')
|
||||
return findDataObjectReferenceShapes(child.children, dataObjectId);
|
||||
else
|
||||
return [];
|
||||
});
|
||||
}
|
||||
|
||||
export function idToHumanReadableName(id) {
|
||||
|
|
|
@ -3,11 +3,12 @@ import { getDi, is } from 'bpmn-js/lib/util/ModelUtil';
|
|||
import { remove as collectionRemove } from 'diagram-js/lib/util/Collections';
|
||||
import {
|
||||
findDataObjects,
|
||||
findDataReferenceShapes,
|
||||
findDataObjectReferences,
|
||||
idToHumanReadableName,
|
||||
} from './DataObjectHelpers';
|
||||
|
||||
const HIGH_PRIORITY = 1500;
|
||||
|
||||
/**
|
||||
* This Command Interceptor functions like the BpmnUpdator in BPMN.js - It hooks into events
|
||||
* from Diagram.js and updates the underlying BPMN model accordingly.
|
||||
|
@ -20,9 +21,40 @@ const HIGH_PRIORITY = 1500;
|
|||
* 4) Don't allow someone to move a DataObjectReference from one process to another process.
|
||||
*/
|
||||
export default class DataObjectInterceptor extends CommandInterceptor {
|
||||
constructor(eventBus, bpmnFactory, commandStack) {
|
||||
|
||||
constructor(eventBus, bpmnFactory, commandStack, bpmnUpdater) {
|
||||
super(eventBus);
|
||||
|
||||
/* The default behavior is to move the data object into whatever object the reference is being created in.
|
||||
* If a data object already has a parent, don't change it.
|
||||
*/
|
||||
bpmnUpdater.updateSemanticParent = (businessObject, parentBusinessObject) => {
|
||||
// Special case for participant - which is a valid place to drop a data object, but it needs to be added
|
||||
// to the particpant's Process (which isn't directly accessible in BPMN.io
|
||||
let realParent = parentBusinessObject;
|
||||
if (is(realParent, 'bpmn:Participant')) {
|
||||
realParent = realParent.processRef;
|
||||
}
|
||||
|
||||
if (is(businessObject, 'bpmn:DataObjectReference')) {
|
||||
// For data object references, always update the flowElements when a parent is provided
|
||||
// The parent could be null if it's being deleted, and I could probably handle that here instead of
|
||||
// when the shape is deleted, but not interested in refactoring at the moment.
|
||||
if (realParent != null) {
|
||||
const flowElements = realParent.get('flowElements');
|
||||
flowElements.push(businessObject);
|
||||
}
|
||||
} else if (is(businessObject, 'bpmn:DataObject')) {
|
||||
// For data objects, only update the flowElements for new data objects, and set the parent so it doesn't get moved.
|
||||
if (typeof(businessObject.$parent) === 'undefined') {
|
||||
const flowElements = realParent.get('flowElements');
|
||||
flowElements.push(businessObject);
|
||||
businessObject.$parent = realParent;
|
||||
}
|
||||
} else
|
||||
bpmnUpdater.__proto__.updateSemanticParent.call(this, businessObject, parentBusinessObject);
|
||||
};
|
||||
|
||||
/**
|
||||
* For DataObjectReferences only ...
|
||||
* Prevent this from calling the CreateDataObjectBehavior in BPMN-js, as it will
|
||||
|
@ -52,9 +84,9 @@ export default class DataObjectInterceptor extends CommandInterceptor {
|
|||
} else {
|
||||
dataObject = bpmnFactory.create('bpmn:DataObject');
|
||||
}
|
||||
|
||||
// set the reference to the DataObject
|
||||
shape.businessObject.dataObjectRef = dataObject;
|
||||
shape.businessObject.$parent = process;
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -84,38 +116,19 @@ export default class DataObjectInterceptor extends CommandInterceptor {
|
|||
*/
|
||||
this.executed(['shape.delete'], HIGH_PRIORITY, function (event) {
|
||||
const { context } = event;
|
||||
const { shape, oldParent } = context;
|
||||
const { shape } = context;
|
||||
if (is(shape, 'bpmn:DataObjectReference') && shape.type !== 'label') {
|
||||
const references = findDataReferenceShapes(
|
||||
oldParent,
|
||||
shape.businessObject.dataObjectRef.id
|
||||
);
|
||||
const dataObject = shape.businessObject.dataObjectRef;
|
||||
let flowElements = shape.businessObject.$parent.get('flowElements');
|
||||
collectionRemove(flowElements, shape.businessObject);
|
||||
let references = findDataObjectReferences(flowElements, dataObject.id);
|
||||
if (references.length === 0) {
|
||||
return; // Use the default bahavior and delete the data object.
|
||||
let flowElements = dataObject.$parent.get('flowElements');
|
||||
collectionRemove(flowElements, dataObject);
|
||||
}
|
||||
// Remove the business Object
|
||||
let containment = '';
|
||||
const { businessObject } = shape;
|
||||
if (is(businessObject, 'bpmn:DataOutputAssociation')) {
|
||||
containment = 'dataOutputAssociations';
|
||||
}
|
||||
if (is(businessObject, 'bpmn:DataInputAssociation')) {
|
||||
containment = 'dataInputAssociations';
|
||||
}
|
||||
const children = businessObject.$parent.get(containment);
|
||||
collectionRemove(children, businessObject);
|
||||
|
||||
// Remove the visible element.
|
||||
const di = getDi(shape);
|
||||
const planeElements = di.$parent.get('planeElement');
|
||||
collectionRemove(planeElements, di);
|
||||
di.$parent = null;
|
||||
|
||||
// Stop the propogation.
|
||||
event.stopPropagation();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
DataObjectInterceptor.$inject = ['eventBus', 'bpmnFactory', 'commandStack'];
|
||||
DataObjectInterceptor.$inject = ['eventBus', 'bpmnFactory', 'commandStack', 'bpmnUpdater'];
|
||||
|
|
|
@ -5,7 +5,11 @@ import {
|
|||
} from '@bpmn-io/properties-panel';
|
||||
import { without } from 'min-dash';
|
||||
import { is } from 'bpmn-js/lib/util/ModelUtil';
|
||||
import {findDataObjects, findDataReferenceShapes, idToHumanReadableName} from '../DataObjectHelpers';
|
||||
import {
|
||||
findDataObjects,
|
||||
findDataObjectReferenceShapes,
|
||||
idToHumanReadableName,
|
||||
} from '../DataObjectHelpers';
|
||||
|
||||
/**
|
||||
* Provides a list of data objects, and allows you to add / remove data objects, and change their ids.
|
||||
|
@ -20,7 +24,7 @@ export function DataObjectArray(props) {
|
|||
let process;
|
||||
|
||||
// This element might be a process, or something that will reference a process.
|
||||
if (is(element.businessObject, 'bpmn:Process')) {
|
||||
if (is(element.businessObject, 'bpmn:Process') || is(element.businessObject, 'bpmn:SubProcess')) {
|
||||
process = element.businessObject;
|
||||
} else if (element.businessObject.processRef) {
|
||||
process = element.businessObject.processRef;
|
||||
|
@ -53,6 +57,7 @@ export function DataObjectArray(props) {
|
|||
const newDataObject = moddle.create('bpmn:DataObject');
|
||||
const newElements = process.get('flowElements');
|
||||
newDataObject.id = moddle.ids.nextPrefixed('DataObject_');
|
||||
newDataObject.$parent = process;
|
||||
newElements.push(newDataObject);
|
||||
commandStack.execute('element.updateModdleProperties', {
|
||||
element,
|
||||
|
@ -79,7 +84,7 @@ function removeFactory(props) {
|
|||
},
|
||||
});
|
||||
// When a data object is removed, remove all references as well.
|
||||
const references = findDataReferenceShapes(element, dataObject.id);
|
||||
const references = findDataObjectReferenceShapes(element.children, dataObject.id);
|
||||
for (const ref of references) {
|
||||
commandStack.execute('shape.delete', { shape: ref });
|
||||
}
|
||||
|
@ -116,7 +121,7 @@ function DataObjectTextField(props) {
|
|||
});
|
||||
|
||||
// Also update the label of all the references
|
||||
const references = findDataReferenceShapes(element, dataObject.id);
|
||||
const references = findDataObjectReferenceShapes(element.children, dataObject.id);
|
||||
for (const ref of references) {
|
||||
commandStack.execute('element.updateProperties', {
|
||||
element: ref,
|
||||
|
|
|
@ -20,7 +20,8 @@ export default function DataObjectPropertiesProvider(
|
|||
);
|
||||
}
|
||||
if (
|
||||
isAny(element, ['bpmn:Process', 'bpmn:SubProcess', 'bpmn:Participant'])
|
||||
isAny(element, ['bpmn:Process', 'bpmn:Participant']) ||
|
||||
(is(element, 'bpmn:SubProcess') && !element.collapsed)
|
||||
) {
|
||||
groups.push(
|
||||
createDataObjectEditor(
|
||||
|
|
|
@ -4,7 +4,11 @@ import { BpmnPropertiesPanelModule, BpmnPropertiesProviderModule } from 'bpmn-js
|
|||
import {
|
||||
inject,
|
||||
} from 'bpmn-js/test/helper';
|
||||
import {findDataObjects, idToHumanReadableName} from '../../app/spiffworkflow/DataObject/DataObjectHelpers';
|
||||
import {
|
||||
findDataObjects,
|
||||
findDataObjectReferenceShapes,
|
||||
idToHumanReadableName,
|
||||
} from '../../app/spiffworkflow/DataObject/DataObjectHelpers';
|
||||
|
||||
describe('DataObject Interceptor', function() {
|
||||
|
||||
|
@ -113,4 +117,52 @@ describe('DataObject Interceptor', function() {
|
|||
expect(dataObjects.length).to.equal(1);
|
||||
}));
|
||||
|
||||
it('Data objects in a process should be visible in a subprocess', inject(function(canvas, modeling, elementRegistry) {
|
||||
|
||||
let subProcessShape = elementRegistry.get('my_subprocess');
|
||||
let subProcess = subProcessShape.businessObject;
|
||||
let dataObjects = findDataObjects(subProcess);
|
||||
expect(dataObjects.length).to.equal(0);
|
||||
|
||||
let rootShape = canvas.getRootElement();
|
||||
const dataObjectRefShape = modeling.createShape({ type: 'bpmn:DataObjectReference' },
|
||||
{ x: 220, y: 220 }, rootShape);
|
||||
|
||||
dataObjects = findDataObjects(subProcess);
|
||||
expect(dataObjects.length).to.equal(1);
|
||||
}));
|
||||
|
||||
it('Data objects in a subprocess should not be visible in a process', inject(function(canvas, modeling, elementRegistry) {
|
||||
|
||||
let subProcessShape = elementRegistry.get('my_subprocess');
|
||||
let subProcess = subProcessShape.businessObject;
|
||||
const dataObjectRefShape = modeling.createShape({ type: 'bpmn:DataObjectReference' },
|
||||
{ x: 220, y: 220 }, subProcessShape);
|
||||
|
||||
let dataObjects = findDataObjects(subProcess);
|
||||
expect(dataObjects.length).to.equal(1);
|
||||
|
||||
let rootShape = canvas.getRootElement();
|
||||
dataObjects = findDataObjects(rootShape);
|
||||
expect(dataObjects.length).to.equal(0);
|
||||
}));
|
||||
|
||||
it('References inside subprocesses should be visible in a process', inject(function(canvas, modeling, elementRegistry) {
|
||||
|
||||
let rootShape = canvas.getRootElement();
|
||||
const refOne = modeling.createShape({ type: 'bpmn:DataObjectReference' },
|
||||
{ x: 220, y: 220 }, rootShape);
|
||||
|
||||
let subProcessShape = elementRegistry.get('my_subprocess');
|
||||
let subProcess = subProcessShape.businessObject;
|
||||
const refTwo = modeling.createShape({ type: 'bpmn:DataObjectReference' },
|
||||
{ x: 320, y: 220 }, subProcessShape);
|
||||
|
||||
let dataObjects = findDataObjects(subProcess);
|
||||
expect(dataObjects.length).to.equal(1);
|
||||
let references = findDataObjectReferenceShapes(rootShape.children, dataObjects[0].id);
|
||||
expect(references.length).to.equal(2);
|
||||
|
||||
}));
|
||||
|
||||
});
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,10 +1,10 @@
|
|||
[tool.poetry]
|
||||
name = "spiffworkflow-arean"
|
||||
name = "spiffworkflow-arena"
|
||||
version = "0.0.0"
|
||||
description = "Spiffworkflow Arena"
|
||||
authors = ["Jason Lantz <sartography@users.noreply.github.com>"]
|
||||
license = "MIT"
|
||||
readme = "README.rst"
|
||||
readme = "README.md"
|
||||
homepage = "https://github.com/sartography/spiffworkflow-arena"
|
||||
repository = "https://github.com/sartography/spiffworkflow-arena"
|
||||
classifiers = [
|
||||
|
@ -48,7 +48,6 @@ APScheduler = "^3.9.1"
|
|||
Jinja2 = "^3.1.2"
|
||||
RestrictedPython = "^6.0"
|
||||
Flask-SQLAlchemy = "^3"
|
||||
orjson = "^3.8.0"
|
||||
|
||||
# type hinting stuff
|
||||
# these need to be in the normal (non dev-dependencies) section
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
"""empty message
|
||||
|
||||
Revision ID: 55b76c4528c5
|
||||
Revision ID: ede2ae7d3c80
|
||||
Revises:
|
||||
Create Date: 2023-03-06 11:11:55.431564
|
||||
Create Date: 2023-03-06 11:14:40.739641
|
||||
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
from sqlalchemy.dialects import mysql
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = '55b76c4528c5'
|
||||
revision = 'ede2ae7d3c80'
|
||||
down_revision = None
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
@ -303,7 +303,7 @@ def upgrade():
|
|||
sa.Column('list_index', sa.Integer(), nullable=True),
|
||||
sa.Column('mimetype', sa.String(length=255), nullable=False),
|
||||
sa.Column('filename', sa.String(length=255), nullable=False),
|
||||
sa.Column('contents', sa.LargeBinary(), nullable=False),
|
||||
sa.Column('contents', sa.LargeBinary().with_variant(mysql.LONGBLOB(), 'mysql'), nullable=False),
|
||||
sa.Column('digest', sa.String(length=64), nullable=False),
|
||||
sa.Column('updated_at_in_seconds', sa.Integer(), nullable=False),
|
||||
sa.Column('created_at_in_seconds', sa.Integer(), nullable=False),
|
File diff suppressed because it is too large
Load Diff
|
@ -75,7 +75,7 @@ pylint = "^2.15.10"
|
|||
|
||||
|
||||
[tool.poetry.dev-dependencies]
|
||||
pytest = "*"
|
||||
pytest = "^7.1.2"
|
||||
coverage = {extras = ["toml"], version = "^6.1"}
|
||||
safety = "^2.3.1"
|
||||
mypy = ">=0.961"
|
||||
|
@ -84,12 +84,12 @@ xdoctest = {extras = ["colors"], version = "^1.0.1"}
|
|||
sphinx = "^5.0.2"
|
||||
sphinx-autobuild = ">=2021.3.14"
|
||||
pre-commit = "^2.20.0"
|
||||
flake8 = "*"
|
||||
flake8 = "^4.0.1"
|
||||
black = ">=21.10b0"
|
||||
flake8-bandit = "*"
|
||||
flake8-bandit = "^2.1.2"
|
||||
|
||||
# 1.7.3 broke us. https://github.com/PyCQA/bandit/issues/841
|
||||
bandit = "*"
|
||||
bandit = "1.7.2"
|
||||
|
||||
flake8-bugbear = "^22.10.25"
|
||||
flake8-docstrings = "^1.6.0"
|
||||
|
|
|
@ -3,6 +3,7 @@ from dataclasses import dataclass
|
|||
from typing import Optional
|
||||
|
||||
from sqlalchemy import ForeignKey
|
||||
from sqlalchemy.dialects.mysql import LONGBLOB
|
||||
|
||||
from spiffworkflow_backend.models.db import db
|
||||
from spiffworkflow_backend.models.db import SpiffworkflowBaseDBModel
|
||||
|
@ -24,7 +25,9 @@ class ProcessInstanceFileDataModel(SpiffworkflowBaseDBModel):
|
|||
mimetype: str = db.Column(db.String(255), nullable=False)
|
||||
filename: str = db.Column(db.String(255), nullable=False)
|
||||
# this is not deferred because there is no reason to query this model if you do not want the contents
|
||||
contents: str = db.Column(db.LargeBinary, nullable=False)
|
||||
contents: str = db.Column(
|
||||
db.LargeBinary().with_variant(LONGBLOB, "mysql"), nullable=False
|
||||
)
|
||||
digest: str = db.Column(db.String(64), nullable=False, index=True)
|
||||
|
||||
updated_at_in_seconds: int = db.Column(db.Integer, nullable=False)
|
||||
|
|
|
@ -14,7 +14,6 @@ from sqlalchemy import ForeignKey
|
|||
from spiffworkflow_backend.models.bpmn_process import BpmnProcessModel
|
||||
from spiffworkflow_backend.models.db import db
|
||||
from spiffworkflow_backend.models.db import SpiffworkflowBaseDBModel
|
||||
from spiffworkflow_backend.models.task_definition import TaskDefinitionModel
|
||||
|
||||
|
||||
class MultiInstanceType(enum.Enum):
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
"""Process_instance_processor."""
|
||||
import _strptime # type: ignore
|
||||
from SpiffWorkflow.task import TaskStateNames # type: ignore
|
||||
from spiffworkflow_backend.models.task import TaskModel # noqa: F401
|
||||
from SpiffWorkflow.task import TaskStateNames # type: ignore
|
||||
from spiffworkflow_backend.models.task import TaskModel # noqa: F401
|
||||
import decimal
|
||||
import json
|
||||
import logging
|
||||
|
@ -987,7 +987,8 @@ class ProcessInstanceProcessor:
|
|||
|
||||
bpmn_process = None
|
||||
if bpmn_process_parent is not None:
|
||||
bpmn_process = BpmnProcessModel.query.filter_by(parent_process_id=bpmn_process_parent.id, guid=bpmn_process_guid).first()
|
||||
bpmn_process = BpmnProcessModel.query.filter_by(
|
||||
parent_process_id=bpmn_process_parent.id, guid=bpmn_process_guid).first()
|
||||
elif self.process_instance_model.bpmn_process_id is not None:
|
||||
bpmn_process = self.process_instance_model.bpmn_process
|
||||
|
||||
|
|
|
@ -24,13 +24,19 @@ const deleteVideosOnSuccess = (on) => {
|
|||
})
|
||||
}
|
||||
|
||||
let spiffWorkflowFrontendUrl = `http://localhost:${process.env.SPIFFWORKFLOW_FRONTEND_PORT || 7001}`
|
||||
|
||||
if (process.env.SPIFFWORKFLOW_FRONTEND_URL) {
|
||||
spiffWorkflowFrontendUrl = process.env.SPIFFWORKFLOW_FRONTEND_URL
|
||||
}
|
||||
|
||||
const cypressConfig = {
|
||||
projectId: 'crax1q',
|
||||
|
||||
videoUploadOnPasses: false,
|
||||
chromeWebSecurity: false,
|
||||
e2e: {
|
||||
baseUrl: `http://localhost:${process.env.SPIFFWORKFLOW_FRONTEND_PORT || 7001}`,
|
||||
baseUrl: spiffWorkflowFrontendUrl,
|
||||
setupNodeEvents(on, config) {
|
||||
deleteVideosOnSuccess(on)
|
||||
require('@cypress/grep/src/plugin')(config);
|
||||
|
|
|
@ -0,0 +1,104 @@
|
|||
const approveWithUser = (
|
||||
username,
|
||||
processInstanceId,
|
||||
expectAdditionalApprovalInfoPage = false
|
||||
) => {
|
||||
cy.login(username, username);
|
||||
cy.visit('/admin/process-instances/find-by-id');
|
||||
cy.get('#process-instance-id-input').type(processInstanceId);
|
||||
cy.get('button')
|
||||
.contains(/^Submit$/)
|
||||
.click();
|
||||
|
||||
cy.contains('Tasks I can complete', { timeout: 20000 });
|
||||
cy.get('.cds--btn').contains(/^Go$/).click();
|
||||
|
||||
// approve!
|
||||
cy.get('#root-app').click();
|
||||
cy.get('button')
|
||||
.contains(/^Submit$/)
|
||||
.click();
|
||||
if (expectAdditionalApprovalInfoPage) {
|
||||
cy.contains(expectAdditionalApprovalInfoPage, { timeout: 20000 });
|
||||
cy.get('button')
|
||||
.contains(/^Continue$/)
|
||||
.click();
|
||||
}
|
||||
cy.location({ timeout: 20000 }).should((loc) => {
|
||||
expect(loc.pathname).to.eq('/tasks');
|
||||
});
|
||||
cy.logout();
|
||||
};
|
||||
|
||||
describe('pp1', () => {
|
||||
it('can run PP1', () => {
|
||||
cy.login('core5.contributor', 'core5.contributor');
|
||||
cy.visit('/');
|
||||
cy.contains('Start New +').click();
|
||||
cy.contains('Raise New Demand Request');
|
||||
cy.runPrimaryBpmnFile(true);
|
||||
cy.contains('Procurement').click();
|
||||
// cy.contains('Submit').click();
|
||||
cy.get('button')
|
||||
.contains(/^Submit$/)
|
||||
.click();
|
||||
cy.contains(
|
||||
'Submit a new demand request for the procurement of needed items',
|
||||
{ timeout: 20000 }
|
||||
);
|
||||
|
||||
cy.url().then((currentUrl) => {
|
||||
// if url is "/tasks/8/d37c2f0f-016a-4066-b669-e0925b759560"
|
||||
// extract the digits after /tasks
|
||||
const processInstanceId = currentUrl.match(/(?<=\/tasks\/)\d+/)[0];
|
||||
|
||||
cy.get('#root_project').select('18564');
|
||||
cy.get('#root_category').select('soft_and_lic');
|
||||
cy.get('#root_purpose').clear().type('need the software for my work');
|
||||
cy.get('#root_criticality').select('High');
|
||||
cy.get('#root_period').clear().type('2023-10-10');
|
||||
cy.get('#root_vendor').clear().type('sartography');
|
||||
cy.get('#root_payment_method').select('Bank Transfer');
|
||||
cy.get('#root_project').select('18564');
|
||||
cy.get('#root_category').select('soft_and_lic');
|
||||
cy.get('button')
|
||||
.contains(/^Submit$/)
|
||||
.click();
|
||||
|
||||
cy.contains('Task: Enter NDR Items', { timeout: 20000 });
|
||||
cy.get('#root_0_sub_category').select('op_src');
|
||||
cy.get('#root_0_item').clear().type('spiffworkflow');
|
||||
cy.get('#root_0_qty').clear().type('1');
|
||||
cy.get('#root_0_currency_type').select('Fiat');
|
||||
cy.get('#root_0_currency').select('AUD');
|
||||
cy.get('#root_0_unit_price').type('100');
|
||||
cy.get('button')
|
||||
.contains(/^Submit$/)
|
||||
.click();
|
||||
|
||||
cy.contains(
|
||||
'Review and provide any supporting information or files for your request.'
|
||||
);
|
||||
cy.contains('Submit the Request').click();
|
||||
cy.get('input[value="Submit the Request"]').click();
|
||||
cy.get('button')
|
||||
.contains(/^Submit$/)
|
||||
.click();
|
||||
|
||||
cy.logout();
|
||||
approveWithUser(
|
||||
'infra.project-lead',
|
||||
processInstanceId,
|
||||
'Task: Reminder: Request Additional Budget'
|
||||
);
|
||||
approveWithUser('ppg.ba.sme', processInstanceId);
|
||||
approveWithUser('security.sme', processInstanceId);
|
||||
approveWithUser(
|
||||
'infra.sme',
|
||||
processInstanceId,
|
||||
'Task: Update Application Landscape'
|
||||
);
|
||||
approveWithUser('legal.sme', processInstanceId);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -41,10 +41,15 @@ Cypress.Commands.add('navigateToAdmin', () => {
|
|||
cy.visit('/admin');
|
||||
});
|
||||
|
||||
Cypress.Commands.add('login', (selector, ...args) => {
|
||||
Cypress.Commands.add('login', (username, password) => {
|
||||
// Cypress.Commands.add('login', (selector, ...args) => {
|
||||
cy.visit('/admin');
|
||||
const username = Cypress.env('SPIFFWORKFLOW_FRONTEND_USERNAME') || 'ciadmin1';
|
||||
const password = Cypress.env('SPIFFWORKFLOW_FRONTEND_PASSWORD') || 'ciadmin1';
|
||||
if (!username) {
|
||||
const username =
|
||||
Cypress.env('SPIFFWORKFLOW_FRONTEND_USERNAME') || 'ciadmin1';
|
||||
const password =
|
||||
Cypress.env('SPIFFWORKFLOW_FRONTEND_PASSWORD') || 'ciadmin1';
|
||||
}
|
||||
cy.get('#username').type(username);
|
||||
cy.get('#password').type(password);
|
||||
if (Cypress.env('SPIFFWORKFLOW_FRONTEND_AUTH_WITH_KEYCLOAK') === true) {
|
||||
|
@ -97,7 +102,12 @@ Cypress.Commands.add('createModel', (groupId, modelId, modelDisplayName) => {
|
|||
Cypress.Commands.add(
|
||||
'runPrimaryBpmnFile',
|
||||
(expectAutoRedirectToHumanTask = false) => {
|
||||
cy.contains('Start').click();
|
||||
// cy.getBySel('start-process-instance').click();
|
||||
// click on button with text Start
|
||||
|
||||
cy.get('button')
|
||||
.contains(/^Start$/)
|
||||
.click();
|
||||
if (expectAutoRedirectToHumanTask) {
|
||||
// the url changes immediately, so also make sure we get some content from the next page, "Task:", or else when we try to interact with the page, it'll re-render and we'll get an error with cypress.
|
||||
cy.url().should('include', `/tasks/`);
|
||||
|
|
|
@ -8065,7 +8065,7 @@
|
|||
},
|
||||
"node_modules/bpmn-js-spiffworkflow": {
|
||||
"version": "0.0.8",
|
||||
"resolved": "git+ssh://git@github.com/sartography/bpmn-js-spiffworkflow.git#f1f008e3e39be43b016718fca6a38b248ab4ecf7",
|
||||
"resolved": "git+ssh://git@github.com/sartography/bpmn-js-spiffworkflow.git#82260144f90d9a311155066d637664d9e2a3f02e",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"inherits": "^2.0.4",
|
||||
|
@ -38214,7 +38214,7 @@
|
|||
}
|
||||
},
|
||||
"bpmn-js-spiffworkflow": {
|
||||
"version": "git+ssh://git@github.com/sartography/bpmn-js-spiffworkflow.git#f1f008e3e39be43b016718fca6a38b248ab4ecf7",
|
||||
"version": "git+ssh://git@github.com/sartography/bpmn-js-spiffworkflow.git#82260144f90d9a311155066d637664d9e2a3f02e",
|
||||
"from": "bpmn-js-spiffworkflow@sartography/bpmn-js-spiffworkflow#main",
|
||||
"requires": {
|
||||
"inherits": "^2.0.4",
|
||||
|
|
|
@ -99,3 +99,6 @@ a:link {
|
|||
padding-bottom: 70px;
|
||||
min-height: 100%;
|
||||
}
|
||||
.djs-palette.two-column.open {
|
||||
width: 96px !important;
|
||||
}
|
||||
|
|
|
@ -126,7 +126,11 @@ export default function ProcessInstanceRun({
|
|||
if (checkPermissions) {
|
||||
return (
|
||||
<Can I="POST" a={processInstanceCreatePath} ability={ability}>
|
||||
<Button onClick={processInstanceCreateAndRun} className={className}>
|
||||
<Button
|
||||
data-qa="start-process-instance"
|
||||
onClick={processInstanceCreateAndRun}
|
||||
className={className}
|
||||
>
|
||||
Start
|
||||
</Button>
|
||||
</Can>
|
||||
|
|
Loading…
Reference in New Issue