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,902 @@
1
+ const libPictFlowCardPropertiesPanel = require('pict-section-flow/source/PictFlowCardPropertiesPanel.js');
2
+
3
+ /**
4
+ * Ultravisor Card Settings Panel
5
+ *
6
+ * A custom properties panel for Ultravisor flow cards that provides
7
+ * per-field mode toggles: Constant, Address, or Default.
8
+ *
9
+ * - Constant: a literal value edited with a type-appropriate input
10
+ * - Address: a Manyfest address expression resolved at execution time
11
+ * - Default: use the task type's default value (field omitted from Data)
12
+ *
13
+ * Each field has a single toggle button to the left of the input that
14
+ * cycles through modes on click. Values are remembered per-mode so
15
+ * switching away and back restores what was there before.
16
+ *
17
+ * The panel reads the task definition schema (SettingsInputs + DefaultSettings)
18
+ * from the panel Configuration, and stores mode metadata in the node's
19
+ * Data._FieldModes object alongside the actual field values.
20
+ *
21
+ * Panel type identifier: 'UltravisorSettings'
22
+ * Service type: 'PictFlowCardPropertiesPanel-UltravisorSettings'
23
+ */
24
+
25
+ // Mode cycle order
26
+ const _ModeCycle = ['constant', 'address', 'default'];
27
+
28
+ // Mode display labels (shown in italic on the toggle button)
29
+ const _ModeLabels =
30
+ {
31
+ 'constant': 'C',
32
+ 'address': 'A',
33
+ 'default': 'D'
34
+ };
35
+
36
+ // Mode tooltip text
37
+ const _ModeTitles =
38
+ {
39
+ 'constant': 'Constant',
40
+ 'address': 'Address',
41
+ 'default': 'Default'
42
+ };
43
+
44
+
45
+ class UltravisorCardSettingsPanel extends libPictFlowCardPropertiesPanel
46
+ {
47
+ constructor(pFable, pOptions, pServiceHash)
48
+ {
49
+ super(pFable, pOptions, pServiceHash);
50
+
51
+ this.serviceType = 'PictFlowCardPropertiesPanel-UltravisorSettings';
52
+
53
+ // Schema from the task definition
54
+ this._Schema = (this._Configuration && Array.isArray(this._Configuration.Schema))
55
+ ? this._Configuration.Schema
56
+ : [];
57
+ this._Defaults = (this._Configuration && typeof(this._Configuration.Defaults) === 'object')
58
+ ? this._Configuration.Defaults
59
+ : {};
60
+
61
+ // Per-field state: { fieldName: { mode, constantValue, addressValue, dataType, defaultValue } }
62
+ this._FieldStates = {};
63
+
64
+ // Track whether CSS has been injected
65
+ this._CSSInjected = false;
66
+ }
67
+
68
+ // ====================================================================
69
+ // Render
70
+ // ====================================================================
71
+
72
+ /**
73
+ * Render the settings panel into the provided container.
74
+ *
75
+ * @param {HTMLElement} pContainer - The DOM element to render into
76
+ * @param {Object} pNodeData - The node data object (has .Data property)
77
+ */
78
+ render(pContainer, pNodeData)
79
+ {
80
+ super.render(pContainer, pNodeData);
81
+
82
+ this._injectCSS();
83
+ this._initializeFieldStates(pNodeData);
84
+
85
+ let tmpHTML = '<div class="uv-settings-panel">';
86
+
87
+ for (let i = 0; i < this._Schema.length; i++)
88
+ {
89
+ let tmpSetting = this._Schema[i];
90
+ let tmpFieldName = tmpSetting.Name;
91
+ let tmpState = this._FieldStates[tmpFieldName];
92
+
93
+ if (!tmpState)
94
+ {
95
+ continue;
96
+ }
97
+
98
+ tmpHTML += this._renderField(tmpSetting, tmpState);
99
+ }
100
+
101
+ tmpHTML += '</div>';
102
+ pContainer.innerHTML = tmpHTML;
103
+
104
+ this._wireEventListeners(pContainer);
105
+ }
106
+
107
+ // ====================================================================
108
+ // Field State Initialization
109
+ // ====================================================================
110
+
111
+ /**
112
+ * Initialize _FieldStates from the node's Data and _FieldModes.
113
+ *
114
+ * Each field stores separate constantValue and addressValue so that
115
+ * switching modes preserves what was entered in each.
116
+ *
117
+ * Backward compatibility: when _FieldModes is absent, infer modes:
118
+ * - string value containing '{~' → address
119
+ * - value present → constant
120
+ * - value absent → default
121
+ *
122
+ * @param {Object} pNodeData
123
+ */
124
+ _initializeFieldStates(pNodeData)
125
+ {
126
+ this._FieldStates = {};
127
+
128
+ let tmpData = (pNodeData && pNodeData.Data && typeof(pNodeData.Data) === 'object')
129
+ ? pNodeData.Data
130
+ : {};
131
+ let tmpFieldModes = (tmpData._FieldModes && typeof(tmpData._FieldModes) === 'object')
132
+ ? tmpData._FieldModes
133
+ : null;
134
+
135
+ for (let i = 0; i < this._Schema.length; i++)
136
+ {
137
+ let tmpSetting = this._Schema[i];
138
+ let tmpFieldName = tmpSetting.Name;
139
+ let tmpDataType = tmpSetting.DataType || 'String';
140
+ let tmpDefault = (this._Defaults.hasOwnProperty(tmpFieldName))
141
+ ? this._Defaults[tmpFieldName]
142
+ : '';
143
+
144
+ let tmpMode = 'default';
145
+ let tmpConstantValue = tmpDefault;
146
+ let tmpAddressValue = '';
147
+
148
+ if (tmpFieldModes && tmpFieldModes.hasOwnProperty(tmpFieldName))
149
+ {
150
+ // Explicit mode from _FieldModes
151
+ tmpMode = tmpFieldModes[tmpFieldName];
152
+
153
+ if (tmpMode === 'address')
154
+ {
155
+ tmpAddressValue = this._extractAddressFromTemplate(tmpData[tmpFieldName]);
156
+ }
157
+ else if (tmpMode === 'constant')
158
+ {
159
+ tmpConstantValue = tmpData.hasOwnProperty(tmpFieldName) ? tmpData[tmpFieldName] : tmpDefault;
160
+ }
161
+ // mode === 'default' → constantValue stays at schema default
162
+ }
163
+ else
164
+ {
165
+ // Infer mode from existing data (backward compatibility)
166
+ if (tmpData.hasOwnProperty(tmpFieldName))
167
+ {
168
+ let tmpExistingValue = tmpData[tmpFieldName];
169
+
170
+ if (typeof(tmpExistingValue) === 'string' && tmpExistingValue.indexOf('{~') >= 0)
171
+ {
172
+ tmpMode = 'address';
173
+ tmpAddressValue = this._extractAddressFromTemplate(tmpExistingValue);
174
+ }
175
+ else
176
+ {
177
+ tmpMode = 'constant';
178
+ tmpConstantValue = tmpExistingValue;
179
+ }
180
+ }
181
+ // else: absent → default
182
+ }
183
+
184
+ this._FieldStates[tmpFieldName] =
185
+ {
186
+ mode: tmpMode,
187
+ constantValue: tmpConstantValue,
188
+ addressValue: tmpAddressValue,
189
+ dataType: tmpDataType,
190
+ defaultValue: tmpDefault
191
+ };
192
+ }
193
+ }
194
+
195
+ // ====================================================================
196
+ // HTML Generation
197
+ // ====================================================================
198
+
199
+ /**
200
+ * Render a single field row: label + [toggle | editor] + description.
201
+ *
202
+ * Layout:
203
+ * FieldName*
204
+ * [C] [ input______________________ ]
205
+ * description text
206
+ *
207
+ * @param {Object} pSetting - The SettingsInput definition
208
+ * @param {Object} pState - The field's current state from _FieldStates
209
+ * @returns {string} HTML string
210
+ */
211
+ _renderField(pSetting, pState)
212
+ {
213
+ let tmpFieldName = pSetting.Name;
214
+ let tmpRequired = pSetting.Required ? '<span class="uv-settings-field-required">*</span>' : '';
215
+ let tmpDescription = pSetting.Description
216
+ ? '<div class="uv-settings-field-description">' + this._escapeHTML(pSetting.Description) + '</div>'
217
+ : '';
218
+ let tmpAttrName = this._escapeAttr(tmpFieldName);
219
+
220
+ let tmpEditorHTML = this._renderFieldEditor(tmpFieldName, pState);
221
+
222
+ let tmpModeClass = 'uv-mode-' + pState.mode;
223
+ let tmpLabel = _ModeLabels[pState.mode] || 'C';
224
+ let tmpTitle = _ModeTitles[pState.mode] || '';
225
+
226
+ return '<div class="uv-settings-field" data-field-name="' + tmpAttrName + '">'
227
+ + '<div class="uv-settings-field-label">' + this._escapeHTML(tmpFieldName) + tmpRequired + '</div>'
228
+ + '<div class="uv-settings-field-row">'
229
+ + '<button class="uv-mode-toggle ' + tmpModeClass + '" data-field="' + tmpAttrName + '" title="' + this._escapeAttr(tmpTitle) + '">' + tmpLabel + '</button>'
230
+ + '<div class="uv-settings-field-editor" data-field="' + tmpAttrName + '">'
231
+ + tmpEditorHTML
232
+ + '</div>'
233
+ + '</div>'
234
+ + tmpDescription
235
+ + '</div>';
236
+ }
237
+
238
+ /**
239
+ * Render the editor widget for a field based on its current mode.
240
+ *
241
+ * @param {string} pFieldName
242
+ * @param {Object} pState
243
+ * @returns {string} HTML string
244
+ */
245
+ _renderFieldEditor(pFieldName, pState)
246
+ {
247
+ let tmpAttrName = this._escapeAttr(pFieldName);
248
+
249
+ switch (pState.mode)
250
+ {
251
+ case 'constant':
252
+ return this._renderConstantEditor(tmpAttrName, pState);
253
+
254
+ case 'address':
255
+ return this._renderAddressEditor(tmpAttrName, pState);
256
+
257
+ case 'default':
258
+ return this._renderDefaultDisplay(pState);
259
+
260
+ default:
261
+ return '';
262
+ }
263
+ }
264
+
265
+ /**
266
+ * Render a type-appropriate constant value editor.
267
+ */
268
+ _renderConstantEditor(pAttrName, pState)
269
+ {
270
+ let tmpValue = pState.constantValue;
271
+
272
+ switch (pState.dataType)
273
+ {
274
+ case 'Boolean':
275
+ {
276
+ let tmpChecked = (tmpValue === true || tmpValue === 'true') ? ' checked' : '';
277
+ return '<label class="uv-settings-checkbox">'
278
+ + '<input type="checkbox" class="uv-settings-input-bool" data-field="' + pAttrName + '"' + tmpChecked + '>'
279
+ + '<span>Enabled</span>'
280
+ + '</label>';
281
+ }
282
+
283
+ case 'Number':
284
+ {
285
+ let tmpNumVal = (tmpValue !== undefined && tmpValue !== null && tmpValue !== '') ? tmpValue : '';
286
+ return '<input type="number" class="uv-settings-input" data-field="' + pAttrName + '" value="' + this._escapeAttr(String(tmpNumVal)) + '">';
287
+ }
288
+
289
+ case 'Array':
290
+ case 'Object':
291
+ {
292
+ let tmpDisplayValue = '';
293
+ if (typeof(tmpValue) === 'object' && tmpValue !== null)
294
+ {
295
+ tmpDisplayValue = JSON.stringify(tmpValue, null, '\t');
296
+ }
297
+ else if (typeof(tmpValue) === 'string')
298
+ {
299
+ tmpDisplayValue = tmpValue;
300
+ }
301
+ return '<textarea class="uv-settings-textarea" data-field="' + pAttrName + '">' + this._escapeHTML(tmpDisplayValue) + '</textarea>';
302
+ }
303
+
304
+ default: // String
305
+ {
306
+ let tmpStrVal = (tmpValue !== undefined && tmpValue !== null) ? String(tmpValue) : '';
307
+ return '<input type="text" class="uv-settings-input" data-field="' + pAttrName + '" value="' + this._escapeAttr(tmpStrVal) + '">';
308
+ }
309
+ }
310
+ }
311
+
312
+ /**
313
+ * Render the address mode editor: text input with placeholder.
314
+ */
315
+ _renderAddressEditor(pAttrName, pState)
316
+ {
317
+ let tmpAddress = (typeof(pState.addressValue) === 'string') ? pState.addressValue : '';
318
+
319
+ return '<input type="text" class="uv-settings-input uv-settings-address-input" data-field="' + pAttrName + '" value="' + this._escapeAttr(tmpAddress) + '" placeholder="e.g. Operation.InputFilePath">';
320
+ }
321
+
322
+ /**
323
+ * Render the default mode display: read-only showing the schema default.
324
+ */
325
+ _renderDefaultDisplay(pState)
326
+ {
327
+ let tmpDefaultStr = '';
328
+
329
+ if (pState.defaultValue === undefined || pState.defaultValue === null || pState.defaultValue === '')
330
+ {
331
+ tmpDefaultStr = 'default: empty';
332
+ }
333
+ else if (typeof(pState.defaultValue) === 'object')
334
+ {
335
+ tmpDefaultStr = 'default: ' + JSON.stringify(pState.defaultValue);
336
+ }
337
+ else
338
+ {
339
+ tmpDefaultStr = 'default: ' + String(pState.defaultValue);
340
+ }
341
+
342
+ return '<div class="uv-settings-default-display">' + this._escapeHTML(tmpDefaultStr) + '</div>';
343
+ }
344
+
345
+ // ====================================================================
346
+ // Event Handling
347
+ // ====================================================================
348
+
349
+ /**
350
+ * Wire up event listeners on the rendered panel DOM.
351
+ *
352
+ * @param {HTMLElement} pContainer
353
+ */
354
+ _wireEventListeners(pContainer)
355
+ {
356
+ let tmpSelf = this;
357
+
358
+ // Mode toggle buttons — use pointerup instead of click to avoid
359
+ // SVG foreignObject event routing issues in Safari
360
+ let tmpToggles = pContainer.querySelectorAll('.uv-mode-toggle');
361
+ for (let i = 0; i < tmpToggles.length; i++)
362
+ {
363
+ tmpToggles[i].addEventListener('pointerdown', function (pEvent)
364
+ {
365
+ pEvent.stopPropagation();
366
+ pEvent.preventDefault();
367
+ });
368
+ tmpToggles[i].addEventListener('pointerup', function (pEvent)
369
+ {
370
+ pEvent.stopPropagation();
371
+ pEvent.preventDefault();
372
+
373
+ let tmpFieldName = this.getAttribute('data-field');
374
+ tmpSelf._cycleFieldMode(pContainer, tmpFieldName);
375
+ });
376
+ }
377
+
378
+ // Wire input listeners for all existing editors
379
+ this._wireInputListeners(pContainer);
380
+
381
+ // Prevent pointer events from propagating to the SVG layer
382
+ this._wirePointerIsolation(pContainer);
383
+ }
384
+
385
+ /**
386
+ * Stop pointer events on interactive elements from reaching the SVG canvas.
387
+ *
388
+ * @param {HTMLElement} pContainer
389
+ */
390
+ _wirePointerIsolation(pContainer)
391
+ {
392
+ let tmpElements = pContainer.querySelectorAll('input, textarea, button, select');
393
+ for (let i = 0; i < tmpElements.length; i++)
394
+ {
395
+ tmpElements[i].addEventListener('pointerdown', function (pEvent)
396
+ {
397
+ pEvent.stopPropagation();
398
+ });
399
+ }
400
+ }
401
+
402
+ /**
403
+ * Attach change/input listeners to editor elements so field state
404
+ * is kept up to date as the user types.
405
+ *
406
+ * @param {HTMLElement} pContainer
407
+ */
408
+ _wireInputListeners(pContainer)
409
+ {
410
+ let tmpSelf = this;
411
+
412
+ // Text and number inputs
413
+ let tmpTextInputs = pContainer.querySelectorAll('.uv-settings-input');
414
+ for (let i = 0; i < tmpTextInputs.length; i++)
415
+ {
416
+ tmpTextInputs[i].addEventListener('input', function ()
417
+ {
418
+ let tmpFieldName = this.getAttribute('data-field');
419
+ let tmpState = tmpSelf._FieldStates[tmpFieldName];
420
+
421
+ if (!tmpState)
422
+ {
423
+ return;
424
+ }
425
+
426
+ if (tmpState.mode === 'address')
427
+ {
428
+ tmpState.addressValue = this.value;
429
+ }
430
+ else if (tmpState.dataType === 'Number')
431
+ {
432
+ tmpState.constantValue = this.value === '' ? '' : Number(this.value);
433
+ }
434
+ else
435
+ {
436
+ tmpState.constantValue = this.value;
437
+ }
438
+ });
439
+ }
440
+
441
+ // Checkbox inputs
442
+ let tmpCheckboxes = pContainer.querySelectorAll('.uv-settings-input-bool');
443
+ for (let i = 0; i < tmpCheckboxes.length; i++)
444
+ {
445
+ tmpCheckboxes[i].addEventListener('change', function ()
446
+ {
447
+ let tmpFieldName = this.getAttribute('data-field');
448
+ let tmpState = tmpSelf._FieldStates[tmpFieldName];
449
+
450
+ if (tmpState)
451
+ {
452
+ tmpState.constantValue = this.checked;
453
+ }
454
+ });
455
+ }
456
+
457
+ // Textareas (Array/Object JSON)
458
+ let tmpTextareas = pContainer.querySelectorAll('.uv-settings-textarea');
459
+ for (let i = 0; i < tmpTextareas.length; i++)
460
+ {
461
+ tmpTextareas[i].addEventListener('input', function ()
462
+ {
463
+ let tmpFieldName = this.getAttribute('data-field');
464
+ let tmpState = tmpSelf._FieldStates[tmpFieldName];
465
+
466
+ if (tmpState)
467
+ {
468
+ // Store raw string; JSON.parse happens in marshal
469
+ tmpState.constantValue = this.value;
470
+ }
471
+ });
472
+ }
473
+ }
474
+
475
+ /**
476
+ * Cycle a field to the next mode (constant → address → default → constant)
477
+ * and re-render just that field's editor + toggle button.
478
+ *
479
+ * @param {HTMLElement} pContainer
480
+ * @param {string} pFieldName
481
+ */
482
+ _cycleFieldMode(pContainer, pFieldName)
483
+ {
484
+ let tmpState = this._FieldStates[pFieldName];
485
+
486
+ if (!tmpState)
487
+ {
488
+ return;
489
+ }
490
+
491
+ // Find next mode in cycle
492
+ let tmpCurrentIndex = _ModeCycle.indexOf(tmpState.mode);
493
+ let tmpNextIndex = (tmpCurrentIndex + 1) % _ModeCycle.length;
494
+ let tmpNewMode = _ModeCycle[tmpNextIndex];
495
+
496
+ tmpState.mode = tmpNewMode;
497
+
498
+ // Update the toggle button
499
+ let tmpFieldContainer = pContainer.querySelector('.uv-settings-field[data-field-name="' + pFieldName + '"]');
500
+
501
+ if (!tmpFieldContainer)
502
+ {
503
+ return;
504
+ }
505
+
506
+ let tmpToggle = tmpFieldContainer.querySelector('.uv-mode-toggle');
507
+ if (tmpToggle)
508
+ {
509
+ // Update CSS class
510
+ tmpToggle.className = 'uv-mode-toggle uv-mode-' + tmpNewMode;
511
+ // Update label
512
+ tmpToggle.textContent = _ModeLabels[tmpNewMode] || 'C';
513
+ // Update tooltip
514
+ tmpToggle.title = _ModeTitles[tmpNewMode] || '';
515
+ }
516
+
517
+ // Re-render the editor area
518
+ let tmpEditorContainer = tmpFieldContainer.querySelector('.uv-settings-field-editor');
519
+ if (tmpEditorContainer)
520
+ {
521
+ tmpEditorContainer.innerHTML = this._renderFieldEditor(pFieldName, tmpState);
522
+
523
+ // Re-wire listeners on new elements
524
+ this._wireInputListeners(tmpEditorContainer);
525
+ this._wirePointerIsolation(tmpEditorContainer);
526
+ }
527
+ }
528
+
529
+ // ====================================================================
530
+ // Marshal
531
+ // ====================================================================
532
+
533
+ /**
534
+ * Marshal data from the panel UI back into the node's Data object.
535
+ *
536
+ * @param {Object} pNodeData
537
+ */
538
+ marshalFromPanel(pNodeData)
539
+ {
540
+ if (!pNodeData || !this._FieldStates)
541
+ {
542
+ return;
543
+ }
544
+
545
+ if (!pNodeData.Data)
546
+ {
547
+ pNodeData.Data = {};
548
+ }
549
+
550
+ let tmpFieldModes = {};
551
+ let tmpHasNonDefault = false;
552
+
553
+ let tmpFieldNames = Object.keys(this._FieldStates);
554
+
555
+ for (let i = 0; i < tmpFieldNames.length; i++)
556
+ {
557
+ let tmpFieldName = tmpFieldNames[i];
558
+ let tmpState = this._FieldStates[tmpFieldName];
559
+
560
+ switch (tmpState.mode)
561
+ {
562
+ case 'constant':
563
+ {
564
+ let tmpValue = tmpState.constantValue;
565
+
566
+ // Parse JSON for Array/Object data types
567
+ if ((tmpState.dataType === 'Array' || tmpState.dataType === 'Object') && typeof(tmpValue) === 'string')
568
+ {
569
+ let tmpTrimmed = tmpValue.trim();
570
+
571
+ if (tmpTrimmed.length > 0)
572
+ {
573
+ try
574
+ {
575
+ tmpValue = JSON.parse(tmpTrimmed);
576
+ }
577
+ catch (pParseError)
578
+ {
579
+ // Keep as raw string if not valid JSON
580
+ }
581
+ }
582
+ }
583
+
584
+ pNodeData.Data[tmpFieldName] = tmpValue;
585
+ tmpFieldModes[tmpFieldName] = 'constant';
586
+ tmpHasNonDefault = true;
587
+ break;
588
+ }
589
+
590
+ case 'address':
591
+ {
592
+ let tmpAddress = (typeof(tmpState.addressValue) === 'string') ? tmpState.addressValue.trim() : '';
593
+ pNodeData.Data[tmpFieldName] = this._buildTemplateFromAddress(tmpAddress);
594
+ tmpFieldModes[tmpFieldName] = 'address';
595
+ tmpHasNonDefault = true;
596
+ break;
597
+ }
598
+
599
+ case 'default':
600
+ {
601
+ // Remove the field so the task falls back to its built-in default
602
+ delete pNodeData.Data[tmpFieldName];
603
+ // Not added to _FieldModes — absent means 'default'
604
+ break;
605
+ }
606
+ }
607
+ }
608
+
609
+ // Store _FieldModes metadata if any field is non-default
610
+ if (tmpHasNonDefault)
611
+ {
612
+ pNodeData.Data._FieldModes = tmpFieldModes;
613
+ }
614
+ else
615
+ {
616
+ delete pNodeData.Data._FieldModes;
617
+ }
618
+ }
619
+
620
+ // ====================================================================
621
+ // Destroy
622
+ // ====================================================================
623
+
624
+ destroy()
625
+ {
626
+ this._Schema = null;
627
+ this._Defaults = null;
628
+ this._FieldStates = null;
629
+ super.destroy();
630
+ }
631
+
632
+ // ====================================================================
633
+ // Address Utilities
634
+ // ====================================================================
635
+
636
+ /**
637
+ * Extract a bare Manyfest address from a Pict template expression.
638
+ *
639
+ * '{~D:Record.Operation.InputFilePath~}' → 'Operation.InputFilePath'
640
+ *
641
+ * @param {*} pTemplateString
642
+ * @returns {string}
643
+ */
644
+ _extractAddressFromTemplate(pTemplateString)
645
+ {
646
+ if (typeof(pTemplateString) !== 'string')
647
+ {
648
+ return '';
649
+ }
650
+
651
+ let tmpMatch = pTemplateString.match(/\{~D:Record\.(.+?)~\}/);
652
+ return tmpMatch ? tmpMatch[1] : '';
653
+ }
654
+
655
+ /**
656
+ * Build a Pict template expression from a bare Manyfest address.
657
+ *
658
+ * 'Operation.InputFilePath' → '{~D:Record.Operation.InputFilePath~}'
659
+ *
660
+ * @param {string} pAddress
661
+ * @returns {string}
662
+ */
663
+ _buildTemplateFromAddress(pAddress)
664
+ {
665
+ if (!pAddress || typeof(pAddress) !== 'string')
666
+ {
667
+ return '';
668
+ }
669
+
670
+ return '{~D:Record.' + pAddress + '~}';
671
+ }
672
+
673
+ // ====================================================================
674
+ // Escape Utilities
675
+ // ====================================================================
676
+
677
+ _escapeHTML(pString)
678
+ {
679
+ if (typeof(pString) !== 'string')
680
+ {
681
+ return '';
682
+ }
683
+
684
+ return pString
685
+ .replace(/&/g, '&amp;')
686
+ .replace(/</g, '&lt;')
687
+ .replace(/>/g, '&gt;')
688
+ .replace(/"/g, '&quot;');
689
+ }
690
+
691
+ _escapeAttr(pString)
692
+ {
693
+ if (typeof(pString) !== 'string')
694
+ {
695
+ return '';
696
+ }
697
+
698
+ return pString
699
+ .replace(/&/g, '&amp;')
700
+ .replace(/"/g, '&quot;')
701
+ .replace(/'/g, '&#39;');
702
+ }
703
+
704
+ // ====================================================================
705
+ // CSS Injection
706
+ // ====================================================================
707
+
708
+ _injectCSS()
709
+ {
710
+ if (this._CSSInjected)
711
+ {
712
+ return;
713
+ }
714
+
715
+ // Use the CSSMap service (same pattern as PictProvider-Flow-CSS)
716
+ if (this.fable && this.fable.CSSMap)
717
+ {
718
+ this.fable.CSSMap.addCSS('UltravisorCardSettingsPanel', UltravisorCardSettingsPanel.CSS, 600, 'UltravisorCardSettingsPanel');
719
+ this.fable.CSSMap.injectCSS();
720
+ this._CSSInjected = true;
721
+ }
722
+ else
723
+ {
724
+ this.log.warn('UltravisorCardSettingsPanel: CSSMap not available; CSS not registered.');
725
+ }
726
+ }
727
+ }
728
+
729
+ // ========================================================================
730
+ // Static CSS
731
+ // ========================================================================
732
+
733
+ UltravisorCardSettingsPanel.CSS = [
734
+ '/* ── Ultravisor Card Settings Panel ───────────────────────────────── */',
735
+
736
+ '.uv-settings-panel {',
737
+ ' padding: 8px 10px;',
738
+ '}',
739
+
740
+ '/* Field container */',
741
+ '.uv-settings-field {',
742
+ ' margin-bottom: 10px;',
743
+ ' padding-bottom: 8px;',
744
+ ' border-bottom: 1px solid var(--pf-panel-titlebar-border, #343c44);',
745
+ '}',
746
+ '.uv-settings-field:last-child {',
747
+ ' border-bottom: none;',
748
+ ' margin-bottom: 0;',
749
+ '}',
750
+
751
+ '/* Field label */',
752
+ '.uv-settings-field-label {',
753
+ ' font-weight: 600;',
754
+ ' font-size: 0.82em;',
755
+ ' color: var(--pf-panel-text, #c8d0d8);',
756
+ ' margin-bottom: 4px;',
757
+ '}',
758
+ '.uv-settings-field-required {',
759
+ ' color: #c44e4e;',
760
+ ' margin-left: 1px;',
761
+ ' font-weight: 700;',
762
+ '}',
763
+
764
+ '/* Input row: toggle button + editor side by side */',
765
+ '.uv-settings-field-row {',
766
+ ' display: flex;',
767
+ ' align-items: flex-start;',
768
+ ' gap: 5px;',
769
+ '}',
770
+
771
+ '/* ── Mode toggle: single cycling button ─────────────────────────── */',
772
+ '.uv-mode-toggle {',
773
+ ' flex-shrink: 0;',
774
+ ' width: 22px;',
775
+ ' height: 24px;',
776
+ ' border: 1px solid var(--pf-panel-titlebar-border, #3a4450);',
777
+ ' background: var(--pf-panel-bg, #1e2228);',
778
+ ' color: #607080;',
779
+ ' font-size: 0.72em;',
780
+ ' font-style: italic;',
781
+ ' font-weight: 700;',
782
+ ' cursor: pointer;',
783
+ ' border-radius: 3px;',
784
+ ' padding: 0;',
785
+ ' line-height: 24px;',
786
+ ' text-align: center;',
787
+ ' margin-top: 1px;',
788
+ '}',
789
+ '/* Mode-specific toggle colors (no :hover — causes compositor desync in SVG foreignObject) */',
790
+ '.uv-mode-toggle.uv-mode-constant {',
791
+ ' border-color: #5ab88a60;',
792
+ ' color: #5ab88a;',
793
+ ' background: #1a2820;',
794
+ '}',
795
+ '.uv-mode-toggle.uv-mode-address {',
796
+ ' border-color: #d4884a60;',
797
+ ' color: #d4884a;',
798
+ ' background: #2a1e14;',
799
+ '}',
800
+ '.uv-mode-toggle.uv-mode-default {',
801
+ ' border-color: var(--pf-panel-titlebar-border, #3a4450);',
802
+ ' color: #607080;',
803
+ ' background: var(--pf-panel-bg, #1e2228);',
804
+ '}',
805
+
806
+ '/* ── Editor area ────────────────────────────────────────────────── */',
807
+ '.uv-settings-field-editor {',
808
+ ' flex: 1;',
809
+ ' min-width: 0;',
810
+ '}',
811
+ '.uv-settings-input {',
812
+ ' width: 100%;',
813
+ ' box-sizing: border-box;',
814
+ ' padding: 4px 8px;',
815
+ ' height: 26px;',
816
+ ' border: 1px solid var(--pf-panel-titlebar-border, #343c44);',
817
+ ' background: var(--pf-panel-input-bg, #181c22);',
818
+ ' color: var(--pf-panel-text, #b8c4cc);',
819
+ ' border-radius: 3px;',
820
+ ' font-size: 0.82em;',
821
+ ' font-family: inherit;',
822
+ '}',
823
+ '.uv-settings-input:focus {',
824
+ ' border-color: #5a9ecb;',
825
+ ' outline: none;',
826
+ '}',
827
+ '.uv-settings-textarea {',
828
+ ' width: 100%;',
829
+ ' box-sizing: border-box;',
830
+ ' min-height: 56px;',
831
+ ' padding: 4px 8px;',
832
+ ' border: 1px solid var(--pf-panel-titlebar-border, #343c44);',
833
+ ' background: var(--pf-panel-input-bg, #181c22);',
834
+ ' color: var(--pf-panel-text, #b8c4cc);',
835
+ ' border-radius: 3px;',
836
+ ' font-family: monospace;',
837
+ ' font-size: 0.78em;',
838
+ ' resize: vertical;',
839
+ '}',
840
+ '.uv-settings-textarea:focus {',
841
+ ' border-color: #5a9ecb;',
842
+ ' outline: none;',
843
+ '}',
844
+ '.uv-settings-checkbox {',
845
+ ' display: flex;',
846
+ ' align-items: center;',
847
+ ' gap: 6px;',
848
+ ' height: 24px;',
849
+ ' color: var(--pf-panel-text, #b8c4cc);',
850
+ ' font-size: 0.82em;',
851
+ ' cursor: pointer;',
852
+ '}',
853
+ '.uv-settings-checkbox input[type="checkbox"] {',
854
+ ' accent-color: #5ab88a;',
855
+ '}',
856
+
857
+ '/* Address mode styling */',
858
+ '.uv-settings-address-input {',
859
+ ' border-color: #d4884a40;',
860
+ ' font-style: italic;',
861
+ '}',
862
+ '.uv-settings-address-input:focus {',
863
+ ' border-color: #d4884a;',
864
+ '}',
865
+
866
+ '/* Default mode */',
867
+ '.uv-settings-default-display {',
868
+ ' padding: 4px 8px;',
869
+ ' height: 24px;',
870
+ ' line-height: 16px;',
871
+ ' background: transparent;',
872
+ ' border: 1px dashed var(--pf-panel-titlebar-border, #343c44);',
873
+ ' border-radius: 3px;',
874
+ ' color: var(--pf-text-tertiary, #506878);',
875
+ ' font-size: 0.78em;',
876
+ ' font-style: italic;',
877
+ '}',
878
+
879
+ '/* Description */',
880
+ '.uv-settings-field-description {',
881
+ ' font-size: 0.68em;',
882
+ ' color: var(--pf-text-tertiary, #506070);',
883
+ ' margin-top: 3px;',
884
+ ' padding-left: 27px;',
885
+ ' line-height: 1.3;',
886
+ '}'
887
+ ].join('\n');
888
+
889
+ module.exports = UltravisorCardSettingsPanel;
890
+
891
+ module.exports.default_configuration = Object.assign(
892
+ {},
893
+ libPictFlowCardPropertiesPanel.default_configuration,
894
+ {
895
+ PanelType: 'UltravisorSettings',
896
+ Configuration:
897
+ {
898
+ Schema: [],
899
+ Defaults: {}
900
+ }
901
+ }
902
+ );