ultravisor 1.0.3 → 1.0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (248) hide show
  1. package/.claude/launch.json +11 -0
  2. package/.claude/ultravisor-dev-config.json +3 -0
  3. package/card-audit.json +1545 -0
  4. package/docs/_sidebar.md +17 -0
  5. package/docs/css/docuserve.css +73 -0
  6. package/docs/features/beacon-authentication.md +209 -0
  7. package/docs/features/beacon-providers.md +1299 -0
  8. package/docs/features/beacons.md +530 -0
  9. package/docs/features/capabilities.md +193 -0
  10. package/docs/features/llm-model-setup.md +505 -0
  11. package/docs/features/llm.md +262 -0
  12. package/docs/features/tasks-content-system.md +110 -0
  13. package/docs/features/tasks-data-transform.md +233 -0
  14. package/docs/features/tasks-extension.md +36 -0
  15. package/docs/features/tasks-file-system.md +203 -0
  16. package/docs/features/tasks-flow-control.md +125 -0
  17. package/docs/features/tasks-http-client.md +119 -0
  18. package/docs/features/tasks-llm.md +118 -0
  19. package/docs/features/tasks-meadow-api.md +163 -0
  20. package/docs/features/tasks-user-interaction.md +49 -0
  21. package/docs/features/tasks.md +14 -0
  22. package/docs/index.html +1 -1
  23. package/docs/retold-catalog.json +1 -1
  24. package/docs/retold-keyword-index.json +17374 -5
  25. package/operation-library/api-data-pipeline.json +143 -0
  26. package/operation-library/beacon-remote-command.json +72 -0
  27. package/operation-library/conditional-file-backup.json +143 -0
  28. package/operation-library/config-processor.json +136 -0
  29. package/operation-library/csv-data-analysis.json +228 -0
  30. package/operation-library/csv-to-json.json +160 -0
  31. package/operation-library/directory-inventory.json +128 -0
  32. package/operation-library/expression-calculator.json +114 -0
  33. package/operation-library/file-search-replace.json +175 -0
  34. package/operation-library/git-status-report.json +368 -0
  35. package/operation-library/health-check-ping.json +329 -0
  36. package/operation-library/json-config-merge.json +313 -0
  37. package/operation-library/llm-embedding-tool-use.json +314 -0
  38. package/operation-library/llm-multi-turn-analysis.json +322 -0
  39. package/operation-library/llm-summarize.json +264 -0
  40. package/operation-library/log-line-counter.json +185 -0
  41. package/operation-library/meadow-crud-lifecycle.json +264 -0
  42. package/operation-library/npm-project-validator.json +193 -0
  43. package/operation-library/rest-api-orchestrator.json +218 -0
  44. package/operation-library/shell-system-info.json +137 -0
  45. package/operation-library/simple-echo.json +95 -0
  46. package/operation-library/template-processor.json +299 -0
  47. package/operation-library/text-sanitizer.json +176 -0
  48. package/package.json +12 -8
  49. package/source/Ultravisor.cjs +30 -3
  50. package/source/beacon/Ultravisor-Beacon-CLI.cjs +143 -0
  51. package/source/beacon/Ultravisor-Beacon-CapabilityProvider.cjs +129 -0
  52. package/source/beacon/Ultravisor-Beacon-Client.cjs +568 -0
  53. package/source/beacon/Ultravisor-Beacon-Executor.cjs +500 -0
  54. package/source/beacon/Ultravisor-Beacon-ProviderRegistry.cjs +330 -0
  55. package/source/beacon/providers/Ultravisor-Beacon-Provider-FileSystem.cjs +331 -0
  56. package/source/beacon/providers/Ultravisor-Beacon-Provider-LLM.cjs +966 -0
  57. package/source/beacon/providers/Ultravisor-Beacon-Provider-Shell.cjs +95 -0
  58. package/source/cli/Ultravisor-CLIProgram.cjs +44 -22
  59. package/source/cli/commands/Ultravisor-Command-SingleOperation.cjs +29 -18
  60. package/source/cli/commands/Ultravisor-Command-SingleTask.cjs +62 -19
  61. package/source/cli/commands/Ultravisor-Command-UpdateTask.cjs +27 -15
  62. package/source/config/Ultravisor-Default-Command-Configuration.cjs +12 -3
  63. package/source/services/Ultravisor-Beacon-Coordinator.cjs +966 -0
  64. package/source/services/Ultravisor-ExecutionEngine.cjs +1093 -0
  65. package/source/services/Ultravisor-ExecutionManifest.cjs +629 -0
  66. package/source/services/Ultravisor-Hypervisor-State.cjs +270 -97
  67. package/source/services/Ultravisor-Hypervisor.cjs +185 -75
  68. package/source/services/Ultravisor-Schedule-Persistence-Base.cjs +45 -0
  69. package/source/services/Ultravisor-StateManager.cjs +253 -0
  70. package/source/services/Ultravisor-TaskTypeRegistry.cjs +213 -0
  71. package/source/services/persistence/Ultravisor-Schedule-Persistence-JSONFile.cjs +140 -0
  72. package/source/services/tasks/Ultravisor-BuiltIn-TaskConfigs.cjs +19 -0
  73. package/source/services/tasks/Ultravisor-TaskHelper-BeaconDispatch.cjs +107 -0
  74. package/source/services/tasks/Ultravisor-TaskType-Base.cjs +125 -0
  75. package/source/services/tasks/content-system/Ultravisor-TaskConfigs-ContentSystem.cjs +90 -0
  76. package/source/services/tasks/content-system/definitions/content-create-folder.json +24 -0
  77. package/source/services/tasks/content-system/definitions/content-list-files.json +27 -0
  78. package/source/services/tasks/content-system/definitions/content-read-file.json +26 -0
  79. package/source/services/tasks/content-system/definitions/content-save-file.json +26 -0
  80. package/source/services/tasks/data-transform/Ultravisor-TaskConfigs-DataTransform.cjs +577 -0
  81. package/source/services/tasks/data-transform/Ultravisor-TaskType-ReplaceString.cjs +80 -0
  82. package/source/services/tasks/data-transform/Ultravisor-TaskType-SetValues.cjs +74 -0
  83. package/source/services/tasks/data-transform/Ultravisor-TaskType-StringAppender.cjs +90 -0
  84. package/source/services/tasks/data-transform/definitions/comprehension-intersect.json +24 -0
  85. package/source/services/tasks/data-transform/definitions/csv-transform.json +24 -0
  86. package/source/services/tasks/data-transform/definitions/expression-solver.json +20 -0
  87. package/source/services/tasks/data-transform/definitions/histogram.json +23 -0
  88. package/source/services/tasks/data-transform/definitions/parse-csv.json +27 -0
  89. package/source/services/tasks/data-transform/definitions/replace-string.json +27 -0
  90. package/source/services/tasks/data-transform/definitions/set-values.json +17 -0
  91. package/source/services/tasks/data-transform/definitions/string-appender.json +22 -0
  92. package/source/services/tasks/data-transform/definitions/template-string.json +20 -0
  93. package/source/services/tasks/extension/Ultravisor-TaskConfigs-Extension.cjs +87 -0
  94. package/source/services/tasks/extension/definitions/beacon-dispatch.json +32 -0
  95. package/source/services/tasks/file-system/Ultravisor-TaskConfigs-FileSystem.cjs +509 -0
  96. package/source/services/tasks/file-system/Ultravisor-TaskType-ReadFile.cjs +96 -0
  97. package/source/services/tasks/file-system/Ultravisor-TaskType-ReadFileBuffered.cjs +123 -0
  98. package/source/services/tasks/file-system/Ultravisor-TaskType-WriteFile.cjs +106 -0
  99. package/source/services/tasks/file-system/definitions/copy-file.json +27 -0
  100. package/source/services/tasks/file-system/definitions/list-files.json +27 -0
  101. package/source/services/tasks/file-system/definitions/read-file-buffered.json +31 -0
  102. package/source/services/tasks/file-system/definitions/read-file.json +26 -0
  103. package/source/services/tasks/file-system/definitions/read-json.json +23 -0
  104. package/source/services/tasks/file-system/definitions/write-file.json +29 -0
  105. package/source/services/tasks/file-system/definitions/write-json.json +30 -0
  106. package/source/services/tasks/flow-control/Ultravisor-TaskConfigs-FlowControl.cjs +353 -0
  107. package/source/services/tasks/flow-control/Ultravisor-TaskType-IfConditional.cjs +125 -0
  108. package/source/services/tasks/flow-control/Ultravisor-TaskType-LaunchOperation.cjs +186 -0
  109. package/source/services/tasks/flow-control/Ultravisor-TaskType-SplitExecute.cjs +164 -0
  110. package/source/services/tasks/flow-control/definitions/if-conditional.json +25 -0
  111. package/source/services/tasks/flow-control/definitions/launch-operation.json +27 -0
  112. package/source/services/tasks/flow-control/definitions/split-execute.json +32 -0
  113. package/source/services/tasks/http-client/Ultravisor-TaskConfigs-HttpClient.cjs +281 -0
  114. package/source/services/tasks/http-client/definitions/get-json.json +26 -0
  115. package/source/services/tasks/http-client/definitions/get-text.json +26 -0
  116. package/source/services/tasks/http-client/definitions/rest-request.json +32 -0
  117. package/source/services/tasks/http-client/definitions/send-json.json +28 -0
  118. package/source/services/tasks/llm/Ultravisor-TaskConfigs-LLM.cjs +605 -0
  119. package/source/services/tasks/llm/definitions/llm-chat-completion.json +46 -0
  120. package/source/services/tasks/llm/definitions/llm-embedding.json +31 -0
  121. package/source/services/tasks/llm/definitions/llm-tool-use.json +42 -0
  122. package/source/services/tasks/meadow-api/Ultravisor-TaskConfigs-MeadowApi.cjs +341 -0
  123. package/source/services/tasks/meadow-api/definitions/meadow-count.json +26 -0
  124. package/source/services/tasks/meadow-api/definitions/meadow-create.json +26 -0
  125. package/source/services/tasks/meadow-api/definitions/meadow-delete.json +23 -0
  126. package/source/services/tasks/meadow-api/definitions/meadow-read.json +26 -0
  127. package/source/services/tasks/meadow-api/definitions/meadow-reads.json +29 -0
  128. package/source/services/tasks/meadow-api/definitions/meadow-update.json +26 -0
  129. package/source/services/tasks/shell/Ultravisor-TaskConfigs-Shell.cjs +63 -0
  130. package/source/services/tasks/shell/definitions/command.json +29 -0
  131. package/source/services/tasks/user-interaction/Ultravisor-TaskConfigs-UserInteraction.cjs +64 -0
  132. package/source/services/tasks/user-interaction/Ultravisor-TaskType-ErrorMessage.cjs +55 -0
  133. package/source/services/tasks/user-interaction/Ultravisor-TaskType-ValueInput.cjs +47 -0
  134. package/source/services/tasks/user-interaction/definitions/error-message.json +18 -0
  135. package/source/services/tasks/user-interaction/definitions/value-input.json +23 -0
  136. package/source/web_server/Ultravisor-API-Server.cjs +849 -124
  137. package/test/Ultravisor_browser_tests.js +2226 -0
  138. package/test/Ultravisor_operation_library_tests.js +894 -0
  139. package/test/Ultravisor_tests.js +4946 -5044
  140. package/test/workflows/test-content-concatenate-all.json +339 -0
  141. package/test/workflows/test-content-full-pipeline.json +159 -0
  142. package/test/workflows/test-content-list-files.json +76 -0
  143. package/test/workflows/test-content-save-and-read.json +106 -0
  144. package/webinterface/css/ultravisor-themes.css +668 -0
  145. package/webinterface/css/ultravisor.css +37 -14
  146. package/webinterface/docs/card-help/beacon-dispatch.md +30 -0
  147. package/webinterface/docs/card-help/command.md +27 -0
  148. package/webinterface/docs/card-help/comprehension-intersect.md +24 -0
  149. package/webinterface/docs/card-help/content-create-folder.md +22 -0
  150. package/webinterface/docs/card-help/content-list-files.md +25 -0
  151. package/webinterface/docs/card-help/content-read-file.md +24 -0
  152. package/webinterface/docs/card-help/content-save-file.md +24 -0
  153. package/webinterface/docs/card-help/copy-file.md +25 -0
  154. package/webinterface/docs/card-help/csv-transform.md +24 -0
  155. package/webinterface/docs/card-help/end.md +11 -0
  156. package/webinterface/docs/card-help/error-message.md +16 -0
  157. package/webinterface/docs/card-help/expression-solver.md +21 -0
  158. package/webinterface/docs/card-help/get-json.md +24 -0
  159. package/webinterface/docs/card-help/get-text.md +24 -0
  160. package/webinterface/docs/card-help/histogram.md +23 -0
  161. package/webinterface/docs/card-help/if-conditional.md +23 -0
  162. package/webinterface/docs/card-help/launch-operation.md +25 -0
  163. package/webinterface/docs/card-help/list-files.md +25 -0
  164. package/webinterface/docs/card-help/llm-chat-completion.md +43 -0
  165. package/webinterface/docs/card-help/llm-embedding.md +24 -0
  166. package/webinterface/docs/card-help/llm-tool-use.md +39 -0
  167. package/webinterface/docs/card-help/meadow-count.md +24 -0
  168. package/webinterface/docs/card-help/meadow-create.md +24 -0
  169. package/webinterface/docs/card-help/meadow-delete.md +19 -0
  170. package/webinterface/docs/card-help/meadow-read.md +24 -0
  171. package/webinterface/docs/card-help/meadow-reads.md +27 -0
  172. package/webinterface/docs/card-help/meadow-update.md +24 -0
  173. package/webinterface/docs/card-help/parse-csv.md +27 -0
  174. package/webinterface/docs/card-help/read-file-buffered.md +29 -0
  175. package/webinterface/docs/card-help/read-file.md +24 -0
  176. package/webinterface/docs/card-help/read-json.md +21 -0
  177. package/webinterface/docs/card-help/replace-string.md +25 -0
  178. package/webinterface/docs/card-help/rest-request.md +30 -0
  179. package/webinterface/docs/card-help/send-json.md +26 -0
  180. package/webinterface/docs/card-help/set-values.md +16 -0
  181. package/webinterface/docs/card-help/split-execute.md +35 -0
  182. package/webinterface/docs/card-help/start.md +11 -0
  183. package/webinterface/docs/card-help/string-appender.md +22 -0
  184. package/webinterface/docs/card-help/template-string.md +21 -0
  185. package/webinterface/docs/card-help/value-input.md +24 -0
  186. package/webinterface/docs/card-help/write-file.md +27 -0
  187. package/webinterface/docs/card-help/write-json.md +28 -0
  188. package/webinterface/html/index.html +5 -0
  189. package/webinterface/package.json +13 -4
  190. package/webinterface/source/Pict-Application-Ultravisor.js +564 -70
  191. package/webinterface/source/Ultravisor-TimingUtils.js +99 -0
  192. package/webinterface/source/card-help-content.js +46 -0
  193. package/webinterface/source/cards/Ultravisor-BuiltIn-CardConfigs.js +174 -0
  194. package/webinterface/source/cards/Ultravisor-CardConfigGenerator.js +431 -0
  195. package/webinterface/source/data/ExampleFlow-CSVPipeline.js +231 -0
  196. package/webinterface/source/data/ExampleFlow-FileProcessor.js +315 -0
  197. package/webinterface/source/data/ExampleFlow-MeadowPipeline.js +328 -0
  198. package/webinterface/source/panels/Ultravisor-CardSettingsPanel.js +902 -0
  199. package/webinterface/source/providers/PictRouter-Ultravisor-Configuration.json +20 -8
  200. package/webinterface/source/views/PictView-Ultravisor-BeaconList.js +817 -0
  201. package/webinterface/source/views/PictView-Ultravisor-BottomBar.js +5 -5
  202. package/webinterface/source/views/PictView-Ultravisor-Dashboard.js +25 -25
  203. package/webinterface/source/views/PictView-Ultravisor-Documentation.js +856 -0
  204. package/webinterface/source/views/PictView-Ultravisor-FlowEditor.js +777 -0
  205. package/webinterface/source/views/PictView-Ultravisor-ManifestList.js +321 -58
  206. package/webinterface/source/views/PictView-Ultravisor-OperationEdit.js +36 -91
  207. package/webinterface/source/views/PictView-Ultravisor-OperationList.js +388 -16
  208. package/webinterface/source/views/PictView-Ultravisor-PendingInput.js +314 -0
  209. package/webinterface/source/views/PictView-Ultravisor-Schedule.js +521 -65
  210. package/webinterface/source/views/PictView-Ultravisor-TimingView.js +333 -71
  211. package/webinterface/source/views/PictView-Ultravisor-TopBar.js +257 -21
  212. package/webinterface/theme-sampler.html +645 -0
  213. package/debug/Harness.js +0 -6
  214. package/source/services/Ultravisor-Operation-Manifest.cjs +0 -160
  215. package/source/services/Ultravisor-Operation.cjs +0 -200
  216. package/source/services/Ultravisor-Task.cjs +0 -349
  217. package/source/services/events/Ultravisor-Hypervisor-Event-Solver.cjs +0 -11
  218. package/source/services/tasks/Ultravisor-Task-Base.cjs +0 -264
  219. package/source/services/tasks/Ultravisor-Task-CollectValues.cjs +0 -188
  220. package/source/services/tasks/Ultravisor-Task-Command.cjs +0 -65
  221. package/source/services/tasks/Ultravisor-Task-CommandEach.cjs +0 -190
  222. package/source/services/tasks/Ultravisor-Task-Conditional.cjs +0 -104
  223. package/source/services/tasks/Ultravisor-Task-DateWindow.cjs +0 -72
  224. package/source/services/tasks/Ultravisor-Task-GeneratePagedOperation.cjs +0 -336
  225. package/source/services/tasks/Ultravisor-Task-LaunchOperation.cjs +0 -143
  226. package/source/services/tasks/Ultravisor-Task-LaunchTask.cjs +0 -146
  227. package/source/services/tasks/Ultravisor-Task-LineMatch.cjs +0 -158
  228. package/source/services/tasks/Ultravisor-Task-Request.cjs +0 -56
  229. package/source/services/tasks/Ultravisor-Task-Solver.cjs +0 -89
  230. package/source/services/tasks/Ultravisor-Task-TemplateString.cjs +0 -93
  231. package/source/services/tasks/rest/Ultravisor-Task-GetBinary.cjs +0 -127
  232. package/source/services/tasks/rest/Ultravisor-Task-GetJSON.cjs +0 -119
  233. package/source/services/tasks/rest/Ultravisor-Task-GetText.cjs +0 -109
  234. package/source/services/tasks/rest/Ultravisor-Task-GetXML.cjs +0 -112
  235. package/source/services/tasks/rest/Ultravisor-Task-RestRequest.cjs +0 -499
  236. package/source/services/tasks/rest/Ultravisor-Task-SendJSON.cjs +0 -150
  237. package/source/services/tasks/stagingfiles/Ultravisor-Task-CopyFile.cjs +0 -110
  238. package/source/services/tasks/stagingfiles/Ultravisor-Task-ListFiles.cjs +0 -89
  239. package/source/services/tasks/stagingfiles/Ultravisor-Task-ReadBinary.cjs +0 -87
  240. package/source/services/tasks/stagingfiles/Ultravisor-Task-ReadJSON.cjs +0 -67
  241. package/source/services/tasks/stagingfiles/Ultravisor-Task-ReadText.cjs +0 -66
  242. package/source/services/tasks/stagingfiles/Ultravisor-Task-ReadXML.cjs +0 -69
  243. package/source/services/tasks/stagingfiles/Ultravisor-Task-WriteBinary.cjs +0 -95
  244. package/source/services/tasks/stagingfiles/Ultravisor-Task-WriteJSON.cjs +0 -96
  245. package/source/services/tasks/stagingfiles/Ultravisor-Task-WriteText.cjs +0 -99
  246. package/source/services/tasks/stagingfiles/Ultravisor-Task-WriteXML.cjs +0 -102
  247. package/webinterface/source/views/PictView-Ultravisor-TaskEdit.js +0 -220
  248. package/webinterface/source/views/PictView-Ultravisor-TaskList.js +0 -248
@@ -0,0 +1,431 @@
1
+ /**
2
+ * Ultravisor Card Config Generator
3
+ *
4
+ * Converts a task type Definition object into a PictFlowCard config object.
5
+ * This allows any task type — built-in or user-defined — to automatically
6
+ * produce a matching flow card without writing a class file.
7
+ *
8
+ * Usage:
9
+ * const generateCardConfig = require('./Ultravisor-CardConfigGenerator.js');
10
+ * let cardConfig = generateCardConfig(taskDefinition, { Width: 220 });
11
+ * // cardConfig can be passed directly to `new PictFlowCard(fable, cardConfig)`
12
+ */
13
+
14
+ // ── Category color palette ────────────────────────────────────────────
15
+ // Maps lowercase category names to title bar / body style colors.
16
+ // Matches the palette established by the existing hand-crafted card files.
17
+ const _CategoryColors =
18
+ {
19
+ 'flow control': { TitleBarColor: '#78909c', BodyStyle: { fill: '#eceff1', stroke: '#78909c' } },
20
+ 'core': { TitleBarColor: '#ab47bc', BodyStyle: { fill: '#f3e5f5', stroke: '#ab47bc' } },
21
+ 'control': { TitleBarColor: '#ab47bc', BodyStyle: { fill: '#f3e5f5', stroke: '#ab47bc' } },
22
+ 'interaction': { TitleBarColor: '#ef5350', BodyStyle: { fill: '#ffebee', stroke: '#ef5350' } },
23
+ 'data': { TitleBarColor: '#ff9800', BodyStyle: { fill: '#fff3e0', stroke: '#ff9800' } },
24
+ 'file i/o': { TitleBarColor: '#42a5f5', BodyStyle: { fill: '#eaf2f8', stroke: '#42a5f5' } },
25
+ 'file-io': { TitleBarColor: '#42a5f5', BodyStyle: { fill: '#eaf2f8', stroke: '#42a5f5' } },
26
+ 'rest': { TitleBarColor: '#29b6f6', BodyStyle: { fill: '#e1f5fe', stroke: '#29b6f6' } },
27
+ 'meadow': { TitleBarColor: '#66bb6a', BodyStyle: { fill: '#e8f5e9', stroke: '#66bb6a' } },
28
+ 'pipeline': { TitleBarColor: '#ec407a', BodyStyle: { fill: '#fce4ec', stroke: '#ec407a' } },
29
+ 'llm': { TitleBarColor: '#26a69a', BodyStyle: { fill: '#e0f7fa', stroke: '#26a69a' } },
30
+ 'extension': { TitleBarColor: '#9c6afe', BodyStyle: { fill: '#ede9fe', stroke: '#9c6afe' } },
31
+ 'content-system': { TitleBarColor: '#42a5f5', BodyStyle: { fill: '#e3f2fd', stroke: '#42a5f5' } }
32
+ };
33
+
34
+ // ── Capability color palette ─────────────────────────────────────────
35
+ // Maps lowercase Capability names to colors. Used as a fallback when
36
+ // Category does not have a specific color (e.g. for future task types).
37
+ const _CapabilityColors =
38
+ {
39
+ 'flow control': { TitleBarColor: '#78909c', BodyStyle: { fill: '#eceff1', stroke: '#78909c' } },
40
+ 'data transform': { TitleBarColor: '#ff9800', BodyStyle: { fill: '#fff3e0', stroke: '#ff9800' } },
41
+ 'file system': { TitleBarColor: '#42a5f5', BodyStyle: { fill: '#eaf2f8', stroke: '#42a5f5' } },
42
+ 'shell': { TitleBarColor: '#ab47bc', BodyStyle: { fill: '#f3e5f5', stroke: '#ab47bc' } },
43
+ 'http client': { TitleBarColor: '#29b6f6', BodyStyle: { fill: '#e1f5fe', stroke: '#29b6f6' } },
44
+ 'meadow api': { TitleBarColor: '#66bb6a', BodyStyle: { fill: '#e8f5e9', stroke: '#66bb6a' } },
45
+ 'user interaction': { TitleBarColor: '#ef5350', BodyStyle: { fill: '#ffebee', stroke: '#ef5350' } },
46
+ 'llm': { TitleBarColor: '#26a69a', BodyStyle: { fill: '#e0f7fa', stroke: '#26a69a' } },
47
+ 'extension': { TitleBarColor: '#9c6afe', BodyStyle: { fill: '#ede9fe', stroke: '#9c6afe' } },
48
+ 'contentsystem': { TitleBarColor: '#42a5f5', BodyStyle: { fill: '#e3f2fd', stroke: '#42a5f5' } }
49
+ };
50
+
51
+ // Default colors for unknown categories
52
+ const _DefaultColors =
53
+ {
54
+ TitleBarColor: '#37474f',
55
+ BodyStyle: { fill: '#eceff1', stroke: '#37474f' }
56
+ };
57
+
58
+ // ── DataType → PictForm InputType mapping ─────────────────────────────
59
+ const _DataTypeInputMap =
60
+ {
61
+ 'String': 'Text',
62
+ 'Number': 'Text',
63
+ 'Boolean': 'Option',
64
+ 'Array': 'TextArea',
65
+ 'Object': 'TextArea'
66
+ };
67
+
68
+
69
+ // ── Helpers ───────────────────────────────────────────────────────────
70
+
71
+ /**
72
+ * Capitalize the first letter of each word in a category string.
73
+ */
74
+ function _titleCase(pString)
75
+ {
76
+ if (!pString || typeof(pString) !== 'string')
77
+ {
78
+ return 'General';
79
+ }
80
+ return pString.replace(/\b\w/g, function (pChar) { return pChar.toUpperCase(); });
81
+ }
82
+
83
+ /**
84
+ * Get colors for a category (case-insensitive lookup).
85
+ */
86
+ function _getColorsForCategory(pCategory)
87
+ {
88
+ if (!pCategory || typeof(pCategory) !== 'string')
89
+ {
90
+ return _DefaultColors;
91
+ }
92
+
93
+ let tmpKey = pCategory.toLowerCase().trim();
94
+
95
+ if (_CategoryColors[tmpKey])
96
+ {
97
+ return _CategoryColors[tmpKey];
98
+ }
99
+
100
+ return _DefaultColors;
101
+ }
102
+
103
+ // ── Zone geometry lookup tables (mirrors PictProvider-Flow-Geometry) ──
104
+ const _SideToEdge =
105
+ {
106
+ 'left-top': 'left', 'left': 'left', 'left-bottom': 'left',
107
+ 'right-top': 'right', 'right': 'right', 'right-bottom': 'right',
108
+ 'top-left': 'top', 'top': 'top', 'top-right': 'top',
109
+ 'bottom-left': 'bottom', 'bottom': 'bottom', 'bottom-right': 'bottom'
110
+ };
111
+
112
+ /**
113
+ * Calculate card dimensions from port arrays.
114
+ *
115
+ * Uses the same adaptive zone sizing as PictProvider-Flow-Geometry:
116
+ * sums the space needed by all occupied zones on each left/right edge.
117
+ * This produces compact cards whose height scales linearly with total
118
+ * port count rather than being inflated by fixed 1/3 zone fractions.
119
+ *
120
+ * @param {Array} pInputs - Input port objects with Side, Direction
121
+ * @param {Array} pOutputs - Output port objects with Side, Direction
122
+ * @returns {{Width: number, Height: number}}
123
+ */
124
+ function _calculateDimensions(pInputs, pOutputs)
125
+ {
126
+ let tmpTitleBarHeight = 22;
127
+ let tmpMinSpacing = 16;
128
+ let tmpBottomPad = 16;
129
+ let tmpWidth = 180;
130
+ let tmpHeight = 80;
131
+
132
+ let tmpAllPorts = (pInputs || []).concat(pOutputs || []);
133
+
134
+ // Count ports per zone
135
+ let tmpCountBySide = {};
136
+ for (let i = 0; i < tmpAllPorts.length; i++)
137
+ {
138
+ let tmpSide = tmpAllPorts[i].Side || (tmpAllPorts[i].Direction === 'input' ? 'left' : 'right');
139
+ if (!tmpCountBySide[tmpSide])
140
+ {
141
+ tmpCountBySide[tmpSide] = 0;
142
+ }
143
+ tmpCountBySide[tmpSide]++;
144
+ }
145
+
146
+ // Sum space needed per edge across all zones.
147
+ // Each zone needs minSpacing * (count + 1) pixels.
148
+ let tmpSpacePerEdge = {};
149
+ for (let tmpSide in tmpCountBySide)
150
+ {
151
+ let tmpCount = tmpCountBySide[tmpSide];
152
+ let tmpEdge = _SideToEdge[tmpSide] || 'right';
153
+
154
+ if (tmpEdge !== 'left' && tmpEdge !== 'right')
155
+ {
156
+ continue;
157
+ }
158
+
159
+ let tmpZoneSpace = tmpMinSpacing * (tmpCount + 1);
160
+
161
+ if (!tmpSpacePerEdge[tmpEdge])
162
+ {
163
+ tmpSpacePerEdge[tmpEdge] = 0;
164
+ }
165
+ tmpSpacePerEdge[tmpEdge] += tmpZoneSpace;
166
+ }
167
+
168
+ // Height = titleBar + bottomPad + max edge space
169
+ for (let tmpEdge in tmpSpacePerEdge)
170
+ {
171
+ let tmpRequired = tmpTitleBarHeight + tmpBottomPad + tmpSpacePerEdge[tmpEdge];
172
+ tmpHeight = Math.max(tmpHeight, Math.ceil(tmpRequired));
173
+ }
174
+
175
+ // Adjust width for many ports
176
+ let tmpMaxPorts = Math.max((pInputs || []).length, (pOutputs || []).length);
177
+ if (tmpMaxPorts >= 4)
178
+ {
179
+ tmpWidth = Math.max(tmpWidth, 220);
180
+ }
181
+ else if (tmpMaxPorts >= 3)
182
+ {
183
+ tmpWidth = Math.max(tmpWidth, 200);
184
+ }
185
+
186
+ return { Width: tmpWidth, Height: tmpHeight };
187
+ }
188
+
189
+ /**
190
+ * Build a PropertiesPanel configuration from SettingsInputs.
191
+ *
192
+ * Uses the UltravisorSettings panel type which provides per-field
193
+ * mode toggles (Constant / Address / Default) and type-appropriate
194
+ * editors driven by the task definition schema.
195
+ */
196
+ function _buildPropertiesPanel(pDefinition)
197
+ {
198
+ let tmpSettings = pDefinition.SettingsInputs;
199
+
200
+ if (!Array.isArray(tmpSettings) || tmpSettings.length === 0)
201
+ {
202
+ return null;
203
+ }
204
+
205
+ let tmpDefaults = pDefinition.DefaultSettings || {};
206
+
207
+ // Account for mode-toggle fields (slightly taller per row) plus port summary sections below
208
+ let tmpPortSummaryHeight = 0;
209
+ if (Array.isArray(pDefinition.EventInputs) && pDefinition.EventInputs.length > 0)
210
+ {
211
+ tmpPortSummaryHeight += 30 + (pDefinition.EventInputs.length * 20);
212
+ }
213
+ if (Array.isArray(pDefinition.EventOutputs) && pDefinition.EventOutputs.length > 0)
214
+ {
215
+ tmpPortSummaryHeight += 30 + (pDefinition.EventOutputs.length * 20);
216
+ }
217
+ if (Array.isArray(pDefinition.StateOutputs) && pDefinition.StateOutputs.length > 0)
218
+ {
219
+ tmpPortSummaryHeight += 30 + (pDefinition.StateOutputs.length * 20);
220
+ }
221
+ let tmpPanelHeight = 160 + (tmpSettings.length * 65) + tmpPortSummaryHeight;
222
+
223
+ return {
224
+ PanelType: 'UltravisorSettings',
225
+ DefaultWidth: 380,
226
+ DefaultHeight: Math.min(tmpPanelHeight, 550),
227
+ Title: (pDefinition.Name || pDefinition.Hash) + ' Settings',
228
+ Configuration:
229
+ {
230
+ Schema: tmpSettings,
231
+ Defaults: tmpDefaults
232
+ }
233
+ };
234
+ }
235
+
236
+
237
+ // ═══════════════════════════════════════════════════════════════════════
238
+ // MAIN GENERATOR FUNCTION
239
+ // ═══════════════════════════════════════════════════════════════════════
240
+
241
+ /**
242
+ * Generate a PictFlowCard config object from a task type Definition.
243
+ *
244
+ * The returned object can be passed directly to `new PictFlowCard(fable, config)`
245
+ * to create a card instance ready for the flow editor palette.
246
+ *
247
+ * @param {object} pTaskDefinition - Task type definition with Hash, Name,
248
+ * Description, Category, EventInputs, EventOutputs, SettingsInputs,
249
+ * StateOutputs, DefaultSettings.
250
+ * @param {object} [pOverrides] - Optional overrides merged on top of the
251
+ * generated config. Use for custom colors, sizes, port adjustments, etc.
252
+ * @returns {object|null} PictFlowCard constructor options, or null on failure.
253
+ */
254
+ function generateCardConfigFromTaskDefinition(pTaskDefinition, pOverrides)
255
+ {
256
+ if (!pTaskDefinition || !pTaskDefinition.Hash)
257
+ {
258
+ return null;
259
+ }
260
+
261
+ let tmpDef = pTaskDefinition;
262
+ let tmpCategory = tmpDef.Category || 'general';
263
+ let tmpColors = _getColorsForCategory(tmpCategory);
264
+
265
+ // Fallback to Capability-based colors when Category has no specific color
266
+ if (tmpColors === _DefaultColors && tmpDef.Capability)
267
+ {
268
+ let tmpCapKey = tmpDef.Capability.toLowerCase().trim();
269
+ if (_CapabilityColors[tmpCapKey])
270
+ {
271
+ tmpColors = _CapabilityColors[tmpCapKey];
272
+ }
273
+ }
274
+
275
+ // ── Build input ports ──────────────────────────────────────────
276
+ let tmpInputs = [];
277
+
278
+ // Event inputs → left-bottom, event-in
279
+ if (Array.isArray(tmpDef.EventInputs))
280
+ {
281
+ for (let i = 0; i < tmpDef.EventInputs.length; i++)
282
+ {
283
+ tmpInputs.push(
284
+ {
285
+ Name: tmpDef.EventInputs[i].Name,
286
+ Side: 'left-bottom',
287
+ PortType: 'event-in',
288
+ MinimumInputCount: 0,
289
+ MaximumInputCount: 1
290
+ });
291
+ }
292
+ }
293
+
294
+ // Settings inputs → left-top, setting
295
+ if (Array.isArray(tmpDef.SettingsInputs))
296
+ {
297
+ for (let i = 0; i < tmpDef.SettingsInputs.length; i++)
298
+ {
299
+ tmpInputs.push(
300
+ {
301
+ Name: tmpDef.SettingsInputs[i].Name,
302
+ Side: 'left-top',
303
+ PortType: 'setting',
304
+ MinimumInputCount: 0,
305
+ MaximumInputCount: 1
306
+ });
307
+ }
308
+ }
309
+
310
+ // ── Build output ports ─────────────────────────────────────────
311
+ let tmpOutputs = [];
312
+
313
+ // Event outputs → right-bottom for normal, bottom for errors
314
+ if (Array.isArray(tmpDef.EventOutputs))
315
+ {
316
+ for (let i = 0; i < tmpDef.EventOutputs.length; i++)
317
+ {
318
+ let tmpEvt = tmpDef.EventOutputs[i];
319
+
320
+ if (tmpEvt.IsError)
321
+ {
322
+ tmpOutputs.push(
323
+ {
324
+ Name: tmpEvt.Name,
325
+ Side: 'bottom',
326
+ PortType: 'error'
327
+ });
328
+ }
329
+ else
330
+ {
331
+ tmpOutputs.push(
332
+ {
333
+ Name: tmpEvt.Name,
334
+ Side: 'right-bottom',
335
+ PortType: 'event-out'
336
+ });
337
+ }
338
+ }
339
+ }
340
+
341
+ // State outputs → right-top, value
342
+ if (Array.isArray(tmpDef.StateOutputs))
343
+ {
344
+ for (let i = 0; i < tmpDef.StateOutputs.length; i++)
345
+ {
346
+ let tmpStateOut =
347
+ {
348
+ Name: tmpDef.StateOutputs[i].Name,
349
+ Side: 'right-top',
350
+ PortType: 'value'
351
+ };
352
+ if (tmpDef.StateOutputs[i].DataType)
353
+ {
354
+ tmpStateOut.DataType = tmpDef.StateOutputs[i].DataType;
355
+ }
356
+ tmpOutputs.push(tmpStateOut);
357
+ }
358
+ }
359
+
360
+ // ── Calculate dimensions ───────────────────────────────────────
361
+ let tmpDimensions = _calculateDimensions(tmpInputs, tmpOutputs);
362
+
363
+ // ── Build PropertiesPanel ──────────────────────────────────────
364
+ let tmpPropertiesPanel = _buildPropertiesPanel(tmpDef);
365
+
366
+ // ── Assemble the card config ───────────────────────────────────
367
+ let tmpConfig =
368
+ {
369
+ Title: tmpDef.Name || tmpDef.Hash,
370
+ Code: tmpDef.Hash,
371
+ Description: tmpDef.Description || '',
372
+ Category: _titleCase(tmpCategory),
373
+ TitleBarColor: tmpColors.TitleBarColor,
374
+ BodyStyle: { fill: tmpColors.BodyStyle.fill, stroke: tmpColors.BodyStyle.stroke },
375
+ Width: tmpDimensions.Width,
376
+ Height: tmpDimensions.Height,
377
+ Inputs: tmpInputs,
378
+ Outputs: tmpOutputs
379
+ };
380
+
381
+ if (tmpPropertiesPanel)
382
+ {
383
+ tmpConfig.PropertiesPanel = tmpPropertiesPanel;
384
+ }
385
+
386
+ // ── Apply overrides ────────────────────────────────────────────
387
+ if (pOverrides && typeof(pOverrides) === 'object')
388
+ {
389
+ let tmpKeys = Object.keys(pOverrides);
390
+
391
+ for (let i = 0; i < tmpKeys.length; i++)
392
+ {
393
+ let tmpKey = tmpKeys[i];
394
+
395
+ // Deep merge for known objects; shallow replace for everything else
396
+ if (tmpKey === 'BodyStyle' && typeof(pOverrides.BodyStyle) === 'object')
397
+ {
398
+ tmpConfig.BodyStyle = Object.assign({}, tmpConfig.BodyStyle, pOverrides.BodyStyle);
399
+ }
400
+ else if (tmpKey === 'PropertiesPanel' && typeof(pOverrides.PropertiesPanel) === 'object')
401
+ {
402
+ if (tmpConfig.PropertiesPanel)
403
+ {
404
+ tmpConfig.PropertiesPanel = Object.assign({}, tmpConfig.PropertiesPanel, pOverrides.PropertiesPanel);
405
+ }
406
+ else
407
+ {
408
+ tmpConfig.PropertiesPanel = pOverrides.PropertiesPanel;
409
+ }
410
+ }
411
+ else
412
+ {
413
+ tmpConfig[tmpKey] = pOverrides[tmpKey];
414
+ }
415
+ }
416
+ }
417
+
418
+ // ── Ensure dimensions accommodate final port layout ───────────
419
+ // Overrides may have replaced Inputs/Outputs, so recompute the
420
+ // minimum dimensions and grow if needed (never shrink).
421
+ let tmpFinalDimensions = _calculateDimensions(tmpConfig.Inputs, tmpConfig.Outputs);
422
+ tmpConfig.Width = Math.max(tmpConfig.Width || 180, tmpFinalDimensions.Width);
423
+ tmpConfig.Height = Math.max(tmpConfig.Height || 80, tmpFinalDimensions.Height);
424
+
425
+ return tmpConfig;
426
+ }
427
+
428
+ module.exports = generateCardConfigFromTaskDefinition;
429
+ module.exports.CategoryColors = _CategoryColors;
430
+ module.exports.CapabilityColors = _CapabilityColors;
431
+ module.exports.DefaultColors = _DefaultColors;
@@ -0,0 +1,231 @@
1
+ /**
2
+ * Example Flow: Config File Processor
3
+ *
4
+ * Demonstrates a file-based config processing pipeline using the new engine task types:
5
+ * Start -> Read File (config template) -> If Conditional (has placeholder?)
6
+ * -> True: Replace String (fill in value) -> Write File (output config) -> End
7
+ * -> False: Error Message (missing placeholder) -> End
8
+ *
9
+ * Shows branching, error handling, and file I/O with the event-driven execution engine.
10
+ */
11
+ module.exports =
12
+ {
13
+ Nodes:
14
+ [
15
+ // ── Entry ────────────────────────────────────────────────
16
+ {
17
+ Hash: 'cfg-start',
18
+ Type: 'start',
19
+ X: 50,
20
+ Y: 200,
21
+ Width: 140,
22
+ Height: 80,
23
+ Title: 'Start',
24
+ Ports:
25
+ [
26
+ { Hash: 'cfg-start-out', Direction: 'output', Side: 'right', Label: 'Out' }
27
+ ],
28
+ Data: {}
29
+ },
30
+ // ── Read the config template ─────────────────────────────
31
+ {
32
+ Hash: 'cfg-read',
33
+ Type: 'read-file',
34
+ X: 270,
35
+ Y: 180,
36
+ Width: 200,
37
+ Height: 80,
38
+ Title: 'Read Config Template',
39
+ Ports:
40
+ [
41
+ { Hash: 'cfg-read-in', Direction: 'input', Side: 'left', Label: 'BeginRead' },
42
+ { Hash: 'cfg-read-done', Direction: 'output', Side: 'right', Label: 'ReadComplete' },
43
+ { Hash: 'cfg-read-err', Direction: 'output', Side: 'bottom', Label: 'Error' }
44
+ ],
45
+ Data: { FilePath: 'config.template.json', Encoding: 'utf8' }
46
+ },
47
+ // ── Check if placeholder exists in the content ───────────
48
+ {
49
+ Hash: 'cfg-check',
50
+ Type: 'if-conditional',
51
+ X: 550,
52
+ Y: 160,
53
+ Width: 220,
54
+ Height: 100,
55
+ Title: 'Has Placeholder?',
56
+ Ports:
57
+ [
58
+ { Hash: 'cfg-check-in', Direction: 'input', Side: 'left', Label: 'Evaluate' },
59
+ { Hash: 'cfg-check-true', Direction: 'output', Side: 'right', Label: 'True' },
60
+ { Hash: 'cfg-check-false', Direction: 'output', Side: 'bottom', Label: 'False' }
61
+ ],
62
+ Data: { DataAddress: 'TaskOutput.cfg-read.FileContent', CompareValue: '{{API_KEY}}', Operator: 'contains' }
63
+ },
64
+ // ── Replace the placeholder with the real value ──────────
65
+ {
66
+ Hash: 'cfg-replace',
67
+ Type: 'replace-string',
68
+ X: 850,
69
+ Y: 140,
70
+ Width: 220,
71
+ Height: 80,
72
+ Title: 'Fill In API Key',
73
+ Ports:
74
+ [
75
+ { Hash: 'cfg-replace-in', Direction: 'input', Side: 'left', Label: 'Replace' },
76
+ { Hash: 'cfg-replace-done', Direction: 'output', Side: 'right', Label: 'ReplaceComplete' },
77
+ { Hash: 'cfg-replace-err', Direction: 'output', Side: 'bottom', Label: 'Error' }
78
+ ],
79
+ Data: { InputString: '{~D:Record.TaskOutput.cfg-read.FileContent~}', SearchString: '{{API_KEY}}', ReplaceString: 'sk-live-abc123def456' }
80
+ },
81
+ // ── Write the processed config ──────────────────────────
82
+ {
83
+ Hash: 'cfg-write',
84
+ Type: 'write-file',
85
+ X: 1150,
86
+ Y: 140,
87
+ Width: 200,
88
+ Height: 80,
89
+ Title: 'Write Config',
90
+ Ports:
91
+ [
92
+ { Hash: 'cfg-write-in', Direction: 'input', Side: 'left', Label: 'BeginWrite' },
93
+ { Hash: 'cfg-write-done', Direction: 'output', Side: 'right', Label: 'WriteComplete' },
94
+ { Hash: 'cfg-write-err', Direction: 'output', Side: 'bottom', Label: 'Error' }
95
+ ],
96
+ Data: { FilePath: 'config.json', Content: '{~D:Record.TaskOutput.cfg-replace.ReplacedString~}', Encoding: 'utf8' }
97
+ },
98
+ // ── Error: placeholder not found ─────────────────────────
99
+ {
100
+ Hash: 'cfg-error',
101
+ Type: 'error-message',
102
+ X: 850,
103
+ Y: 340,
104
+ Width: 220,
105
+ Height: 80,
106
+ Title: 'Missing Placeholder',
107
+ Ports:
108
+ [
109
+ { Hash: 'cfg-error-in', Direction: 'input', Side: 'left', Label: 'Trigger' },
110
+ { Hash: 'cfg-error-done', Direction: 'output', Side: 'right', Label: 'Complete' }
111
+ ],
112
+ Data: { MessageTemplate: 'Config template does not contain the {{API_KEY}} placeholder' }
113
+ },
114
+ // ── Exit ─────────────────────────────────────────────────
115
+ {
116
+ Hash: 'cfg-end',
117
+ Type: 'end',
118
+ X: 1430,
119
+ Y: 220,
120
+ Width: 140,
121
+ Height: 80,
122
+ Title: 'End',
123
+ Ports:
124
+ [
125
+ { Hash: 'cfg-end-in', Direction: 'input', Side: 'left', Label: 'In' }
126
+ ],
127
+ Data: {}
128
+ }
129
+ ],
130
+ Connections:
131
+ [
132
+ // Start -> Read Config Template
133
+ {
134
+ Hash: 'cfg-c1',
135
+ SourceNodeHash: 'cfg-start',
136
+ SourcePortHash: 'cfg-start-out',
137
+ TargetNodeHash: 'cfg-read',
138
+ TargetPortHash: 'cfg-read-in',
139
+ Data: {}
140
+ },
141
+ // Read Config Template -> Has Placeholder?
142
+ {
143
+ Hash: 'cfg-c2',
144
+ SourceNodeHash: 'cfg-read',
145
+ SourcePortHash: 'cfg-read-done',
146
+ TargetNodeHash: 'cfg-check',
147
+ TargetPortHash: 'cfg-check-in',
148
+ Data: {}
149
+ },
150
+ // Has Placeholder? (True) -> Fill In API Key
151
+ {
152
+ Hash: 'cfg-c3',
153
+ SourceNodeHash: 'cfg-check',
154
+ SourcePortHash: 'cfg-check-true',
155
+ TargetNodeHash: 'cfg-replace',
156
+ TargetPortHash: 'cfg-replace-in',
157
+ Data: {}
158
+ },
159
+ // Fill In API Key -> Write Config
160
+ {
161
+ Hash: 'cfg-c4',
162
+ SourceNodeHash: 'cfg-replace',
163
+ SourcePortHash: 'cfg-replace-done',
164
+ TargetNodeHash: 'cfg-write',
165
+ TargetPortHash: 'cfg-write-in',
166
+ Data: {}
167
+ },
168
+ // Write Config -> End
169
+ {
170
+ Hash: 'cfg-c5',
171
+ SourceNodeHash: 'cfg-write',
172
+ SourcePortHash: 'cfg-write-done',
173
+ TargetNodeHash: 'cfg-end',
174
+ TargetPortHash: 'cfg-end-in',
175
+ Data: {}
176
+ },
177
+ // Has Placeholder? (False) -> Missing Placeholder
178
+ {
179
+ Hash: 'cfg-c6',
180
+ SourceNodeHash: 'cfg-check',
181
+ SourcePortHash: 'cfg-check-false',
182
+ TargetNodeHash: 'cfg-error',
183
+ TargetPortHash: 'cfg-error-in',
184
+ Data: {}
185
+ },
186
+ // Missing Placeholder -> End
187
+ {
188
+ Hash: 'cfg-c7',
189
+ SourceNodeHash: 'cfg-error',
190
+ SourcePortHash: 'cfg-error-done',
191
+ TargetNodeHash: 'cfg-end',
192
+ TargetPortHash: 'cfg-end-in',
193
+ Data: {}
194
+ },
195
+ // Read Config Template error -> End
196
+ {
197
+ Hash: 'cfg-c8',
198
+ SourceNodeHash: 'cfg-read',
199
+ SourcePortHash: 'cfg-read-err',
200
+ TargetNodeHash: 'cfg-end',
201
+ TargetPortHash: 'cfg-end-in',
202
+ Data: {}
203
+ },
204
+ // Fill In API Key error -> End
205
+ {
206
+ Hash: 'cfg-c9',
207
+ SourceNodeHash: 'cfg-replace',
208
+ SourcePortHash: 'cfg-replace-err',
209
+ TargetNodeHash: 'cfg-end',
210
+ TargetPortHash: 'cfg-end-in',
211
+ Data: {}
212
+ },
213
+ // Write Config error -> End
214
+ {
215
+ Hash: 'cfg-c10',
216
+ SourceNodeHash: 'cfg-write',
217
+ SourcePortHash: 'cfg-write-err',
218
+ TargetNodeHash: 'cfg-end',
219
+ TargetPortHash: 'cfg-end-in',
220
+ Data: {}
221
+ }
222
+ ],
223
+ ViewState:
224
+ {
225
+ PanX: 0,
226
+ PanY: 0,
227
+ Zoom: 1,
228
+ SelectedNodeHash: null,
229
+ SelectedConnectionHash: null
230
+ }
231
+ };