mirror of
https://github.com/sartography/spiff-arena.git
synced 2025-02-27 16:40:32 +00:00
merged in main and resolved conflicts w/ burnettk
This commit is contained in:
commit
96ef81af34
4037
poetry.lock
generated
4037
poetry.lock
generated
File diff suppressed because it is too large
Load Diff
@ -1,10 +1,10 @@
|
|||||||
[tool.poetry]
|
[tool.poetry]
|
||||||
name = "spiffworkflow-arean"
|
name = "spiffworkflow-arena"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
description = "Spiffworkflow Arena"
|
description = "Spiffworkflow Arena"
|
||||||
authors = ["Jason Lantz <sartography@users.noreply.github.com>"]
|
authors = ["Jason Lantz <sartography@users.noreply.github.com>"]
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
readme = "README.rst"
|
readme = "README.md"
|
||||||
homepage = "https://github.com/sartography/spiffworkflow-arena"
|
homepage = "https://github.com/sartography/spiffworkflow-arena"
|
||||||
repository = "https://github.com/sartography/spiffworkflow-arena"
|
repository = "https://github.com/sartography/spiffworkflow-arena"
|
||||||
classifiers = [
|
classifiers = [
|
||||||
@ -48,7 +48,6 @@ APScheduler = "^3.9.1"
|
|||||||
Jinja2 = "^3.1.2"
|
Jinja2 = "^3.1.2"
|
||||||
RestrictedPython = "^6.0"
|
RestrictedPython = "^6.0"
|
||||||
Flask-SQLAlchemy = "^3"
|
Flask-SQLAlchemy = "^3"
|
||||||
orjson = "^3.8.0"
|
|
||||||
|
|
||||||
# type hinting stuff
|
# type hinting stuff
|
||||||
# these need to be in the normal (non dev-dependencies) section
|
# these need to be in the normal (non dev-dependencies) section
|
||||||
|
@ -1,16 +1,16 @@
|
|||||||
"""empty message
|
"""empty message
|
||||||
|
|
||||||
Revision ID: 55b76c4528c5
|
Revision ID: ede2ae7d3c80
|
||||||
Revises:
|
Revises:
|
||||||
Create Date: 2023-03-06 11:11:55.431564
|
Create Date: 2023-03-06 11:14:40.739641
|
||||||
|
|
||||||
"""
|
"""
|
||||||
from alembic import op
|
from alembic import op
|
||||||
import sqlalchemy as sa
|
import sqlalchemy as sa
|
||||||
|
from sqlalchemy.dialects import mysql
|
||||||
|
|
||||||
# revision identifiers, used by Alembic.
|
# revision identifiers, used by Alembic.
|
||||||
revision = '55b76c4528c5'
|
revision = 'ede2ae7d3c80'
|
||||||
down_revision = None
|
down_revision = None
|
||||||
branch_labels = None
|
branch_labels = None
|
||||||
depends_on = None
|
depends_on = None
|
||||||
@ -303,7 +303,7 @@ def upgrade():
|
|||||||
sa.Column('list_index', sa.Integer(), nullable=True),
|
sa.Column('list_index', sa.Integer(), nullable=True),
|
||||||
sa.Column('mimetype', sa.String(length=255), nullable=False),
|
sa.Column('mimetype', sa.String(length=255), nullable=False),
|
||||||
sa.Column('filename', 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('digest', sa.String(length=64), nullable=False),
|
||||||
sa.Column('updated_at_in_seconds', sa.Integer(), nullable=False),
|
sa.Column('updated_at_in_seconds', sa.Integer(), nullable=False),
|
||||||
sa.Column('created_at_in_seconds', sa.Integer(), nullable=False),
|
sa.Column('created_at_in_seconds', sa.Integer(), nullable=False),
|
4224
spiffworkflow-backend/poetry.lock
generated
4224
spiffworkflow-backend/poetry.lock
generated
File diff suppressed because it is too large
Load Diff
@ -75,7 +75,7 @@ pylint = "^2.15.10"
|
|||||||
|
|
||||||
|
|
||||||
[tool.poetry.dev-dependencies]
|
[tool.poetry.dev-dependencies]
|
||||||
pytest = "*"
|
pytest = "^7.1.2"
|
||||||
coverage = {extras = ["toml"], version = "^6.1"}
|
coverage = {extras = ["toml"], version = "^6.1"}
|
||||||
safety = "^2.3.1"
|
safety = "^2.3.1"
|
||||||
mypy = ">=0.961"
|
mypy = ">=0.961"
|
||||||
@ -84,12 +84,12 @@ xdoctest = {extras = ["colors"], version = "^1.0.1"}
|
|||||||
sphinx = "^5.0.2"
|
sphinx = "^5.0.2"
|
||||||
sphinx-autobuild = ">=2021.3.14"
|
sphinx-autobuild = ">=2021.3.14"
|
||||||
pre-commit = "^2.20.0"
|
pre-commit = "^2.20.0"
|
||||||
flake8 = "*"
|
flake8 = "^4.0.1"
|
||||||
black = ">=21.10b0"
|
black = ">=21.10b0"
|
||||||
flake8-bandit = "*"
|
flake8-bandit = "^2.1.2"
|
||||||
|
|
||||||
# 1.7.3 broke us. https://github.com/PyCQA/bandit/issues/841
|
# 1.7.3 broke us. https://github.com/PyCQA/bandit/issues/841
|
||||||
bandit = "*"
|
bandit = "1.7.2"
|
||||||
|
|
||||||
flake8-bugbear = "^22.10.25"
|
flake8-bugbear = "^22.10.25"
|
||||||
flake8-docstrings = "^1.6.0"
|
flake8-docstrings = "^1.6.0"
|
||||||
|
@ -3,6 +3,7 @@ from dataclasses import dataclass
|
|||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
from sqlalchemy import ForeignKey
|
from sqlalchemy import ForeignKey
|
||||||
|
from sqlalchemy.dialects.mysql import LONGBLOB
|
||||||
|
|
||||||
from spiffworkflow_backend.models.db import db
|
from spiffworkflow_backend.models.db import db
|
||||||
from spiffworkflow_backend.models.db import SpiffworkflowBaseDBModel
|
from spiffworkflow_backend.models.db import SpiffworkflowBaseDBModel
|
||||||
@ -24,7 +25,9 @@ class ProcessInstanceFileDataModel(SpiffworkflowBaseDBModel):
|
|||||||
mimetype: str = db.Column(db.String(255), nullable=False)
|
mimetype: str = db.Column(db.String(255), nullable=False)
|
||||||
filename: 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
|
# 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)
|
digest: str = db.Column(db.String(64), nullable=False, index=True)
|
||||||
|
|
||||||
updated_at_in_seconds: int = db.Column(db.Integer, nullable=False)
|
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.bpmn_process import BpmnProcessModel
|
||||||
from spiffworkflow_backend.models.db import db
|
from spiffworkflow_backend.models.db import db
|
||||||
from spiffworkflow_backend.models.db import SpiffworkflowBaseDBModel
|
from spiffworkflow_backend.models.db import SpiffworkflowBaseDBModel
|
||||||
from spiffworkflow_backend.models.task_definition import TaskDefinitionModel
|
|
||||||
|
|
||||||
|
|
||||||
class MultiInstanceType(enum.Enum):
|
class MultiInstanceType(enum.Enum):
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
"""Process_instance_processor."""
|
"""Process_instance_processor."""
|
||||||
import _strptime # type: ignore
|
import _strptime # type: ignore
|
||||||
from SpiffWorkflow.task import TaskStateNames # type: ignore
|
from SpiffWorkflow.task import TaskStateNames # type: ignore
|
||||||
from spiffworkflow_backend.models.task import TaskModel # noqa: F401
|
from spiffworkflow_backend.models.task import TaskModel # noqa: F401
|
||||||
import decimal
|
import decimal
|
||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
@ -987,7 +987,8 @@ class ProcessInstanceProcessor:
|
|||||||
|
|
||||||
bpmn_process = None
|
bpmn_process = None
|
||||||
if bpmn_process_parent is not 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:
|
elif self.process_instance_model.bpmn_process_id is not None:
|
||||||
bpmn_process = self.process_instance_model.bpmn_process
|
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 = {
|
const cypressConfig = {
|
||||||
projectId: 'crax1q',
|
projectId: 'crax1q',
|
||||||
|
|
||||||
videoUploadOnPasses: false,
|
videoUploadOnPasses: false,
|
||||||
chromeWebSecurity: false,
|
chromeWebSecurity: false,
|
||||||
e2e: {
|
e2e: {
|
||||||
baseUrl: `http://localhost:${process.env.SPIFFWORKFLOW_FRONTEND_PORT || 7001}`,
|
baseUrl: spiffWorkflowFrontendUrl,
|
||||||
setupNodeEvents(on, config) {
|
setupNodeEvents(on, config) {
|
||||||
deleteVideosOnSuccess(on)
|
deleteVideosOnSuccess(on)
|
||||||
require('@cypress/grep/src/plugin')(config);
|
require('@cypress/grep/src/plugin')(config);
|
||||||
|
104
spiffworkflow-frontend/cypress/e2e/pp1.cy.js
Normal file
104
spiffworkflow-frontend/cypress/e2e/pp1.cy.js
Normal file
@ -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');
|
cy.visit('/admin');
|
||||||
});
|
});
|
||||||
|
|
||||||
Cypress.Commands.add('login', (selector, ...args) => {
|
Cypress.Commands.add('login', (username, password) => {
|
||||||
|
// Cypress.Commands.add('login', (selector, ...args) => {
|
||||||
cy.visit('/admin');
|
cy.visit('/admin');
|
||||||
const username = Cypress.env('SPIFFWORKFLOW_FRONTEND_USERNAME') || 'ciadmin1';
|
if (!username) {
|
||||||
const password = Cypress.env('SPIFFWORKFLOW_FRONTEND_PASSWORD') || 'ciadmin1';
|
const username =
|
||||||
|
Cypress.env('SPIFFWORKFLOW_FRONTEND_USERNAME') || 'ciadmin1';
|
||||||
|
const password =
|
||||||
|
Cypress.env('SPIFFWORKFLOW_FRONTEND_PASSWORD') || 'ciadmin1';
|
||||||
|
}
|
||||||
cy.get('#username').type(username);
|
cy.get('#username').type(username);
|
||||||
cy.get('#password').type(password);
|
cy.get('#password').type(password);
|
||||||
if (Cypress.env('SPIFFWORKFLOW_FRONTEND_AUTH_WITH_KEYCLOAK') === true) {
|
if (Cypress.env('SPIFFWORKFLOW_FRONTEND_AUTH_WITH_KEYCLOAK') === true) {
|
||||||
@ -97,7 +102,12 @@ Cypress.Commands.add('createModel', (groupId, modelId, modelDisplayName) => {
|
|||||||
Cypress.Commands.add(
|
Cypress.Commands.add(
|
||||||
'runPrimaryBpmnFile',
|
'runPrimaryBpmnFile',
|
||||||
(expectAutoRedirectToHumanTask = false) => {
|
(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) {
|
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.
|
// 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/`);
|
cy.url().should('include', `/tasks/`);
|
||||||
|
4
spiffworkflow-frontend/package-lock.json
generated
4
spiffworkflow-frontend/package-lock.json
generated
@ -8065,7 +8065,7 @@
|
|||||||
},
|
},
|
||||||
"node_modules/bpmn-js-spiffworkflow": {
|
"node_modules/bpmn-js-spiffworkflow": {
|
||||||
"version": "0.0.8",
|
"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",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"inherits": "^2.0.4",
|
"inherits": "^2.0.4",
|
||||||
@ -38214,7 +38214,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"bpmn-js-spiffworkflow": {
|
"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",
|
"from": "bpmn-js-spiffworkflow@sartography/bpmn-js-spiffworkflow#main",
|
||||||
"requires": {
|
"requires": {
|
||||||
"inherits": "^2.0.4",
|
"inherits": "^2.0.4",
|
||||||
|
@ -99,3 +99,6 @@ a:link {
|
|||||||
padding-bottom: 70px;
|
padding-bottom: 70px;
|
||||||
min-height: 100%;
|
min-height: 100%;
|
||||||
}
|
}
|
||||||
|
.djs-palette.two-column.open {
|
||||||
|
width: 96px !important;
|
||||||
|
}
|
||||||
|
@ -126,7 +126,11 @@ export default function ProcessInstanceRun({
|
|||||||
if (checkPermissions) {
|
if (checkPermissions) {
|
||||||
return (
|
return (
|
||||||
<Can I="POST" a={processInstanceCreatePath} ability={ability}>
|
<Can I="POST" a={processInstanceCreatePath} ability={ability}>
|
||||||
<Button onClick={processInstanceCreateAndRun} className={className}>
|
<Button
|
||||||
|
data-qa="start-process-instance"
|
||||||
|
onClick={processInstanceCreateAndRun}
|
||||||
|
className={className}
|
||||||
|
>
|
||||||
Start
|
Start
|
||||||
</Button>
|
</Button>
|
||||||
</Can>
|
</Can>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user