Skip to content

Commit

Permalink
feat: support cron expressions for timer cycle props
Browse files Browse the repository at this point in the history
  • Loading branch information
barmac committed Sep 21, 2022
1 parent 649f5ce commit 9fc0299
Show file tree
Hide file tree
Showing 9 changed files with 939 additions and 3 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ All notable changes to [bpmn-js-properties-panel](https://github.com/bpmn-io/bpm

___Note:__ Yet to be released changes appear here._

* `FEAT`: support cron expressions for timer cycle ([#772](https://github.com/bpmn-io/bpmn-js-properties-panel/pull/772))
* `DEPS`: update to `@bpmn-io/properties-panel@0.21.0`

## 1.6.1
Expand Down
3 changes: 2 additions & 1 deletion src/provider/bpmn/properties/TimerProps.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ import {
isTimerSupported,
getTimerEventDefinition,
getTimerDefinitionType
} from '../utils/EventDefinitionUtil';
} from '../../../utils/EventDefinitionUtil';


import {
SelectEntry,
Expand Down
14 changes: 14 additions & 0 deletions src/provider/camunda-platform/CamundaPlatformPropertiesProvider.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import {
ProcessVariablesProps,
ScriptTaskProps,
TasklistProps,
TimerProps,
UserAssignmentProps,
VersionTagProps
} from './properties';
Expand Down Expand Up @@ -119,6 +120,7 @@ export default class CamundaPlatformPropertiesProvider {
updateErrorGroup(groups, element);
updateEscalationGroup(groups, element);
updateMultiInstanceGroup(groups, element);
updateTimerGroup(groups, element);

// (3) move groups given specific priorities
moveImplementationGroup(groups);
Expand Down Expand Up @@ -203,6 +205,18 @@ function updateEscalationGroup(groups, element) {
EscalationProps({ element, entries });
}

function updateTimerGroup(groups, element) {
const timerEventGroup = findGroup(groups, 'timer');

if (!timerEventGroup) {
return;
}

timerEventGroup.entries = [
...TimerProps({ element })
];
}

function ImplementationGroup(element) {

const group = {
Expand Down
241 changes: 241 additions & 0 deletions src/provider/camunda-platform/properties/TimerProps.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,241 @@
import {
getBusinessObject,
is
} from 'bpmn-js/lib/util/ModelUtil';

import {
useService
} from '../../../hooks';

import {
isTimerSupported,
getTimerEventDefinition,
getTimerDefinitionType
} from '../../../utils/EventDefinitionUtil';

import {
SelectEntry,
isSelectEntryEdited,
TextFieldEntry,
isTextFieldEntryEdited
} from '@bpmn-io/properties-panel';


/**
* @typedef { import('@bpmn-io/properties-panel').EntryDefinition } Entry
*/

/**
* @returns {Array<Entry>} entries
*/
export function TimerProps(props) {
const {
element,
listener,
idPrefix
} = props;

let {
timerEventDefinition
} = props;

if (!timerEventDefinition) {
const businessObject = getBusinessObject(element);
timerEventDefinition = getTimerEventDefinition(businessObject);
}

const timerEventDefinitionType = getTimerDefinitionType(timerEventDefinition);

// (1) Only show for supported elements
if (!isTimerSupported(element) && !isTimerSupportedOnListener(listener)) {
return [];
}

// (2) Provide entries, have a value only if selection was made
const entries = [];

entries.push({
id: getId(idPrefix, 'timerEventDefinitionType'),
component: TimerEventDefinitionType,
isEdited: isSelectEntryEdited,
timerEventDefinition,
timerEventDefinitionType
});

if (timerEventDefinitionType) {
entries.push({
id: getId(idPrefix, 'timerEventDefinitionValue'),
component: TimerEventDefinitionValue,
isEdited: isTextFieldEntryEdited,
timerEventDefinition,
timerEventDefinitionType
});
}

return entries;
}


/**
* TimerEventDefinitionType - Generic select entry allowing to select a specific
* timerEventDefintionType. To be used together with timerEventDefinitionValue.
*
* @param {type} props
* @return {SelectEntry}
*/
function TimerEventDefinitionType(props) {
const {
element,
timerEventDefinition,
timerEventDefinitionType
} = props;

const commandStack = useService('commandStack'),
bpmnFactory = useService('bpmnFactory'),
translate = useService('translate');

const getValue = () => {
return timerEventDefinitionType || '';
};

const setValue = (value) => {

// (1) Check if value is different to current type
if (value === timerEventDefinitionType) {
return;
}

// (2) Create empty formalExpression element
const formalExpression = bpmnFactory.create('bpmn:FormalExpression', { body: undefined });
formalExpression.$parent = timerEventDefinition;

// (3) Set the value for selected timerEventDefinitionType
const newProps = {
timeDuration: undefined,
timeDate: undefined,
timeCycle: undefined
};

if (value !== '') {
newProps[value] = formalExpression;
}

// (4) Execute businessObject update
commandStack.execute('element.updateModdleProperties', {
element,
moddleElement: timerEventDefinition,
properties: newProps
});
};

const getOptions = (element) => {
return [
{ value: '', label: translate('<none>') },
{ value: 'timeDate', label: translate('Date') },
{ value: 'timeDuration', label: translate('Duration') },
{ value: 'timeCycle', label: translate('Cycle') }
];
};

return SelectEntry({
element,
id: 'timerEventDefinitionType',
label: translate('Type'),
getValue,
setValue,
getOptions
});
}

/**
* TimerEventDefinitionValue - Generic textField entry allowing to specify the
* timerEventDefintionValue based on the set timerEventDefintionType. To be used
* together with timerEventDefinitionType.
*
* @param {type} props
* @return {TextFieldEntry}
*/
function TimerEventDefinitionValue(props) {
const {
element,
timerEventDefinition,
timerEventDefinitionType
} = props;

const commandStack = useService('commandStack'),
translate = useService('translate'),
debounce = useService('debounceInput');

const timerEventFormalExpression = timerEventDefinition.get(timerEventDefinitionType);

const getValue = () => {
return timerEventFormalExpression && timerEventFormalExpression.get('body');
};

const setValue = (value) => {
commandStack.execute('element.updateModdleProperties', {
element,
moddleElement: timerEventFormalExpression,
properties: {
body: value
}
});
};

return TextFieldEntry({
element,
id: 'timerEventDefinitionValue',
label: translate('Value'),
getValue,
setValue,
debounce,
description: getTimerEventDefinitionValueDescription(timerEventDefinitionType, translate)
});
}


// helper //////////////////////////

function getTimerEventDefinitionValueDescription(timerDefinitionType, translate) {
switch (timerDefinitionType) {
case 'timeDate':
return (<div>
<p>{ translate('A specific point in time defined as ISO 8601 combined date and time representation.') }</p>
<ul>
<li><code>2019-10-01T12:00:00Z</code> - { translate('UTC time') }</li>
<li><code>2019-10-02T08:09:40+02:00</code> - { translate('UTC plus 2 hours zone offset') }</li>
</ul>
<a href="https://docs.camunda.org/manual/latest/reference/bpmn20/events/timer-events/#time-date" target="_blank" rel="noopener">{ translate('Documentation: Timer events') }</a>
</div>);

case 'timeCycle':
return (<div>
<p>{ translate('A cycle defined as ISO 8601 repeating intervals format, or a cron expression.') }</p>
<ul>
<li><code>R5/PT10S</code> - { translate('every 10 seconds, up to 5 times') }</li>
<li><code>R/P1D</code> - { translate('every day, infinitely') }</li>
<li><code>0 0 9-17 * * MON-FRI</code> - { translate('every hour on the hour from 9-5 p.m. UTC Monday-Friday') }</li>
</ul>
<a href="https://docs.camunda.org/manual/latest/reference/bpmn20/events/timer-events/#time-cycle" target="_blank" rel="noopener">{ translate('Documentation: Timer events') }</a>
</div>);

case 'timeDuration':
return (<div>
<p>{ translate('A time duration defined as ISO 8601 durations format.') }</p>
<ul>
<li><code>PT15S</code> - { translate('15 seconds') }</li>
<li><code>PT1H30M</code> - { translate('1 hour and 30 minutes') }</li>
<li><code>P14D</code> - { translate('14 days') }</li>
</ul>
<a href="https://docs.camunda.org/manual/latest/reference/bpmn20/events/timer-events/#time-duration" target="_blank" rel="noopener">{ translate('Documentation: Timer events') }</a>
</div>);
}
}

function isTimerSupportedOnListener(listener) {
return listener && is(listener, 'camunda:TaskListener') && getTimerEventDefinition(listener);
}

function getId(idPrefix, id) {
return idPrefix ? idPrefix + id : id;
}
1 change: 1 addition & 0 deletions src/provider/camunda-platform/properties/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,4 @@ export { ScriptTaskProps } from './ScriptTaskProps';
export { TasklistProps } from './TasklistProps';
export { UserAssignmentProps } from './UserAssignmentProps';
export { VersionTagProps } from './VersionTagProps';
export { TimerProps } from './TimerProps';
5 changes: 3 additions & 2 deletions src/provider/zeebe/properties/TimerProps.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import {
isTimerSupported,
getTimerEventDefinition,
getTimerDefinitionType
} from '../../bpmn/utils/EventDefinitionUtil';
} from '../../../utils/EventDefinitionUtil';

import {
FeelEntry, isFeelEntryEdited,
Expand Down Expand Up @@ -355,10 +355,11 @@ function getTimerEventDefinitionValueDescription(timerDefinitionType, translate)

case 'timeCycle':
return (<div>
<p>{ translate('A cycle defined as ISO 8601 repeating intervals format.') }</p>
<p>{ translate('A cycle defined as ISO 8601 repeating intervals format, or a cron expression.') }</p>
<ul>
<li><code>R5/PT10S</code> - { translate('every 10 seconds, up to 5 times') }</li>
<li><code>R/P1D</code> - { translate('every day, infinitely') }</li>
<li><code>0 0 9-17 * * MON-FRI</code> - { translate('every hour on the hour from 9-5 p.m. UTC Monday-Friday') }</li>
</ul>
<a href="https://docs.camunda.io/docs/reference/bpmn-processes/timer-events/timer-events#time-cycle" target="_blank" rel="noopener" title={ translate('Timer documentation') }>{ translate('How to configure a timer') }</a>
</div>);
Expand Down
Loading

0 comments on commit 9fc0299

Please sign in to comment.