This commit is contained in:
jokob-sk
2025-03-14 07:58:29 +11:00
parent 432a4d9d69
commit 7d6855053e
4 changed files with 493 additions and 79 deletions

View File

@@ -3,12 +3,12 @@ name: docker
on: on:
push: push:
branches: branches:
- '**' - main
tags: tags:
- '*.*.*' - '*.*.*'
pull_request: pull_request:
branches: branches:
- master - main
jobs: jobs:
docker_dev: docker_dev:

View File

@@ -1868,6 +1868,11 @@ input[readonly] {
display: contents; display: contents;
} }
.workflow-card .panel-title
{
padding: 10px;
}
.workflow-card, .condition-list, .actions-list .workflow-card, .condition-list, .actions-list
{ {
display: grid; display: grid;

View File

@@ -47,7 +47,7 @@ let operatorTypes = [
]; ];
let actionTypes = [ let actionTypes = [
"update_field", "run_plugin" "update_field", "run_plugin", "delete_device"
]; ];
// -------------------------------------- // --------------------------------------
@@ -60,11 +60,16 @@ function getData() {
$.get('php/server/query_json.php?file=workflows.json', function (res) { $.get('php/server/query_json.php?file=workflows.json', function (res) {
workflows = res; workflows = res;
console.log(workflows); console.log(workflows);
// Store the updated workflows object back into cache
setCache('workflows', JSON.stringify(workflows));
renderWorkflows(); renderWorkflows();
hideSpinner(); hideSpinner();
}); });
} }
// -------------------------------------- // --------------------------------------
// Render all workflows // Render all workflows
function renderWorkflows() { function renderWorkflows() {
@@ -80,18 +85,18 @@ function renderWorkflows() {
// -------------------------------------- // --------------------------------------
// Generate UI for a single workflow // Generate UI for a single workflow
function generateWorkflowUI(wf, index) { function generateWorkflowUI(wf, wfIndex) {
let $wfContainer = $("<div>", { let $wfContainer = $("<div>", {
class: "workflow-card box box-solid box-primary panel panel-default", class: "workflow-card box box-solid box-primary panel panel-default",
id: `wf-${index}-container` id: `wf-${wfIndex}-container`
}); });
// Workflow Name // Workflow Name
let $wfLinkWrap = $("<div>", let $wfLinkWrap = $("<div>",
{ {
class: " ", class: " ",
id: `wf-${index}-header` id: `wf-${wfIndex}-header`
} }
) )
@@ -101,7 +106,7 @@ function generateWorkflowUI(wf, index) {
"data-toggle": "collapse", "data-toggle": "collapse",
"data-parent": "#workflowContainer", "data-parent": "#workflowContainer",
"aria-expanded": false, "aria-expanded": false,
"href" : `#wf-${index}-collapsible-panel` "href" : `#wf-${wfIndex}-collapsible-panel`
} }
) )
@@ -114,15 +119,26 @@ function generateWorkflowUI(wf, index) {
$wfContainer.append($wfHeaderLink.append($wfLinkWrap.append($wfHeaderHeading))); $wfContainer.append($wfHeaderLink.append($wfLinkWrap.append($wfHeaderHeading)));
// Collapsible panel start // Collapsible panel start
// Get saved state from localStorage
let panelState = localStorage.getItem(`wf-${wfIndex}-collapsible-panel`);
let isOpen = panelState === "true"; // Convert stored string to boolean
console.log(`panel isOpen: ${isOpen}` );
let $wfCollapsiblePanel = $("<div>", { let $wfCollapsiblePanel = $("<div>", {
class: "panel-collapse collapse ", class: `panel-collapse collapse ${isOpen ? 'in' : ''}`,
id: `wf-${index}-collapsible-panel` id: `wf-${wfIndex}-collapsible-panel`
}); });
let $wfNameInput = createEditableInput("Workflow name", wf.name, `wf-name-${index}`, "workflow-name-input", function(newValue) { let $wfNameInput = createEditableInput(
console.log(`Saved new value: ${newValue}`); `[${wfIndex}].name`,
wf.name = newValue; // Update the workflow object with the new name "Workflow name",
}); wf.name,
`wf-${wfIndex}-name`,
"workflow-name-input"
);
$wfCollapsiblePanel.append($wfNameInput) $wfCollapsiblePanel.append($wfNameInput)
@@ -133,13 +149,21 @@ function generateWorkflowUI(wf, index) {
} }
).append("<strong>Trigger:</strong> "); ).append("<strong>Trigger:</strong> ");
let $triggerTypeDropdown = createEditableDropdown("Trigger Type", triggerTypes, wf.trigger.object_type, `trigger-${index}-type`, function(newValue) { let $triggerTypeDropdown = createEditableDropdown(
wf.trigger.object_type = newValue; // Update trigger's object_type `[${wfIndex}].trigger.object_type`,
}); "Trigger Type",
triggerTypes,
wf.trigger.object_type,
`wf-${wfIndex}-trigger-object-type`
);
let $eventTypeDropdown = createEditableDropdown("Event Type", ["update", "create", "delete"], wf.trigger.event_type, `event-${index}-type`, function(newValue) { let $eventTypeDropdown = createEditableDropdown(
wf.trigger.event_type = newValue; // Update trigger's event_type `[${wfIndex}].trigger.event_type`,
}); "Event Type",
["update", "create", "delete"],
wf.trigger.event_type,
`wf-${wfIndex}-trigger-event-type`
);
$triggerSection.append($triggerTypeDropdown); $triggerSection.append($triggerTypeDropdown);
$triggerSection.append($eventTypeDropdown); $triggerSection.append($eventTypeDropdown);
@@ -147,7 +171,7 @@ function generateWorkflowUI(wf, index) {
// Conditions // Conditions
let $conditionsContainer = $("<div>").append("<strong>Conditions:</strong>"); let $conditionsContainer = $("<div>").append("<strong>Conditions:</strong>");
$conditionsContainer.append(renderConditions(wf.conditions)); $conditionsContainer.append(renderConditions(wfIndex, `[${wfIndex}]`, 0, wf.conditions));
$wfCollapsiblePanel.append($conditionsContainer); $wfCollapsiblePanel.append($conditionsContainer);
@@ -159,36 +183,53 @@ function generateWorkflowUI(wf, index) {
} }
).append("<strong>Actions:</strong>"); ).append("<strong>Actions:</strong>");
$.each(wf.actions, function (_, action) { lastActionIndex = 0
$.each(wf.actions, function (actionIndex, action) {
let $actionEl = $("<div>"); let $actionEl = $("<div>");
// Dropdown for action.field // Dropdown for action.field
let $fieldDropdown = createEditableDropdown("Field", fieldOptions, action.field, `action-${index}-field`, function(newValue) { let $fieldDropdown = createEditableDropdown(
action.field = newValue; // Update action.field when a new value is selected `[${wfIndex}].actions[${actionIndex}].field`,
}); "Field",
fieldOptions,
action.field,
`wf-${wfIndex}-actionIndex-${actionIndex}-field`
);
// Dropdown for action.type // Dropdown for action.type
let $actionDropdown= createEditableDropdown("Action", actionTypes, action.field, `action-${index}-type`, function(newValue) { let $actionDropdown= createEditableDropdown(
action.field = newValue; // Update action.field when a new value is selected `[${wfIndex}].actions[${actionIndex}].type`,
}); "Type",
actionTypes,
action.field,
`wf-${wfIndex}-actionIndex-${actionIndex}-type`
);
// Action Value Input (Editable) // Action Value Input (Editable)
let $actionValueInput = createEditableInput("Value", action.value, `action-${index}-value`, "action-value-input", function(newValue) { let $actionValueInput = createEditableInput(
action.value = newValue; // Update action.value when saved `[${wfIndex}].actions[${actionIndex}].value`,
}); "Value",
action.value,
`wf-${wfIndex}-actionIndex-${actionIndex}-value`,
"action-value-input"
);
$actionEl.append($actionDropdown); $actionEl.append($actionDropdown);
$actionEl.append($fieldDropdown); $actionEl.append($fieldDropdown);
$actionEl.append($actionValueInput); $actionEl.append($actionValueInput);
$actionsContainer.append($actionEl); $actionsContainer.append($actionEl);
lastActionIndex = actionIndex
}); });
// add conditions group button // add actions group button
let $actionAddButton = $("<button>", { let $actionAddButton = $("<button>", {
class : "btn btn-secondary " class : "btn btn-secondary add-action",
lastActionIndex : lastActionIndex,
wfIndex: wfIndex
}).text("Add Action") }).text("Add Action")
$actionsContainer.append($actionAddButton) $actionsContainer.append($actionAddButton)
@@ -202,12 +243,18 @@ function generateWorkflowUI(wf, index) {
// -------------------------------------- // --------------------------------------
// Render conditions recursively // Render conditions recursively
function renderConditions(conditions) { function renderConditions(wfIndex, parentIndexPath, conditionGroupsIndex, conditions) {
let $conditionList = $("<div>", { let $conditionList = $("<div>", {
class: "condition-list panel " class: "condition-list ",
parentIndexPath: parentIndexPath
}); });
$.each(conditions, function (index, condition) { lastConditionIndex = 0
$.each(conditions, function (conditionIndex, condition) {
let currentPath = `${parentIndexPath}.conditions[${conditionIndex}]`;
if (condition.logic) { if (condition.logic) {
let $nestedCondition = $("<div>", let $nestedCondition = $("<div>",
{ {
@@ -215,70 +262,116 @@ function renderConditions(conditions) {
} }
); );
let $logicDropdown = createEditableDropdown("Logic Rules", ["AND", "OR"], condition.logic, `logic-${condition.field}`, function(newValue) { let $logicDropdown = createEditableDropdown(
condition.logic = newValue; // Update condition logic when a new value is selected `${currentPath}.logic`,
}); "Logic Rules",
["AND", "OR"],
condition.logic,
`wf-${wfIndex}-${currentPath.replace(/\./g, "-")}-logic` // id
);
$nestedCondition.append($logicDropdown); $nestedCondition.append($logicDropdown);
$conditionListNested = renderConditions(wfIndex, currentPath, conditionGroupsIndex+1, condition.conditions)
$conditionListNested = renderConditions(condition.conditions)
// add conditions group button
let $conditionAddButton = $("<button>", {
class : "btn btn-secondary "
}).text("Add Condition")
$conditionListNested.append($conditionAddButton);
$nestedCondition.append($conditionListNested); // Recursive call for nested conditions $nestedCondition.append($conditionListNested); // Recursive call for nested conditions
$conditionList.append($nestedCondition); $conditionList.append($nestedCondition);
} else { } else {
// INDIVIDUAL CONDITIONS
let $conditionItem = $("<div>", let $conditionItem = $("<div>",
{ {
class: "panel" class: "panel",
conditionIndex: conditionIndex,
wfIndex: wfIndex
}); });
// Create dropdown for condition field // Create dropdown for condition field
let $fieldDropdown = createEditableDropdown("Field", fieldOptions, condition.field, `condition-${index}-field-${condition.field}`, function(newValue) { let $fieldDropdown = createEditableDropdown(
condition.field = newValue; // Update condition field when a new value is selected `${currentPath}.field`,"Field",
}); fieldOptions,
condition.field,
`wf-${wfIndex}-${currentPath.replace(/\./g, "-")}-field`
);
// Create dropdown for operator // Create dropdown for operator
let $operatorDropdown = createEditableDropdown("Operator", operatorTypes, condition.operator, `condition-${index}operator-${condition.field}`, function(newValue) { let $operatorDropdown = createEditableDropdown(
condition.operator = newValue; // Update operator when a new value is selected `${currentPath}.operator`,
}); "Operator",
operatorTypes,
condition.operator,
`wf-${wfIndex}-${currentPath.replace(/\./g, "-")}-operator`
);
// Editable input for condition value // Editable input for condition value
let $editableInput = createEditableInput("Condition Value", condition.value, `condition-${index}-value-${condition.field}`, "condition-value-input", function(newValue) { let $editableInput = createEditableInput(
condition.value = newValue; // Update condition value when saved `${currentPath}.value`,
}); "Condition Value",
condition.value,
`wf-${wfIndex}-${currentPath.replace(/\./g, "-")}-value`,
"condition-value-input"
);
$conditionItem.append($fieldDropdown); // Append field dropdown $conditionItem.append($fieldDropdown); // Append field dropdown
$conditionItem.append($operatorDropdown); // Append operator dropdown $conditionItem.append($operatorDropdown); // Append operator dropdown
$conditionItem.append($editableInput); // Append editable input for condition value $conditionItem.append($editableInput); // Append editable input for condition value
$conditionList.append($conditionItem);
let $conditionRemoveButton = $("<button>", {
class : "btn btn-secondary remove-condition",
lastConditionIndex : lastConditionIndex,
wfIndex: wfIndex,
parentIndexPath: parentIndexPath
}).text("Remove Condition")
$conditionItem.append($conditionRemoveButton);
$conditionList.append($conditionItem);
} }
lastConditionIndex = conditionIndex
}); });
if(conditionGroupsIndex != 0){
// add conditions group button
let $conditionAddButton = $("<button>", {
class : "btn btn-secondary add-condition",
lastConditionIndex : lastConditionIndex,
wfIndex: wfIndex,
parentIndexPath: parentIndexPath
}).text("Add Condition")
// add conditions group button
let $conditionGroupRemoveButton = $("<button>", {
class : "btn btn-secondary remove-condition-group",
lastConditionIndex : lastConditionIndex,
wfIndex: wfIndex,
parentIndexPath: parentIndexPath
}).text("Remove Condition Group")
$conditionList.append($conditionAddButton);
$conditionList.append($conditionGroupRemoveButton);
}
// add conditions group button // add conditions group button
let $conditionsGroupAddButton = $("<button>", { let $conditionsGroupAddButton = $("<button>", {
class : "btn btn-secondary" class : "btn btn-secondary add-condition-group",
wfIndex: wfIndex,
parentIndexPath: parentIndexPath
}).text("Add Condition Group") }).text("Add Condition Group")
$conditionList.append($conditionsGroupAddButton); $conditionList.append($conditionsGroupAddButton);
return $conditionList; return $conditionList;
} }
// -------------------------------------- // --------------------------------------
// Render SELECT Dropdown with Predefined Values // Render SELECT Dropdown with Predefined Values
function createEditableDropdown(labelText, options, selectedValue, id, onSave) { function createEditableDropdown(jsonPath, labelText, options, selectedValue, id) {
let $wrapper = $("<div>", { let $wrapper = $("<div>", {
class: "form-group col-xs-12" class: "form-group col-xs-12"
@@ -297,6 +390,7 @@ function createEditableDropdown(labelText, options, selectedValue, id, onSave) {
// Create select element // Create select element
let $select = $("<select>", { let $select = $("<select>", {
id: id, id: id,
jsonPath: jsonPath,
class: "form-control col-sm-8 col-xs-12" class: "form-control col-sm-8 col-xs-12"
}); });
@@ -313,9 +407,10 @@ function createEditableDropdown(labelText, options, selectedValue, id, onSave) {
$select.on("change", function() { $select.on("change", function() {
let newValue = $select.val(); let newValue = $select.val();
console.log(`Selected new value: ${newValue}`); console.log(`Selected new value: ${newValue}`);
if (onSave && typeof onSave === "function") { console.log(`Selected new jsonPath: ${$select.attr("jsonPath")}`);
onSave(newValue); // Call onSave callback with the new value
} updateWorkflowObject(newValue, $select.attr("jsonPath")); // Call the onSave callback with the new value
}); });
$wrapper.append($label); $wrapper.append($label);
@@ -323,11 +418,9 @@ function createEditableDropdown(labelText, options, selectedValue, id, onSave) {
return $wrapper; return $wrapper;
} }
// -------------------------------------- // --------------------------------------
// Render INPUT HTML element // Render INPUT HTML element
function createEditableInput(labelText, value, id, className = "", onSave = null) { function createEditableInput(jsonPath, labelText, value, id, className = "") {
// prepare wrapper // prepare wrapper
$wrapper = $("<div>", { $wrapper = $("<div>", {
@@ -344,9 +437,11 @@ function createEditableInput(labelText, value, id, className = "", onSave = null
class: "col-sm-8 col-xs-12" class: "col-sm-8 col-xs-12"
}); });
// console.log(jsonPath);
let $input = $("<input>", { let $input = $("<input>", {
type: "text", type: "text",
jsonPath: jsonPath,
id: id, id: id,
value: value, value: value,
class: className + " col-sm-8 col-xs-12 form-control " class: className + " col-sm-8 col-xs-12 form-control "
@@ -360,10 +455,11 @@ function createEditableInput(labelText, value, id, className = "", onSave = null
// Trigger onSave when the user presses Enter or the input loses focus // Trigger onSave when the user presses Enter or the input loses focus
$input.on("blur keyup", function (e) { $input.on("blur keyup", function (e) {
if (e.type === "blur" || e.key === "Enter") { if (e.type === "blur" || e.key === "Enter") {
if (onSave && typeof onSave === "function") { let newValue = $input.val();
onSave($input.val()); // Call the onSave callback with the new value console.log(`Selected new value: ${newValue}`);
}
updateWorkflowObject(newValue, $input.attr("jsonPath")); // Call the onSave callback with the new value
} }
}); });
@@ -372,8 +468,308 @@ function createEditableInput(labelText, value, id, className = "", onSave = null
return $wrapper; return $wrapper;
} }
// --------------------------------------
// Updating the in-memory workflow object
function updateWorkflowObject(newValue, jsonPath) {
// Load workflows from cache if available
let workflows = JSON.parse(getCache('workflows')) || []; // Initialize as an array
console.log("Initial workflows:", workflows);
workflows = updateJsonByPath(workflows, jsonPath, newValue)
console.log("Updated workflows:", workflows);
// Store the updated workflows object back into cache
setCache('workflows', JSON.stringify(workflows)); // Store as a string in localStorage
}
/**
* Updates the given JSON structure at the location specified by a JSON path.
* @param {object|array} json - The JSON object or array to update.
* @param {string} path - The JSON path string, e.g. "[1].conditions[0].conditions[2].conditions[0].field".
* @param {*} newValue - The new value to set at the given path.
* @returns {object|array} - The updated JSON.
*/
function updateJsonByPath(json, path, newValue) {
const tokens = parsePath(path);
recursiveUpdate(json, tokens, newValue);
return json;
}
/**
* Recursively traverses the JSON structure to update the property defined by tokens.
* @param {object|array} current - The current JSON object or array.
* @param {Array<string|number>} tokens - An array of tokens representing the path.
* @param {*} newValue - The value to set at the target location.
*/
function recursiveUpdate(current, tokens, newValue) {
// When only one token is left, update that property/element with newValue.
if (tokens.length === 1) {
const key = tokens[0];
current[key] = newValue;
return;
}
const token = tokens[0];
// If the next level does not exist, optionally create it.
if (current[token] === undefined) {
// Determine if the next token is an array index or a property.
current[token] = typeof tokens[1] === 'number' ? [] : {};
}
// Recursively update the next level.
recursiveUpdate(current[token], tokens.slice(1), newValue);
}
/**
* Parses a JSON path string into an array of tokens.
* For example, "[1].conditions[0].conditions[2].conditions[0].field" becomes:
* [1, "conditions", 0, "conditions", 2, "conditions", 0, "field"]
* @param {string} path - The JSON path string.
* @returns {Array<string|number>} - An array of tokens.
*/
function parsePath(path) {
const tokens = [];
const regex = /(\w+)|\[(\d+)\]/g;
let match;
while ((match = regex.exec(path)) !== null) {
if (match[1]) {
tokens.push(match[1]);
} else if (match[2]) {
tokens.push(Number(match[2]));
}
}
return tokens;
}
// ---------------------------------------------------
// Buttons functionality
// ---------------------------------------------------
// ---------------------------------------------------
// Function to add a new condition
function addCondition(wfIndex, parentIndexPath) {
if (!parentIndexPath) return;
// Navigate to the target nested object
let target = getNestedObject(workflows, parentIndexPath);
console.log("Target:", target);
if (!target || !target.conditions) {
console.error("❌ Invalid path or conditions array missing:", parentIndexPath);
return;
}
// Add a new condition to the conditions array
target.conditions.push({
field: fieldOptions[0], // First option from field dropdown
operator: operatorTypes[0], // First operator
value: "" // Default empty value
});
// 🔥 Ensure the workflows object is updated in memory
workflows[wfIndex] = { ...workflows[wfIndex] };
// 🔥 Update the cache with the modified workflows object
setCache("workflows", JSON.stringify(workflows));
// Re-render the UI
renderWorkflows();
}
// ---------------------------------------------------
// Function to add a new condition group
function addConditionGroup(wfIndex, parentIndexPath) {
if (!parentIndexPath) return;
// Navigate to the target nested object
let target = getNestedObject(workflows, parentIndexPath);
console.log("Target:", target);
if (!target || !target.conditions) {
console.error("❌ Invalid path or conditions array missing:", parentIndexPath);
return;
}
// Add a new condition group to the conditions array
target.conditions.push({
logic: "AND",
conditions: []
});
// 🔥 Ensure the workflows object is updated in memory
workflows[wfIndex] = { ...workflows[wfIndex] };
// 🔥 Update the cache with the modified workflows object
setCache("workflows", JSON.stringify(workflows));
// Re-render the UI
renderWorkflows();
}
// ---------------------------------------------------
// Function to add a new action
function addAction(wfIndex) {
let newAction = {
type: actionTypes[0],
field: fieldOptions[0],
value: ""
};
workflows[wfIndex].actions.push(newAction);
renderWorkflows();
}
function removeCondition(wfIndex, parentIndexPath, lastConditionIndex) {
if (!parentIndexPath || lastConditionIndex === undefined) return;
// Navigate to the target nested object
let target = getNestedObject(workflows, parentIndexPath);
console.log("Target before removal:", target);
if (!target || !Array.isArray(target.conditions)) {
console.error("❌ Invalid path or conditions array missing:", parentIndexPath);
return;
}
// Remove the specified condition
target.conditions.splice(lastConditionIndex, 1);
// 🔥 Ensure the workflows object is updated in memory
workflows[wfIndex] = { ...workflows[wfIndex] };
// 🔥 Update the cache with the modified workflows object
setCache("workflows", JSON.stringify(workflows));
// Re-render the UI
renderWorkflows();
}
function removeConditionGroup(wfIndex, parentIndexPath) {
if (!parentIndexPath) return;
// Split the path by dots
const parts = parentIndexPath.split('.');
// Extract the last part (index)
const lastIndex = parts.pop().replace(/\D/g, ''); // Remove any non-numeric characters
// Rebuild the path without the last part
const newPath = parts.join('.');
console.log(parentIndexPath);
console.log(newPath);
// Navigate to the target nested object
let target = getNestedObject(workflows, newPath);
console.log("Target before removal:", target);
if (!target || !Array.isArray(target.conditions)) {
console.error("❌ Invalid path or conditions array missing:", parentIndexPath);
return;
}
// Remove the specified condition group
delete target.conditions.splice(lastIndex, 1);
// 🔥 Ensure the workflows object is updated in memory
workflows[wfIndex] = { ...workflows[wfIndex] };
// 🔥 Update the cache with the modified workflows object
setCache("workflows", JSON.stringify(workflows));
// Re-render the UI
renderWorkflows();
}
// ---------------------------------------------------
// Helper function to navigate to a nested object using the provided path
function getNestedObject(obj, path) {
// console.log("🔍 Getting nested object:", { obj, path });
// Convert bracket notation to dot notation (e.g., '[1].conditions[0]' → '1.conditions.0')
const keys = path.replace(/\[(\d+)\]/g, '.$1').split('.').filter(Boolean);
return keys.reduce((o, key, index) => {
if (o && o[key] !== undefined) {
// console.log(`✅ Found: ${keys.slice(0, index + 1).join('.')} ->`, o[key]);
return o[key];
} else {
console.warn(`❌ Failed at: ${keys.slice(0, index + 1).join('.')}`);
console.warn("🔍 Tried getting nested object:", { obj, path });
return null;
}
}, obj);
}
// ---------------------------------------------------
// Event listeners
$(document).on("click", ".add-condition", function () {
let wfIndex = $(this).attr("wfindex");
let parentIndexPath = $(this).attr("parentIndexPath");
addCondition(wfIndex, parentIndexPath);
});
$(document).on("click", ".add-condition-group", function () {
let wfIndex = $(this).attr("wfindex");
let parentIndexPath = $(this).attr("parentIndexPath");
addConditionGroup(wfIndex, parentIndexPath);
});
$(document).on("click", ".add-action", function () {
let wfIndex = $(this).attr("wfIndex");
addAction(wfIndex);
});
// Event Listeners for Removing Conditions
$(document).on("click", ".remove-condition", function () {
let wfIndex = $(this).attr("wfindex");
let parentIndexPath = $(this).attr("parentIndexPath");
let lastConditionIndex = parseInt($(this).attr("lastConditionIndex"), 10);
removeCondition(wfIndex, parentIndexPath, lastConditionIndex);
});
// Event Listeners for Removing Condition Groups
$(document).on("click", ".remove-condition-group", function () {
let wfIndex = $(this).attr("wfindex");
let parentIndexPath = $(this).attr("parentIndexPath");
let lastConditionIndex = parseInt($(this).attr("lastConditionIndex"), 10);
removeConditionGroup(wfIndex, parentIndexPath);
});
// ---------------------------------------------------
// Handling open/closed state of collapsible panels
$(document).ready(function() {
$(".panel-collapse").each(function() {
let panelId = $(this).attr("id");
let isOpen = localStorage.getItem(panelId) === "true";
if (isOpen) {
$(this).addClass("in");
}
});
$(document).on("shown.bs.collapse", ".panel-collapse", function() {
localStorage.setItem($(this).attr("id"), "true");
console.log("Panel opened:", $(this).attr("id"));
});
$(document).on("hidden.bs.collapse", ".panel-collapse", function() {
localStorage.setItem($(this).attr("id"), "false");
console.log("Panel closed:", $(this).attr("id"));
});
});
// -------------------------------------- // --------------------------------------
// Initialize // Initialize

View File

@@ -1,4 +1,17 @@
[ [
{
"name": "Empty Workflow",
"trigger": {
"object_type": "",
"event_type": ""
},
"conditions": [
],
"actions": [
]
},
{ {
"name": "Sample Device Update Workflow", "name": "Sample Device Update Workflow",
"trigger": { "trigger": {
@@ -23,14 +36,14 @@
"logic": "OR", "logic": "OR",
"conditions": [ "conditions": [
{ {
"field": "devIsNew", "field": "devSite",
"operator": "equals", "operator": "equals",
"value": "1" "value": "Home"
}, },
{ {
"field": "devName", "field": "devName",
"operator": "contains", "operator": "contains",
"value": "Google" "value": "Motorola"
} }
] ]
} }