make main look like bd16223ccf

This commit is contained in:
burnettk 2024-02-05 15:24:46 -05:00
parent 52f2a9bd98
commit 2bb11c33bb
No known key found for this signature in database
24 changed files with 145 additions and 1094 deletions

21
LICENSE Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2022 Sartography
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -96,3 +96,10 @@ Below is a table of all the events that are sent and accepted:
| spff.dmn\_files.requested | request of list of local dmn files. | | | |
| spiff.json\_files.returned | Return a list of available json files | Recieved | options | \[{lable:'My Label', value:'1'}\] |
| spff.dmn\_files.returned | Return a list of available dmn files. | Recieved | options | \[{lable:'My Label', value:'1'}\] |
## License
MIT

View File

@ -23,13 +23,6 @@ try {
keyboard: { bindTo: document },
propertiesPanel: {
parent: panelEl,
layout: {
groups: {
general: {
open: true
}
}
}
},
additionalModules: [
spiffworkflow,
@ -189,8 +182,8 @@ bpmnModeler.on('spiff.dmn_files.requested', (event) => {
bpmnModeler.on('spiff.data_stores.requested', (event) => {
event.eventBus.fire('spiff.data_stores.returned', {
options: [
{ id: 'countriesID', type: 'json', name: 'countries', clz: 'JSONDataStore' },
{ id: 'foodsID', type: 'kkv', name: 'foods', clz: 'JSONDataStore' }
{ type: 'typeahead', name: 'countries' },
{ type: 'kkv', name: 'foods' }
],
});
});
@ -213,7 +206,7 @@ bpmnModeler.on('import.parse.complete', event => {
refs.forEach(ref => {
const props = {
id: ref.id,
name: ref.id ? typeof (ref.name) === 'undefined' : ref.name,
name: ref.id ? typeof(ref.name) === 'undefined': ref.name,
};
let elem = bpmnModeler._moddle.create(desc, props);
elem.$parent = ref.element;
@ -221,10 +214,7 @@ bpmnModeler.on('import.parse.complete', event => {
});
});
bpmnModeler.importXML(diagramXML).then(() => {
// Zoom up and center workflow in the middle of the canvas
bpmnModeler.get('canvas').zoom('fit-viewport', 'auto');
});
bpmnModeler.importXML(diagramXML).then(() => {});
// This handles the download and upload buttons - it isn't specific to
// the BPMN modeler or these extensions, just a quick way to allow you to

View File

@ -1,8 +1,6 @@
html,
body {
html, body {
height: 100%;
margin: 0;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}
.hidden {
@ -11,7 +9,8 @@ body {
#container {
display: flex;
height: calc(100% - 80px);
width: 100%;
height: 100%;
}
#modeler {
@ -19,14 +18,16 @@ body {
}
#panel {
background-color: white;
border-left: 1px solid #5F5F5F;
/* background-color: #fafafa; */
/* border: solid 1px #ccc; */
/* border-radius: 2px; */
background-color: #fafafa;
border: solid 1px #ccc;
border-radius: 2px;
font-family: 'Arial', sans-serif;
padding: 10px;
min-width: 400px;
}
.djs-label {
font-family: 'Arial', sans-serif;
/* padding: 10px; */
min-width: 350px;
}
.spiffworkflow-properties-panel-button {
@ -37,342 +38,46 @@ body {
/* Style buttons */
.bpmn-js-spiffworkflow-btn {
background-color: #ffffff;
color: #393939;
border: 1px solid #393939;
padding: 8px 15px;
cursor: pointer;
font-size: 16px;
margin: 12px;
}
.main-btn {
background-color: #0F62FE;
background-color: DodgerBlue;
border: none;
color: white;
border: 1px solid #0F62FE;
padding: 8px 15px;
cursor: pointer;
font-size: 16px;
margin: 12px;
}
.main-btn i {
margin-left: 15px;
}
/* Darker background on mouse-over */
.bpmn-js-spiffworkflow-btn:hover {
background-color: rgb(0, 0, 0);
border: 1px solid #000000;
color: white;
background-color: RoyalBlue;
}
/* Code Editor -- provided as a div overlay */
.overlay {
position: fixed;
/* Sit on top of the page content */
display: none;
/* Hidden by default */
width: 100%;
/* Full width (cover the whole page) */
height: 100%;
/* Full height (cover the whole page) */
position: fixed; /* Sit on top of the page content */
display: none; /* Hidden by default */
width: 100%; /* Full width (cover the whole page) */
height: 100%; /* Full height (cover the whole page) */
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.5);
/* Black background with opacity */
z-index: 200;
/* BPMN Canvas has some huge z-indexes, pop-up tools are 100 for ex.*/
background-color: rgba(0,0,0,0.5); /* Black background with opacity */
z-index: 200; /* BPMN Canvas has some huge z-indexes, pop-up tools are 100 for ex.*/
}
#code_editor,
#markdown_editor {
#code_editor, #markdown_editor {
background-color: #ccc;
margin: 50px auto 10px auto;
max-width: 800px;
}
#code_buttons,
#markdown_buttons {
#code_buttons, #markdown_buttons {
margin: 50px auto 10px auto;
max-width: 800px;
right: 10px;
}
/* Header */
#header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 10px;
background-color: #ffffff;
color: black;
border-bottom: 1px solid #5F5F5F;
}
#header-actions-center {
/* Adjust as needed */
display: flex;
justify-content: center;
align-items: center;
border-radius: 8px;
border: 0.75px solid #8F8F8F;
}
.header-btn {
background: none;
color: #3c3c3c;
border: none;
padding: 10px 10px;
cursor: pointer;
margin-left: 5px;
font-size: 20px;
}
.header-btn i {
margin-right: 5px;
/* Icon spacing */
}
#process-info h1 {
margin: 0;
font-size: 24px;
}
#process-info p {
margin: 5px 0 0 0;
font-size: 14px;
color: #666;
}
#header-actions {
display: flex;
align-items: center;
}
.bpmn-js-spiffworkflow-btn {
margin-left: 8px;
}
/* Left sidebar */
#left-sidebar {
display: flex;
max-width: 300px;
background-color: #ffffff;
/* background-color: #f4f4f4; */
overflow: hidden;
height: calc(100% - 80px);
float: left;
}
.tabs {
display: flex;
flex-direction: column;
border-right: 1px solid #5F5F5F;
}
.tab-button {
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
height: 50px;
background: none;
border: none;
cursor: pointer;
width: 100%;
}
.tab-button i {
font-size: 18px;
color: #333;
/* margin-bottom: 5px; */
padding: 5px;
}
.tab-button .text {
font-size: 12px;
display: block;
}
.tab-button.active i {
color: #146D83;
}
.tab-button i {
transition: color 0.2s;
}
.tab-button.active i {
transition: color 0.2s;
}
.tab-button:hover {
background-color: #ddd;
}
.tab-button.active,
.tab-button:hover {
background-color: #e9e9e9;
color: DodgerBlue;
}
.tab-content {
display: none;
height: 100%;
width: 300px;
border-right: 1px solid #5F5F5F;
}
.tab-content.active {
display: block;
}
#container::after {
content: "";
clear: both;
display: table;
}
#BPMNElements {
border-bottom: 1px solid #5F5F5F;
}
.bpmn-elements-header {
display: flex;
justify-content: space-between;
align-items: center;
border-bottom: 1px solid #5F5F5F;
padding: 10px;
}
.bpmn-elements-title {
font-weight: bold;
}
.bpmn-elements-toggle {
background: none;
border: none;
cursor: pointer;
padding: 5px;
font-size: 1em;
}
.group-title {
display: flex;
align-items: center;
justify-content: space-between;
padding-block: 5px;
padding-inline: 10px;
/* background: #f8f8f8; */
/* background: #f5f5f58c; */
/* border-bottom: 1px solid #ddd; */
/* cursor: pointer; */
}
.group-title span {
font-weight: 600;
}
.group.collapsed .entry {
display: none;
}
.group-toggle {
background: none;
border: none;
cursor: pointer;
}
.entry-label {
color: #22242A;
text-align: center;
font-family: unset;
font-size: 12px;
font-style: normal;
font-weight: 400;
line-height: normal;
}
.entries-container {
display: flex;
flex-wrap: wrap;
align-items: flex-start;
gap: 10px;
}
.entry {
flex: 0 0 calc(25% - 10px);
display: flex;
align-items: center;
justify-content: center;
margin-block: 5px;
}
.property-tabs {
display: -webkit-box;
width: 100%;
list-style-type: none;
padding: 0;
margin: 0;
border-right: unset;
justify-content: space-between;
text-align: center;
}
.property-tabs li {
padding: 10px 20px;
cursor: pointer;
border-bottom: 2px solid grey;
width: 50%;
}
.property-tabs li.active {
border-bottom: 2px solid blue;
font-weight: bold;
}
.tabs-group .tab-content {
width: 100%;
border: unset;
}
/* BPMN JS CSS */
/* Override default palette styles */
.bjs-container .djs-palette {
width: 100% !important;
height: 90%;
overflow-y: auto;
}
.bjs-container .djs-palette.two-column.open {
width: 230px !important;
}
.bjs-container .djs-palette-entries {
display: grid;
}
.djs-palette .entry,
.djs-palette .djs-palette-toggle {
justify-items: center;
height: unset;
width: unset;
line-height: unset;
display: inline-grid;
cursor: pointer;
}
.bio-properties-panel-header {
background-color: #FAFAFA;
}
.djs-label {
font-family: 'Arial', sans-serif;
.djs-palette.two-column.open {
width: 95px;
}

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 KiB

View File

@ -32,28 +32,6 @@ export default function setupFileOperations(bpmnModeler) {
uploadBtn.addEventListener('click', (_event) => {
openFile(bpmnModeler);
});
// Handle header actions
const headerButtons = document.querySelectorAll('.header-btn');
headerButtons.forEach(function (btn) {
btn.addEventListener('click', function (event) {
const action = event.target.closest('.header-btn').getAttribute('data-action');
handleHeaderAction(action, bpmnModeler);
});
});
// Handle sidebar toggle button
const toggleButtons = document.querySelectorAll('.bpmn-elements-toggle');
toggleButtons.forEach(function (btn) {
btn.addEventListener('click', function (event) {
// Use a data attribute to identify which tab to toggle
const tabTarget = event.target.closest('button').getAttribute('data-tab-target');
toggleTab(tabTarget);
});
});
// Setup tabs after modeler is initialized
setupTabs();
}
function clickElem(elem) {
@ -99,88 +77,3 @@ export function openFile(bpmnModeler) {
document.body.appendChild(fileInput);
clickElem(fileInput);
}
/** ****************************************
* Tab functionality
*/
function openTab(event, tabName) {
// Hide all tab contents
const tabContents = document.querySelectorAll('.tab-content');
tabContents.forEach(content => {
content.classList.remove('active');
});
// Remove active class from all tabs
const tabButtons = document.querySelectorAll('.tab-button');
tabButtons.forEach(button => {
button.classList.remove('active');
});
// append active tab content class to the clicked tab button
document.getElementById(tabName).classList.add('active');
event.currentTarget.classList.add('active');
}
function setupTabs() {
const tabs = document.querySelectorAll('.tab-button');
tabs.forEach(tab => {
tab.addEventListener('click', function (event) {
openTab(event, this.getAttribute('data-tab-target'));
});
});
}
function toggleTab(tabId) {
const tabContent = document.getElementById(tabId);
const allTabContents = document.querySelectorAll('.tab-content');
// Remove 'active' from all tabs
allTabContents.forEach(function (tab) {
tab.classList.remove('active');
});
}
/**
* Header functionality
*/
function handleHeaderAction(action, bpmnModeler) {
var commandStack = bpmnModeler.get('commandStack');
var paletteProvider = bpmnModeler.get('paletteProvider');
var canvas = bpmnModeler.get('canvas');
switch (action) {
case 'zoom-in':
bpmnModeler.get('zoomScroll').stepZoom(1);
break;
case 'zoom-out':
bpmnModeler.get('zoomScroll').stepZoom(-1);
break;
case 'expand':
canvas.zoom('fit-viewport', 'auto');
break;
case 'undo':
commandStack.undo();
break;
case 'redo':
commandStack.redo();
break;
case 'hand':
const handTool = paletteProvider._handTool;
handTool.activateHand();
break;
case 'lasso':
const lassoTool = paletteProvider._lassoTool;
lassoTool.activateSelection(event);
break;
case 'space':
const spaceTool = paletteProvider._spaceTool;
spaceTool.activateSelection();
break;
case 'connect':
const globalConnect = paletteProvider._globalConnect;
globalConnect.start();
break;
default:
console.log('Unknown action:', action);
}
}

View File

@ -1,19 +1,22 @@
<!DOCTYPE html>
<html>
<head>
<!--
IMPORTANT:
This is here to provide an exmaple of how you might use this library in your application.
You should be able to take this example, and modify it to suite your own needs.
-->
<title>bpmn-js-spiffworkflow</title>
<meta charset="utf-8" />
<meta charset="utf-8"/>
<!-- here are the core dependencies you will need to include -->
<link rel="stylesheet" href="vendor/bpmn-js/assets/diagram-js.css" />
<link rel="stylesheet" href="vendor/bpmn-js/assets/bpmn-js.css" />
<link rel="stylesheet" href="vendor/bpmn-js/assets/bpmn-font/css/bpmn-embedded.css" />
<link rel="stylesheet" href="vendor/bpmn-js-properties-panel/assets/properties-panel.css" />
<link rel="stylesheet" href="vendor/bpmn-js/assets/diagram-js.css"/>
<link rel="stylesheet" href="vendor/bpmn-js/assets/bpmn-js.css"/>
<link rel="stylesheet" href="vendor/bpmn-js/assets/bpmn-font/css/bpmn-embedded.css"/>
<link rel="stylesheet" href="vendor/bpmn-js-properties-panel/assets/properties-panel.css"/>
<!-- Some local css settings -->
<link rel="stylesheet" href="css/app.css" />
<!-- <link rel="stylesheet" href="css/bpmn-js.css" /> -->
<link rel="stylesheet" href="css/app.css"/>
<link rel="shortcut icon" href="#">
<!-- A python code editor, we are using CodeMirror here -- see app.js for how this is wired in -->
@ -29,163 +32,33 @@
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
</head>
<style>
.djs-palette {
position: relative;
display: block;
width: 100% !important;
height: 90%;
overflow-y: auto;
padding: 0;
margin: 0;
left: 0;
top: 0;
}
.djs-palette.two-column.open {
width: 100% !important;
}
</style>
<body>
<div id="header">
<div id="process-info">
<h1>Process Name</h1>
<p>. / Process Groups / bpmn_process.bpmn </p>
</div>
<div id="header-actions-center">
<button class="header-btn" title="Hand" data-action="hand">
<i class="bpmn-icon-hand-tool"></i>
</button>
<button class="header-btn" title="LassoTool" data-action="lasso">
<i class="bpmn-icon-lasso-tool"></i>
</button>
<button class="header-btn" title="SpaceTool" data-action="space">
<i class="bpmn-icon-space-tool"></i>
</button>
<button class="header-btn" title="Connect" data-action="connect">
<i class="bpmn-icon-connection-multi"></i>
</button>
<button class="header-btn" title="Zoom In" data-action="zoom-in">
<i class="fa fa-search-plus"></i>
</button>
<button class="header-btn" title="Zoom Out" data-action="zoom-out">
<i class="fa fa-search-minus"></i>
</button>
<button class="header-btn" title="Expand" data-action="expand">
<i class="fa fa-expand"></i>
</button>
<button class="header-btn" title="Undo" data-action="undo">
<i class="fa fa-undo"></i>
</button>
<button class="header-btn" title="Redo" data-action="redo">
<i class="fa fa-repeat"></i>
</button>
</div>
<div id="header-actions">
<button id="downloadButton" class="bpmn-js-spiffworkflow-btn">
Download
</button>
<button id="uploadButton" class="bpmn-js-spiffworkflow-btn">Open a file</button>
<button id="viewXmlButton" class="bpmn-js-spiffworkflow-btn">View XML</button>
<button id="saveButton" class="bpmn-js-spiffworkflow-btn main-btn">
Save <i class="fa fa-long-arrow-right"></i>
</button>
</div>
<div id="menu">
<button id="downloadButton" class="bpmn-js-spiffworkflow-btn"><i class="fa fa-download"></i> Download</button>
<button id="uploadButton" class="bpmn-js-spiffworkflow-btn">Open a file</button>
</div>
<div id="container">
<div id="modeler"></div>
<div id="panel"></div>
</div>
<!-- the following are overlays to provide editors for Python and Markdown -->
<div id="code_overlay" class="overlay">
<div id="code_editor"></div>
<div id="code_buttons">
<button id="saveCode" class="bpmn-js-spiffworkflow-btn">Save</button>
</div>
<div id="left-sidebar">
<div class="tabs">
<button class="tab-button active" data-tab-target="BPMNElements">
<i class="fa fa-th-large"></i>
</button>
<button class="tab-button" data-tab-target="SearchTab">
<i class="fa fa-search"></i>
</button>
<button class="tab-button" data-tab-target="ActionTab">
<i class="fa fa-bolt"></i>
</button>
<button class="tab-button" data-tab-target="ConnectorTab">
<i class="fa fa-cube"></i>
</button>
<button class="tab-button" data-tab-target="HistoryTab">
<i class="fa fa-clock-o"></i>
</button>
</div>
</div>
<div id="markdown_overlay" class="overlay">
<div id="markdown_editor">
<textarea id="markdown_textarea"></textarea>
</div>
<div id="markdown_buttons">
<button id="saveMarkdown" class="bpmn-js-spiffworkflow-btn">Save</button>
</div>
</div>
<div id="BPMNElements" class="tab-content active">
<div class="bpmn-elements-header">
<span class="bpmn-elements-title">BPMN Elements</span>
<button class="bpmn-elements-toggle">
<i class="fa fa-outdent" aria-hidden="true"></i>
</button>
</div>
<!-- Content for BPMN Elements -->
</div>
<div id="HistoryTab" class="tab-content">
<div class="bpmn-elements-header">
<span class="bpmn-elements-title">History</span>
<button class="bpmn-elements-toggle">
<i class="fa fa-outdent" aria-hidden="true"></i>
</button>
</div>
<!-- Content for BPMN Elements -->
History Tab Content
</div>
<div id="ActionTab" class="tab-content">
<div class="bpmn-elements-header">
<span class="bpmn-elements-title">Visual Activity</span>
<button class="bpmn-elements-toggle">
<i class="fa fa-outdent" aria-hidden="true"></i>
</button>
</div>
<!-- Content for BPMN Elements -->
Pre built Actions Tab Content
</div>
<div id="SearchTab" class="tab-content">
<div class="bpmn-elements-header">
<span class="bpmn-elements-title">Search</span>
<button class="bpmn-elements-toggle">
<i class="fa fa-outdent" aria-hidden="true"></i>
</button>
</div>
<!-- Content for BPMN Elements -->
Search Tab Content
</div>
<div id="ConnectorTab" class="tab-content">
<div class="bpmn-elements-header">
<span class="bpmn-elements-title">Integrations / Connectors </span>
<button class="bpmn-elements-toggle">
<i class="fa fa-outdent" aria-hidden="true"></i>
</button>
</div>
<!-- Content for BPMN Elements -->
Connectors Tab Content
</div>
</div>
<div id="container">
<div id="modeler"></div>
<div id="panel"></div>
</div>
<!-- the following are overlays to provide editors for Python and Markdown -->
<div id="code_overlay" class="overlay">
<div id="code_editor"></div>
<div id="code_buttons">
<button id="saveCode" class="bpmn-js-spiffworkflow-btn">Save</button>
</div>
</div>
<div id="markdown_overlay" class="overlay">
<div id="markdown_editor">
<textarea id="markdown_textarea"></textarea>
</div>
<div id="markdown_buttons">
<button id="saveMarkdown" class="bpmn-js-spiffworkflow-btn">Save</button>
</div>
</div>
<!-- Here we load up our application, it's where the configuration happens. -->
<script src="app.js"></script>
<!-- Here we load up our application, it's where the configuration happens. -->
<script src="app.js"></script>
</body>
</html>
</html><!---->

View File

@ -68,7 +68,6 @@ function createDataObjectSelector(element, translate, moddle, commandStack, mode
return {
id: 'data_object_properties',
label: translate('Data Object Properties'),
isDefault: true,
entries: [
{
id: 'selectDataObject',

View File

@ -51,7 +51,6 @@ function createCustomDataStoreGroup(
const group = {
label: translate('Custom Data Store Properties'),
id: 'custom-datastore-properties',
isDefault: true,
entries: [],
};

View File

@ -21,19 +21,13 @@ export function DataStoreSelect(props) {
const bpmnFactory = useService('bpmnFactory');
const getValue = () => {
const dtRef = element.businessObject.dataStoreRef;
return dtRef
? `${dtRef.id}___${dtRef.name}`
return element.businessObject.dataStoreRef
? element.businessObject.dataStoreRef.id
: '';
};
const setValue = (value) => {
const splitValue = value.split('___');
const valId = splitValue[0]
const valClz = splitValue[1]
if (!valId || valId == '') {
if (!value || value == '') {
modeling.updateProperties(element, {
dataStoreRef: null,
});
@ -52,20 +46,19 @@ export function DataStoreSelect(props) {
// Create DataStore
let dataStore = definitions.get('rootElements').find(element =>
element.$type === 'bpmn:DataStore' && element.id === valId
element.$type === 'bpmn:DataStore' && element.id === value
);
// If the DataStore doesn't exist, create new one
if (!dataStore) {
dataStore = bpmnFactory.create('bpmn:DataStore', {
id: valId,
name: valClz
id: value,
name: 'DataStore_' + value
});
definitions.get('rootElements').push(dataStore);
}
modeling.updateProperties(element, {
name: `Data Store (${valId})`,
dataStoreRef: dataStore,
});
@ -96,7 +89,7 @@ export function DataStoreSelect(props) {
spiffExtensionOptions[optionType].forEach((opt) => {
optionList.push({
label: opt.name,
value: `${opt.id}___${opt.clz}`,
value: opt.name,
});
});
}

View File

@ -4,34 +4,19 @@ import translate from 'diagram-js/lib/i18n/translate/translate';
/**
* Add data inputs and data outputs to the panel.
*/
export default function IoPalette(palette, create, elementFactory, eventBus, handTool, globalConnect, lassoTool, spaceTool) {
export default function IoPalette(palette, create, elementFactory,) {
this._create = create;
this._elementFactory = elementFactory;
this._handTool = handTool;
this._globalConnect = globalConnect;
this._lassoTool = lassoTool;
this._spaceTool = spaceTool;
eventBus.on('palette.create', function (event) {
this.init(event);
}.bind(this));
palette.registerProvider(this);
}
IoPalette.$inject = [
'palette',
'create',
'elementFactory',
'eventBus',
'handTool',
'globalConnect',
'lassoTool',
'spaceTool'
'elementFactory'
];
IoPalette.prototype.getPaletteEntries = function (e) {
IoPalette.prototype.getPaletteEntries = function() {
let input_type = 'bpmn:DataInput';
let output_type = 'bpmn:DataOutput';
@ -39,7 +24,7 @@ IoPalette.prototype.getPaletteEntries = function (e) {
function createListener(event, type) {
let shape = elementFactory.createShape(assign({ type: type }, {}));
shape.width = 36;
shape.width = 36; // Fix up the shape dimensions from the defaults.
shape.height = 50;
create.start(event, shape);
}
@ -52,268 +37,26 @@ IoPalette.prototype.getPaletteEntries = function (e) {
createListener(event, output_type);
}
function createShape(type, options = {}) {
return function (event) {
let shape = elementFactory.createShape(assign({ type: type }, options));
create.start(event, shape);
};
}
return {
// Events
'create.start-event': {
group: 'events',
className: 'bpmn-icon-start-event-none',
title: translate('Start'),
action: {
dragstart: createShape('bpmn:StartEvent'),
click: createShape('bpmn:StartEvent')
}
},
'create.intermediate-event': {
group: 'events',
className: 'bpmn-icon-intermediate-event-none',
title: translate('Intermediate'),
action: {
dragstart: createShape('bpmn:IntermediateCatchEvent'),
click: createShape('bpmn:IntermediateCatchEvent')
}
},
'create.end-event': {
group: 'events',
className: 'bpmn-icon-end-event-none',
title: translate('End'),
action: {
dragstart: createShape('bpmn:EndEvent'),
click: createShape('bpmn:EndEvent')
}
},
// Activities
'create.task': {
group: 'activities',
className: 'bpmn-icon-task',
title: translate('Task'),
action: {
dragstart: createShape('bpmn:Task'),
click: createShape('bpmn:Task')
}
},
'create.user-task': {
group: 'activities',
className: 'bpmn-icon-user',
title: translate('User Task'),
action: {
dragstart: createShape('bpmn:UserTask'),
click: createShape('bpmn:UserTask')
}
},
'create.scirpt-task': {
group: 'activities',
className: 'bpmn-icon-script',
title: translate('Script Task'),
action: {
dragstart: createShape('bpmn:ScriptTask'),
click: createShape('bpmn:ScriptTask')
}
},
'create.service-task': {
group: 'activities',
className: 'bpmn-icon-service',
title: translate('Service Task'),
action: {
dragstart: createShape('bpmn:ServiceTask'),
click: createShape('bpmn:ServiceTask')
}
},
// 'create.dmn-task': {
// group: 'activities',
// className: 'bpmn-icon-business-rule',
// title: translate('Business Rule Task'),
// action: {
// dragstart: createShape('bpmn:BusinessRuleTask'),
// click: createShape('bpmn:BusinessRuleTask')
// }
// },
// Gateways
'create.condition-gateaway': {
group: 'decisions',
className: 'bpmn-icon-gateway-xor',
title: translate('Decision'),
action: {
dragstart: createShape('bpmn:ExclusiveGateway'),
click: createShape('bpmn:ExclusiveGateway')
}
},
'create.parallel-gateaway': {
group: 'decisions',
className: 'bpmn-icon-gateway-parallel',
title: translate('Parallel'),
action: {
dragstart: createShape('bpmn:ParallelGateway'),
click: createShape('bpmn:ParallelGateway')
}
},
'create.eventbased-gateaway': {
group: 'decisions',
className: 'bpmn-icon-gateway-eventbased',
title: translate('Event Based'),
action: {
dragstart: createShape('bpmn:EventBasedGateway'),
click: createShape('bpmn:EventBasedGateway')
}
},
'create.inclusive-gateaway': {
group: 'decisions',
className: 'bpmn-icon-gateway-or',
title: translate('xOR'),
action: {
dragstart: createShape('bpmn:InclusiveGateway'),
click: createShape('bpmn:InclusiveGateway')
}
},
// Data Object
'create.data-store': {
group: 'data',
className: 'bpmn-icon-data-store',
title: translate('Data Store'),
action: {
dragstart: createShape('bpmn:DataStoreReference'),
click: createShape('bpmn:DataStoreReference')
}
},
'create.data-object': {
group: 'data',
className: 'bpmn-icon-data-object',
title: translate('Data Object'),
action: {
dragstart: createShape('bpmn:DataObjectReference'),
click: createShape('bpmn:DataObjectReference')
}
},
'create.data-input': {
group: 'data',
group: 'data-object',
className: 'bpmn-icon-data-input',
title: translate('Data Input'),
title: translate('Create DataInput'),
action: {
dragstart: createInputListener,
click: createInputListener
}
},
'create.data-output': {
group: 'data',
group: 'data-object',
className: 'bpmn-icon-data-output',
title: translate('Data Output'),
title: translate('Create DataOutput'),
action: {
dragstart: createOutputListener,
click: createOutputListener
}
},
// Advanced
'create.call-activity': {
group: 'advanced',
className: 'bpmn-icon-call-activity',
title: translate('Call Activity'),
action: {
dragstart: createShape('bpmn:CallActivity'),
click: createShape('bpmn:CallActivity')
}
},
'create.participant': {
group: 'advanced',
className: 'bpmn-icon-participant',
title: translate('Participant'),
action: {
dragstart: createShape('bpmn:Participant'),
click: createShape('bpmn:Participant')
}
},
'create.sub-process-expanded': {
group: 'advanced',
className: 'bpmn-icon-subprocess-expanded',
title: translate('Sub Process'),
action: {
dragstart: createShape('bpmn:SubProcess', { isExpanded: true }),
click: createShape('bpmn:SubProcess', { isExpanded: true })
}
},
'create.transaction': {
group: 'advanced',
className: 'bpmn-icon-transaction',
title: translate('Transaction'),
action: {
dragstart: createShape('bpmn:Transaction', { isExpanded: true }),
click: createShape('bpmn:Transaction', { isExpanded: true })
}
},
}
};
};
IoPalette.prototype.init = function (event) {
// Override Palette DOM Generated by BPMN-JS Library
const paletteContainer = event.container;
const bpmnElementsDiv = document.getElementById('BPMNElements');
setTimeout(() => {
// Query all group elements
const groups = paletteContainer.querySelectorAll('.group');
groups.forEach(group => {
const groupName = group.getAttribute('data-group');
const title = groupName.charAt(0).toUpperCase() + groupName.slice(1).replace(/-/g, ' '); // Capitalize and format the title
// Check if group title already exists
let header = group.querySelector('.group-title');
let entriesContainer = group.querySelector('.entries-container'); // Container for entries
if (!header) {
// Creation the collapsible header
header = document.createElement('div');
header.classList.add('group-title');
// Creation the title span
const titleSpan = document.createElement('span');
titleSpan.textContent = title;
header.appendChild(titleSpan);
// Creation the toggle button
const toggleButton = document.createElement('button');
toggleButton.classList.add('group-toggle');
toggleButton.innerHTML = '<i class="fa fa-chevron-down" aria-hidden="true"></i>';
header.appendChild(toggleButton);
// Insert the header
group.insertBefore(header, group.firstChild);
// Create the entries container
entriesContainer = document.createElement('div');
entriesContainer.classList.add('entries-container');
group.appendChild(entriesContainer); // Append entries container after the header
toggleButton.addEventListener('click', function () {
entriesContainer.style.display = entriesContainer.style.display === 'none' ? '' : 'none';
toggleButton.innerHTML = entriesContainer.style.display === 'none' ? '<i class="fa fa-chevron-right" aria-hidden="true"></i>' : '<i class="fa fa-chevron-down" aria-hidden="true"></i>';
});
}
const entries = group.querySelectorAll('.entry');
entries.forEach(entry => {
entriesContainer.appendChild(entry);
let label = entry.querySelector('.entry-label');
if (!label) {
label = document.createElement('span');
label.classList.add('entry-label');
entry.appendChild(label);
}
label.textContent = entry.getAttribute('title');
});
});
// Move the palette
bpmnElementsDiv ? bpmnElementsDiv.appendChild(paletteContainer): null;
}, 0);
};

View File

@ -36,7 +36,6 @@ function createCalledElementGroup(element, translate, moddle, commandStack) {
return {
id: 'called_element',
label: translate('Called Element'),
isDefault: true,
entries: [
{
id: `called_element_text_field`,

View File

@ -48,8 +48,6 @@ function createConditionsGroup(element, translate, moddle, commandStack) {
return {
id: 'conditions',
label: translate('Conditions'),
// is default property is mainly used to mark this group as a high priority group that located in General Tab
isDefault: true,
entries: conditionGroup(
element,
moddle,

View File

@ -87,7 +87,6 @@ function getConfigureGroupForType(eventDetails, label, includeCode, getSelect) {
return {
id: `${idPrefix}-group`,
label: label,
isDefault: true,
entries,
}
}

View File

@ -95,7 +95,7 @@ export function setExtensionValue(element, name, value, moddle, commandStack, bu
}
function getExtension(businessObject, name) {
if (!businessObject.extensionElements) {
if (!businessObject || !businessObject.extensionElements) {
return null;
}
const extensionElements = businessObject.extensionElements.get('values');

View File

@ -9,14 +9,14 @@ import {
ServiceTaskParameterArray,
ServiceTaskOperatorSelect, ServiceTaskResultTextInput,
} from './SpiffExtensionServiceProperties';
import { OPTION_TYPE, spiffExtensionOptions, SpiffExtensionSelect } from './SpiffExtensionSelect';
import { SpiffExtensionLaunchButton } from './SpiffExtensionLaunchButton';
import { SpiffExtensionTextArea } from './SpiffExtensionTextArea';
import { SpiffExtensionTextInput } from './SpiffExtensionTextInput';
import { SpiffExtensionCheckboxEntry } from './SpiffExtensionCheckboxEntry';
import { hasEventDefinition } from 'bpmn-js/lib/util/DiUtil';
import {OPTION_TYPE, spiffExtensionOptions, SpiffExtensionSelect} from './SpiffExtensionSelect';
import {SpiffExtensionLaunchButton} from './SpiffExtensionLaunchButton';
import {SpiffExtensionTextArea} from './SpiffExtensionTextArea';
import {SpiffExtensionTextInput} from './SpiffExtensionTextInput';
import {SpiffExtensionCheckboxEntry} from './SpiffExtensionCheckboxEntry';
import {hasEventDefinition} from 'bpmn-js/lib/util/DiUtil';
import { PropertyDescription } from 'bpmn-js-properties-panel/';
import { setExtensionValue } from "../extensionHelpers";
import {setExtensionValue} from "../extensionHelpers";
const LOW_PRIORITY = 500;
@ -112,8 +112,6 @@ function createScriptGroup(element, translate, moddle, commandStack) {
return {
id: 'spiff_script',
label: translate('Script'),
// is default property is mainly used to mark this group as a high priority group that located in General Tab
isDefault: true,
entries: scriptGroup({
element,
moddle,
@ -156,7 +154,7 @@ function preScriptPostScriptGroup(element, translate, moddle, commandStack) {
}),
];
const loopCharacteristics = element.businessObject.loopCharacteristics;
if (typeof (loopCharacteristics) !== 'undefined') {
if (typeof(loopCharacteristics) !== 'undefined') {
entries.push({
id: 'scriptValence',
component: ScriptValenceCheckbox,
@ -213,14 +211,13 @@ function createUserGroup(element, translate, moddle, commandStack) {
setExtensionValue(element, 'formUiSchemaFilename', uiName, moddle, commandStack);
const matches = spiffExtensionOptions[OPTION_TYPE.json_schema_files].filter((opt) => opt.value === value);
if (matches.length === 0) {
spiffExtensionOptions[OPTION_TYPE.json_schema_files].push({ label: value, value: value });
spiffExtensionOptions[OPTION_TYPE.json_schema_files].push({label: value, value: value});
}
}
return {
id: 'user_task_properties',
label: translate('Web Form (with Json Schemas)'),
isDefault: true,
entries: [
{
element,
@ -291,7 +288,7 @@ function createBusinessRuleGroup(element, translate, moddle, commandStack) {
* @param moddle
* @returns entries
*/
function createUserInstructionsGroup(
function createUserInstructionsGroup (
element,
translate,
moddle,
@ -332,7 +329,7 @@ function createUserInstructionsGroup(
* @param moddle
* @returns entries
*/
function createAllowGuestGroup(
function createAllowGuestGroup (
element,
translate,
moddle,
@ -382,14 +379,14 @@ function createAllowGuestGroup(
* @param moddle
* @returns entries
*/
function createSignalButtonGroup(
function createSignalButtonGroup (
element,
translate,
moddle,
commandStack
) {
let description =
<p style={{ maxWidth: "330px" }}> If attached to a user/manual task, setting this value will display a button which a user can click to immediately fire this signal event.
<p style={{maxWidth : "330px"}}> If attached to a user/manual task, setting this value will display a button which a user can click to immediately fire this signal event.
</p>
return {
id: 'signal_button',
@ -420,7 +417,6 @@ function createServiceGroup(element, translate, moddle, commandStack) {
return {
id: 'service_task_properties',
label: translate('Spiffworkflow Service Properties'),
isDefault: true,
entries: [
{
element,

View File

@ -18,7 +18,6 @@ import EscalationPropertiesProvider from './escalations/propertiesPanel/Escalati
import CallActivityPropertiesProvider from './callActivity/propertiesPanel/CallActivityPropertiesProvider';
import StandardLoopPropertiesProvider from './loops/propertiesPanel/StandardLoopPropertiesProvider';
import MultiInstancePropertiesProvider from './loops/propertiesPanel/MultiInstancePropertiesProvider';
import PropertiesPanelProvider from './properties/PropertiesPanelProvider';
export default {
__depends__: [RulesModule],
@ -37,8 +36,6 @@ export default {
'escalationPropertiesProvider',
'callActivityPropertiesProvider',
'ioPalette',
'paletteProvider',
'propertiesPanelProvider',
'ioRules',
'ioInterceptor',
'dataObjectRenderer',
@ -60,8 +57,6 @@ export default {
messagesPropertiesProvider: ['type', MessagesPropertiesProvider],
callActivityPropertiesProvider: ['type', CallActivityPropertiesProvider],
ioPalette: ['type', IoPalette],
paletteProvider: ['type', IoPalette],
propertiesPanelProvider: ['type', PropertiesPanelProvider],
ioRules: ['type', IoRules],
ioInterceptor: ['type', IoInterceptor],
multiInstancePropertiesProvider: ['type', MultiInstancePropertiesProvider],

View File

@ -181,7 +181,6 @@ function createMessageGroup(
return {
id: 'messages',
label: translate('Message'),
isDefault: true,
entries,
};
}

View File

@ -1,159 +0,0 @@
const LOW_PRIORITY = 800;
export default function PropertiesPanelProvider(propertiesPanel, eventBus) {
let el;
// eventBus.on('propertiesPanel.providersChanged', function (event) {
// console.log('------------------- propertiesPanel.providersChanged', event);
// });
// eventBus.on('propertiesPanel.getProviders', function (event) {
// console.log('------------------- propertiesPanel.getProviders', event);
// });
// eventBus.on('propertiesPanel.setLayout', function (event) {
// console.log('------------------- propertiesPanel.setLayout', event);
// });
// eventBus.on('propertiesPanel.layoutChanged', function (event) {
// console.log('------------------- propertiesPanel.layoutChanged', event);
// });
this.getGroups = function (element) {
return function (groups) {
// Only render when : el is undefined (editor onload state) or user selects new element or user changes the type of a selected element
if (!el || element.id !== el.id || (element.type !== el.type && element.id === el.id)) {
el = {
id: element.id,
type: element.type
}
this.render(groups);
}
return groups;
}.bind(this);
};
propertiesPanel.registerProvider(LOW_PRIORITY, this);
}
PropertiesPanelProvider.$inject = ['propertiesPanel', 'eventBus'];
PropertiesPanelProvider.prototype.render = function (groups) {
setTimeout(() => {
const propertiesPanelContainer = document.querySelector('.bio-properties-panel-container');
if (!propertiesPanelContainer) return;
// Within that big container, find the part where we can scroll
const scrollContainer = propertiesPanelContainer.querySelector('.bio-properties-panel-scroll-container');
if (!scrollContainer) return;
// Functions :
// This function makes the groups able to open and close.
function makeGroupCollapsible(group) {
const header = group.querySelector('.bio-properties-panel-group-header');
const entries = group.querySelector('.bio-properties-panel-group-entries');
const arrow = header.querySelector('svg');
let isFirstClick = true;
if (header && entries && arrow) {
header.classList.add('open');
entries.classList.add('open');
arrow.classList.add('bio-properties-panel-arrow-down');
arrow.classList.remove('bio-properties-panel-arrow-right');
// Handles the first click, to prevent the bpmn js library from handling it instead
header.addEventListener('click', function() {
if (isFirstClick) {
header.click();
isFirstClick = false;
}
});
}
}
// This function decides what to show based on which tab is clicked.
function updateTabContent(activeTab) {
const allGroups = scrollContainer.querySelectorAll('.bio-properties-panel-group');
allGroups.forEach(group => group.style.display = 'none'); // Hide everything first.
groups.forEach(group => {
const groupElement = scrollContainer.querySelector(`[data-group-id="group-${group.id}"]`);
if (groupElement) {
// If we're on the "General" tab, show the general groups and any group that's set as default.
if (activeTab.dataset.tab === 'general' && (group.id === 'general' || group.isDefault)) {
groupElement.style.display = '';
if (group.isDefault) {
makeGroupCollapsible(groupElement);
}
} else if (activeTab.dataset.tab === 'advanced' && group.id !== 'general' && !group.isDefault) {
groupElement.style.display = '';
}
}
});
}
// Function to always start with the 'General' tab opened
function resetTabsToShowGeneral() {
const generalTab = scrollContainer.querySelector('li[data-tab="general"]');
const advancedTab = scrollContainer.querySelector('li[data-tab="advanced"]');
if (generalTab && advancedTab) {
generalTab.classList.add('active');
advancedTab.classList.remove('active');
updateTabContent(generalTab);
}
}
// Add a click event to each tab to change what's shown
document.querySelectorAll('.tabs li').forEach(tab => {
tab.addEventListener('click', function (event) {
document.querySelectorAll('.tabs li').forEach(t => t.classList.remove('active'));
tab.classList.add('active');
updateTabContent(tab);
});
});
// Create the tabs if they don't exist yet.
if (!scrollContainer.querySelector('.tabs')) {
const tabsHeader = document.createElement('ul');
tabsHeader.className = 'tabs property-tabs';
const generalTab = document.createElement('li');
generalTab.textContent = 'General';
generalTab.dataset.tab = 'general';
generalTab.className = 'active';
tabsHeader.appendChild(generalTab);
const advancedTab = document.createElement('li');
advancedTab.textContent = 'Advanced';
advancedTab.dataset.tab = 'advanced';
tabsHeader.appendChild(advancedTab);
scrollContainer.insertBefore(tabsHeader, scrollContainer.firstChild);
}
// Make sure each tab can do its thing when clicked.
const tabs = scrollContainer.querySelectorAll('.tabs li');
tabs.forEach(tab => {
if (!tab.dataset.listenerAttached) {
tab.addEventListener('click', function (event) {
tabs.forEach(t => t.classList.remove('active'));
tab.classList.add('active');
updateTabContent(tab);
});
tab.dataset.listenerAttached = 'true'; // This is just to make sure we don't add the same event more than once.
}
});
// When we first load, show the right tab and its contents.
const activeTab = document.querySelector('.tabs li.active');
if (activeTab) {
updateTabContent(activeTab);
}
resetTabsToShowGeneral();
}, 0);
}

2
package-lock.json generated
View File

@ -7,7 +7,7 @@
"": {
"name": "bpmn-js-spiffworkflow",
"version": "0.0.8",
"license": "LGPL",
"license": "MIT",
"dependencies": {
"inherits": "^2.0.4",
"inherits-browser": "^0.0.1",

View File

@ -31,7 +31,7 @@
"url": "https://github.com/bpmn-io"
}
],
"license": "LGPL",
"license": "MIT",
"devDependencies": {
"@babel/core": "^7.18.6",
"@babel/plugin-transform-react-jsx": "^7.17.12",

View File

@ -22,8 +22,8 @@ describe('BPMN Input / Output', function() {
it('should have a data input and data output in the properties panel', function() {
var paletteElement = domQuery('.djs-palette', CONTAINER);
var entries = domQueryAll('.entry', paletteElement);
expect(entries[14].title).to.equals('Data Input');
expect(entries[15].title).to.equals('Data Output');
expect(entries[11].title).to.equals('Create DataInput');
expect(entries[12].title).to.equals('Create DataOutput');
});
});

View File

@ -23,8 +23,8 @@ import DataStoreInterceptor from '../../app/spiffworkflow/DataStoreReference/Dat
const return_datastores = (event) => {
event.eventBus.fire('spiff.data_stores.returned', {
options: [
{ id: 'countriesID', type: 'json', name: 'countries', clz: 'JSONDataStore' },
{ id: 'foodsID', type: 'kkv', name: 'foods', clz: 'JSONDataStore' }
{ type: 'typeahead', name: 'countries' },
{ type: 'kkv', name: 'foods' }
],
});
}
@ -83,11 +83,11 @@ describe('Data Source Reference Test cases', function () {
// Verification if the dataStoreRef attribute is updated
let selector = findSelect(entry);
expect(selector.length).to.equal(3);
expect(selector[1].value === 'foodsID___JSONDataStore');
expect(selector[2].value === 'countriesID___JSONDataStore');
expect(selector[1].value === 'countries');
expect(selector[2].value === 'foods');
});
it('should update dataStoreRef after a select event && should add new DataStore in the level of process definition - DataStoreReference element', async function () {
it('should update dataStoreRef after a select event && should add new DataState in the level of process definition - DataStoreReference element', async function () {
const modeler = getBpmnJS();
modeler.get('eventBus').once('spiff.data_stores.requested', return_datastores);
@ -104,16 +104,17 @@ describe('Data Source Reference Test cases', function () {
// Verification if the dataStoreRef attribute is updated
let selector = findSelect(entry);
changeInput(selector, 'foodsID___JSONDataStore');
changeInput(selector, 'foods');
const nwbusinessObject = getBusinessObject(shapeElement);
expect(nwbusinessObject.get('dataStoreRef').id).to.equal('foodsID');
expect(nwbusinessObject.get('dataStoreRef').id).to.equal('foods');
// Check if the DataStore is added at the root level
const definitions = modeler.getDefinitions();
const dataStoreExists = definitions.get('rootElements').some(element =>
element.$type === 'bpmn:DataStore' && element.id === 'foodsID'
element.$type === 'bpmn:DataStore' && element.id === 'foods'
);
expect(dataStoreExists, "DataStore 'foodsID' should be added at the root level").to.be.true;
expect(dataStoreExists, "DataStore 'foods' should be added at the root level").to.be.true;
});
it('should delete dataStore if dataStorRef is updated - DataStoreReference element', async function () {
@ -133,22 +134,22 @@ describe('Data Source Reference Test cases', function () {
// Verification if the dataStoreRef attribute is updated
let selector = findSelect(entry);
changeInput(selector, 'foodsID___JSONDataStore');
changeInput(selector, 'foods');
let nwbusinessObject = getBusinessObject(shapeElement);
expect(nwbusinessObject.get('dataStoreRef').id).to.equal('foodsID');
expect(nwbusinessObject.get('dataStoreRef').id).to.equal('foods');
// Then choose new dataStore
changeInput(selector, 'countriesID___JSONDataStore');
changeInput(selector, 'countries');
nwbusinessObject = getBusinessObject(shapeElement);
expect(nwbusinessObject.get('dataStoreRef').id).to.equal('countriesID');
expect(nwbusinessObject.get('dataStoreRef').id).to.equal('countries');
// Check if the DataStore is added at the root level with the updated dataStore
const definitions = modeler.getDefinitions();
const countriesDataStoreExists = definitions.get('rootElements').some(element =>
element.$type === 'bpmn:DataStore' && element.id === 'countriesID'
element.$type === 'bpmn:DataStore' && element.id === 'countries'
);
expect(countriesDataStoreExists, "DataStore 'countries' should be added at the root level").to.be.true;
const foodsDataStoreExists = definitions.get('rootElements').some(element =>
element.$type === 'bpmn:DataStore' && element.id === 'foodsID'
element.$type === 'bpmn:DataStore' && element.id === 'foods'
);
expect(foodsDataStoreExists, "DataStore 'countries' should be removed from the root level").not.to.be.true;