Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions core/Extensions/subflow-test/grandchild-data-extension.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{
"key": "grandchild-data-extension",
"version": "1.0.0",
"domain": "core",
"flow": "sys-extensions",
"flowVersion": "1.0.0",
"tags": [
"subflow-test",
"grandchild-extension",
"data-extension",
"longpolling-test",
"deep-nested-test"
],
"attributes": {
"type": 2,
"scope": 1,
"task": {
"order": 1,
"task": {
"key": "test-http-task",
"domain": "core",
"version": "1.0.0",
"flow": "sys-tasks"
},
"mapping": {
"location": "./src/GrandchildDataExtensionMapping.csx",
"code": "dXNpbmcgU3lzdGVtOwp1c2luZyBTeXN0ZW0uVGhyZWFkaW5nLlRhc2tzOwp1c2luZyBCQlQuV29ya2Zsb3cuU2NyaXB0aW5nOwp1c2luZyBCQlQuV29ya2Zsb3cuRGVmaW5pdGlvbnM7CgovLy8gPHN1bW1hcnk+Ci8vLyBHcmFuZGNoaWxkIERhdGEgRXh0ZW5zaW9uIE1hcHBpbmcgLSBQcm92aWRlcyBhZGRpdGlvbmFsIGRhdGEgZm9yIGdyYW5kY2hpbGQgd29ya2Zsb3cgdmlldwovLy8gVGhpcyBleHRlbnNpb24gaXMgdXNlZCB0byB0ZXN0IGxvbmdwb2xsaW5nIGZ1bmN0aW9uYWxpdHkgZm9yIGRlZXBseSBuZXN0ZWQgd29ya2Zsb3cgdmlld3MuCi8vLyA8L3N1bW1hcnk+CnB1YmxpYyBjbGFzcyBHcmFuZGNoaWxkRGF0YUV4dGVuc2lvbk1hcHBpbmcgOiBJTWFwcGluZwp7CiAgICBwdWJsaWMgVGFzazxTY3JpcHRSZXNwb25zZT4gSW5wdXRIYW5kbGVyKFdvcmtmbG93VGFzayB0YXNrLCBTY3JpcHRDb250ZXh0IGNvbnRleHQpCiAgICB7CiAgICAgICAgdHJ5CiAgICAgICAgewogICAgICAgICAgICB2YXIgaHR0cFRhc2sgPSB0YXNrIGFzIEh0dHBUYXNrOwogICAgICAgICAgICBpZiAoaHR0cFRhc2sgPT0gbnVsbCkKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgdGhyb3cgbmV3IEludmFsaWRPcGVyYXRpb25FeGNlcHRpb24oIlRhc2sgbXVzdCBiZSBhbiBIdHRwVGFzayIpOwogICAgICAgICAgICB9CgogICAgICAgICAgICAvLyBQcmVwYXJlIHJlcXVlc3QgYm9keSBmb3IgZXh0ZW5zaW9uIGRhdGEKICAgICAgICAgICAgdmFyIHJlcXVlc3RCb2R5ID0gbmV3CiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgIGV4dGVuc2lvblR5cGUgPSAiZ3JhbmRjaGlsZC1kYXRhLWV4dGVuc2lvbiIsCiAgICAgICAgICAgICAgICBpbnN0YW5jZUlkID0gY29udGV4dC5JbnN0YW5jZT8uSWQsCiAgICAgICAgICAgICAgICB3b3JrZmxvd0tleSA9IGNvbnRleHQuV29ya2Zsb3c/LktleSwKICAgICAgICAgICAgICAgIHBhcmVudEluc3RhbmNlSWQgPSBjb250ZXh0Lkluc3RhbmNlPy5EYXRhPy5wYXJlbnRJbnN0YW5jZUlkLAogICAgICAgICAgICAgICAgY2hpbGRJbnN0YW5jZUlkID0gY29udGV4dC5JbnN0YW5jZT8uRGF0YT8uY2hpbGRJbnN0YW5jZUlkLAogICAgICAgICAgICAgICAgbmVzdGluZ0xldmVsID0gMywKICAgICAgICAgICAgICAgIHJlcXVlc3RlZEF0ID0gRGF0ZVRpbWUuVXRjTm93CiAgICAgICAgICAgIH07CgogICAgICAgICAgICBodHRwVGFzay5TZXRCb2R5KHJlcXVlc3RCb2R5KTsKCiAgICAgICAgICAgIC8vIFNldCBoZWFkZXJzCiAgICAgICAgICAgIHZhciBoZWFkZXJzID0gbmV3IERpY3Rpb25hcnk8c3RyaW5nLCBzdHJpbmc/PgogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICBbIkNvbnRlbnQtVHlwZSJdID0gImFwcGxpY2F0aW9uL2pzb24iLAogICAgICAgICAgICAgICAgWyJYLUV4dGVuc2lvbi1UeXBlIl0gPSAiZ3JhbmRjaGlsZC1kYXRhIiwKICAgICAgICAgICAgICAgIFsiWC1OZXN0aW5nLUxldmVsIl0gPSAiMyIsCiAgICAgICAgICAgICAgICBbIlgtUmVxdWVzdC1JZCJdID0gR3VpZC5OZXdHdWlkKCkuVG9TdHJpbmcoKQogICAgICAgICAgICB9OwogICAgICAgICAgICBodHRwVGFzay5TZXRIZWFkZXJzKGhlYWRlcnMpOwoKICAgICAgICAgICAgcmV0dXJuIFRhc2suRnJvbVJlc3VsdChuZXcgU2NyaXB0UmVzcG9uc2UoKSk7CiAgICAgICAgfQogICAgICAgIGNhdGNoIChFeGNlcHRpb24gZXgpCiAgICAgICAgewogICAgICAgICAgICByZXR1cm4gVGFzay5Gcm9tUmVzdWx0KG5ldyBTY3JpcHRSZXNwb25zZQogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICBLZXkgPSAiZ3JhbmRjaGlsZC1leHRlbnNpb24taW5wdXQtZXJyb3IiLAogICAgICAgICAgICAgICAgRGF0YSA9IG5ldyB7IGVycm9yID0gZXguTWVzc2FnZSB9CiAgICAgICAgICAgIH0pOwogICAgICAgIH0KICAgIH0KCiAgICBwdWJsaWMgYXN5bmMgVGFzazxTY3JpcHRSZXNwb25zZT4gT3V0cHV0SGFuZGxlcihTY3JpcHRDb250ZXh0IGNvbnRleHQpCiAgICB7CiAgICAgICAgdHJ5CiAgICAgICAgewogICAgICAgICAgICByZXR1cm4gbmV3IFNjcmlwdFJlc3BvbnNlCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgIEtleSA9ICJncmFuZGNoaWxkLWV4dGVuc2lvbi1zdWNjZXNzIiwKICAgICAgICAgICAgICAgIERhdGEgPSBuZXcKICAgICAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICAgICBncmFuZGNoaWxkRXh0ZW5zaW9uID0gbmV3CiAgICAgICAgICAgICAgICAgICAgewogICAgICAgICAgICAgICAgICAgICAgICBleHRlbnNpb25OYW1lID0gImdyYW5kY2hpbGQtZGF0YS1leHRlbnNpb24iLAogICAgICAgICAgICAgICAgICAgICAgICBzb3VyY2UgPSAiZ3JhbmRjaGlsZC13b3JrZmxvdyIsCiAgICAgICAgICAgICAgICAgICAgICAgIG5lc3RpbmdMZXZlbCA9IDMsCiAgICAgICAgICAgICAgICAgICAgICAgIGxvYWRlZEF0ID0gRGF0ZVRpbWUuVXRjTm93LAogICAgICAgICAgICAgICAgICAgICAgICBkYXRhID0gbmV3CiAgICAgICAgICAgICAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyYW5kY2hpbGRDb25maWcgPSBuZXcKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpc1N1YmZsb3cgPSB0cnVlLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlzRGVlcE5lc3RlZCA9IHRydWUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYmxvY2tzUGFyZW50ID0gdHJ1ZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb21wbGV0aW9uUmVxdWlyZWQgPSB0cnVlCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JhbmRjaGlsZE1ldGFkYXRhID0gbmV3CiAgICAgICAgICAgICAgICAgICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgd29ya2Zsb3dUeXBlID0gImRlZXAtc3ViZmxvdyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFyZW50V29ya2Zsb3cgPSAic3ViZmxvdy12aWV3LXRlc3QtY2hpbGQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyYW5kcGFyZW50V29ya2Zsb3cgPSAic3ViZmxvdy12aWV3LXRlc3QtcGFyZW50IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBleHRlbnNpb25WZXJzaW9uID0gIjEuMC4wIgogICAgICAgICAgICAgICAgICAgICAgICAgICAgfSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhpZXJhcmNoeVBhdGggPSBuZXcKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZXZlbDEgPSAic3ViZmxvdy12aWV3LXRlc3QtcGFyZW50IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZXZlbDIgPSAic3ViZmxvdy12aWV3LXRlc3QtY2hpbGQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxldmVsMyA9ICJzdWJmbG93LXZpZXctdGVzdC1ncmFuZGNoaWxkIgogICAgICAgICAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgfSwKICAgICAgICAgICAgICAgIFRhZ3MgPSBuZXdbXSB7ICJzdWJmbG93LXRlc3QiLCAiZ3JhbmRjaGlsZC1leHRlbnNpb24iLCAibG9uZ3BvbGxpbmciLCAiZGVlcC1uZXN0ZWQiIH0KICAgICAgICAgICAgfTsKICAgICAgICB9CiAgICAgICAgY2F0Y2ggKEV4Y2VwdGlvbiBleCkKICAgICAgICB7CiAgICAgICAgICAgIHJldHVybiBuZXcgU2NyaXB0UmVzcG9uc2UKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgS2V5ID0gImdyYW5kY2hpbGQtZXh0ZW5zaW9uLWVycm9yIiwKICAgICAgICAgICAgICAgIERhdGEgPSBuZXcgeyBlcnJvciA9IGV4Lk1lc3NhZ2UgfQogICAgICAgICAgICB9OwogICAgICAgIH0KICAgIH0KfQo="
}
}
}
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

It's good practice to end JSON files with a newline character for better compatibility with various tools and version control systems.

  }
}

110 changes: 110 additions & 0 deletions core/Extensions/subflow-test/src/GrandchildDataExtensionMapping.csx
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
using System;
using System.Threading.Tasks;
using BBT.Workflow.Scripting;
using BBT.Workflow.Definitions;

/// <summary>
/// Grandchild Data Extension Mapping - Provides additional data for grandchild workflow view
/// This extension is used to test longpolling functionality for deeply nested workflow views.
/// </summary>
public class GrandchildDataExtensionMapping : IMapping
{
public Task<ScriptResponse> InputHandler(WorkflowTask task, ScriptContext context)
{
try
{
var httpTask = task as HttpTask;
if (httpTask == null)
{
throw new InvalidOperationException("Task must be an HttpTask");
}

// Prepare request body for extension data
var requestBody = new
{
extensionType = "grandchild-data-extension",
instanceId = context.Instance?.Id,
workflowKey = context.Workflow?.Key,
parentInstanceId = context.Instance?.Data?.parentInstanceId,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

In the context of a grandchild workflow, context.Instance?.Data?.parentInstanceId would refer to the child workflow's instance ID. To avoid confusion, consider renaming this field to childInstanceId or parentOfGrandchildInstanceId to clearly indicate its role in the hierarchy.

                childInstanceId = context.Instance?.Data?.parentInstanceId,

childInstanceId = context.Instance?.Data?.childInstanceId,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

If context.Instance?.Data?.childInstanceId is intended to represent the grandchild's own instance ID, it might be clearer to use context.Instance?.Id directly or rename this field to grandchildInstanceId for better readability and to prevent confusion in a deeply nested context.

                grandchildInstanceId = context.Instance?.Data?.childInstanceId,

nestingLevel = 3,
requestedAt = DateTime.UtcNow

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The field name requestedAt might be misleading as this is an extension mapping, not a direct request. Consider renaming it to generatedAt or createdAt for better semantic clarity.

                generatedAt = DateTime.UtcNow

};

httpTask.SetBody(requestBody);

// Set headers
var headers = new Dictionary<string, string?>
{
["Content-Type"] = "application/json",
["X-Extension-Type"] = "grandchild-data",
["X-Nesting-Level"] = "3",
["X-Request-Id"] = Guid.NewGuid().ToString()
};
httpTask.SetHeaders(headers);

return Task.FromResult(new ScriptResponse());
}
catch (Exception ex)
{
return Task.FromResult(new ScriptResponse
{
Key = "grandchild-extension-input-error",
Data = new { error = ex.Message }
});
}
}

public async Task<ScriptResponse> OutputHandler(ScriptContext context)
{
try
{
return new ScriptResponse
{
Key = "grandchild-extension-success",
Data = new
{
grandchildExtension = new
{
extensionName = "grandchild-data-extension",
source = "grandchild-workflow",
nestingLevel = 3,
loadedAt = DateTime.UtcNow,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Similar to requestedAt, loadedAt might be better named generatedAt or createdAt for consistency and to reflect when the data was actually produced by the extension.

                        generatedAt = DateTime.UtcNow,

data = new
{
grandchildConfig = new
{
isSubflow = true,
isDeepNested = true,
blocksParent = true,
completionRequired = true
},
grandchildMetadata = new
{
workflowType = "deep-subflow",
parentWorkflow = "subflow-view-test-child",
grandparentWorkflow = "subflow-view-test-parent",
Comment on lines +85 to +86

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Hardcoding workflow keys like "subflow-view-test-child" and "subflow-view-test-parent" can make the code less flexible and harder to maintain if workflow names change. Consider deriving these values from the context.Instance?.Data if available, or using configurable constants.

                                parentWorkflow = context.Instance?.Data?.childWorkflowId,
                                grandparentWorkflow = context.Instance?.Data?.parentWorkflowId,

extensionVersion = "1.0.0"
},
hierarchyPath = new
{
level1 = "subflow-view-test-parent",
level2 = "subflow-view-test-child",
Comment on lines +90 to +92

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Hardcoding the hierarchy path can lead to maintenance issues if workflow names change. It would be more robust to construct this path dynamically based on the workflow keys available in the context.Instance?.Data.

                                level1 = context.Instance?.Data?.parentWorkflowId,
                                level2 = context.Instance?.Data?.childWorkflowId,
                                level3 = context.Workflow?.Key

level3 = "subflow-view-test-grandchild"
}
}
}
},
Tags = new[] { "subflow-test", "grandchild-extension", "longpolling", "deep-nested" }
};
}
catch (Exception ex)
{
return new ScriptResponse
{
Key = "grandchild-extension-error",
Data = new { error = ex.Message }
};
}
}
}
22 changes: 22 additions & 0 deletions core/Tasks/subflow-test/start-busy-subprocess-task.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"key": "start-busy-subprocess-task",
"flow": "sys-tasks",
"domain": "core",
"version": "1.0.0",
"flowVersion": "1.0.0",
"tags": [
"subflow-test",
"subprocess",
"busy-state",
"trigger-task"
],
"attributes": {
"type": "11",
"config": {
"domain": "core",
"flow": "sys-flows",
"key": "busy-subprocess-workflow",
"version": "1.0.0"
}
}
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

It's good practice to end JSON files with a newline character for better compatibility with various tools and version control systems.

    }
  }
}

22 changes: 22 additions & 0 deletions core/Tasks/subflow-test/trigger-busy-completion-task.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"key": "trigger-busy-completion-task",
"flow": "sys-tasks",
"domain": "core",
"version": "1.0.0",
"flowVersion": "1.0.0",
"tags": [
"subflow-test",
"direct-trigger",
"busy-state",
"trigger-task"
],
"attributes": {
"type": "12",
"config": {
"domain": "core",
"flow": "sys-flows",
"transitionName": "complete-busy-state",
"body": {}
}
}
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

It's good practice to end JSON files with a newline character for better compatibility with various tools and version control systems.

    }
  }
}

29 changes: 29 additions & 0 deletions core/Views/subflow-test/grandchild-workflow-view.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{
"key": "grandchild-workflow-view",
"version": "1.0.0",
"domain": "core",
"flow": "sys-views",
"flowVersion": "1.0.0",
"tags": [
"subflow-test",
"grandchild-workflow",
"view",
"longpolling-test",
"deep-nested-test"
],
"attributes": {
"type": 1,
"labels": [
{
"language": "en-US",
"label": "Grandchild Workflow View"
},
{
"language": "tr-TR",
"label": "Torun Akış Görünümü"
}
],
"display": "full-page",
"content": "{\"type\":\"form\",\"title\":{\"en-US\":\"Grandchild Workflow - Active (Level 3)\",\"tr-TR\":\"Torun Akış - Aktif (Seviye 3)\"},\"description\":{\"en-US\":\"This is the grandchild (nested subflow) workflow view. This is the deepest level of the subflow hierarchy. Complete this workflow to continue the child.\",\"tr-TR\":\"Bu torun (iç içe alt akış) görünümüdür. Bu alt akış hiyerarşisinin en derin seviyesidir. Alt akışın devam etmesi için bu akışı tamamlayın.\"},\"fields\":[{\"key\":\"grandchildStatus\",\"type\":\"text\",\"label\":{\"en-US\":\"Grandchild Status\",\"tr-TR\":\"Torun Akış Durumu\"},\"readonly\":true,\"defaultValue\":\"active\"},{\"key\":\"nestingLevel\",\"type\":\"text\",\"label\":{\"en-US\":\"Nesting Level\",\"tr-TR\":\"İç İçe Seviye\"},\"readonly\":true,\"defaultValue\":\"3 (Parent > Child > Grandchild)\"},{\"key\":\"grandchildInfo\",\"type\":\"info\",\"label\":{\"en-US\":\"Grandchild Info\",\"tr-TR\":\"Torun Akış Bilgisi\"},\"content\":{\"en-US\":\"This view includes grandchild extension data for deep nested longpolling test.\",\"tr-TR\":\"Bu görünüm derin iç içe longpolling testi için torun akış extension verisini içerir.\"}}],\"buttons\":[{\"key\":\"complete\",\"label\":{\"en-US\":\"Complete Grandchild Workflow\",\"tr-TR\":\"Torun Akışı Tamamla\"},\"style\":\"success\",\"action\":\"submit\",\"transition\":\"complete-grandchild\"}]}"
}
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

It's good practice to end JSON files with a newline character for better compatibility with various tools and version control systems.

  }
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
{
"workflow": "busy-subprocess-workflow",
"version": "1.0.0",
"diagram": {
"nodes": [
{
"id": "start",
"type": "start",
"label": "Start SubProcess",
"position": { "x": 100, "y": 100 }
},
{
"id": "processing",
"type": "state",
"label": "Processing",
"stateType": "initial",
"subType": "normal",
"position": { "x": 300, "y": 100 }
},
{
"id": "trigger-parent",
"type": "state",
"label": "Trigger Parent",
"stateType": "intermediate",
"subType": "normal",
"description": "Uses DirectTriggerTask to trigger parent workflow",
"position": { "x": 500, "y": 100 }
},
{
"id": "completed",
"type": "state",
"label": "Completed",
"stateType": "final",
"subType": "success",
"position": { "x": 700, "y": 100 }
}
],
"edges": [
{
"id": "start-to-processing",
"source": "start",
"target": "processing",
"label": "start-subprocess",
"type": "start-transition"
},
{
"id": "processing-to-trigger",
"source": "processing",
"target": "trigger-parent",
"label": "complete-processing (auto)",
"type": "auto-transition",
"description": "Always true rule"
},
{
"id": "trigger-to-completed",
"source": "trigger-parent",
"target": "completed",
"label": "finish-subprocess (auto)",
"type": "auto-transition",
"description": "Always true rule"
}
]
},
"metadata": {
"description": "Busy state subprocess workflow - runs independently and triggers parent when complete",
"purpose": "Test busy state (subType: 5) behavior with subprocess trigger pattern",
"features": [
"Independent subprocess execution",
"DirectTriggerTask to trigger parent workflow",
"Automatic state transitions",
"Fire-and-forget pattern"
]
}
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

It's good practice to end JSON files with a newline character for better compatibility with various tools and version control systems.

    ]
  }
}

Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
"y": 100
},
"child-completed": {
"x": 496,
"y": 100
"x": 551.6088888888888,
"y": 96.37333333333333
},
"__start__": {
"x": -296,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"nodePos": {
"grandchild-active": {
"x": 100,
"y": 100
},
"grandchild-completed": {
"x": 670,
"y": 36
},
"__start__": {
"x": -296,
"y": 100
},
"grandchild-after-busy": {
"x": 126,
"y": -162
}
}
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

It's good practice to end JSON files with a newline character for better compatibility with various tools and version control systems.

    }
  }
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"nodePos": {
"parent-initial": {
"x": 100,
"y": 100
},
"waiting-for-subflow": {
"x": 496,
"y": 100
},
"parent-after-subflow": {
"x": 892,
"y": 100
},
"parent-completed": {
"x": 1288,
"y": 100
},
"__start__": {
"x": -296,
"y": 100
}
}
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

It's good practice to end JSON files with a newline character for better compatibility with various tools and version control systems.

    }
  }
}

Loading