@apidaze/node-red-contrib-apidaze
Version:
Node-RED module for Apidaze
421 lines (371 loc) • 11.2 kB
HTML
<script type="text/javascript">
const conditionProperties = [
{
name: 'Message',
value: 'text',
},
{
name: 'Called Number',
value: 'called_number',
},
{
name: 'Caller Number',
value: 'caller_number',
},
{
name: 'Caller ID',
value: 'caller_id',
},
{
name: 'Caller Username',
value: 'caller_username',
},
{
name: 'DTMF Digits',
value: 'digits_dialed',
},
{
name: 'Custom String',
value: 'custom_string',
},
];
const conditionOperations = [
{
name: 'Equal',
value: 'equal',
},
{
name: 'Not Equal',
value: 'notEqual',
},
{
name: 'Contains',
value: 'contains',
},
{
name: 'Not Contains',
value: 'notContains',
},
{
name: 'Regex',
value: 'regex',
},
];
const conditionActions = [
{
name: 'Remove Message',
value: 'removeMessage',
},
{
name: 'Remove Matching part of message',
value: 'removeMatch',
},
{
name: 'Keep message',
value: 'keepMessage',
},
];
RED.nodes.registerType('message-processor', {
category: 'apidaze',
color: '#E9967A',
defaults: {
callUuid: {
value: '',
},
matches: {
value: [],
},
},
inputs: 1,
outputs: 1,
icon: 'font-awesome/fa-commenting',
label: 'Message processor',
oneditprepare: function () {
const node = this;
const commonEditableListOptions = {
removable: true,
sortable: true,
};
function addLabel($container, text) {
const $label = $(`<label><i class="fa fa-list"></i> ${text}</label>`);
$container.before($label);
}
function addConditionList($container, conditions = []) {
const $conditions = $('<ol />', {
class: 'node-input-conditions-container',
})
.appendTo($container)
.editableList({
...commonEditableListOptions,
addButton: 'add condition',
addItem: ($row, index, data) => {
addConditionEntry($row, data);
},
});
addLabel($conditions, 'Conditions');
for (const condition of conditions) {
$conditions.editableList('addItem', condition);
}
return $conditions;
}
function addConditionEntry($container, condition) {
const {
property,
propertyValueExp,
operation,
value,
action,
} = condition;
function createSelectElem(options, name, selectedOptionValue) {
const $select = $('<select />', { name });
$.each(options, (index, item) => {
const { name, value } = item;
const $option = $('<option />', {
value,
text: name,
selected: value === selectedOptionValue,
});
$select.append($option);
});
return $select;
}
const $propertyRow = $('<div />', { class: 'fieldset' }).appendTo(
$container
);
const $property = createSelectElem(
conditionProperties,
'property',
property
)
.appendTo($propertyRow)
.before('Property: <br>');
const $propertyValueExpRow = $('<div />', {
class: 'fieldset',
}).appendTo($container);
if (property !== 'custom_string') {
$propertyValueExpRow.hide();
}
const $propertyValueExp = $('<input/>', {
class: 'node-input-value-key',
type: 'text',
name: 'propertyValueExp',
})
.appendTo($propertyValueExpRow)
.typedInput({
default: 'jsonata',
types: ['jsonata'],
})
.typedInput('value', propertyValueExp)
.before('Custom string: <br>');
const $operationRow = $('<div />', { class: 'fieldset' }).appendTo(
$container
);
const $operation = createSelectElem(
conditionOperations,
'operation',
operation
)
.appendTo($operationRow)
.before('Operation: <br>');
const $valueRow = $('<div />', { class: 'fieldset' }).appendTo(
$container
);
const $keyField = $('<input/>', {
class: 'node-input-value-key',
type: 'text',
name: 'value',
})
.appendTo($valueRow)
.typedInput({
default: 'str',
types: [
{
value: 'str',
label: 'string',
icon: 'red/images/typedInput/az.svg',
},
],
})
.typedInput('value', value);
$keyField.before('Value: <br>');
const $actionRow = $('<div />', { class: 'fieldset' }).appendTo(
$container
);
if (property !== 'text') {
$actionRow.hide();
}
const $action = createSelectElem(conditionActions, 'action', action)
.appendTo($actionRow)
.before('Action: <br>');
$property.on('change', function (event) {
const newValue = $(this).val();
if (newValue === 'text') {
$actionRow.show();
$propertyValueExpRow.hide();
} else if (newValue === 'custom_string') {
$actionRow.hide();
$propertyValueExpRow.show();
$propertyValueExp.typedInput('width', '220px');
} else {
$actionRow.hide();
$propertyValueExpRow.hide();
}
});
}
function addPropertyList($container, properties = []) {
const $properties = $('<ol />', {
class: 'node-input-properties-container',
})
.appendTo($container)
.editableList({
...commonEditableListOptions,
addButton: 'add property',
addItem: ($row, index, data) => {
addPropertyEntry($row, data);
},
});
addLabel($container, 'Match');
addLabel($properties, 'Properties');
for (const property of properties) {
$properties.editableList('addItem', property);
}
return $properties;
}
function addPropertyEntry($container, property) {
const { key, value } = property;
const $keyRow = $('<div />', { class: 'fieldset' }).appendTo(
$container
);
const $keyField = $('<input/>', {
class: 'node-input-property-key',
type: 'text',
name: 'key',
})
.appendTo($keyRow)
.typedInput({
default: 'str',
types: [
{
value: 'str',
label: 'string',
icon: 'red/images/typedInput/az.svg',
},
],
})
.typedInput('value', key);
$keyField.before('Property to set: <br>');
const $valueRow = $('<div />', { class: 'fieldset' }).appendTo(
$container
);
const $valueField = $('<input/>', {
class: 'node-input-property-value',
type: 'text',
name: 'value',
})
.appendTo($valueRow)
.typedInput({
default: 'str',
types: [
{
value: 'str',
label: 'string',
icon: 'red/images/typedInput/az.svg',
},
],
})
.typedInput('value', value);
$valueField.before('Value to set: <br>');
}
function addMatch($container, match) {
$container.css({ paddingLeft: '10px' });
const $conditions = addConditionList($container, match.conditions);
const $properties = addPropertyList($container, match.properties);
return [$conditions, $properties];
}
const $container = $('#node-input-matches-container');
$container.editableList({
...commonEditableListOptions,
addButton: 'add case',
addItem: ($row, index, data) => {
addMatch($row, data);
},
});
for (const match of this.matches) {
const conditions = match.conditions || [];
const properties = match.properties || [];
const hasConditions = conditions.length >= 0;
const hasProperties = properties.length >= 0;
if (hasConditions || hasProperties) {
$container.editableList('addItem', match);
}
}
},
oneditsave: function () {
const $container = $('#node-input-matches-container');
const $matches = $container.editableList('items');
this.matches = $.map($matches, ($match) => {
const $conditions = $match
.find('.node-input-conditions-container')
.editableList('items');
const $properties = $match
.find('.node-input-properties-container')
.editableList('items');
const conditions = $.map($conditions, ($condition) => {
const property = $condition.find('[name="property"]').val();
const propertyValueExp = $condition
.find('[name="propertyValueExp"]')
.typedInput('value');
const operation = $condition.find('[name="operation"]').val();
const value = $condition.find('[name="value"]').val();
const action = $condition.find('[name="action"]').val();
const condition = {
property,
propertyValueExp,
operation,
value,
action,
};
return condition;
});
const properties = $.map($properties, ($property) => {
const key = $property.find('[name="key"]').typedInput('value');
const value = $property.find('[name="value"]').typedInput('value');
const property = {
key,
value,
};
return property;
});
return { conditions, properties };
});
},
});
</script>
<script type="text/html" data-template-name="message-processor">
<div class="form-row">
<label for="node-input-callUuid"><i class="fa fa-hashtag"></i> Call UUID</label>
<input type="text" id="node-input-callUuid" />
</div>
<div class="node-row-matches">
<div class="form-row">
<label><i class="fa fa-list"></i> Matches</label>
<div class="form-row node-input-matches-container-row">
<ol id="node-input-matches-container"></ol>
</div>
</div>
</div>
<input type="hidden" id="node-input-outputs" />
<style>
.fieldset + .fieldset {
margin-top: 0.5rem;
}
.red-ui-editableList-item-removable + .red-ui-editableList-item-removable,
.red-ui-editableList + .red-ui-editableList,
.red-ui-editableList + label {
margin-top: 1rem;
}
</style>
</script>
<script type="text/html" data-help-name="message-processor">
<p>Lets incoming SMS message requests proceed in the flow.</p>
</script>