Squashed 'spiffworkflow-frontend/' changes from cdae31a57..2149f03f5
2149f03f5 fix breadcrumb 4106c5aac Merge pull request #28 from sartography/bug/browser_lock_on_dmn_selection d9f04b932 one instance test left for cypress w/ burnettk db4ff9019 kill a few consoles 8fd0cbafc fixing up routes for launching editor. Also some fixes in the bpmn-js-spiffworkflow to avoid locking up the browser if no files are available. 063fc1e0c process model cypress tests are passing a1de9eca1 camelcase 67116e6ac fix process model create and a couple tests, docker build refactor 6dbdbffad fixed lint issue w/ burnettk cullerton 441e300c6 merged in main and resolved conflicts w/ burnettk cullerton 8c29bc3f6 fixed some acceptance tests w/ burnettk cullerton cf9af691e updated breadcrumbs to work with new process models ids w/ burnettk cullerton 23ff4e816 made a process model form w/ burnettk dbe0b9c71 Merge branch 'main' into feature/nested-groups 099ce24bb lint da1bd979d return next task when running an instance w/ burnettk ee76c5c81 More frontend changes ff0e4c762 process model show page lists files as accordion with action icons w/ burnettk a8cf19162 Merge remote-tracking branch 'origin/main' into feature/carbon_process_model_show 0b334f08d some minor chnages to prepare for chnaging actions dropdown to buttons 4e7d4733f First pass at custom report/perspective for Process Instance List (#23) 381cd4578 change action dropdown direction based on if it is the last one or not ec72afceb add back run and edit and add actions menu 331c079e1 added a table for files w/ burnettk 65874023b updated process modal show page to use accordion component w/ burnettk d50d23f14 First stab at fixing routes and urls d26b67865 Merge remote-tracking branch 'origin/main' into feature/carbon_process_model_show 6d8fee5eb Merge commit '44e49e6ae6a1f644162489a27618c39194f4628d' into main 01218b3ca update gitignore. ee11c1c2f updated the breadcrumb component and added a test for buttons in file dropdown git-subtree-dir: spiffworkflow-frontend git-subtree-split: 2149f03f5d352ba2f40b4dc41e9435cfb396d0e5
This commit is contained in:
parent
44e49e6ae6
commit
0a0bb2281a
|
@ -27,3 +27,6 @@ cypress/screenshots
|
|||
|
||||
# i keep accidentally committing these
|
||||
/test*.json
|
||||
|
||||
# Editors
|
||||
.idea
|
10
Dockerfile
10
Dockerfile
|
@ -1,19 +1,23 @@
|
|||
### STAGE 1: Build ###
|
||||
FROM quay.io/sartography/node:latest
|
||||
|
||||
RUN mkdir /app
|
||||
WORKDIR /app
|
||||
ADD package.json /app/
|
||||
ADD package-lock.json /app/
|
||||
COPY . /app/
|
||||
|
||||
# this matches total memory on spiffworkflow-demo
|
||||
ENV NODE_OPTIONS=--max_old_space_size=2048
|
||||
|
||||
ADD package.json /app/
|
||||
ADD package-lock.json /app/
|
||||
|
||||
# npm ci because it respects the lock file.
|
||||
# --ignore-scripts because authors can do bad things in postinstall scripts.
|
||||
# https://cheatsheetseries.owasp.org/cheatsheets/NPM_Security_Cheat_Sheet.html
|
||||
# npx can-i-ignore-scripts can check that it's safe to ignore scripts.
|
||||
RUN npm ci --ignore-scripts
|
||||
|
||||
COPY . /app/
|
||||
|
||||
RUN npm run build
|
||||
|
||||
ENTRYPOINT ["/app/bin/boot_server_in_docker"]
|
||||
|
|
|
@ -3,10 +3,10 @@ import { DATE_FORMAT, PROCESS_STATUSES } from '../../src/config';
|
|||
|
||||
const filterByDate = (fromDate) => {
|
||||
cy.get('#date-picker-start-from').clear().type(format(fromDate, DATE_FORMAT));
|
||||
cy.contains('Start Range').click();
|
||||
cy.contains('Start date from').click();
|
||||
cy.get('#date-picker-end-from').clear().type(format(fromDate, DATE_FORMAT));
|
||||
cy.contains('Start Range').click();
|
||||
cy.contains('Filter').click();
|
||||
cy.contains('End date from').click();
|
||||
cy.getBySel('filter-button').click();
|
||||
};
|
||||
|
||||
const updateDmnText = (oldText, newText, elementId = 'wonderful_process') => {
|
||||
|
@ -68,6 +68,7 @@ describe('process-instances', () => {
|
|||
cy.login();
|
||||
cy.navigateToProcessModel(
|
||||
'Acceptance Tests Group One',
|
||||
'Acceptance Tests Model 1',
|
||||
'acceptance-tests-model-1'
|
||||
);
|
||||
});
|
||||
|
@ -90,28 +91,29 @@ describe('process-instances', () => {
|
|||
cy.runPrimaryBpmnFile();
|
||||
|
||||
// Change dmn
|
||||
cy.contains(dmnFile).click();
|
||||
cy.contains(`Process Model File: ${dmnFile}`);
|
||||
cy.getBySel('files-accordion').click();
|
||||
cy.getBySel(`edit-file-${dmnFile.replace('.', '-')}`).click();
|
||||
updateDmnText(originalDmnOutputForKevin, newDmnOutputForKevin);
|
||||
|
||||
cy.contains('acceptance-tests-model-1').click();
|
||||
cy.runPrimaryBpmnFile();
|
||||
|
||||
cy.contains(dmnFile).click();
|
||||
cy.contains(`Process Model File: ${dmnFile}`);
|
||||
cy.getBySel('files-accordion').click();
|
||||
cy.getBySel(`edit-file-${dmnFile.replace('.', '-')}`).click();
|
||||
updateDmnText(newDmnOutputForKevin, originalDmnOutputForKevin);
|
||||
cy.contains('acceptance-tests-model-1').click();
|
||||
cy.runPrimaryBpmnFile();
|
||||
|
||||
// Change bpmn
|
||||
cy.contains(bpmnFile).click();
|
||||
cy.getBySel('files-accordion').click();
|
||||
cy.getBySel(`edit-file-${bpmnFile.replace('.', '-')}`).click();
|
||||
cy.contains(`Process Model File: ${bpmnFile}`);
|
||||
updateBpmnPythonScript(newPythonScript);
|
||||
cy.contains('acceptance-tests-model-1').click();
|
||||
cy.runPrimaryBpmnFile();
|
||||
|
||||
cy.contains(bpmnFile).click();
|
||||
cy.contains(`Process Model File: ${bpmnFile}`);
|
||||
cy.getBySel('files-accordion').click();
|
||||
cy.getBySel(`edit-file-${bpmnFile.replace('.', '-')}`).click();
|
||||
updateBpmnPythonScript(originalPythonScript);
|
||||
cy.contains('acceptance-tests-model-1').click();
|
||||
cy.runPrimaryBpmnFile();
|
||||
|
@ -125,13 +127,15 @@ describe('process-instances', () => {
|
|||
const bpmnFile = 'process_model_one.bpmn';
|
||||
|
||||
// Change bpmn
|
||||
cy.contains(bpmnFile).click();
|
||||
cy.getBySel('files-accordion').click();
|
||||
cy.getBySel(`edit-file-${bpmnFile.replace('.', '-')}`).click();
|
||||
cy.contains(`Process Model File: ${bpmnFile}`);
|
||||
updateBpmnPythonScriptWithMonaco(newPythonScript);
|
||||
cy.contains('acceptance-tests-model-1').click();
|
||||
cy.runPrimaryBpmnFile();
|
||||
|
||||
cy.contains(bpmnFile).click();
|
||||
cy.getBySel('files-accordion').click();
|
||||
cy.getBySel(`edit-file-${bpmnFile.replace('.', '-')}`).click();
|
||||
cy.contains(`Process Model File: ${bpmnFile}`);
|
||||
updateBpmnPythonScriptWithMonaco(originalPythonScript);
|
||||
cy.contains('acceptance-tests-model-1').click();
|
||||
|
@ -161,25 +165,27 @@ describe('process-instances', () => {
|
|||
cy.basicPaginationTest();
|
||||
});
|
||||
|
||||
it('can filter', () => {
|
||||
it.only('can filter', () => {
|
||||
cy.getBySel('process-instance-list-link').click();
|
||||
cy.assertAtLeastOneItemInPaginatedResults();
|
||||
|
||||
PROCESS_STATUSES.forEach((processStatus) => {
|
||||
if (!['all', 'waiting'].includes(processStatus)) {
|
||||
cy.get('[name=process-status-selection]').click();
|
||||
cy.get('[name=process-status-selection]').type(processStatus);
|
||||
cy.get(`[aria-label=${processStatus}]`).click();
|
||||
cy.contains('Process Status').click();
|
||||
cy.contains('Filter').click();
|
||||
cy.assertAtLeastOneItemInPaginatedResults();
|
||||
cy.getBySel(`process-instance-status-${processStatus}`).contains(
|
||||
processStatus
|
||||
);
|
||||
// there should really only be one, but in CI there are sometimes more
|
||||
cy.get('button[aria-label=Remove]:first').click();
|
||||
}
|
||||
});
|
||||
// PROCESS_STATUSES.forEach((processStatus) => {
|
||||
// if (!['all', 'waiting'].includes(processStatus)) {
|
||||
// cy.get('#process-instance-status-select').click();
|
||||
// cy.get('#process-instance-status-select')
|
||||
// .contains(processStatus)
|
||||
// .click();
|
||||
// // close the dropdown again
|
||||
// cy.get('#process-instance-status-select').click();
|
||||
// cy.getBySel('filter-button').click();
|
||||
// cy.assertAtLeastOneItemInPaginatedResults();
|
||||
// cy.getBySel(`process-instance-status-${processStatus}`).contains(
|
||||
// processStatus
|
||||
// );
|
||||
// // there should really only be one, but in CI there are sometimes more
|
||||
// cy.get('div[aria-label="Clear all selected items"]:first').click();
|
||||
// }
|
||||
// });
|
||||
|
||||
const date = new Date();
|
||||
date.setHours(date.getHours() - 1);
|
||||
|
|
|
@ -16,19 +16,14 @@ describe('process-models', () => {
|
|||
const modelId = `test-model-2-${id}`;
|
||||
cy.contains(groupDisplayName).click();
|
||||
cy.createModel(groupId, modelId, modelDisplayName);
|
||||
cy.contains(`Process Group: ${groupId}`).click();
|
||||
cy.contains(modelId);
|
||||
|
||||
cy.contains(modelId).click();
|
||||
cy.url().should('include', `process-models/${groupId}/${modelId}`);
|
||||
cy.contains(`Process Model: ${modelId}`);
|
||||
cy.url().should('include', `process-models/${groupId}:${modelId}`);
|
||||
cy.contains(`Process Model: ${modelDisplayName}`);
|
||||
|
||||
cy.contains('Edit process model').click();
|
||||
cy.get('input[name=display_name]').clear().type(newModelDisplayName);
|
||||
cy.contains('Submit').click();
|
||||
cy.contains(`Process Model: ${modelId}`);
|
||||
|
||||
cy.contains('Edit process model').click();
|
||||
cy.contains(`Process Model: ${groupId}/${modelId}`);
|
||||
cy.contains('Submit').click();
|
||||
cy.get('input[name=display_name]').should(
|
||||
'have.value',
|
||||
newModelDisplayName
|
||||
|
@ -36,7 +31,7 @@ describe('process-models', () => {
|
|||
|
||||
cy.contains('Delete').click();
|
||||
cy.contains('Are you sure');
|
||||
cy.contains('OK').click();
|
||||
cy.getBySel('modal-confirmation-dialog').find('.cds--btn--danger').click();
|
||||
cy.url().should('include', `process-groups/${groupId}`);
|
||||
cy.contains(modelId).should('not.exist');
|
||||
});
|
||||
|
@ -55,18 +50,17 @@ describe('process-models', () => {
|
|||
|
||||
cy.contains(groupDisplayName).click();
|
||||
cy.createModel(groupId, modelId, modelDisplayName);
|
||||
cy.contains(`Process Group: ${groupId}`).click();
|
||||
cy.contains(modelId);
|
||||
|
||||
cy.contains(groupId).click();
|
||||
cy.contains(modelId).click();
|
||||
cy.url().should('include', `process-models/${groupId}/${modelId}`);
|
||||
cy.contains(`Process Model: ${modelId}`);
|
||||
cy.url().should('include', `process-models/${groupId}:${modelId}`);
|
||||
cy.contains(`Process Model: ${modelDisplayName}`);
|
||||
cy.getBySel('files-accordion').click();
|
||||
cy.contains(`${bpmnFileName}.bpmn`).should('not.exist');
|
||||
cy.contains(`${dmnFileName}.dmn`).should('not.exist');
|
||||
cy.contains(`${jsonFileName}.json`).should('not.exist');
|
||||
|
||||
// add new bpmn file
|
||||
cy.contains('Add New BPMN File').click();
|
||||
cy.contains('New BPMN File').click();
|
||||
cy.contains(/^Process Model File$/);
|
||||
cy.get('g[data-element-id=StartEvent_1]').click().should('exist');
|
||||
cy.contains('General').click();
|
||||
|
@ -78,11 +72,12 @@ describe('process-models', () => {
|
|||
cy.contains('Save Changes').click();
|
||||
cy.contains(`Process Model File: ${bpmnFileName}`);
|
||||
cy.contains(modelId).click();
|
||||
cy.contains(`Process Model: ${modelId}`);
|
||||
cy.contains(`Process Model: ${modelDisplayName}`);
|
||||
cy.getBySel('files-accordion').click();
|
||||
cy.contains(`${bpmnFileName}.bpmn`).should('exist');
|
||||
|
||||
// add new dmn file
|
||||
cy.contains('Add New DMN File').click();
|
||||
cy.contains('New DMN File').click();
|
||||
cy.contains(/^Process Model File$/);
|
||||
cy.get('g[data-element-id=decision_1]').click().should('exist');
|
||||
cy.contains('General').click();
|
||||
|
@ -91,11 +86,12 @@ describe('process-models', () => {
|
|||
cy.contains('Save Changes').click();
|
||||
cy.contains(`Process Model File: ${dmnFileName}`);
|
||||
cy.contains(modelId).click();
|
||||
cy.contains(`Process Model: ${modelId}`);
|
||||
cy.contains(`Process Model: ${modelDisplayName}`);
|
||||
cy.getBySel('files-accordion').click();
|
||||
cy.contains(`${dmnFileName}.dmn`).should('exist');
|
||||
|
||||
// add new json file
|
||||
cy.contains('Add New JSON File').click();
|
||||
cy.contains('New JSON File').click();
|
||||
cy.contains(/^Process Model File$/);
|
||||
// Some reason, cypress evals json strings so we have to escape it it with '{{}'
|
||||
cy.get('.view-line').type('{{} "test_key": "test_value" }');
|
||||
|
@ -106,13 +102,14 @@ describe('process-models', () => {
|
|||
// wait for json to load before clicking away to avoid network errors
|
||||
cy.wait(500);
|
||||
cy.contains(modelId).click();
|
||||
cy.contains(`Process Model: ${modelId}`);
|
||||
cy.contains(`Process Model: ${modelDisplayName}`);
|
||||
cy.getBySel('files-accordion').click();
|
||||
cy.contains(`${jsonFileName}.json`).should('exist');
|
||||
|
||||
cy.contains('Edit process model').click();
|
||||
cy.contains('Delete').click();
|
||||
cy.contains('Are you sure');
|
||||
cy.contains('OK').click();
|
||||
cy.getBySel('modal-confirmation-dialog').find('.cds--btn--danger').click();
|
||||
cy.url().should('include', `process-groups/${groupId}`);
|
||||
cy.contains(modelId).should('not.exist');
|
||||
});
|
||||
|
@ -128,36 +125,35 @@ describe('process-models', () => {
|
|||
cy.contains(groupDisplayName).click();
|
||||
cy.createModel(groupId, modelId, modelDisplayName);
|
||||
|
||||
// seeing if getBySel works better, because we are seeing tests fail in CI
|
||||
// when looking for the "Add a process model" link, so it seems like the
|
||||
// click on the breadcrumb element must have failed.
|
||||
cy.getBySel('process-group-breadcrumb-link').click();
|
||||
// cy.contains(`Process Group: ${groupId}`).click();
|
||||
|
||||
cy.contains(`${groupId}`).click();
|
||||
cy.contains('Add a process model');
|
||||
|
||||
cy.contains(modelId).click();
|
||||
cy.url().should('include', `process-models/${groupId}/${modelId}`);
|
||||
cy.contains(`Process Model: ${modelId}`);
|
||||
cy.url().should('include', `process-models/${groupId}:${modelId}`);
|
||||
cy.contains(`Process Model: ${modelDisplayName}`);
|
||||
|
||||
cy.get('input[type=file]').selectFile(
|
||||
cy.getBySel('files-accordion').click();
|
||||
cy.getBySel('upload-file-button').click();
|
||||
cy.contains('Add file').selectFile(
|
||||
'cypress/fixtures/test_bpmn_file_upload.bpmn'
|
||||
);
|
||||
cy.contains('Submit').click();
|
||||
cy.getBySel('modal-upload-file-dialog')
|
||||
.find('.cds--btn--primary')
|
||||
.contains('Upload')
|
||||
.click();
|
||||
cy.runPrimaryBpmnFile();
|
||||
|
||||
cy.getBySel('process-instance-list-link').click();
|
||||
cy.getBySel('process-instance-show-link').click();
|
||||
cy.contains('Delete').click();
|
||||
cy.contains('Are you sure');
|
||||
cy.contains('OK').click();
|
||||
cy.getBySel('modal-confirmation-dialog').find('.cds--btn--danger').click();
|
||||
cy.contains(`Process Instances for: ${groupId}/${modelId}`);
|
||||
cy.contains(modelId).click();
|
||||
|
||||
cy.contains('Edit process model').click();
|
||||
cy.contains('Delete').click();
|
||||
cy.contains('Are you sure');
|
||||
cy.contains('OK').click();
|
||||
cy.getBySel('modal-confirmation-dialog').find('.cds--btn--danger').click();
|
||||
cy.url().should('include', `process-groups/${groupId}`);
|
||||
cy.contains(modelId).should('not.exist');
|
||||
});
|
||||
|
|
|
@ -25,10 +25,11 @@ describe('tasks', () => {
|
|||
it('can complete and navigate a form', () => {
|
||||
const groupDisplayName = 'Acceptance Tests Group One';
|
||||
const modelId = `acceptance-tests-model-2`;
|
||||
const modelDisplayName = `Acceptance Tests Model 2`;
|
||||
const completedTaskClassName = 'completed-task-highlight';
|
||||
const activeTaskClassName = 'active-task-highlight';
|
||||
|
||||
cy.navigateToProcessModel(groupDisplayName, modelId);
|
||||
cy.navigateToProcessModel(groupDisplayName, modelDisplayName, modelId);
|
||||
|
||||
// avoid reloading so we can click on the task link that appears on running the process instance
|
||||
cy.runPrimaryBpmnFile(false);
|
||||
|
@ -67,7 +68,7 @@ describe('tasks', () => {
|
|||
);
|
||||
|
||||
cy.contains('Task: get_user_generated_number_four');
|
||||
cy.navigateToProcessModel(groupDisplayName, modelId);
|
||||
cy.navigateToProcessModel(groupDisplayName, modelDisplayName, modelId);
|
||||
cy.getBySel('process-instance-list-link').click();
|
||||
cy.assertAtLeastOneItemInPaginatedResults();
|
||||
|
||||
|
@ -84,7 +85,7 @@ describe('tasks', () => {
|
|||
checkTaskHasClass('form2', completedTaskClassName);
|
||||
checkTaskHasClass('form3', completedTaskClassName);
|
||||
checkTaskHasClass('form4', activeTaskClassName);
|
||||
cy.get('.modal .btn-close').click();
|
||||
cy.get('.is-visible .cds--modal-close').click();
|
||||
|
||||
cy.navigateToHome();
|
||||
cy.contains('Tasks').should('exist');
|
||||
|
@ -99,7 +100,7 @@ describe('tasks', () => {
|
|||
);
|
||||
cy.url().should('include', '/tasks');
|
||||
|
||||
cy.navigateToProcessModel(groupDisplayName, modelId);
|
||||
cy.navigateToProcessModel(groupDisplayName, modelDisplayName, modelId);
|
||||
cy.getBySel('process-instance-list-link').click();
|
||||
cy.assertAtLeastOneItemInPaginatedResults();
|
||||
|
||||
|
@ -112,6 +113,7 @@ describe('tasks', () => {
|
|||
it('can paginate items', () => {
|
||||
cy.navigateToProcessModel(
|
||||
'Acceptance Tests Group One',
|
||||
'Acceptance Tests Model 2',
|
||||
'acceptance-tests-model-2'
|
||||
);
|
||||
|
||||
|
|
|
@ -76,8 +76,8 @@ Cypress.Commands.add('createModel', (groupId, modelId, modelDisplayName) => {
|
|||
cy.get('input[name=id]').should('have.value', modelId);
|
||||
cy.contains('Submit').click();
|
||||
|
||||
cy.url().should('include', `process-models/${groupId}/${modelId}`);
|
||||
cy.contains(`Process Model: ${modelId}`);
|
||||
cy.url().should('include', `process-models/${groupId}:${modelId}`);
|
||||
cy.contains(`Process Model: ${modelDisplayName}`);
|
||||
});
|
||||
|
||||
Cypress.Commands.add('runPrimaryBpmnFile', (reload = true) => {
|
||||
|
@ -91,13 +91,12 @@ Cypress.Commands.add('runPrimaryBpmnFile', (reload = true) => {
|
|||
|
||||
Cypress.Commands.add(
|
||||
'navigateToProcessModel',
|
||||
(groupDisplayName, modelDisplayName) => {
|
||||
(groupDisplayName, modelDisplayName, modelIdentifier) => {
|
||||
cy.navigateToAdmin();
|
||||
cy.contains(groupDisplayName).click();
|
||||
cy.contains(`Process Group: ${groupDisplayName}`);
|
||||
// https://stackoverflow.com/q/51254946/6090676
|
||||
cy.getBySel('process-model-show-link').contains(modelDisplayName).click();
|
||||
// cy.url().should('include', `process-models/${groupDisplayName}/${modelDisplayName}`);
|
||||
cy.getBySel('process-model-show-link').contains(modelIdentifier).click();
|
||||
cy.contains(`Process Model: ${modelDisplayName}`);
|
||||
}
|
||||
);
|
||||
|
@ -115,12 +114,14 @@ Cypress.Commands.add('basicPaginationTest', () => {
|
|||
});
|
||||
|
||||
Cypress.Commands.add('assertAtLeastOneItemInPaginatedResults', () => {
|
||||
cy.getBySel('total-paginated-items')
|
||||
.invoke('text')
|
||||
.then(parseFloat)
|
||||
.should('be.gt', 0);
|
||||
cy.contains(/\b[1-9]\d*–[1-9]\d* of [1-9]\d*/);
|
||||
});
|
||||
|
||||
Cypress.Commands.add('assertNoItemInPaginatedResults', () => {
|
||||
cy.getBySel('total-paginated-items').contains('0');
|
||||
});
|
||||
|
||||
Cypress.Commands.add('modifyProcessModelPath', (path) => {
|
||||
path.replace('/', ':');
|
||||
return path;
|
||||
});
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
"bootstrap": "^5.2.0",
|
||||
"bpmn-js": "^9.3.2",
|
||||
"bpmn-js-properties-panel": "^1.10.0",
|
||||
"bpmn-js-spiffworkflow": "sartography/bpmn-js-spiffworkflow#feature/more_launch_buttons_and_dropdowns",
|
||||
"bpmn-js-spiffworkflow": "sartography/bpmn-js-spiffworkflow#main",
|
||||
"craco": "^0.0.3",
|
||||
"date-fns": "^2.28.0",
|
||||
"diagram-js": "^8.5.0",
|
||||
|
@ -7485,7 +7485,7 @@
|
|||
},
|
||||
"node_modules/bpmn-js-spiffworkflow": {
|
||||
"version": "0.0.8",
|
||||
"resolved": "git+ssh://git@github.com/sartography/bpmn-js-spiffworkflow.git#84593aee1ead7328efdc7da03ab3c9cd34364496",
|
||||
"resolved": "git+ssh://git@github.com/sartography/bpmn-js-spiffworkflow.git#24c2cc36067adf8fed75990c6bf4a1a67bc9122b",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"inherits": "^2.0.4",
|
||||
|
@ -7890,9 +7890,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/caniuse-lite": {
|
||||
"version": "1.0.30001418",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001418.tgz",
|
||||
"integrity": "sha512-oIs7+JL3K9JRQ3jPZjlH6qyYDp+nBTCais7hjh0s+fuBwufc7uZ7hPYMXrDOJhV360KGMTcczMRObk0/iMqZRg==",
|
||||
"version": "1.0.30001431",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001431.tgz",
|
||||
"integrity": "sha512-zBUoFU0ZcxpvSt9IU66dXVT/3ctO1cy4y9cscs1szkPlcWb6pasYM144GqrUygUbT+k7cmUCW61cvskjcv0enQ==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "opencollective",
|
||||
|
@ -35755,8 +35755,8 @@
|
|||
}
|
||||
},
|
||||
"bpmn-js-spiffworkflow": {
|
||||
"version": "git+ssh://git@github.com/sartography/bpmn-js-spiffworkflow.git#84593aee1ead7328efdc7da03ab3c9cd34364496",
|
||||
"from": "bpmn-js-spiffworkflow@sartography/bpmn-js-spiffworkflow#feature/more_launch_buttons_and_dropdowns",
|
||||
"version": "git+ssh://git@github.com/sartography/bpmn-js-spiffworkflow.git#24c2cc36067adf8fed75990c6bf4a1a67bc9122b",
|
||||
"from": "bpmn-js-spiffworkflow@sartography/bpmn-js-spiffworkflow#main",
|
||||
"requires": {
|
||||
"inherits": "^2.0.4",
|
||||
"inherits-browser": "^0.0.1",
|
||||
|
@ -36070,9 +36070,9 @@
|
|||
}
|
||||
},
|
||||
"caniuse-lite": {
|
||||
"version": "1.0.30001418",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001418.tgz",
|
||||
"integrity": "sha512-oIs7+JL3K9JRQ3jPZjlH6qyYDp+nBTCais7hjh0s+fuBwufc7uZ7hPYMXrDOJhV360KGMTcczMRObk0/iMqZRg=="
|
||||
"version": "1.0.30001431",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001431.tgz",
|
||||
"integrity": "sha512-zBUoFU0ZcxpvSt9IU66dXVT/3ctO1cy4y9cscs1szkPlcWb6pasYM144GqrUygUbT+k7cmUCW61cvskjcv0enQ=="
|
||||
},
|
||||
"case-sensitive-paths-webpack-plugin": {
|
||||
"version": "2.4.0",
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
"bootstrap": "^5.2.0",
|
||||
"bpmn-js": "^9.3.2",
|
||||
"bpmn-js-properties-panel": "^1.10.0",
|
||||
"bpmn-js-spiffworkflow": "sartography/bpmn-js-spiffworkflow#feature/more_launch_buttons_and_dropdowns",
|
||||
"bpmn-js-spiffworkflow": "sartography/bpmn-js-spiffworkflow#main",
|
||||
"craco": "^0.0.3",
|
||||
"date-fns": "^2.28.0",
|
||||
"diagram-js": "^8.5.0",
|
||||
|
|
|
@ -4,10 +4,14 @@ import { Button, Modal } from '@carbon/react';
|
|||
|
||||
type OwnProps = {
|
||||
description?: string;
|
||||
buttonLabel: string;
|
||||
buttonLabel?: string;
|
||||
onConfirmation: (..._args: any[]) => any;
|
||||
title?: string;
|
||||
confirmButtonLabel?: string;
|
||||
kind?: string;
|
||||
renderIcon?: boolean;
|
||||
iconDescription?: string | null;
|
||||
hasIconOnly?: boolean;
|
||||
};
|
||||
|
||||
export default function ButtonWithConfirmation({
|
||||
|
@ -16,6 +20,10 @@ export default function ButtonWithConfirmation({
|
|||
onConfirmation,
|
||||
title = 'Are you sure?',
|
||||
confirmButtonLabel = 'OK',
|
||||
kind = 'danger',
|
||||
renderIcon = false,
|
||||
iconDescription = null,
|
||||
hasIconOnly = false,
|
||||
}: OwnProps) {
|
||||
const [showConfirmationPrompt, setShowConfirmationPrompt] = useState(false);
|
||||
|
||||
|
@ -49,7 +57,13 @@ export default function ButtonWithConfirmation({
|
|||
|
||||
return (
|
||||
<>
|
||||
<Button onClick={handleShowConfirmationPrompt} kind="danger">
|
||||
<Button
|
||||
onClick={handleShowConfirmationPrompt}
|
||||
kind={kind}
|
||||
renderIcon={renderIcon}
|
||||
iconDescription={iconDescription}
|
||||
hasIconOnly={hasIconOnly}
|
||||
>
|
||||
{buttonLabel}
|
||||
</Button>
|
||||
{confirmationDialog()}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import React from 'react';
|
||||
import HttpService from '../services/HttpService';
|
||||
import { modifyProcessModelPath } from '../helpers';
|
||||
|
||||
type Props = {
|
||||
processGroupId: string;
|
||||
|
@ -27,7 +28,10 @@ export default class FileInput extends React.Component<Props> {
|
|||
|
||||
handleSubmit(event: any) {
|
||||
event.preventDefault();
|
||||
const url = `/process-models/${this.processGroupId}/${this.processModelId}/files`;
|
||||
const modifiedProcessModelId = modifyProcessModelPath(
|
||||
`${this.processGroupId}/${this.processModelId}`
|
||||
);
|
||||
const url = `/process-models/${modifiedProcessModelId}/files`;
|
||||
const formData = new FormData();
|
||||
formData.append('file', this.fileInput.current.files[0]);
|
||||
formData.append('fileName', this.fileInput.current.files[0].name);
|
||||
|
|
|
@ -1,12 +1,46 @@
|
|||
import { Link } from 'react-router-dom';
|
||||
import Breadcrumb from 'react-bootstrap/Breadcrumb';
|
||||
import { BreadcrumbItem } from '../interfaces';
|
||||
// @ts-ignore
|
||||
import { Breadcrumb, BreadcrumbItem } from '@carbon/react';
|
||||
import { splitProcessModelId } from '../helpers';
|
||||
import { HotCrumbItem } from '../interfaces';
|
||||
|
||||
type OwnProps = {
|
||||
processModelId?: string;
|
||||
processGroupId?: string;
|
||||
linkProcessModel?: boolean;
|
||||
hotCrumbs?: BreadcrumbItem[];
|
||||
hotCrumbs?: HotCrumbItem[];
|
||||
};
|
||||
|
||||
const explodeCrumb = (crumb: HotCrumbItem) => {
|
||||
const url: string = crumb[1] || '';
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const [_unused, processModelId, link] = url.split(':');
|
||||
const processModelIdSegments = splitProcessModelId(processModelId);
|
||||
const paths: string[] = [];
|
||||
const lastPathItem = processModelIdSegments.pop();
|
||||
const breadcrumbItems = processModelIdSegments.map(
|
||||
(processModelIdSegment: string) => {
|
||||
paths.push(processModelIdSegment);
|
||||
const fullUrl = `/admin/process-groups/${paths.join(':')}`;
|
||||
return (
|
||||
<BreadcrumbItem key={processModelIdSegment} href={fullUrl}>
|
||||
{processModelIdSegment}
|
||||
</BreadcrumbItem>
|
||||
);
|
||||
}
|
||||
);
|
||||
if (link === 'link') {
|
||||
const lastUrl = `/admin/process-models/${paths.join(':')}:${lastPathItem}`;
|
||||
breadcrumbItems.push(
|
||||
<BreadcrumbItem key={lastPathItem} href={lastUrl}>
|
||||
{lastPathItem}
|
||||
</BreadcrumbItem>
|
||||
);
|
||||
} else {
|
||||
breadcrumbItems.push(
|
||||
<BreadcrumbItem isCurrentPage>{lastPathItem}</BreadcrumbItem>
|
||||
);
|
||||
}
|
||||
return breadcrumbItems;
|
||||
};
|
||||
|
||||
export default function ProcessBreadcrumb({
|
||||
|
@ -18,66 +52,58 @@ export default function ProcessBreadcrumb({
|
|||
let processGroupBreadcrumb = null;
|
||||
let processModelBreadcrumb = null;
|
||||
if (hotCrumbs) {
|
||||
const lastItem = hotCrumbs.pop();
|
||||
if (lastItem === undefined) {
|
||||
return null;
|
||||
}
|
||||
const lastCrumb = <Breadcrumb.Item active>{lastItem[0]}</Breadcrumb.Item>;
|
||||
const leadingCrumbLinks = hotCrumbs.map((crumb) => {
|
||||
const leadingCrumbLinks = hotCrumbs.map((crumb: any) => {
|
||||
const valueLabel = crumb[0];
|
||||
const url = crumb[1];
|
||||
if (!url) {
|
||||
return <BreadcrumbItem isCurrentPage>{valueLabel}</BreadcrumbItem>;
|
||||
}
|
||||
if (url && url.startsWith('process_model:')) {
|
||||
return explodeCrumb(crumb);
|
||||
}
|
||||
return (
|
||||
<Breadcrumb.Item key={valueLabel} linkAs={Link} linkProps={{ to: url }}>
|
||||
<BreadcrumbItem key={valueLabel} href={url}>
|
||||
{valueLabel}
|
||||
</Breadcrumb.Item>
|
||||
</BreadcrumbItem>
|
||||
);
|
||||
});
|
||||
return (
|
||||
<Breadcrumb>
|
||||
{leadingCrumbLinks}
|
||||
{lastCrumb}
|
||||
</Breadcrumb>
|
||||
);
|
||||
return <Breadcrumb noTrailingSlash>{leadingCrumbLinks}</Breadcrumb>;
|
||||
}
|
||||
if (processModelId) {
|
||||
if (linkProcessModel) {
|
||||
processModelBreadcrumb = (
|
||||
<Breadcrumb.Item
|
||||
linkAs={Link}
|
||||
linkProps={{
|
||||
to: `/admin/process-models/${processGroupId}/${processModelId}`,
|
||||
}}
|
||||
<BreadcrumbItem
|
||||
href={`/admin/process-models/${processGroupId}/${processModelId}`}
|
||||
>
|
||||
Process Model: {processModelId}
|
||||
</Breadcrumb.Item>
|
||||
{`Process Model: ${processModelId}`}
|
||||
</BreadcrumbItem>
|
||||
);
|
||||
} else {
|
||||
processModelBreadcrumb = (
|
||||
<Breadcrumb.Item active>
|
||||
Process Model: {processModelId}
|
||||
</Breadcrumb.Item>
|
||||
<BreadcrumbItem isCurrentPage>
|
||||
{`Process Model: ${processModelId}`}
|
||||
</BreadcrumbItem>
|
||||
);
|
||||
}
|
||||
processGroupBreadcrumb = (
|
||||
<Breadcrumb.Item
|
||||
linkAs={Link}
|
||||
<BreadcrumbItem
|
||||
data-qa="process-group-breadcrumb-link"
|
||||
linkProps={{ to: `/admin/process-groups/${processGroupId}` }}
|
||||
href={`/admin/process-groups/${processGroupId}`}
|
||||
>
|
||||
Process Group: {processGroupId}
|
||||
</Breadcrumb.Item>
|
||||
{`Process Group: ${processGroupId}`}
|
||||
</BreadcrumbItem>
|
||||
);
|
||||
} else if (processGroupId) {
|
||||
processGroupBreadcrumb = (
|
||||
<Breadcrumb.Item active>Process Group: {processGroupId}</Breadcrumb.Item>
|
||||
<BreadcrumbItem isCurrentPage>
|
||||
{`Process Group: ${processGroupId}`}
|
||||
</BreadcrumbItem>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Breadcrumb>
|
||||
<Breadcrumb.Item linkAs={Link} linkProps={{ to: '/admin' }}>
|
||||
Process Groups
|
||||
</Breadcrumb.Item>
|
||||
<Breadcrumb noTrailingSlash>
|
||||
<BreadcrumbItem href="/admin">Process Groups</BreadcrumbItem>
|
||||
{processGroupBreadcrumb}
|
||||
{processModelBreadcrumb}
|
||||
</Breadcrumb>
|
||||
|
|
|
@ -95,7 +95,7 @@ export default function ProcessGroupForm({
|
|||
const onDisplayNameChanged = (newDisplayName: any) => {
|
||||
setDisplayNameInvalid(false);
|
||||
const updateDict = { display_name: newDisplayName };
|
||||
if (!idHasBeenUpdatedByUser) {
|
||||
if (!idHasBeenUpdatedByUser && mode === 'new') {
|
||||
Object.assign(updateDict, { id: slugifyString(newDisplayName) });
|
||||
}
|
||||
updateProcessGroup(updateDict);
|
||||
|
|
|
@ -0,0 +1,198 @@
|
|||
import { useState } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
// @ts-ignore
|
||||
import { Button, ButtonSet, Form, Stack, TextInput } from '@carbon/react';
|
||||
import {
|
||||
getGroupFromModifiedModelId,
|
||||
modifyProcessModelPath,
|
||||
slugifyString,
|
||||
} from '../helpers';
|
||||
import HttpService from '../services/HttpService';
|
||||
import { ProcessModel } from '../interfaces';
|
||||
import ButtonWithConfirmation from './ButtonWithConfirmation';
|
||||
|
||||
type OwnProps = {
|
||||
mode: string;
|
||||
processModel: ProcessModel;
|
||||
processGroupId?: string;
|
||||
setProcessModel: (..._args: any[]) => any;
|
||||
};
|
||||
|
||||
export default function ProcessModelForm({
|
||||
mode,
|
||||
processModel,
|
||||
processGroupId,
|
||||
setProcessModel,
|
||||
}: OwnProps) {
|
||||
const [identifierInvalid, setIdentifierInvalid] = useState<boolean>(false);
|
||||
const [idHasBeenUpdatedByUser, setIdHasBeenUpdatedByUser] =
|
||||
useState<boolean>(false);
|
||||
const [displayNameInvalid, setDisplayNameInvalid] = useState<boolean>(false);
|
||||
const navigate = useNavigate();
|
||||
const modifiedProcessModelPath = modifyProcessModelPath(processModel.id);
|
||||
|
||||
const navigateToProcessModel = (result: ProcessModel) => {
|
||||
if ('id' in result) {
|
||||
const modifiedProcessModelPathFromResult = modifyProcessModelPath(
|
||||
result.id
|
||||
);
|
||||
navigate(`/admin/process-models/${modifiedProcessModelPathFromResult}`);
|
||||
}
|
||||
};
|
||||
|
||||
const navigateToProcessModels = (_result: any) => {
|
||||
navigate(
|
||||
`/admin/process-groups/${getGroupFromModifiedModelId(
|
||||
modifiedProcessModelPath
|
||||
)}`
|
||||
);
|
||||
};
|
||||
|
||||
const hasValidIdentifier = (identifierToCheck: string) => {
|
||||
return identifierToCheck.match(/^[a-z0-9][0-9a-z-]+[a-z0-9]$/);
|
||||
};
|
||||
|
||||
const deleteProcessModel = () => {
|
||||
HttpService.makeCallToBackend({
|
||||
path: `/process-models/${modifiedProcessModelPath}`,
|
||||
successCallback: navigateToProcessModels,
|
||||
httpMethod: 'DELETE',
|
||||
});
|
||||
};
|
||||
|
||||
const handleFormSubmission = (event: any) => {
|
||||
event.preventDefault();
|
||||
let hasErrors = false;
|
||||
if (!hasValidIdentifier(processModel.id)) {
|
||||
setIdentifierInvalid(true);
|
||||
hasErrors = true;
|
||||
}
|
||||
if (processModel.display_name === '') {
|
||||
setDisplayNameInvalid(true);
|
||||
hasErrors = true;
|
||||
}
|
||||
if (hasErrors) {
|
||||
return;
|
||||
}
|
||||
let path = `/process-models`;
|
||||
if (mode === 'edit') {
|
||||
path = `/process-models/${modifiedProcessModelPath}`;
|
||||
}
|
||||
let httpMethod = 'POST';
|
||||
if (mode === 'edit') {
|
||||
httpMethod = 'PUT';
|
||||
}
|
||||
const postBody = {
|
||||
display_name: processModel.display_name,
|
||||
description: processModel.description,
|
||||
};
|
||||
if (mode === 'new') {
|
||||
Object.assign(postBody, {
|
||||
id: `${processGroupId}/${processModel.id}`,
|
||||
});
|
||||
}
|
||||
|
||||
HttpService.makeCallToBackend({
|
||||
path,
|
||||
successCallback: navigateToProcessModel,
|
||||
httpMethod,
|
||||
postBody,
|
||||
});
|
||||
};
|
||||
|
||||
const updateProcessModel = (newValues: any) => {
|
||||
const processModelToCopy = {
|
||||
...processModel,
|
||||
};
|
||||
Object.assign(processModelToCopy, newValues);
|
||||
setProcessModel(processModelToCopy);
|
||||
};
|
||||
|
||||
const onDisplayNameChanged = (newDisplayName: any) => {
|
||||
setDisplayNameInvalid(false);
|
||||
const updateDict = { display_name: newDisplayName };
|
||||
if (!idHasBeenUpdatedByUser && mode === 'new') {
|
||||
Object.assign(updateDict, { id: slugifyString(newDisplayName) });
|
||||
}
|
||||
updateProcessModel(updateDict);
|
||||
};
|
||||
|
||||
const formElements = () => {
|
||||
const textInputs = [
|
||||
<TextInput
|
||||
id="process-model-display-name"
|
||||
name="display_name"
|
||||
invalidText="Display Name is required."
|
||||
invalid={displayNameInvalid}
|
||||
labelText="Display Name*"
|
||||
value={processModel.display_name}
|
||||
onChange={(event: any) => {
|
||||
onDisplayNameChanged(event.target.value);
|
||||
}}
|
||||
onBlur={(event: any) => console.log('event', event)}
|
||||
/>,
|
||||
];
|
||||
|
||||
if (mode === 'new') {
|
||||
textInputs.push(
|
||||
<TextInput
|
||||
id="process-model-identifier"
|
||||
name="id"
|
||||
invalidText="Identifier is required and must be all lowercase characters and hyphens."
|
||||
invalid={identifierInvalid}
|
||||
labelText="Identifier*"
|
||||
value={processModel.id}
|
||||
onChange={(event: any) => {
|
||||
updateProcessModel({ id: event.target.value });
|
||||
// was invalid, and now valid
|
||||
if (identifierInvalid && hasValidIdentifier(event.target.value)) {
|
||||
setIdentifierInvalid(false);
|
||||
}
|
||||
setIdHasBeenUpdatedByUser(true);
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
textInputs.push(
|
||||
<TextInput
|
||||
id="process-model-description"
|
||||
name="description"
|
||||
labelText="Description"
|
||||
value={processModel.description}
|
||||
onChange={(event: any) =>
|
||||
updateProcessModel({ description: event.target.value })
|
||||
}
|
||||
/>
|
||||
);
|
||||
|
||||
return textInputs;
|
||||
};
|
||||
|
||||
const formButtons = () => {
|
||||
const buttons = [
|
||||
<Button kind="secondary" type="submit">
|
||||
Submit
|
||||
</Button>,
|
||||
];
|
||||
if (mode === 'edit') {
|
||||
buttons.push(
|
||||
<ButtonWithConfirmation
|
||||
description={`Delete Process Model ${processModel.id}?`}
|
||||
onConfirmation={deleteProcessModel}
|
||||
buttonLabel="Delete"
|
||||
confirmButtonLabel="Delete"
|
||||
/>
|
||||
);
|
||||
}
|
||||
return <ButtonSet>{buttons}</ButtonSet>;
|
||||
};
|
||||
return (
|
||||
<Form onSubmit={handleFormSubmission}>
|
||||
<Stack gap={5}>
|
||||
{formElements()}
|
||||
{formButtons()}
|
||||
</Stack>
|
||||
</Form>
|
||||
);
|
||||
}
|
|
@ -21,7 +21,7 @@ export default function ProcessModelSearch({
|
|||
const shouldFilterProcessModel = (options: any) => {
|
||||
const processModel: ProcessModel = options.item;
|
||||
const { inputValue } = options;
|
||||
return `${processModel.process_group_id}/${processModel.id} (${processModel.display_name})`.includes(
|
||||
return `${processModel.id} (${processModel.display_name})`.includes(
|
||||
inputValue
|
||||
);
|
||||
};
|
||||
|
@ -33,9 +33,10 @@ export default function ProcessModelSearch({
|
|||
items={processModels}
|
||||
itemToString={(processModel: ProcessModel) => {
|
||||
if (processModel) {
|
||||
return `${processModel.process_group_id}/${
|
||||
processModel.id
|
||||
} (${truncateString(processModel.display_name, 20)})`;
|
||||
return `${processModel.id} (${truncateString(
|
||||
processModel.display_name,
|
||||
20
|
||||
)})`;
|
||||
}
|
||||
return null;
|
||||
}}
|
||||
|
|
|
@ -59,7 +59,6 @@ import { makeid } from '../helpers';
|
|||
|
||||
type OwnProps = {
|
||||
processModelId: string;
|
||||
processGroupId: string;
|
||||
diagramType: string;
|
||||
readyOrWaitingBpmnTaskIds?: string[] | null;
|
||||
completedTasksBpmnIds?: string[] | null;
|
||||
|
@ -83,7 +82,6 @@ type OwnProps = {
|
|||
// https://codesandbox.io/s/quizzical-lake-szfyo?file=/src/App.js was a handy reference
|
||||
export default function ReactDiagramEditor({
|
||||
processModelId,
|
||||
processGroupId,
|
||||
diagramType,
|
||||
readyOrWaitingBpmnTaskIds,
|
||||
completedTasksBpmnIds,
|
||||
|
@ -408,6 +406,7 @@ export default function ReactDiagramEditor({
|
|||
}
|
||||
|
||||
function fetchDiagramFromURL(urlToUse: any) {
|
||||
console.log(`urlToUse: ${urlToUse}`);
|
||||
fetch(urlToUse)
|
||||
.then((response) => response.text())
|
||||
.then((text) => {
|
||||
|
@ -424,7 +423,7 @@ export default function ReactDiagramEditor({
|
|||
|
||||
function fetchDiagramFromJsonAPI() {
|
||||
HttpService.makeCallToBackend({
|
||||
path: `/process-models/${processGroupId}/${processModelId}/files/${fileName}`,
|
||||
path: `/process-models/${processModelId}/files/${fileName}`,
|
||||
successCallback: setDiagramXMLStringFromResponseJson,
|
||||
});
|
||||
}
|
||||
|
@ -470,7 +469,6 @@ export default function ReactDiagramEditor({
|
|||
completedTasksBpmnIds,
|
||||
fileName,
|
||||
performingXmlUpdates,
|
||||
processGroupId,
|
||||
processModelId,
|
||||
url,
|
||||
]);
|
||||
|
|
|
@ -95,13 +95,10 @@ export const getProcessModelFullIdentifierFromSearchParams = (
|
|||
searchParams: any
|
||||
) => {
|
||||
let processModelFullIdentifier = null;
|
||||
if (
|
||||
searchParams.get('process_model_identifier') &&
|
||||
searchParams.get('process_group_identifier')
|
||||
) {
|
||||
if (searchParams.get('process_model_identifier')) {
|
||||
processModelFullIdentifier = `${searchParams.get(
|
||||
'process_group_identifier'
|
||||
)}/${searchParams.get('process_model_identifier')}`;
|
||||
'process_model_identifier'
|
||||
)}`;
|
||||
}
|
||||
return processModelFullIdentifier;
|
||||
};
|
||||
|
@ -113,3 +110,22 @@ export const truncateString = (text: string, len: number) => {
|
|||
}
|
||||
return text;
|
||||
};
|
||||
|
||||
// Because of limitations in the way openapi defines parameters, we have to modify process models ids
|
||||
// which are basically paths to the models
|
||||
export const modifyProcessModelPath = (path: string) => {
|
||||
return path.replace('/', ':') || '';
|
||||
};
|
||||
|
||||
export const unModifyProcessModelPath = (path: string) => {
|
||||
return path.replace(':', '/') || '';
|
||||
};
|
||||
|
||||
export const getGroupFromModifiedModelId = (modifiedId: string) => {
|
||||
const finalSplitIndex = modifiedId.lastIndexOf(':');
|
||||
return modifiedId.slice(0, finalSplitIndex);
|
||||
};
|
||||
|
||||
export const splitProcessModelId = (processModelId: string) => {
|
||||
return processModelId.split('/');
|
||||
};
|
||||
|
|
|
@ -40,6 +40,18 @@ span.bjs-crumb {
|
|||
opacity: .4;
|
||||
}
|
||||
|
||||
.accordion-item-label {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.cds--breadcrumb {
|
||||
margin-bottom: 2em;
|
||||
}
|
||||
|
||||
.process-description {
|
||||
margin-bottom: 2em;
|
||||
}
|
||||
|
||||
.diagram-editor-canvas {
|
||||
border:1px solid #000000;
|
||||
height:70vh;
|
||||
|
|
|
@ -1,10 +1,22 @@
|
|||
// @use '@carbon/react/scss/themes';
|
||||
// @use '@carbon/react/scss/theme' with ($theme: themes.$g100);
|
||||
|
||||
// @use '@carbon/react/scss/theme' with
|
||||
// (
|
||||
// $theme: (
|
||||
// cds-link-primary: #525252
|
||||
// )
|
||||
// );
|
||||
|
||||
@use '@carbon/react';
|
||||
@use '@carbon/styles';
|
||||
// @include grid.flex-grid();
|
||||
|
||||
@use '@carbon/colors';
|
||||
// @use '@carbon/react/scss/colors';
|
||||
@use '@carbon/react/scss/themes';
|
||||
|
||||
// var(--cds-link-text-color, var(--cds-link-primary, #0f62fe))
|
||||
|
||||
// site is mainly using white theme.
|
||||
// header is mainly using g100
|
||||
|
@ -13,3 +25,75 @@
|
|||
// background-color: colors.$gray-100;
|
||||
color: white;
|
||||
}
|
||||
h1{
|
||||
height: 36px;
|
||||
font-family: 'IBM Plex Sans';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-size: 28px;
|
||||
line-height: 36px;
|
||||
color: #161616;
|
||||
flex: none;
|
||||
order: 0;
|
||||
align-self: stretch;
|
||||
flex-grow: 0;
|
||||
margin-bottom: 1em
|
||||
}
|
||||
|
||||
|
||||
.cds--breadcrumb-item a.cds--link:hover {
|
||||
color: #525252;
|
||||
}
|
||||
.cds--breadcrumb-item a.cds--link:visited {
|
||||
color: #525252;
|
||||
}
|
||||
.cds--breadcrumb-item a.cds--link:visited:hover {
|
||||
color: #525252;
|
||||
}
|
||||
.cds--breadcrumb-item a.cds--link {
|
||||
color: #525252;
|
||||
}
|
||||
|
||||
.cds--btn--ghost {
|
||||
color: black;
|
||||
}
|
||||
.cds--btn--ghost:visited {
|
||||
color: black;
|
||||
}
|
||||
.cds--btn--ghost:hover {
|
||||
color: black;
|
||||
}
|
||||
.cds--btn--ghost:visited:hover {
|
||||
color: black;
|
||||
}
|
||||
|
||||
$slightly-lighter-gray: #474747;
|
||||
$spiff-header-background-color: #161616;
|
||||
|
||||
.cds--header__global .cds--btn--primary {
|
||||
background-color: $spiff-header-background-color;
|
||||
}
|
||||
.cds--btn--primary {
|
||||
background-color: #393939;
|
||||
}
|
||||
.cds--btn--primary:hover {
|
||||
background-color: $slightly-lighter-gray;
|
||||
}
|
||||
// .cds--btn--ghost:visited {
|
||||
// color: black;
|
||||
// }
|
||||
// .cds--btn--ghost:hover {
|
||||
// color: black;
|
||||
// }
|
||||
// .cds--btn--ghost:visited:hover {
|
||||
// color: black;
|
||||
// }
|
||||
|
||||
|
||||
// :root {
|
||||
// --cds-link-primary: #525252;
|
||||
// }
|
||||
// .card {
|
||||
// background: var(--orange);
|
||||
// --orange: hsl(255, 72%, var(--lightness));
|
||||
// }
|
||||
|
|
|
@ -27,23 +27,23 @@ export interface ProcessFile {
|
|||
content_type: string;
|
||||
last_modified: string;
|
||||
name: string;
|
||||
process_group_id: string;
|
||||
process_model_id: string;
|
||||
references: ProcessFileReference[];
|
||||
size: number;
|
||||
type: string;
|
||||
file_contents?: string;
|
||||
}
|
||||
|
||||
export interface ProcessModel {
|
||||
id: string;
|
||||
process_group_id: string;
|
||||
description: string;
|
||||
display_name: string;
|
||||
primary_file_name: string;
|
||||
files: ProcessFile[];
|
||||
}
|
||||
|
||||
// tuple of display value and URL
|
||||
export type BreadcrumbItem = [displayValue: string, url?: string];
|
||||
export type HotCrumbItem = [displayValue: string, url?: string];
|
||||
|
||||
export interface ErrorForDisplay {
|
||||
message: string;
|
||||
|
|
|
@ -53,35 +53,35 @@ export default function AdminRoutes() {
|
|||
element={<ProcessModelNew />}
|
||||
/>
|
||||
<Route
|
||||
path="process-models/:process_group_id/:process_model_id"
|
||||
path="process-models/:process_model_id"
|
||||
element={<ProcessModelShow />}
|
||||
/>
|
||||
<Route
|
||||
path="process-models/:process_group_id/:process_model_id/files"
|
||||
path="process-models/:process_model_id/files"
|
||||
element={<ProcessModelEditDiagram />}
|
||||
/>
|
||||
<Route
|
||||
path="process-models/:process_group_id/:process_model_id/files/:file_name"
|
||||
path="process-models/:process_model_id/files/:file_name"
|
||||
element={<ProcessModelEditDiagram />}
|
||||
/>
|
||||
<Route
|
||||
path="process-models/:process_group_id/:process_model_id/process-instances"
|
||||
path="process-models/:process_model_id/process-instances"
|
||||
element={<ProcessInstanceList />}
|
||||
/>
|
||||
<Route
|
||||
path="process-models/:process_group_id/:process_model_id/edit"
|
||||
path="process-models/:process_model_id/edit"
|
||||
element={<ProcessModelEdit />}
|
||||
/>
|
||||
<Route
|
||||
path="process-models/:process_group_id/:process_model_id/process-instances/:process_instance_id"
|
||||
path="process-models/:process_model_id/process-instances/:process_instance_id"
|
||||
element={<ProcessInstanceShow />}
|
||||
/>
|
||||
<Route
|
||||
path="process-models/:process_group_id/:process_model_id/process-instances/:process_instance_id/:spiff_step"
|
||||
path="process-models/:process_model_id/process-instances/:process_instance_id/:spiff_step"
|
||||
element={<ProcessInstanceShow />}
|
||||
/>
|
||||
<Route
|
||||
path="process-models/:process_group_id/:process_model_id/process-instances/reports"
|
||||
path="process-models/:process_model_id/process-instances/reports"
|
||||
element={<ProcessInstanceReportList />}
|
||||
/>
|
||||
<Route
|
||||
|
@ -97,15 +97,15 @@ export default function AdminRoutes() {
|
|||
element={<ProcessInstanceReportEdit />}
|
||||
/>
|
||||
<Route
|
||||
path="process-models/:process_group_id/:process_model_id/form"
|
||||
path="process-models/:process_model_id/form"
|
||||
element={<ReactFormEditor />}
|
||||
/>
|
||||
<Route
|
||||
path="process-models/:process_group_id/:process_model_id/form/:file_name"
|
||||
path="process-models/:process_model_id/form/:file_name"
|
||||
element={<ReactFormEditor />}
|
||||
/>
|
||||
<Route
|
||||
path="process-models/:process_group_id/:process_model_id/process-instances/:process_instance_id/logs"
|
||||
path="process-models/:process_model_id/process-instances/:process_instance_id/logs"
|
||||
element={<ProcessInstanceLogList />}
|
||||
/>
|
||||
<Route path="process-instances" element={<ProcessInstanceList />} />
|
||||
|
|
|
@ -3,7 +3,10 @@ import { useEffect, useState } from 'react';
|
|||
import { Button, Table } from '@carbon/react';
|
||||
import { Link, useSearchParams } from 'react-router-dom';
|
||||
import PaginationForTable from '../components/PaginationForTable';
|
||||
import { getPageInfoFromSearchParams } from '../helpers';
|
||||
import {
|
||||
getPageInfoFromSearchParams,
|
||||
modifyProcessModelPath,
|
||||
} from '../helpers';
|
||||
import HttpService from '../services/HttpService';
|
||||
import { PaginationObject, RecentProcessModel } from '../interfaces';
|
||||
|
||||
|
@ -39,12 +42,15 @@ export default function HomePage() {
|
|||
const rows = tasks.map((row) => {
|
||||
const rowToUse = row as any;
|
||||
const taskUrl = `/tasks/${rowToUse.process_instance_id}/${rowToUse.id}`;
|
||||
const modifiedProcessModelIdentifier = modifyProcessModelPath(
|
||||
rowToUse.process_model_identifier
|
||||
);
|
||||
return (
|
||||
<tr key={rowToUse.id}>
|
||||
<td>
|
||||
<Link
|
||||
data-qa="process-model-show-link"
|
||||
to={`/admin/process-models/${rowToUse.process_group_identifier}/${rowToUse.process_model_identifier}`}
|
||||
to={`/admin/process-models/${modifiedProcessModelIdentifier}`}
|
||||
>
|
||||
{rowToUse.process_model_display_name}
|
||||
</Link>
|
||||
|
@ -52,7 +58,7 @@ export default function HomePage() {
|
|||
<td>
|
||||
<Link
|
||||
data-qa="process-instance-show-link"
|
||||
to={`/admin/process-models/${rowToUse.process_group_identifier}/${rowToUse.process_model_identifier}/process-instances/${rowToUse.process_instance_id}`}
|
||||
to={`/admin/process-models/${modifiedProcessModelIdentifier}/process-instances/${rowToUse.process_instance_id}`}
|
||||
>
|
||||
View {rowToUse.process_instance_id}
|
||||
</Link>
|
||||
|
@ -96,6 +102,9 @@ export default function HomePage() {
|
|||
const buildRecentProcessModelSection = () => {
|
||||
const rows = recentProcessModels.map((row) => {
|
||||
const rowToUse = row as any;
|
||||
const modifiedProcessModelId = modifyProcessModelPath(
|
||||
rowToUse.processModelIdentifier
|
||||
);
|
||||
return (
|
||||
<tr
|
||||
key={`${rowToUse.processGroupIdentifier}/${rowToUse.processModelIdentifier}`}
|
||||
|
@ -103,7 +112,7 @@ export default function HomePage() {
|
|||
<td>
|
||||
<Link
|
||||
data-qa="process-model-show-link"
|
||||
to={`/admin/process-models/${rowToUse.processGroupIdentifier}/${rowToUse.processModelIdentifier}`}
|
||||
to={`/admin/process-models/${modifiedProcessModelId}`}
|
||||
>
|
||||
{rowToUse.processModelDisplayName}
|
||||
</Link>
|
||||
|
|
|
@ -13,7 +13,10 @@ import {
|
|||
import ProcessBreadcrumb from '../components/ProcessBreadcrumb';
|
||||
import PaginationForTable from '../components/PaginationForTable';
|
||||
import HttpService from '../services/HttpService';
|
||||
import { getPageInfoFromSearchParams } from '../helpers';
|
||||
import {
|
||||
getPageInfoFromSearchParams,
|
||||
modifyProcessModelPath,
|
||||
} from '../helpers';
|
||||
import { CarbonComboBoxSelection, ProcessGroup } from '../interfaces';
|
||||
import ProcessModelSearch from '../components/ProcessModelSearch';
|
||||
|
||||
|
@ -36,7 +39,7 @@ export default function ProcessGroupList() {
|
|||
};
|
||||
const processResultForProcessModels = (result: any) => {
|
||||
const selectionArray = result.results.map((item: any) => {
|
||||
const label = `${item.process_group_id}/${item.id}`;
|
||||
const label = `${item.id}`;
|
||||
Object.assign(item, { label });
|
||||
return item;
|
||||
});
|
||||
|
@ -120,7 +123,7 @@ export default function ProcessGroupList() {
|
|||
const processModelSearchOnChange = (selection: CarbonComboBoxSelection) => {
|
||||
const processModel = selection.selectedItem;
|
||||
navigate(
|
||||
`/admin/process-models/${processModel.process_group_id}/${processModel.id}`
|
||||
`/admin/process-models/${modifyProcessModelPath(processModel.id)}`
|
||||
);
|
||||
};
|
||||
return (
|
||||
|
|
|
@ -24,6 +24,7 @@ export default function ProcessGroupShow() {
|
|||
setPagination(result.pagination);
|
||||
};
|
||||
const processResult = (result: any) => {
|
||||
console.log(result);
|
||||
setProcessGroup(result);
|
||||
HttpService.makeCallToBackend({
|
||||
path: `/process-models?process_group_identifier=${params.process_group_id}&per_page=${perPage}&page=${page}`,
|
||||
|
@ -41,11 +42,12 @@ export default function ProcessGroupShow() {
|
|||
return null;
|
||||
}
|
||||
const rows = processModels.map((row) => {
|
||||
const modifiedProcessModelId: String = (row as any).id.replace('/', ':');
|
||||
return (
|
||||
<tr key={(row as any).id}>
|
||||
<td>
|
||||
<Link
|
||||
to={`/admin/process-models/${processGroup.id}/${(row as any).id}`}
|
||||
to={`/admin/process-models/${modifiedProcessModelId}`}
|
||||
data-qa="process-model-show-link"
|
||||
>
|
||||
{(row as any).id}
|
||||
|
|
|
@ -17,11 +17,9 @@ import {
|
|||
Grid,
|
||||
Column,
|
||||
MultiSelect,
|
||||
// TableHeader,
|
||||
// TableHead,
|
||||
// TableRow,
|
||||
// TableBody,
|
||||
// TableCell,
|
||||
TableHeader,
|
||||
TableHead,
|
||||
TableRow,
|
||||
// @ts-ignore
|
||||
} from '@carbon/react';
|
||||
import { PROCESS_STATUSES, DATE_FORMAT, DATE_FORMAT_CARBON } from '../config';
|
||||
|
@ -30,6 +28,7 @@ import {
|
|||
convertSecondsToFormattedDate,
|
||||
getPageInfoFromSearchParams,
|
||||
getProcessModelFullIdentifierFromSearchParams,
|
||||
modifyProcessModelPath,
|
||||
} from '../helpers';
|
||||
|
||||
import PaginationForTable from '../components/PaginationForTable';
|
||||
|
@ -49,6 +48,7 @@ export default function ProcessInstanceList() {
|
|||
const navigate = useNavigate();
|
||||
|
||||
const [processInstances, setProcessInstances] = useState([]);
|
||||
const [reportMetadata, setReportMetadata] = useState({});
|
||||
const [pagination, setPagination] = useState<PaginationObject | null>(null);
|
||||
|
||||
const oneHourInSeconds = 3600;
|
||||
|
@ -84,7 +84,6 @@ export default function ProcessInstanceList() {
|
|||
|
||||
const parametersToGetFromSearchParams = useMemo(() => {
|
||||
return {
|
||||
process_group_identifier: null,
|
||||
process_model_identifier: null,
|
||||
process_status: null,
|
||||
};
|
||||
|
@ -95,6 +94,7 @@ export default function ProcessInstanceList() {
|
|||
function setProcessInstancesFromResult(result: any) {
|
||||
const processInstancesFromApi = result.results;
|
||||
setProcessInstances(processInstancesFromApi);
|
||||
setReportMetadata(result.report_metadata);
|
||||
setPagination(result.pagination);
|
||||
}
|
||||
function getProcessInstances() {
|
||||
|
@ -111,6 +111,7 @@ export default function ProcessInstanceList() {
|
|||
searchParamValue as any
|
||||
);
|
||||
functionToCall(dateString);
|
||||
setShowFilterOptions(true);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -123,6 +124,7 @@ export default function ProcessInstanceList() {
|
|||
if (functionToCall !== null) {
|
||||
functionToCall(searchParams.get(paramName) || '');
|
||||
}
|
||||
setShowFilterOptions(true);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
@ -135,7 +137,7 @@ export default function ProcessInstanceList() {
|
|||
const processModelFullIdentifier =
|
||||
getProcessModelFullIdentifierFromSearchParams(searchParams);
|
||||
const selectionArray = result.results.map((item: any) => {
|
||||
const label = `${item.process_group_id}/${item.id}`;
|
||||
const label = `${item.id}`;
|
||||
Object.assign(item, { label });
|
||||
if (label === processModelFullIdentifier) {
|
||||
setProcessModelSelection(item);
|
||||
|
@ -160,6 +162,7 @@ export default function ProcessInstanceList() {
|
|||
getProcessInstances();
|
||||
}
|
||||
|
||||
// populate process model selection
|
||||
HttpService.makeCallToBackend({
|
||||
path: `/process-models?per_page=1000`,
|
||||
successCallback: processResultForProcessModels,
|
||||
|
@ -241,7 +244,7 @@ export default function ProcessInstanceList() {
|
|||
}
|
||||
|
||||
if (processModelSelection) {
|
||||
queryParamString += `&process_group_identifier=${processModelSelection.process_group_id}&process_model_identifier=${processModelSelection.id}`;
|
||||
queryParamString += `&process_model_identifier=${processModelSelection.id}`;
|
||||
}
|
||||
|
||||
setErrorMessage(null);
|
||||
|
@ -296,6 +299,7 @@ export default function ProcessInstanceList() {
|
|||
return (
|
||||
<MultiSelect
|
||||
label="Choose Status"
|
||||
className="our-class"
|
||||
id="process-instance-status-select"
|
||||
titleText="Status"
|
||||
items={processStatusAllOptions}
|
||||
|
@ -367,7 +371,11 @@ export default function ProcessInstanceList() {
|
|||
>
|
||||
Clear
|
||||
</Button>
|
||||
<Button kind="secondary" onClick={applyFilter}>
|
||||
<Button
|
||||
kind="secondary"
|
||||
onClick={applyFilter}
|
||||
data-qa="filter-button"
|
||||
>
|
||||
Filter
|
||||
</Button>
|
||||
</ButtonSet>
|
||||
|
@ -378,54 +386,86 @@ export default function ProcessInstanceList() {
|
|||
};
|
||||
|
||||
const buildTable = () => {
|
||||
const rows = processInstances.map((row: any) => {
|
||||
const formattedStartDate =
|
||||
convertSecondsToFormattedDate(row.start_in_seconds) || '-';
|
||||
const formattedEndDate =
|
||||
convertSecondsToFormattedDate(row.end_in_seconds) || '-';
|
||||
|
||||
return (
|
||||
<tr key={row.id}>
|
||||
<td>
|
||||
<Link
|
||||
data-qa="process-instance-show-link"
|
||||
to={`/admin/process-models/${row.process_group_identifier}/${row.process_model_identifier}/process-instances/${row.id}`}
|
||||
>
|
||||
{row.id}
|
||||
</Link>
|
||||
</td>
|
||||
<td>
|
||||
<Link to={`/admin/process-groups/${row.process_group_identifier}`}>
|
||||
{row.process_group_identifier}
|
||||
</Link>
|
||||
</td>
|
||||
<td>
|
||||
<Link
|
||||
to={`/admin/process-models/${row.process_group_identifier}/${row.process_model_identifier}`}
|
||||
>
|
||||
{row.process_model_identifier}
|
||||
</Link>
|
||||
</td>
|
||||
<td>{formattedStartDate}</td>
|
||||
<td>{formattedEndDate}</td>
|
||||
<td data-qa={`process-instance-status-${row.status}`}>
|
||||
{row.status}
|
||||
</td>
|
||||
</tr>
|
||||
);
|
||||
const headerLabels: Record<string, string> = {
|
||||
id: 'Process Instance Id',
|
||||
process_model_identifier: 'Process Model',
|
||||
start_in_seconds: 'Start Time',
|
||||
end_in_seconds: 'End Time',
|
||||
status: 'Status',
|
||||
spiff_step: 'SpiffWorkflow Step',
|
||||
};
|
||||
const getHeaderLabel = (header: string) => {
|
||||
return headerLabels[header] ?? header;
|
||||
};
|
||||
const headers = (reportMetadata as any).columns.map((column: any) => {
|
||||
// return <th>{getHeaderLabel((column as any).Header)}</th>;
|
||||
return getHeaderLabel((column as any).Header);
|
||||
});
|
||||
|
||||
const formatProcessInstanceId = (row: any, id: any) => {
|
||||
const modifiedProcessModelId: String = modifyProcessModelPath(
|
||||
row.process_model_identifier
|
||||
);
|
||||
return (
|
||||
<Link
|
||||
data-qa="process-instance-show-link"
|
||||
to={`/admin/process-models/${modifiedProcessModelId}/process-instances/${row.id}`}
|
||||
>
|
||||
{id}
|
||||
</Link>
|
||||
);
|
||||
};
|
||||
const formatProcessModelIdentifier = (_row: any, identifier: any) => {
|
||||
return (
|
||||
<Link
|
||||
to={`/admin/process-models/${modifyProcessModelPath(identifier)}`}
|
||||
>
|
||||
{identifier}
|
||||
</Link>
|
||||
);
|
||||
};
|
||||
const formatSecondsForDisplay = (_row: any, seconds: any) => {
|
||||
return convertSecondsToFormattedDate(seconds) || '-';
|
||||
};
|
||||
const defaultFormatter = (_row: any, value: any) => {
|
||||
return value;
|
||||
};
|
||||
|
||||
const columnFormatters: Record<string, any> = {
|
||||
id: formatProcessInstanceId,
|
||||
process_model_identifier: formatProcessModelIdentifier,
|
||||
start_in_seconds: formatSecondsForDisplay,
|
||||
end_in_seconds: formatSecondsForDisplay,
|
||||
};
|
||||
const formattedColumn = (row: any, column: any) => {
|
||||
const formatter = columnFormatters[column.accessor] ?? defaultFormatter;
|
||||
const value = row[column.accessor];
|
||||
if (column.accessor === 'status') {
|
||||
return (
|
||||
<td data-qa={`process-instance-status-${value}`}>
|
||||
{formatter(row, value)}
|
||||
</td>
|
||||
);
|
||||
}
|
||||
return <td>{formatter(row, value)}</td>;
|
||||
};
|
||||
|
||||
const rows = processInstances.map((row: any) => {
|
||||
const currentRow = (reportMetadata as any).columns.map((column: any) => {
|
||||
return formattedColumn(row, column);
|
||||
});
|
||||
return <tr key={row.id}>{currentRow}</tr>;
|
||||
});
|
||||
|
||||
return (
|
||||
<Table size="lg">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Process Instance Id</th>
|
||||
<th>Process Group</th>
|
||||
<th>Process Model</th>
|
||||
<th>Start Time</th>
|
||||
<th>End Time</th>
|
||||
<th>Status</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
{headers.map((header: any) => (
|
||||
<TableHeader key={header}>{header}</TableHeader>
|
||||
))}
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
<tbody>{rows}</tbody>
|
||||
</Table>
|
||||
);
|
||||
|
@ -440,7 +480,11 @@ export default function ProcessInstanceList() {
|
|||
return (
|
||||
<h2>
|
||||
Process Instances for:{' '}
|
||||
<Link to={`/admin/process-models/${processModelFullIdentifier}`}>
|
||||
<Link
|
||||
to={`/admin/process-models/${modifyProcessModelPath(
|
||||
processModelFullIdentifier
|
||||
)}`}
|
||||
>
|
||||
{processModelFullIdentifier}
|
||||
</Link>
|
||||
</h2>
|
||||
|
@ -457,9 +501,13 @@ export default function ProcessInstanceList() {
|
|||
<>
|
||||
{processInstanceTitleElement()}
|
||||
<Grid fullWidth>
|
||||
<Column lg={15} />
|
||||
<Column lg={1}>
|
||||
<Column
|
||||
sm={{ span: 1, offset: 3 }}
|
||||
md={{ span: 1, offset: 7 }}
|
||||
lg={{ span: 1, offset: 15 }}
|
||||
>
|
||||
<Button
|
||||
data-qa="filter-section-expand-toggle"
|
||||
kind="ghost"
|
||||
renderIcon={Filter}
|
||||
iconDescription="Filter Options"
|
||||
|
@ -471,18 +519,14 @@ export default function ProcessInstanceList() {
|
|||
</Grid>
|
||||
{filterOptions()}
|
||||
<br />
|
||||
<Grid fullWidth>
|
||||
<Column lg={16}>
|
||||
<PaginationForTable
|
||||
page={page}
|
||||
perPage={perPage}
|
||||
pagination={pagination}
|
||||
tableToDisplay={buildTable()}
|
||||
queryParamString={getSearchParamsAsQueryString()}
|
||||
path="/admin/process-instances"
|
||||
/>
|
||||
</Column>
|
||||
</Grid>
|
||||
<PaginationForTable
|
||||
page={page}
|
||||
perPage={perPage}
|
||||
pagination={pagination}
|
||||
tableToDisplay={buildTable()}
|
||||
queryParamString={getSearchParamsAsQueryString()}
|
||||
path="/admin/process-instances"
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ import ProcessBreadcrumb from '../components/ProcessBreadcrumb';
|
|||
import {
|
||||
getPageInfoFromSearchParams,
|
||||
convertSecondsToFormattedDate,
|
||||
modifyProcessModelPath,
|
||||
} from '../helpers';
|
||||
import HttpService from '../services/HttpService';
|
||||
|
||||
|
@ -15,6 +16,9 @@ export default function ProcessInstanceLogList() {
|
|||
const [searchParams] = useSearchParams();
|
||||
const [processInstanceLogs, setProcessInstanceLogs] = useState([]);
|
||||
const [pagination, setPagination] = useState(null);
|
||||
const modifiedProcessModelId = modifyProcessModelPath(
|
||||
`${params.process_model_id}`
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
const setProcessInstanceLogListFromResult = (result: any) => {
|
||||
|
@ -23,7 +27,7 @@ export default function ProcessInstanceLogList() {
|
|||
};
|
||||
const { page, perPage } = getPageInfoFromSearchParams(searchParams);
|
||||
HttpService.makeCallToBackend({
|
||||
path: `/process-models/${params.process_group_id}/${params.process_model_id}/process-instances/${params.process_instance_id}/logs?per_page=${perPage}&page=${page}`,
|
||||
path: `/process-instances/${params.process_instance_id}/logs?per_page=${perPage}&page=${page}`,
|
||||
successCallback: setProcessInstanceLogListFromResult,
|
||||
});
|
||||
}, [searchParams, params]);
|
||||
|
@ -32,6 +36,7 @@ export default function ProcessInstanceLogList() {
|
|||
// return null;
|
||||
const rows = processInstanceLogs.map((row) => {
|
||||
const rowToUse = row as any;
|
||||
console.log(`rowToUse: ${rowToUse}`);
|
||||
return (
|
||||
<tr key={rowToUse.id}>
|
||||
<td>{rowToUse.bpmn_process_identifier}</td>
|
||||
|
@ -43,7 +48,7 @@ export default function ProcessInstanceLogList() {
|
|||
<td>
|
||||
<Link
|
||||
data-qa="process-instance-show-link"
|
||||
to={`/admin/process-models/${params.process_group_id}/${params.process_model_id}/process-instances/${rowToUse.process_instance_id}/${rowToUse.spiff_step}`}
|
||||
to={`/admin/process-models/${modifiedProcessModelId}/process-instances/${rowToUse.process_instance_id}/${rowToUse.spiff_step}`}
|
||||
>
|
||||
{convertSecondsToFormattedDate(rowToUse.timestamp)}
|
||||
</Link>
|
||||
|
@ -83,7 +88,7 @@ export default function ProcessInstanceLogList() {
|
|||
perPage={perPage}
|
||||
pagination={pagination}
|
||||
tableToDisplay={buildTable()}
|
||||
path={`/admin/process-models/${params.process_group_id}/${params.process_model_id}/process-instances/${params.process_instance_id}/logs`}
|
||||
path={`/admin/process-models/${modifiedProcessModelId}/process-instances/${params.process_instance_id}/logs`}
|
||||
/>
|
||||
</main>
|
||||
);
|
||||
|
|
|
@ -56,7 +56,7 @@ export default function ProcessInstanceReportEdit() {
|
|||
};
|
||||
function getProcessInstanceReport() {
|
||||
HttpService.makeCallToBackend({
|
||||
path: `/process-models/${params.process_group_id}/${params.process_model_id}/process-instances/reports/${params.report_identifier}?per_page=1`,
|
||||
path: `/process-instances/reports/${params.report_identifier}?per_page=1`,
|
||||
successCallback: processResult,
|
||||
});
|
||||
}
|
||||
|
@ -88,7 +88,7 @@ export default function ProcessInstanceReportEdit() {
|
|||
.filter((n) => n);
|
||||
|
||||
HttpService.makeCallToBackend({
|
||||
path: `/process-models/${params.process_group_id}/${params.process_model_id}/process-instances/reports/${params.report_identifier}`,
|
||||
path: `/process-instances/reports/${params.report_identifier}`,
|
||||
successCallback: navigateToProcessInstanceReport,
|
||||
httpMethod: 'PUT',
|
||||
postBody: {
|
||||
|
@ -103,7 +103,7 @@ export default function ProcessInstanceReportEdit() {
|
|||
|
||||
const deleteProcessInstanceReport = () => {
|
||||
HttpService.makeCallToBackend({
|
||||
path: `/process-models/${params.process_group_id}/${params.process_model_id}/process-instances/reports/${params.report_identifier}`,
|
||||
path: `/process-instances/reports/${params.report_identifier}`,
|
||||
successCallback: navigateToProcessInstanceReports,
|
||||
httpMethod: 'DELETE',
|
||||
});
|
||||
|
|
|
@ -4,14 +4,18 @@ import { Button, Table } from '@carbon/react';
|
|||
import { useParams, Link } from 'react-router-dom';
|
||||
import ProcessBreadcrumb from '../components/ProcessBreadcrumb';
|
||||
import HttpService from '../services/HttpService';
|
||||
import { modifyProcessModelPath } from '../helpers';
|
||||
|
||||
export default function ProcessInstanceReportList() {
|
||||
const params = useParams();
|
||||
const [processInstanceReports, setProcessInstanceReports] = useState([]);
|
||||
const modifiedProcessModelId = modifyProcessModelPath(
|
||||
params.process_model_id || ''
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
HttpService.makeCallToBackend({
|
||||
path: `/process-models/${params.process_group_id}/${params.process_model_id}/process-instances/reports`,
|
||||
path: `/process-instances/reports`,
|
||||
successCallback: setProcessInstanceReports,
|
||||
});
|
||||
}, [params]);
|
||||
|
@ -23,7 +27,7 @@ export default function ProcessInstanceReportList() {
|
|||
<tr key={(row as any).id}>
|
||||
<td>
|
||||
<Link
|
||||
to={`/admin/process-models/${params.process_group_id}/${params.process_model_id}/process-instances/reports/${rowToUse.identifier}`}
|
||||
to={`/admin/process-models/${modifiedProcessModelId}/process-instances/reports/${rowToUse.identifier}`}
|
||||
>
|
||||
{rowToUse.identifier}
|
||||
</Link>
|
||||
|
@ -52,7 +56,7 @@ export default function ProcessInstanceReportList() {
|
|||
/>
|
||||
<h2>Reports for Process Model: {params.process_model_id}</h2>
|
||||
<Button
|
||||
href={`/admin/process-models/${params.process_group_id}/${params.process_model_id}/process-instances/reports/new`}
|
||||
href={`/admin/process-models/${modifiedProcessModelId}/process-instances/reports/new`}
|
||||
>
|
||||
Add a process instance report
|
||||
</Button>
|
||||
|
|
|
@ -42,7 +42,7 @@ export default function ProcessInstanceReportNew() {
|
|||
.filter((n) => n);
|
||||
|
||||
HttpService.makeCallToBackend({
|
||||
path: `/process-models/${params.process_group_id}/${params.process_model_id}/process-instances/reports`,
|
||||
path: `/process-instances/reports`,
|
||||
successCallback: navigateToNewProcessInstance,
|
||||
httpMethod: 'POST',
|
||||
postBody: {
|
||||
|
|
|
@ -39,7 +39,7 @@ export default function ProcessInstanceReport() {
|
|||
}
|
||||
});
|
||||
HttpService.makeCallToBackend({
|
||||
path: `/process-models/${params.process_group_id}/${params.process_model_id}/process-instances/reports/${params.report_identifier}?${query}`,
|
||||
path: `/process-instances/reports/${params.report_identifier}${query}`,
|
||||
successCallback: processResult,
|
||||
});
|
||||
}
|
||||
|
|
|
@ -6,7 +6,10 @@ import { Button, Modal, Stack } from '@carbon/react';
|
|||
import ProcessBreadcrumb from '../components/ProcessBreadcrumb';
|
||||
import HttpService from '../services/HttpService';
|
||||
import ReactDiagramEditor from '../components/ReactDiagramEditor';
|
||||
import { convertSecondsToFormattedDate } from '../helpers';
|
||||
import {
|
||||
convertSecondsToFormattedDate,
|
||||
unModifyProcessModelPath,
|
||||
} from '../helpers';
|
||||
import ButtonWithConfirmation from '../components/ButtonWithConfirmation';
|
||||
import ErrorContext from '../contexts/ErrorContext';
|
||||
|
||||
|
@ -22,15 +25,20 @@ export default function ProcessInstanceShow() {
|
|||
|
||||
const setErrorMessage = (useContext as any)(ErrorContext)[1];
|
||||
|
||||
const unModifiedProcessModelId = unModifyProcessModelPath(
|
||||
`${params.process_model_id}`
|
||||
);
|
||||
const modifiedProcessModelId = params.process_model_id;
|
||||
|
||||
const navigateToProcessInstances = (_result: any) => {
|
||||
navigate(
|
||||
`/admin/process-instances?process_group_identifier=${params.process_group_id}&process_model_identifier=${params.process_model_id}`
|
||||
`/admin/process-instances?process_model_identifier=${unModifiedProcessModelId}`
|
||||
);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
HttpService.makeCallToBackend({
|
||||
path: `/process-models/${params.process_group_id}/${params.process_model_id}/process-instances/${params.process_instance_id}`,
|
||||
path: `/process-models/${modifiedProcessModelId}/process-instances/${params.process_instance_id}`,
|
||||
successCallback: setProcessInstance,
|
||||
});
|
||||
if (typeof params.spiff_step === 'undefined')
|
||||
|
@ -43,11 +51,11 @@ export default function ProcessInstanceShow() {
|
|||
path: `/process-instance/${params.process_instance_id}/tasks?all_tasks=true&spiff_step=${params.spiff_step}`,
|
||||
successCallback: setTasks,
|
||||
});
|
||||
}, [params]);
|
||||
}, [params, modifiedProcessModelId]);
|
||||
|
||||
const deleteProcessInstance = () => {
|
||||
HttpService.makeCallToBackend({
|
||||
path: `/process-models/${params.process_group_id}/${params.process_model_id}/process-instances/${params.process_instance_id}`,
|
||||
path: `/process-instances/${params.process_instance_id}`,
|
||||
successCallback: navigateToProcessInstances,
|
||||
httpMethod: 'DELETE',
|
||||
});
|
||||
|
@ -60,7 +68,7 @@ export default function ProcessInstanceShow() {
|
|||
|
||||
const terminateProcessInstance = () => {
|
||||
HttpService.makeCallToBackend({
|
||||
path: `/process-models/${params.process_group_id}/${params.process_model_id}/process-instances/${params.process_instance_id}/terminate`,
|
||||
path: `/process-instances/${params.process_instance_id}/terminate`,
|
||||
successCallback: refreshPage,
|
||||
httpMethod: 'POST',
|
||||
});
|
||||
|
@ -68,7 +76,7 @@ export default function ProcessInstanceShow() {
|
|||
|
||||
const suspendProcessInstance = () => {
|
||||
HttpService.makeCallToBackend({
|
||||
path: `/process-models/${params.process_group_id}/${params.process_model_id}/process-instances/${params.process_instance_id}/suspend`,
|
||||
path: `/process-instances/${params.process_instance_id}/suspend`,
|
||||
successCallback: refreshPage,
|
||||
httpMethod: 'POST',
|
||||
});
|
||||
|
@ -76,7 +84,7 @@ export default function ProcessInstanceShow() {
|
|||
|
||||
const resumeProcessInstance = () => {
|
||||
HttpService.makeCallToBackend({
|
||||
path: `/process-models/${params.process_group_id}/${params.process_model_id}/process-instances/${params.process_instance_id}/resume`,
|
||||
path: `/process-instances/${params.process_instance_id}/resume`,
|
||||
successCallback: refreshPage,
|
||||
httpMethod: 'POST',
|
||||
});
|
||||
|
@ -125,7 +133,7 @@ export default function ProcessInstanceShow() {
|
|||
<Link
|
||||
reloadDocument
|
||||
data-qa="process-instance-step-link"
|
||||
to={`/admin/process-models/${params.process_group_id}/${
|
||||
to={`/admin/process-models/${
|
||||
params.process_model_id
|
||||
}/process-instances/${params.process_instance_id}/${
|
||||
currentSpiffStep(processInstanceToUse) + distance
|
||||
|
@ -179,7 +187,7 @@ export default function ProcessInstanceShow() {
|
|||
<li>
|
||||
<Link
|
||||
data-qa="process-instance-log-list-link"
|
||||
to={`/admin/process-models/${params.process_group_id}/${params.process_model_id}/process-instances/${params.process_instance_id}/logs`}
|
||||
to={`/admin/process-models/${modifiedProcessModelId}/process-instances/${params.process_instance_id}/logs`}
|
||||
>
|
||||
Logs
|
||||
</Link>
|
||||
|
@ -187,7 +195,7 @@ export default function ProcessInstanceShow() {
|
|||
<li>
|
||||
<Link
|
||||
data-qa="process-instance-message-instance-list-link"
|
||||
to={`/admin/messages?process_group_id=${params.process_group_id}&process_model_id=${params.process_model_id}&process_instance_id=${params.process_instance_id}`}
|
||||
to={`/admin/messages?process_model_id=${params.process_model_id}&process_instance_id=${params.process_instance_id}`}
|
||||
>
|
||||
Messages
|
||||
</Link>
|
||||
|
@ -284,7 +292,7 @@ export default function ProcessInstanceShow() {
|
|||
const taskToUse: any = taskToDisplay;
|
||||
const previousTask: any = getTaskById(taskToUse.parent);
|
||||
HttpService.makeCallToBackend({
|
||||
path: `/process-models/${params.process_group_id}/${params.process_model_id}/script-unit-tests`,
|
||||
path: `/process-models/${modifiedProcessModelId}/script-unit-tests`,
|
||||
httpMethod: 'POST',
|
||||
successCallback: processScriptUnitTestCreateResult,
|
||||
postBody: {
|
||||
|
@ -428,13 +436,21 @@ export default function ProcessInstanceShow() {
|
|||
if (processInstance && tasks) {
|
||||
const processInstanceToUse = processInstance as any;
|
||||
const taskIds = getTaskIds();
|
||||
const processModelId = unModifyProcessModelPath(
|
||||
params.process_model_id ? params.process_model_id : ''
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
<ProcessBreadcrumb
|
||||
processModelId={params.process_model_id}
|
||||
processGroupId={params.process_group_id}
|
||||
linkProcessModel
|
||||
hotCrumbs={[
|
||||
['Process Groups', '/admin'],
|
||||
[
|
||||
`Process Model: ${processModelId}`,
|
||||
`process_model:${processModelId}:link`,
|
||||
],
|
||||
[`Process Instance: ${params.process_instance_id}`],
|
||||
]}
|
||||
/>
|
||||
<Stack orientation="horizontal" gap={3}>
|
||||
<h2>Process Instance Id: {processInstanceToUse.id}</h2>
|
||||
|
@ -450,8 +466,7 @@ export default function ProcessInstanceShow() {
|
|||
{getInfoTag(processInstanceToUse)}
|
||||
{taskDataDisplayArea()}
|
||||
<ReactDiagramEditor
|
||||
processModelId={params.process_model_id || ''}
|
||||
processGroupId={params.process_group_id || ''}
|
||||
processModelId={processModelId || ''}
|
||||
diagramXML={processInstanceToUse.bpmn_xml_file_contents || ''}
|
||||
fileName={processInstanceToUse.bpmn_xml_file_contents || ''}
|
||||
readyOrWaitingBpmnTaskIds={taskIds.readyOrWaiting}
|
||||
|
|
|
@ -1,97 +1,33 @@
|
|||
import { useState, useEffect, useContext } from 'react';
|
||||
import { useParams, useNavigate } from 'react-router-dom';
|
||||
import { useState, useEffect } from 'react';
|
||||
import { useParams } from 'react-router-dom';
|
||||
// @ts-ignore
|
||||
import { Button, Stack } from '@carbon/react';
|
||||
import ProcessBreadcrumb from '../components/ProcessBreadcrumb';
|
||||
import HttpService from '../services/HttpService';
|
||||
import ButtonWithConfirmation from '../components/ButtonWithConfirmation';
|
||||
import ErrorContext from '../contexts/ErrorContext';
|
||||
import ProcessModelForm from '../components/ProcessModelForm';
|
||||
|
||||
export default function ProcessModelEdit() {
|
||||
const [displayName, setDisplayName] = useState('');
|
||||
const params = useParams();
|
||||
const navigate = useNavigate();
|
||||
const [processModel, setProcessModel] = useState(null);
|
||||
const setErrorMessage = (useContext as any)(ErrorContext)[1];
|
||||
|
||||
const processModelPath = `process-models/${params.process_group_id}/${params.process_model_id}`;
|
||||
const processModelPath = `process-models/${params.process_model_id}`;
|
||||
|
||||
useEffect(() => {
|
||||
const processResult = (result: any) => {
|
||||
setProcessModel(result);
|
||||
setDisplayName(result.display_name);
|
||||
};
|
||||
HttpService.makeCallToBackend({
|
||||
path: `/${processModelPath}`,
|
||||
successCallback: processResult,
|
||||
successCallback: setProcessModel,
|
||||
});
|
||||
}, [processModelPath]);
|
||||
|
||||
const navigateToProcessModel = (_result: any) => {
|
||||
navigate(`/admin/${processModelPath}`);
|
||||
};
|
||||
|
||||
const navigateToProcessModels = (_result: any) => {
|
||||
navigate(`/admin/process-groups/${params.process_group_id}`);
|
||||
};
|
||||
|
||||
const updateProcessModel = (event: any) => {
|
||||
const processModelToUse = processModel as any;
|
||||
event.preventDefault();
|
||||
const processModelToPass = Object.assign(processModelToUse, {
|
||||
display_name: displayName,
|
||||
});
|
||||
HttpService.makeCallToBackend({
|
||||
path: `/${processModelPath}`,
|
||||
successCallback: navigateToProcessModel,
|
||||
httpMethod: 'PUT',
|
||||
postBody: processModelToPass,
|
||||
});
|
||||
};
|
||||
|
||||
const deleteProcessModel = () => {
|
||||
setErrorMessage(null);
|
||||
const processModelToUse = processModel as any;
|
||||
const processModelShowPath = `/process-models/${processModelToUse.process_group_id}/${processModelToUse.id}`;
|
||||
HttpService.makeCallToBackend({
|
||||
path: `${processModelShowPath}`,
|
||||
successCallback: navigateToProcessModels,
|
||||
httpMethod: 'DELETE',
|
||||
failureCallback: setErrorMessage,
|
||||
});
|
||||
};
|
||||
|
||||
const onDisplayNameChanged = (newDisplayName: any) => {
|
||||
setDisplayName(newDisplayName);
|
||||
};
|
||||
|
||||
if (processModel) {
|
||||
return (
|
||||
<>
|
||||
<ProcessBreadcrumb processGroupId={(processModel as any).id} />
|
||||
<h2>Edit Process Group: {(processModel as any).id}</h2>
|
||||
<form onSubmit={updateProcessModel}>
|
||||
<label>Display Name:</label>
|
||||
<input
|
||||
name="display_name"
|
||||
type="text"
|
||||
value={displayName}
|
||||
onChange={(e) => onDisplayNameChanged(e.target.value)}
|
||||
/>
|
||||
<br />
|
||||
<br />
|
||||
<Stack orientation="horizontal" gap={3}>
|
||||
<Button type="submit">Submit</Button>
|
||||
<Button variant="secondary" href={`/admin/${processModelPath}`}>
|
||||
Cancel
|
||||
</Button>
|
||||
<ButtonWithConfirmation
|
||||
description={`Delete Process Model ${(processModel as any).id}?`}
|
||||
onConfirmation={deleteProcessModel}
|
||||
buttonLabel="Delete"
|
||||
/>
|
||||
</Stack>
|
||||
</form>
|
||||
<ProcessBreadcrumb processGroupId={params.process_group_id} />
|
||||
<h2>Edit Process Model: {(processModel as any).id}</h2>
|
||||
<ProcessModelForm
|
||||
mode="edit"
|
||||
processGroupId={params.process_group_id}
|
||||
processModel={processModel}
|
||||
setProcessModel={setProcessModel}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ import ReactDiagramEditor from '../components/ReactDiagramEditor';
|
|||
import ProcessBreadcrumb from '../components/ProcessBreadcrumb';
|
||||
import HttpService from '../services/HttpService';
|
||||
import ErrorContext from '../contexts/ErrorContext';
|
||||
import { makeid } from '../helpers';
|
||||
import { makeid, modifyProcessModelPath } from '../helpers';
|
||||
import { ProcessFile, ProcessModel } from '../interfaces';
|
||||
|
||||
export default function ProcessModelEditDiagram() {
|
||||
|
@ -77,12 +77,18 @@ export default function ProcessModelEditDiagram() {
|
|||
const [searchParams] = useSearchParams();
|
||||
|
||||
const setErrorMessage = (useContext as any)(ErrorContext)[1];
|
||||
const [processModelFile, setProcessModelFile] = useState(null);
|
||||
const [processModelFile, setProcessModelFile] = useState<ProcessFile | null>(
|
||||
null
|
||||
);
|
||||
const [newFileName, setNewFileName] = useState('');
|
||||
const [bpmnXmlForDiagramRendering, setBpmnXmlForDiagramRendering] =
|
||||
useState(null);
|
||||
|
||||
const processModelPath = `process-models/${params.process_group_id}/${params.process_model_id}`;
|
||||
const modifiedProcessModelId = modifyProcessModelPath(
|
||||
(params as any).process_model_id
|
||||
);
|
||||
|
||||
const processModelPath = `process-models/${modifiedProcessModelId}`;
|
||||
|
||||
useEffect(() => {
|
||||
const processResult = (result: ProcessModel) => {
|
||||
|
@ -119,7 +125,7 @@ export default function ProcessModelEditDiagram() {
|
|||
'file_type'
|
||||
)}`;
|
||||
navigate(
|
||||
`/admin/process-models/${params.process_group_id}/${params.process_model_id}/files/${fileNameWithExtension}`
|
||||
`/admin/process-models/${modifiedProcessModelId}/files/${fileNameWithExtension}`
|
||||
);
|
||||
}
|
||||
};
|
||||
|
@ -128,7 +134,7 @@ export default function ProcessModelEditDiagram() {
|
|||
setErrorMessage(null);
|
||||
setBpmnXmlForDiagramRendering(bpmnXML);
|
||||
|
||||
let url = `/process-models/${params.process_group_id}/${params.process_model_id}/files`;
|
||||
let url = `/process-models/${modifiedProcessModelId}/files`;
|
||||
let httpMethod = 'PUT';
|
||||
let fileNameWithExtension = fileName;
|
||||
|
||||
|
@ -162,13 +168,11 @@ export default function ProcessModelEditDiagram() {
|
|||
};
|
||||
|
||||
const onDeleteFile = (fileName = params.file_name) => {
|
||||
const url = `/process-models/${params.process_group_id}/${params.process_model_id}/files/${fileName}`;
|
||||
const url = `/process-models/${modifiedProcessModelId}/files/${fileName}`;
|
||||
const httpMethod = 'DELETE';
|
||||
|
||||
const navigateToProcessModelShow = (_httpResult: any) => {
|
||||
navigate(
|
||||
`/admin/process-models/${params.process_group_id}/${params.process_model_id}`
|
||||
);
|
||||
navigate(`/admin/process-models/${modifiedProcessModelId}`);
|
||||
};
|
||||
HttpService.makeCallToBackend({
|
||||
path: url,
|
||||
|
@ -178,7 +182,7 @@ export default function ProcessModelEditDiagram() {
|
|||
};
|
||||
|
||||
const onSetPrimaryFile = (fileName = params.file_name) => {
|
||||
const url = `/process-models/${params.process_group_id}/${params.process_model_id}`;
|
||||
const url = `/process-models/${modifiedProcessModelId}`;
|
||||
const httpMethod = 'PUT';
|
||||
|
||||
const navigateToProcessModelShow = (_httpResult: any) => {
|
||||
|
@ -428,7 +432,7 @@ export default function ProcessModelEditDiagram() {
|
|||
if (currentScriptUnitTest && scriptElement) {
|
||||
resetUnitTextResult();
|
||||
HttpService.makeCallToBackend({
|
||||
path: `/process-models/${params.process_group_id}/${params.process_model_id}/script-unit-tests/run`,
|
||||
path: `/process-models/${modifiedProcessModelId}/script-unit-tests/run`,
|
||||
httpMethod: 'POST',
|
||||
successCallback: processScriptUnitTestRunResult,
|
||||
postBody: {
|
||||
|
@ -680,42 +684,34 @@ export default function ProcessModelEditDiagram() {
|
|||
* fixme: Not currently in use. This would only work for bpmn files within the process model. Which is right for DMN and json, but not right here. Need to merge in work on the nested process groups before tackling this.
|
||||
* @param processId
|
||||
*/
|
||||
|
||||
const fileNameTemplatePath =
|
||||
'/admin/process-models/:process_model_id/files/:file_name';
|
||||
|
||||
const onLaunchBpmnEditor = (processId: string) => {
|
||||
const file = findFileNameForReferenceId(processId, 'bpmn');
|
||||
if (file) {
|
||||
const path = generatePath(
|
||||
'/admin/process-models/:process_group_id/:process_model_id/files/:file_name',
|
||||
{
|
||||
process_group_id: params.process_group_id,
|
||||
process_model_id: params.process_model_id,
|
||||
file_name: file.name,
|
||||
}
|
||||
);
|
||||
const path = generatePath(fileNameTemplatePath, {
|
||||
process_model_id: params.process_model_id,
|
||||
file_name: file.name,
|
||||
});
|
||||
window.open(path);
|
||||
}
|
||||
};
|
||||
const onLaunchJsonEditor = (fileName: string) => {
|
||||
const path = generatePath(
|
||||
'/admin/process-models/:process_group_id/:process_model_id/form/:file_name',
|
||||
{
|
||||
process_group_id: params.process_group_id,
|
||||
process_model_id: params.process_model_id,
|
||||
file_name: fileName,
|
||||
}
|
||||
);
|
||||
const path = generatePath(fileNameTemplatePath, {
|
||||
process_model_id: params.process_model_id,
|
||||
file_name: fileName,
|
||||
});
|
||||
window.open(path);
|
||||
};
|
||||
const onLaunchDmnEditor = (processId: string) => {
|
||||
const file = findFileNameForReferenceId(processId, 'dmn');
|
||||
if (file) {
|
||||
const path = generatePath(
|
||||
'/admin/process-models/:process_group_id/:process_model_id/files/:file_name',
|
||||
{
|
||||
process_group_id: params.process_group_id,
|
||||
process_model_id: params.process_model_id,
|
||||
file_name: file.name,
|
||||
}
|
||||
);
|
||||
const path = generatePath(fileNameTemplatePath, {
|
||||
process_model_id: params.process_model_id,
|
||||
file_name: file.name,
|
||||
});
|
||||
window.open(path);
|
||||
}
|
||||
};
|
||||
|
@ -730,7 +726,6 @@ export default function ProcessModelEditDiagram() {
|
|||
return (
|
||||
<ReactDiagramEditor
|
||||
processModelId={params.process_model_id || ''}
|
||||
processGroupId={params.process_group_id || ''}
|
||||
saveDiagram={saveDiagram}
|
||||
onDeleteFile={onDeleteFile}
|
||||
diagramXML={bpmnXmlForDiagramRendering}
|
||||
|
@ -752,7 +747,6 @@ export default function ProcessModelEditDiagram() {
|
|||
return (
|
||||
<ReactDiagramEditor
|
||||
processModelId={params.process_model_id || ''}
|
||||
processGroupId={params.process_group_id || ''}
|
||||
saveDiagram={saveDiagram}
|
||||
onDeleteFile={onDeleteFile}
|
||||
onSetPrimaryFile={onSetPrimaryFileCallback}
|
||||
|
@ -773,16 +767,22 @@ export default function ProcessModelEditDiagram() {
|
|||
|
||||
// if a file name is not given then this is a new model and the ReactDiagramEditor component will handle it
|
||||
if ((bpmnXmlForDiagramRendering || !params.file_name) && processModel) {
|
||||
const processModelFileName = processModelFile ? processModelFile.name : '';
|
||||
return (
|
||||
<>
|
||||
<ProcessBreadcrumb
|
||||
processGroupId={params.process_group_id}
|
||||
processModelId={params.process_model_id}
|
||||
linkProcessModel
|
||||
hotCrumbs={[
|
||||
['Process Groups', '/admin'],
|
||||
[
|
||||
`Process Model: ${processModel.id}`,
|
||||
`process_model:${processModel.id}:link`,
|
||||
],
|
||||
[processModelFileName],
|
||||
]}
|
||||
/>
|
||||
<h2>
|
||||
Process Model File
|
||||
{processModelFile ? `: ${(processModelFile as any).name}` : ''}
|
||||
Process Model File{processModelFile ? ': ' : ''}
|
||||
{processModelFileName}
|
||||
</h2>
|
||||
{appropriateEditor()}
|
||||
{newFileNameBox()}
|
||||
|
|
|
@ -1,75 +1,29 @@
|
|||
import { useState } from 'react';
|
||||
import { useNavigate, useParams } from 'react-router-dom';
|
||||
import Button from 'react-bootstrap/Button';
|
||||
import Form from 'react-bootstrap/Form';
|
||||
import { useParams } from 'react-router-dom';
|
||||
import ProcessBreadcrumb from '../components/ProcessBreadcrumb';
|
||||
import { slugifyString } from '../helpers';
|
||||
import HttpService from '../services/HttpService';
|
||||
import { ProcessModel } from '../interfaces';
|
||||
import ProcessModelForm from '../components/ProcessModelForm';
|
||||
|
||||
export default function ProcessModelNew() {
|
||||
const params = useParams();
|
||||
|
||||
const [identifier, setIdentifier] = useState('');
|
||||
const [idHasBeenUpdatedByUser, setIdHasBeenUpdatedByUser] = useState(false);
|
||||
const [displayName, setDisplayName] = useState('');
|
||||
const navigate = useNavigate();
|
||||
|
||||
const navigateToNewProcessModel = (_result: any) => {
|
||||
navigate(`/admin/process-models/${params.process_group_id}/${identifier}`);
|
||||
};
|
||||
|
||||
const addProcessModel = (event: any) => {
|
||||
event.preventDefault();
|
||||
HttpService.makeCallToBackend({
|
||||
path: `/process-models`,
|
||||
successCallback: navigateToNewProcessModel,
|
||||
httpMethod: 'POST',
|
||||
postBody: {
|
||||
id: identifier,
|
||||
display_name: displayName,
|
||||
description: displayName,
|
||||
process_group_id: params.process_group_id,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const onDisplayNameChanged = (newDisplayName: any) => {
|
||||
setDisplayName(newDisplayName);
|
||||
if (!idHasBeenUpdatedByUser) {
|
||||
setIdentifier(slugifyString(newDisplayName));
|
||||
}
|
||||
};
|
||||
const [processModel, setProcessModel] = useState<ProcessModel>({
|
||||
id: '',
|
||||
display_name: '',
|
||||
description: '',
|
||||
primary_file_name: '',
|
||||
files: [],
|
||||
});
|
||||
|
||||
return (
|
||||
<>
|
||||
<ProcessBreadcrumb />
|
||||
<h2>Add Process Model</h2>
|
||||
<Form onSubmit={addProcessModel}>
|
||||
<Form.Group className="mb-3" controlId="display_name">
|
||||
<Form.Label>Display Name:</Form.Label>
|
||||
<Form.Control
|
||||
name="display_name"
|
||||
type="text"
|
||||
value={displayName}
|
||||
onChange={(e) => onDisplayNameChanged(e.target.value)}
|
||||
/>
|
||||
</Form.Group>
|
||||
<Form.Group className="mb-3" controlId="identifier">
|
||||
<Form.Label>ID:</Form.Label>
|
||||
<Form.Control
|
||||
name="id"
|
||||
type="text"
|
||||
value={identifier}
|
||||
onChange={(e) => {
|
||||
setIdentifier(e.target.value);
|
||||
setIdHasBeenUpdatedByUser(true);
|
||||
}}
|
||||
/>
|
||||
</Form.Group>
|
||||
<Button variant="primary" type="submit">
|
||||
Submit
|
||||
</Button>
|
||||
</Form>
|
||||
<ProcessModelForm
|
||||
mode="new"
|
||||
processGroupId={params.process_group_id}
|
||||
processModel={processModel}
|
||||
setProcessModel={setProcessModel}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,12 +1,36 @@
|
|||
import { useContext, useEffect, useState } from 'react';
|
||||
import { Link, useParams } from 'react-router-dom';
|
||||
// @ts-ignore
|
||||
import { Button, Stack } from '@carbon/react';
|
||||
import { Link, useNavigate, useParams } from 'react-router-dom';
|
||||
import {
|
||||
Add,
|
||||
Upload,
|
||||
Download,
|
||||
TrashCan,
|
||||
Favorite,
|
||||
Edit,
|
||||
// @ts-ignore
|
||||
} from '@carbon/icons-react';
|
||||
import {
|
||||
Accordion,
|
||||
AccordionItem,
|
||||
Button,
|
||||
Stack,
|
||||
ButtonSet,
|
||||
Modal,
|
||||
FileUploader,
|
||||
Table,
|
||||
TableHead,
|
||||
TableHeader,
|
||||
TableRow,
|
||||
TableCell,
|
||||
TableBody,
|
||||
// @ts-ignore
|
||||
} from '@carbon/react';
|
||||
import ProcessBreadcrumb from '../components/ProcessBreadcrumb';
|
||||
import FileInput from '../components/FileInput';
|
||||
import HttpService from '../services/HttpService';
|
||||
import ErrorContext from '../contexts/ErrorContext';
|
||||
import { RecentProcessModel } from '../interfaces';
|
||||
import { modifyProcessModelPath, unModifyProcessModelPath } from '../helpers';
|
||||
import { ProcessFile, ProcessModel, RecentProcessModel } from '../interfaces';
|
||||
import ButtonWithConfirmation from '../components/ButtonWithConfirmation';
|
||||
|
||||
const storeRecentProcessModelInLocalStorage = (
|
||||
processModelForStorage: any,
|
||||
|
@ -66,26 +90,34 @@ export default function ProcessModelShow() {
|
|||
const params = useParams();
|
||||
const setErrorMessage = (useContext as any)(ErrorContext)[1];
|
||||
|
||||
const [processModel, setProcessModel] = useState({});
|
||||
const [processModel, setProcessModel] = useState<ProcessModel | null>(null);
|
||||
const [processInstanceResult, setProcessInstanceResult] = useState(null);
|
||||
const [reloadModel, setReloadModel] = useState(false);
|
||||
const [reloadModel, setReloadModel] = useState<boolean>(false);
|
||||
const [filesToUpload, setFilesToUpload] = useState<any>(null);
|
||||
const [showFileUploadModal, setShowFileUploadModal] =
|
||||
useState<boolean>(false);
|
||||
const navigate = useNavigate();
|
||||
|
||||
const modifiedProcessModelId = modifyProcessModelPath(
|
||||
`${params.process_model_id}`
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
const processResult = (result: object) => {
|
||||
const processResult = (result: ProcessModel) => {
|
||||
setProcessModel(result);
|
||||
setReloadModel(false);
|
||||
storeRecentProcessModelInLocalStorage(result, params);
|
||||
};
|
||||
HttpService.makeCallToBackend({
|
||||
path: `/process-models/${params.process_group_id}/${params.process_model_id}`,
|
||||
path: `/process-models/${modifiedProcessModelId}`,
|
||||
successCallback: processResult,
|
||||
});
|
||||
}, [params, reloadModel]);
|
||||
}, [params, reloadModel, modifiedProcessModelId]);
|
||||
|
||||
const processModelRun = (processInstance: any) => {
|
||||
setErrorMessage(null);
|
||||
HttpService.makeCallToBackend({
|
||||
path: `/process-models/${params.process_group_id}/${params.process_model_id}/process-instances/${processInstance.id}/run`,
|
||||
path: `/process-instances/${processInstance.id}/run`,
|
||||
successCallback: setProcessInstanceResult,
|
||||
failureCallback: setErrorMessage,
|
||||
httpMethod: 'POST',
|
||||
|
@ -94,102 +126,246 @@ export default function ProcessModelShow() {
|
|||
|
||||
const processInstanceCreateAndRun = () => {
|
||||
HttpService.makeCallToBackend({
|
||||
path: `/process-models/${params.process_group_id}/${params.process_model_id}/process-instances`,
|
||||
path: `/process-models/${modifiedProcessModelId}/process-instances`,
|
||||
successCallback: processModelRun,
|
||||
httpMethod: 'POST',
|
||||
});
|
||||
};
|
||||
|
||||
let processInstanceResultTag = null;
|
||||
if (processInstanceResult) {
|
||||
let takeMeToMyTaskBlurb = null;
|
||||
// FIXME: ensure that the task is actually for the current user as well
|
||||
const processInstanceId = (processInstanceResult as any).id;
|
||||
const nextTask = (processInstanceResult as any).next_task;
|
||||
if (nextTask && nextTask.state === 'READY') {
|
||||
takeMeToMyTaskBlurb = (
|
||||
<span>
|
||||
You have a task to complete. Go to{' '}
|
||||
<Link to={`/tasks/${processInstanceId}/${nextTask.id}`}>my task</Link>
|
||||
.
|
||||
</span>
|
||||
const processInstanceResultTag = () => {
|
||||
if (processModel && processInstanceResult) {
|
||||
let takeMeToMyTaskBlurb = null;
|
||||
// FIXME: ensure that the task is actually for the current user as well
|
||||
const processInstanceId = (processInstanceResult as any).id;
|
||||
const nextTask = (processInstanceResult as any).next_task;
|
||||
if (nextTask && nextTask.state === 'READY') {
|
||||
takeMeToMyTaskBlurb = (
|
||||
<span>
|
||||
You have a task to complete. Go to{' '}
|
||||
<Link to={`/tasks/${processInstanceId}/${nextTask.id}`}>
|
||||
my task
|
||||
</Link>
|
||||
.
|
||||
</span>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<div className="alert alert-success" role="alert">
|
||||
<p>
|
||||
Process Instance {processInstanceId} kicked off (
|
||||
<Link
|
||||
to={`/admin/process-models/${modifiedProcessModelId}/process-instances/${processInstanceId}`}
|
||||
data-qa="process-instance-show-link"
|
||||
>
|
||||
view
|
||||
</Link>
|
||||
). {takeMeToMyTaskBlurb}
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
processInstanceResultTag = (
|
||||
<div className="alert alert-success" role="alert">
|
||||
<p>
|
||||
Process Instance {processInstanceId} kicked off (
|
||||
<Link
|
||||
to={`/admin/process-models/${
|
||||
(processModel as any).process_group_id
|
||||
}/${
|
||||
(processModel as any).id
|
||||
}/process-instances/${processInstanceId}`}
|
||||
data-qa="process-instance-show-link"
|
||||
>
|
||||
view
|
||||
</Link>
|
||||
). {takeMeToMyTaskBlurb}
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
const onUploadedCallback = () => {
|
||||
setReloadModel(true);
|
||||
};
|
||||
const reloadModelOhYeah = (_httpResult: any) => {
|
||||
setReloadModel(!reloadModel);
|
||||
};
|
||||
|
||||
const processModelFileList = () => {
|
||||
let constructedTag;
|
||||
const tags = (processModel as any).files.map((processModelFile: any) => {
|
||||
// Remove this code from
|
||||
const onDeleteFile = (fileName: string) => {
|
||||
const url = `/process-models/${modifiedProcessModelId}/files/${fileName}`;
|
||||
const httpMethod = 'DELETE';
|
||||
HttpService.makeCallToBackend({
|
||||
path: url,
|
||||
successCallback: reloadModelOhYeah,
|
||||
httpMethod,
|
||||
});
|
||||
};
|
||||
|
||||
const onSetPrimaryFile = (fileName: string) => {
|
||||
const url = `/process-models/${modifiedProcessModelId}`;
|
||||
const httpMethod = 'PUT';
|
||||
|
||||
const processModelToPass = {
|
||||
primary_file_name: fileName,
|
||||
};
|
||||
HttpService.makeCallToBackend({
|
||||
path: url,
|
||||
successCallback: onUploadedCallback,
|
||||
httpMethod,
|
||||
postBody: processModelToPass,
|
||||
});
|
||||
};
|
||||
const handleProcessModelFileResult = (processModelFile: ProcessFile) => {
|
||||
if (
|
||||
!('file_contents' in processModelFile) ||
|
||||
processModelFile.file_contents === undefined
|
||||
) {
|
||||
setErrorMessage({
|
||||
message: `Could not file file contents for file: ${processModelFile.name}`,
|
||||
});
|
||||
return;
|
||||
}
|
||||
let contentType = 'application/xml';
|
||||
if (processModelFile.type === 'json') {
|
||||
contentType = 'application/json';
|
||||
}
|
||||
const element = document.createElement('a');
|
||||
const file = new Blob([processModelFile.file_contents], {
|
||||
type: contentType,
|
||||
});
|
||||
const downloadFileName = processModelFile.name;
|
||||
element.href = URL.createObjectURL(file);
|
||||
element.download = downloadFileName;
|
||||
document.body.appendChild(element);
|
||||
element.click();
|
||||
};
|
||||
|
||||
const downloadFile = (fileName: string) => {
|
||||
setErrorMessage(null);
|
||||
const processModelPath = `process-models/${modifiedProcessModelId}`;
|
||||
HttpService.makeCallToBackend({
|
||||
path: `/${processModelPath}/files/${fileName}`,
|
||||
successCallback: handleProcessModelFileResult,
|
||||
});
|
||||
};
|
||||
|
||||
const navigateToFileEdit = (processModelFile: ProcessFile) => {
|
||||
if (processModel) {
|
||||
if (processModelFile.name.match(/\.(dmn|bpmn)$/)) {
|
||||
let primarySuffix = '';
|
||||
if (processModelFile.name === (processModel as any).primary_file_name) {
|
||||
primarySuffix = '- Primary File';
|
||||
}
|
||||
constructedTag = (
|
||||
<li key={processModelFile.name}>
|
||||
<Link
|
||||
to={`/admin/process-models/${
|
||||
(processModel as any).process_group_id
|
||||
}/${(processModel as any).id}/files/${processModelFile.name}`}
|
||||
>
|
||||
{processModelFile.name}
|
||||
</Link>
|
||||
{primarySuffix}
|
||||
</li>
|
||||
navigate(
|
||||
`/admin/process-models/${modifiedProcessModelId}/files/${processModelFile.name}`
|
||||
);
|
||||
} else if (processModelFile.name.match(/\.(json|md)$/)) {
|
||||
constructedTag = (
|
||||
<li key={processModelFile.name}>
|
||||
<Link
|
||||
to={`/admin/process-models/${
|
||||
(processModel as any).process_group_id
|
||||
}/${(processModel as any).id}/form/${processModelFile.name}`}
|
||||
>
|
||||
{processModelFile.name}
|
||||
</Link>
|
||||
</li>
|
||||
);
|
||||
} else {
|
||||
constructedTag = (
|
||||
<li key={processModelFile.name}>{processModelFile.name}</li>
|
||||
navigate(
|
||||
`/admin/process-models/${modifiedProcessModelId}/form/${processModelFile.name}`
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const renderButtonElements = (
|
||||
processModelFile: ProcessFile,
|
||||
isPrimaryBpmnFile: boolean
|
||||
) => {
|
||||
const elements = [];
|
||||
elements.push(
|
||||
<Button
|
||||
kind="ghost"
|
||||
renderIcon={Edit}
|
||||
iconDescription="Edit File"
|
||||
hasIconOnly
|
||||
size="lg"
|
||||
data-qa={`edit-file-${processModelFile.name.replace('.', '-')}`}
|
||||
onClick={() => navigateToFileEdit(processModelFile)}
|
||||
/>
|
||||
);
|
||||
elements.push(
|
||||
<Button
|
||||
kind="ghost"
|
||||
renderIcon={Download}
|
||||
iconDescription="Download File"
|
||||
hasIconOnly
|
||||
size="lg"
|
||||
onClick={() => downloadFile(processModelFile.name)}
|
||||
/>
|
||||
);
|
||||
|
||||
elements.push(
|
||||
<ButtonWithConfirmation
|
||||
kind="ghost"
|
||||
renderIcon={TrashCan}
|
||||
iconDescription="Delete File"
|
||||
hasIconOnly
|
||||
description={`Delete file: ${processModelFile.name}`}
|
||||
onConfirmation={() => {
|
||||
onDeleteFile(processModelFile.name);
|
||||
}}
|
||||
confirmButtonLabel="Delete"
|
||||
/>
|
||||
);
|
||||
if (processModelFile.name.match(/\.bpmn$/) && !isPrimaryBpmnFile) {
|
||||
elements.push(
|
||||
<Button
|
||||
kind="ghost"
|
||||
renderIcon={Favorite}
|
||||
iconDescription="Set As Primary File"
|
||||
hasIconOnly
|
||||
size="lg"
|
||||
onClick={() => onSetPrimaryFile(processModelFile.name)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
return elements;
|
||||
};
|
||||
|
||||
const processModelFileList = () => {
|
||||
if (!processModel) {
|
||||
return null;
|
||||
}
|
||||
let constructedTag;
|
||||
const tags = processModel.files.map((processModelFile: ProcessFile) => {
|
||||
const isPrimaryBpmnFile =
|
||||
processModelFile.name === processModel.primary_file_name;
|
||||
|
||||
let actionsTableCell = null;
|
||||
if (processModelFile.name.match(/\.(dmn|bpmn|json|md)$/)) {
|
||||
actionsTableCell = (
|
||||
<TableCell key={`${processModelFile.name}-cell`}>
|
||||
{renderButtonElements(processModelFile, isPrimaryBpmnFile)}
|
||||
</TableCell>
|
||||
);
|
||||
}
|
||||
|
||||
let primarySuffix = '';
|
||||
if (isPrimaryBpmnFile) {
|
||||
primarySuffix = '- Primary File';
|
||||
}
|
||||
constructedTag = (
|
||||
<TableRow key={processModelFile.name}>
|
||||
<TableCell key={`${processModelFile.name}-cell`}>
|
||||
{processModelFile.name}
|
||||
{primarySuffix}
|
||||
</TableCell>
|
||||
{actionsTableCell}
|
||||
</TableRow>
|
||||
);
|
||||
return constructedTag;
|
||||
});
|
||||
|
||||
return <ul>{tags}</ul>;
|
||||
// return <ul>{tags}</ul>;
|
||||
const headers = ['Name', 'Actions'];
|
||||
return (
|
||||
<Table size="lg" useZebraStyles={false}>
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
{headers.map((header) => (
|
||||
<TableHeader id={header} key={header}>
|
||||
{header}
|
||||
</TableHeader>
|
||||
))}
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
<TableBody>{tags}</TableBody>
|
||||
</Table>
|
||||
);
|
||||
};
|
||||
|
||||
const processInstancesUl = () => {
|
||||
const unmodifiedProcessModelId: String = unModifyProcessModelPath(
|
||||
`${params.process_model_id}`
|
||||
);
|
||||
if (!processModel) {
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<ul>
|
||||
<li>
|
||||
<Link
|
||||
to={`/admin/process-instances?process_group_identifier=${
|
||||
(processModel as any).process_group_id
|
||||
}&process_model_identifier=${(processModel as any).id}`}
|
||||
to={`/admin/process-instances?process_model_identifier=${unmodifiedProcessModelId}`}
|
||||
data-qa="process-instance-list-link"
|
||||
>
|
||||
List
|
||||
|
@ -197,9 +373,7 @@ export default function ProcessModelShow() {
|
|||
</li>
|
||||
<li>
|
||||
<Link
|
||||
to={`/admin/process-models/${
|
||||
(processModel as any).process_group_id
|
||||
}/${(processModel as any).id}/process-instances/reports`}
|
||||
to={`/admin/process-models/${modifiedProcessModelId}/process-instances/reports`}
|
||||
data-qa="process-instance-reports-link"
|
||||
>
|
||||
Reports
|
||||
|
@ -209,79 +383,157 @@ export default function ProcessModelShow() {
|
|||
);
|
||||
};
|
||||
|
||||
const processModelButtons = () => {
|
||||
const handleFileUploadCancel = () => {
|
||||
setShowFileUploadModal(false);
|
||||
};
|
||||
|
||||
const handleFileUpload = (event: any) => {
|
||||
if (processModel) {
|
||||
event.preventDefault();
|
||||
const url = `/process-models/${modifiedProcessModelId}/files`;
|
||||
const formData = new FormData();
|
||||
formData.append('file', filesToUpload[0]);
|
||||
formData.append('fileName', filesToUpload[0].name);
|
||||
HttpService.makeCallToBackend({
|
||||
path: url,
|
||||
successCallback: onUploadedCallback,
|
||||
httpMethod: 'POST',
|
||||
postBody: formData,
|
||||
});
|
||||
}
|
||||
setShowFileUploadModal(false);
|
||||
};
|
||||
|
||||
const fileUploadModal = () => {
|
||||
return (
|
||||
<Stack orientation="horizontal" gap={3}>
|
||||
<Button onClick={processInstanceCreateAndRun} variant="primary">
|
||||
Run
|
||||
</Button>
|
||||
<Button
|
||||
href={`/admin/process-models/${
|
||||
(processModel as any).process_group_id
|
||||
}/${(processModel as any).id}/edit`}
|
||||
variant="secondary"
|
||||
>
|
||||
Edit process model
|
||||
</Button>
|
||||
<Button
|
||||
href={`/admin/process-models/${
|
||||
(processModel as any).process_group_id
|
||||
}/${(processModel as any).id}/files?file_type=bpmn`}
|
||||
variant="warning"
|
||||
>
|
||||
Add New BPMN File
|
||||
</Button>
|
||||
<Button
|
||||
href={`/admin/process-models/${
|
||||
(processModel as any).process_group_id
|
||||
}/${(processModel as any).id}/files?file_type=dmn`}
|
||||
variant="success"
|
||||
>
|
||||
Add New DMN File
|
||||
</Button>
|
||||
<Button
|
||||
href={`/admin/process-models/${
|
||||
(processModel as any).process_group_id
|
||||
}/${(processModel as any).id}/form?file_ext=json`}
|
||||
variant="info"
|
||||
>
|
||||
Add New JSON File
|
||||
</Button>
|
||||
<Button
|
||||
href={`/admin/process-models/${
|
||||
(processModel as any).process_group_id
|
||||
}/${(processModel as any).id}/form?file_ext=md`}
|
||||
variant="info"
|
||||
>
|
||||
Add New Markdown File
|
||||
</Button>
|
||||
</Stack>
|
||||
<Modal
|
||||
data-qa="modal-upload-file-dialog"
|
||||
open={showFileUploadModal}
|
||||
modalHeading="Upload File"
|
||||
primaryButtonText="Upload"
|
||||
secondaryButtonText="Cancel"
|
||||
onSecondarySubmit={handleFileUploadCancel}
|
||||
onRequestClose={handleFileUploadCancel}
|
||||
onRequestSubmit={handleFileUpload}
|
||||
>
|
||||
<FileUploader
|
||||
labelTitle="Upload files"
|
||||
labelDescription="Max file size is 500mb. Only .bpmn, .dmn, and .json files are supported."
|
||||
buttonLabel="Add file"
|
||||
buttonKind="primary"
|
||||
size="md"
|
||||
filenameStatus="edit"
|
||||
role="button"
|
||||
accept={['.bpmn', '.dmn', '.json']}
|
||||
disabled={false}
|
||||
iconDescription="Delete file"
|
||||
name=""
|
||||
multiple={false}
|
||||
onChange={(event: any) => setFilesToUpload(event.target.files)}
|
||||
/>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
|
||||
if (Object.keys(processModel).length > 1) {
|
||||
const processModelButtons = () => {
|
||||
if (!processModel) {
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<Accordion>
|
||||
<AccordionItem
|
||||
data-qa="files-accordion"
|
||||
title={
|
||||
<Stack orientation="horizontal">
|
||||
<span>
|
||||
<Button size="sm" kind="ghost">
|
||||
Files
|
||||
</Button>
|
||||
</span>
|
||||
</Stack>
|
||||
}
|
||||
>
|
||||
<ButtonSet>
|
||||
<Button
|
||||
renderIcon={Upload}
|
||||
data-qa="upload-file-button"
|
||||
onClick={() => setShowFileUploadModal(true)}
|
||||
size="sm"
|
||||
kind=""
|
||||
className="button-white-background"
|
||||
>
|
||||
Upload File
|
||||
</Button>
|
||||
<Button
|
||||
renderIcon={Add}
|
||||
href={`/admin/process-models/${modifiedProcessModelId}/files?file_type=bpmn`}
|
||||
size="sm"
|
||||
>
|
||||
New BPMN File
|
||||
</Button>
|
||||
<Button
|
||||
renderIcon={Add}
|
||||
href={`/admin/process-models/${modifiedProcessModelId}/files?file_type=dmn`}
|
||||
size="sm"
|
||||
>
|
||||
New DMN File
|
||||
</Button>
|
||||
<Button
|
||||
renderIcon={Add}
|
||||
href={`/admin/process-models/${modifiedProcessModelId}/form?file_ext=json`}
|
||||
size="sm"
|
||||
>
|
||||
New JSON File
|
||||
</Button>
|
||||
<Button
|
||||
renderIcon={Add}
|
||||
href={`/admin/process-models/${modifiedProcessModelId}/form?file_ext=md`}
|
||||
size="sm"
|
||||
>
|
||||
New Markdown File
|
||||
</Button>
|
||||
</ButtonSet>
|
||||
<br />
|
||||
{processModelFileList()}
|
||||
</AccordionItem>
|
||||
</Accordion>
|
||||
);
|
||||
};
|
||||
|
||||
if (processModel) {
|
||||
return (
|
||||
<>
|
||||
{fileUploadModal()}
|
||||
<ProcessBreadcrumb
|
||||
processGroupId={(processModel as any).process_group_id}
|
||||
processModelId={(processModel as any).id}
|
||||
/>
|
||||
{processInstanceResultTag}
|
||||
<FileInput
|
||||
processModelId={(processModel as any).id}
|
||||
processGroupId={(processModel as any).process_group_id}
|
||||
onUploadedCallback={onUploadedCallback}
|
||||
hotCrumbs={[
|
||||
['Process Groups', '/admin'],
|
||||
[
|
||||
`Process Model: ${processModel.id}`,
|
||||
`process_model:${processModel.id}`,
|
||||
],
|
||||
]}
|
||||
/>
|
||||
<h1>Process Model: {processModel.display_name}</h1>
|
||||
<p className="process-description">{processModel.description}</p>
|
||||
<Stack orientation="horizontal" gap={3}>
|
||||
<Button onClick={processInstanceCreateAndRun} variant="primary">
|
||||
Run
|
||||
</Button>
|
||||
<Button
|
||||
href={`/admin/process-models/${modifiedProcessModelId}/edit`}
|
||||
variant="secondary"
|
||||
>
|
||||
Edit process model
|
||||
</Button>
|
||||
</Stack>
|
||||
<br />
|
||||
<br />
|
||||
{processInstanceResultTag()}
|
||||
{processModelButtons()}
|
||||
<br />
|
||||
<br />
|
||||
<h3>Process Instances</h3>
|
||||
{processInstancesUl()}
|
||||
<br />
|
||||
<br />
|
||||
<h3>Files</h3>
|
||||
{processModelFileList()}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -6,6 +6,8 @@ import { Button, Modal } from '@carbon/react';
|
|||
import ProcessBreadcrumb from '../components/ProcessBreadcrumb';
|
||||
import HttpService from '../services/HttpService';
|
||||
import ButtonWithConfirmation from '../components/ButtonWithConfirmation';
|
||||
import { modifyProcessModelPath, unModifyProcessModelPath } from '../helpers';
|
||||
import { ProcessFile } from '../interfaces';
|
||||
|
||||
// NOTE: This is mostly the same as ProcessModelEditDiagram and if we go this route could
|
||||
// possibly be merged into it. I'm leaving as a separate file now in case it does
|
||||
|
@ -18,7 +20,9 @@ export default function ReactFormEditor() {
|
|||
const handleShowFileNameEditor = () => setShowFileNameEditor(true);
|
||||
const navigate = useNavigate();
|
||||
|
||||
const [processModelFile, setProcessModelFile] = useState(null);
|
||||
const [processModelFile, setProcessModelFile] = useState<ProcessFile | null>(
|
||||
null
|
||||
);
|
||||
const [processModelFileContents, setProcessModelFileContents] = useState('');
|
||||
|
||||
const fileExtension = (() => {
|
||||
|
@ -34,6 +38,10 @@ export default function ReactFormEditor() {
|
|||
|
||||
const editorDefaultLanguage = fileExtension === 'md' ? 'markdown' : 'json';
|
||||
|
||||
const modifiedProcessModelId = modifyProcessModelPath(
|
||||
`${params.process_model_id}`
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
const processResult = (result: any) => {
|
||||
setProcessModelFile(result);
|
||||
|
@ -42,23 +50,23 @@ export default function ReactFormEditor() {
|
|||
|
||||
if (params.file_name) {
|
||||
HttpService.makeCallToBackend({
|
||||
path: `/process-models/${params.process_group_id}/${params.process_model_id}/files/${params.file_name}`,
|
||||
path: `/process-models/${modifiedProcessModelId}/files/${params.file_name}`,
|
||||
successCallback: processResult,
|
||||
});
|
||||
}
|
||||
}, [params]);
|
||||
}, [params, modifiedProcessModelId]);
|
||||
|
||||
const navigateToProcessModelFile = (_result: any) => {
|
||||
if (!params.file_name) {
|
||||
const fileNameWithExtension = `${newFileName}.${fileExtension}`;
|
||||
navigate(
|
||||
`/admin/process-models/${params.process_group_id}/${params.process_model_id}/form/${fileNameWithExtension}`
|
||||
`/admin/process-models/${modifiedProcessModelId}/form/${fileNameWithExtension}`
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
const saveFile = () => {
|
||||
let url = `/process-models/${params.process_group_id}/${params.process_model_id}/files`;
|
||||
let url = `/process-models/${modifiedProcessModelId}/files`;
|
||||
let httpMethod = 'PUT';
|
||||
let fileNameWithExtension = params.file_name;
|
||||
|
||||
|
@ -90,13 +98,11 @@ export default function ReactFormEditor() {
|
|||
};
|
||||
|
||||
const deleteFile = () => {
|
||||
const url = `/process-models/${params.process_group_id}/${params.process_model_id}/files/${params.file_name}`;
|
||||
const url = `/process-models/${modifiedProcessModelId}/files/${params.file_name}`;
|
||||
const httpMethod = 'DELETE';
|
||||
|
||||
const navigateToProcessModelShow = (_httpResult: any) => {
|
||||
navigate(
|
||||
`/admin/process-models/${params.process_group_id}/${params.process_model_id}`
|
||||
);
|
||||
navigate(`/admin/process-models/${modifiedProcessModelId}`);
|
||||
};
|
||||
|
||||
HttpService.makeCallToBackend({
|
||||
|
@ -143,16 +149,29 @@ export default function ReactFormEditor() {
|
|||
};
|
||||
|
||||
if (processModelFile || !params.file_name) {
|
||||
const processModelFileName = processModelFile ? processModelFile.name : '';
|
||||
return (
|
||||
<main>
|
||||
<ProcessBreadcrumb
|
||||
processGroupId={params.process_group_id}
|
||||
processModelId={params.process_model_id}
|
||||
linkProcessModel
|
||||
hotCrumbs={[
|
||||
['Process Groups', '/admin'],
|
||||
[
|
||||
`Process Model: ${unModifyProcessModelPath(
|
||||
params.process_model_id || ''
|
||||
)}`,
|
||||
`process_model:${unModifyProcessModelPath(
|
||||
params.process_model_id || ''
|
||||
)}:link`,
|
||||
],
|
||||
[processModelFileName],
|
||||
]}
|
||||
/>
|
||||
<h2>
|
||||
Process Model File
|
||||
{processModelFile ? `: ${(processModelFile as any).name}` : ''}
|
||||
Process Model File{processModelFile ? ': ' : ''}
|
||||
{processModelFileName}
|
||||
</h2>
|
||||
{newFileNameBox()}
|
||||
<Button onClick={saveFile} variant="danger" data-qa="file-save-button">
|
||||
|
|
Loading…
Reference in New Issue