ultravisor 1.0.3 → 1.0.4

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 (109) hide show
  1. package/.claude/launch.json +11 -0
  2. package/.claude/ultravisor-dev-config.json +3 -0
  3. package/.ultravisor.json +426 -0
  4. package/package.json +7 -6
  5. package/source/Ultravisor.cjs +22 -3
  6. package/source/cli/Ultravisor-CLIProgram.cjs +35 -23
  7. package/source/cli/commands/Ultravisor-Command-SingleOperation.cjs +29 -18
  8. package/source/cli/commands/Ultravisor-Command-SingleTask.cjs +62 -19
  9. package/source/cli/commands/Ultravisor-Command-UpdateTask.cjs +27 -15
  10. package/source/config/Ultravisor-Default-Command-Configuration.cjs +5 -3
  11. package/source/services/Ultravisor-ExecutionEngine.cjs +1039 -0
  12. package/source/services/Ultravisor-ExecutionManifest.cjs +399 -0
  13. package/source/services/Ultravisor-Hypervisor-State.cjs +270 -97
  14. package/source/services/Ultravisor-Hypervisor.cjs +38 -83
  15. package/source/services/Ultravisor-StateManager.cjs +241 -0
  16. package/source/services/Ultravisor-TaskTypeRegistry.cjs +143 -0
  17. package/source/services/tasks/Ultravisor-TaskType-Base.cjs +105 -0
  18. package/source/services/tasks/control/Ultravisor-TaskType-IfConditional.cjs +148 -0
  19. package/source/services/tasks/control/Ultravisor-TaskType-LaunchOperation.cjs +187 -0
  20. package/source/services/tasks/control/Ultravisor-TaskType-SplitExecute.cjs +184 -0
  21. package/source/services/tasks/data/Ultravisor-TaskType-ReplaceString.cjs +82 -0
  22. package/source/services/tasks/data/Ultravisor-TaskType-SetValues.cjs +81 -0
  23. package/source/services/tasks/data/Ultravisor-TaskType-StringAppender.cjs +101 -0
  24. package/source/services/tasks/file-io/Ultravisor-TaskType-ReadFile.cjs +103 -0
  25. package/source/services/tasks/file-io/Ultravisor-TaskType-WriteFile.cjs +117 -0
  26. package/source/services/tasks/interaction/Ultravisor-TaskType-ErrorMessage.cjs +54 -0
  27. package/source/services/tasks/interaction/Ultravisor-TaskType-ValueInput.cjs +62 -0
  28. package/source/web_server/Ultravisor-API-Server.cjs +237 -124
  29. package/test/Ultravisor_browser_tests.js +2226 -0
  30. package/test/Ultravisor_tests.js +1143 -5830
  31. package/webinterface/css/ultravisor.css +23 -0
  32. package/webinterface/package.json +6 -3
  33. package/webinterface/source/Pict-Application-Ultravisor.js +93 -73
  34. package/webinterface/source/cards/FlowCard-CSVTransform.js +43 -0
  35. package/webinterface/source/cards/FlowCard-Command.js +86 -0
  36. package/webinterface/source/cards/FlowCard-ComprehensionIntersect.js +40 -0
  37. package/webinterface/source/cards/FlowCard-Conditional.js +87 -0
  38. package/webinterface/source/cards/FlowCard-CopyFile.js +55 -0
  39. package/webinterface/source/cards/FlowCard-End.js +29 -0
  40. package/webinterface/source/cards/FlowCard-GetJSON.js +55 -0
  41. package/webinterface/source/cards/FlowCard-GetText.js +54 -0
  42. package/webinterface/source/cards/FlowCard-Histogram.js +176 -0
  43. package/webinterface/source/cards/FlowCard-LaunchOperation.js +82 -0
  44. package/webinterface/source/cards/FlowCard-ListFiles.js +55 -0
  45. package/webinterface/source/cards/FlowCard-MeadowCount.js +44 -0
  46. package/webinterface/source/cards/FlowCard-MeadowCreate.js +44 -0
  47. package/webinterface/source/cards/FlowCard-MeadowDelete.js +45 -0
  48. package/webinterface/source/cards/FlowCard-MeadowRead.js +46 -0
  49. package/webinterface/source/cards/FlowCard-MeadowReads.js +46 -0
  50. package/webinterface/source/cards/FlowCard-MeadowUpdate.js +44 -0
  51. package/webinterface/source/cards/FlowCard-ParseCSV.js +85 -0
  52. package/webinterface/source/cards/FlowCard-ReadJSON.js +54 -0
  53. package/webinterface/source/cards/FlowCard-ReadText.js +54 -0
  54. package/webinterface/source/cards/FlowCard-RestRequest.js +59 -0
  55. package/webinterface/source/cards/FlowCard-SendJSON.js +57 -0
  56. package/webinterface/source/cards/FlowCard-Solver.js +77 -0
  57. package/webinterface/source/cards/FlowCard-Start.js +29 -0
  58. package/webinterface/source/cards/FlowCard-TemplateString.js +77 -0
  59. package/webinterface/source/cards/FlowCard-WriteJSON.js +54 -0
  60. package/webinterface/source/cards/FlowCard-WriteText.js +54 -0
  61. package/webinterface/source/data/ExampleFlow-CSVPipeline.js +231 -0
  62. package/webinterface/source/data/ExampleFlow-FileProcessor.js +315 -0
  63. package/webinterface/source/data/ExampleFlow-MeadowPipeline.js +328 -0
  64. package/webinterface/source/providers/PictRouter-Ultravisor-Configuration.json +8 -8
  65. package/webinterface/source/views/PictView-Ultravisor-Dashboard.js +6 -6
  66. package/webinterface/source/views/PictView-Ultravisor-FlowEditor.js +436 -0
  67. package/webinterface/source/views/PictView-Ultravisor-ManifestList.js +45 -43
  68. package/webinterface/source/views/PictView-Ultravisor-OperationEdit.js +34 -89
  69. package/webinterface/source/views/PictView-Ultravisor-OperationList.js +128 -13
  70. package/webinterface/source/views/PictView-Ultravisor-PendingInput.js +314 -0
  71. package/webinterface/source/views/PictView-Ultravisor-Schedule.js +18 -53
  72. package/webinterface/source/views/PictView-Ultravisor-TimingView.js +27 -14
  73. package/webinterface/source/views/PictView-Ultravisor-TopBar.js +2 -1
  74. package/debug/Harness.js +0 -6
  75. package/source/services/Ultravisor-Operation-Manifest.cjs +0 -160
  76. package/source/services/Ultravisor-Operation.cjs +0 -200
  77. package/source/services/Ultravisor-Task.cjs +0 -349
  78. package/source/services/events/Ultravisor-Hypervisor-Event-Solver.cjs +0 -11
  79. package/source/services/tasks/Ultravisor-Task-Base.cjs +0 -264
  80. package/source/services/tasks/Ultravisor-Task-CollectValues.cjs +0 -188
  81. package/source/services/tasks/Ultravisor-Task-Command.cjs +0 -65
  82. package/source/services/tasks/Ultravisor-Task-CommandEach.cjs +0 -190
  83. package/source/services/tasks/Ultravisor-Task-Conditional.cjs +0 -104
  84. package/source/services/tasks/Ultravisor-Task-DateWindow.cjs +0 -72
  85. package/source/services/tasks/Ultravisor-Task-GeneratePagedOperation.cjs +0 -336
  86. package/source/services/tasks/Ultravisor-Task-LaunchOperation.cjs +0 -143
  87. package/source/services/tasks/Ultravisor-Task-LaunchTask.cjs +0 -146
  88. package/source/services/tasks/Ultravisor-Task-LineMatch.cjs +0 -158
  89. package/source/services/tasks/Ultravisor-Task-Request.cjs +0 -56
  90. package/source/services/tasks/Ultravisor-Task-Solver.cjs +0 -89
  91. package/source/services/tasks/Ultravisor-Task-TemplateString.cjs +0 -93
  92. package/source/services/tasks/rest/Ultravisor-Task-GetBinary.cjs +0 -127
  93. package/source/services/tasks/rest/Ultravisor-Task-GetJSON.cjs +0 -119
  94. package/source/services/tasks/rest/Ultravisor-Task-GetText.cjs +0 -109
  95. package/source/services/tasks/rest/Ultravisor-Task-GetXML.cjs +0 -112
  96. package/source/services/tasks/rest/Ultravisor-Task-RestRequest.cjs +0 -499
  97. package/source/services/tasks/rest/Ultravisor-Task-SendJSON.cjs +0 -150
  98. package/source/services/tasks/stagingfiles/Ultravisor-Task-CopyFile.cjs +0 -110
  99. package/source/services/tasks/stagingfiles/Ultravisor-Task-ListFiles.cjs +0 -89
  100. package/source/services/tasks/stagingfiles/Ultravisor-Task-ReadBinary.cjs +0 -87
  101. package/source/services/tasks/stagingfiles/Ultravisor-Task-ReadJSON.cjs +0 -67
  102. package/source/services/tasks/stagingfiles/Ultravisor-Task-ReadText.cjs +0 -66
  103. package/source/services/tasks/stagingfiles/Ultravisor-Task-ReadXML.cjs +0 -69
  104. package/source/services/tasks/stagingfiles/Ultravisor-Task-WriteBinary.cjs +0 -95
  105. package/source/services/tasks/stagingfiles/Ultravisor-Task-WriteJSON.cjs +0 -96
  106. package/source/services/tasks/stagingfiles/Ultravisor-Task-WriteText.cjs +0 -99
  107. package/source/services/tasks/stagingfiles/Ultravisor-Task-WriteXML.cjs +0 -102
  108. package/webinterface/source/views/PictView-Ultravisor-TaskEdit.js +0 -220
  109. package/webinterface/source/views/PictView-Ultravisor-TaskList.js +0 -248
@@ -0,0 +1,314 @@
1
+ const libPictView = require('pict-view');
2
+
3
+ const _ViewConfiguration =
4
+ {
5
+ ViewIdentifier: "Ultravisor-PendingInput",
6
+
7
+ DefaultRenderable: "Ultravisor-PendingInput-Content",
8
+ DefaultDestinationAddress: "#Ultravisor-Content-Container",
9
+
10
+ AutoRender: false,
11
+
12
+ CSS: /*css*/`
13
+ .ultravisor-pendinginput {
14
+ padding: 2em;
15
+ max-width: 1200px;
16
+ margin: 0 auto;
17
+ }
18
+ .ultravisor-pendinginput-header {
19
+ display: flex;
20
+ justify-content: space-between;
21
+ align-items: center;
22
+ margin-bottom: 1.5em;
23
+ padding-bottom: 1em;
24
+ border-bottom: 1px solid #2a2a4a;
25
+ }
26
+ .ultravisor-pendinginput-header h1 {
27
+ margin: 0;
28
+ font-size: 2em;
29
+ font-weight: 300;
30
+ color: #e0e0e0;
31
+ }
32
+ .ultravisor-pendinginput-card {
33
+ background: #16213e;
34
+ border: 1px solid #f57f17;
35
+ border-radius: 8px;
36
+ padding: 1.5em;
37
+ margin-bottom: 1em;
38
+ }
39
+ .ultravisor-pendinginput-card-header {
40
+ display: flex;
41
+ justify-content: space-between;
42
+ align-items: center;
43
+ margin-bottom: 1em;
44
+ }
45
+ .ultravisor-pendinginput-card-header h3 {
46
+ margin: 0;
47
+ color: #e0e0e0;
48
+ font-weight: 500;
49
+ }
50
+ .ultravisor-pendinginput-meta {
51
+ color: #78909c;
52
+ font-size: 0.85em;
53
+ margin-bottom: 1em;
54
+ }
55
+ .ultravisor-pendinginput-meta code {
56
+ color: #4fc3f7;
57
+ font-size: 0.9em;
58
+ }
59
+ .ultravisor-pendinginput-task {
60
+ background: #1a1a2e;
61
+ border-radius: 4px;
62
+ padding: 1em;
63
+ margin-bottom: 0.75em;
64
+ }
65
+ .ultravisor-pendinginput-prompt {
66
+ color: #fff9c4;
67
+ font-size: 1.1em;
68
+ margin-bottom: 0.75em;
69
+ }
70
+ .ultravisor-pendinginput-address {
71
+ color: #78909c;
72
+ font-size: 0.8em;
73
+ margin-bottom: 0.75em;
74
+ }
75
+ .ultravisor-pendinginput-form {
76
+ display: flex;
77
+ gap: 0.75em;
78
+ align-items: center;
79
+ }
80
+ .ultravisor-pendinginput-form input[type="text"] {
81
+ flex: 1;
82
+ padding: 0.5em 0.75em;
83
+ border: 1px solid #2a2a4a;
84
+ border-radius: 4px;
85
+ background: #0d1117;
86
+ color: #e0e0e0;
87
+ font-size: 1em;
88
+ font-family: monospace;
89
+ }
90
+ .ultravisor-pendinginput-form input[type="text"]:focus {
91
+ outline: none;
92
+ border-color: #f57f17;
93
+ }
94
+ .ultravisor-pendinginput-submit {
95
+ padding: 0.5em 1.25em;
96
+ background-color: #f57f17;
97
+ color: #1a1a2e;
98
+ border: none;
99
+ border-radius: 4px;
100
+ font-weight: 600;
101
+ cursor: pointer;
102
+ font-size: 0.95em;
103
+ }
104
+ .ultravisor-pendinginput-submit:hover {
105
+ background-color: #ff8f00;
106
+ }
107
+ .ultravisor-pendinginput-submit:disabled {
108
+ opacity: 0.5;
109
+ cursor: not-allowed;
110
+ }
111
+ .ultravisor-pendinginput-result {
112
+ margin-top: 0.75em;
113
+ padding: 0.5em 0.75em;
114
+ border-radius: 4px;
115
+ font-size: 0.85em;
116
+ }
117
+ .ultravisor-pendinginput-result.success {
118
+ background: #1b5e20;
119
+ color: #c8e6c9;
120
+ }
121
+ .ultravisor-pendinginput-result.error {
122
+ background: #b71c1c;
123
+ color: #ffcdd2;
124
+ }
125
+ `,
126
+
127
+ Templates:
128
+ [
129
+ {
130
+ Hash: "Ultravisor-PendingInput-Template",
131
+ Template: /*html*/`
132
+ <div class="ultravisor-pendinginput">
133
+ <div class="ultravisor-pendinginput-header">
134
+ <h1>Pending Input</h1>
135
+ <button class="ultravisor-btn ultravisor-btn-secondary" onclick="{~P~}.PictApplication.showView('Ultravisor-PendingInput')">Refresh</button>
136
+ </div>
137
+ <div id="Ultravisor-PendingInput-Body"></div>
138
+ </div>
139
+ `
140
+ }
141
+ ],
142
+
143
+ Renderables:
144
+ [
145
+ {
146
+ RenderableHash: "Ultravisor-PendingInput-Content",
147
+ TemplateHash: "Ultravisor-PendingInput-Template",
148
+ DestinationAddress: "#Ultravisor-Content-Container",
149
+ RenderMethod: "replace"
150
+ }
151
+ ]
152
+ };
153
+
154
+ class UltravisorPendingInputView extends libPictView
155
+ {
156
+ constructor(pFable, pOptions, pServiceHash)
157
+ {
158
+ super(pFable, pOptions, pServiceHash);
159
+ }
160
+
161
+ onAfterRender(pRenderable, pRenderDestinationAddress, pRecord, pContent)
162
+ {
163
+ this.pict.PictApplication.loadPendingInputs(
164
+ function ()
165
+ {
166
+ this.renderPendingInputs();
167
+ }.bind(this));
168
+
169
+ return super.onAfterRender(pRenderable, pRenderDestinationAddress, pRecord, pContent);
170
+ }
171
+
172
+ renderPendingInputs()
173
+ {
174
+ let tmpPendingInputs = this.pict.AppData.Ultravisor.PendingInputs;
175
+ let tmpGlobalRef = '_Pict';
176
+ let tmpViewRef = tmpGlobalRef + ".views['Ultravisor-PendingInput']";
177
+
178
+ if (!tmpPendingInputs || tmpPendingInputs.length === 0)
179
+ {
180
+ this.pict.ContentAssignment.assignContent('#Ultravisor-PendingInput-Body',
181
+ '<div class="ultravisor-empty-message">No operations waiting for input.</div>');
182
+ return;
183
+ }
184
+
185
+ let tmpHTML = '';
186
+
187
+ for (let i = 0; i < tmpPendingInputs.length; i++)
188
+ {
189
+ let tmpPending = tmpPendingInputs[i];
190
+ let tmpRunHash = tmpPending.RunHash || '';
191
+ let tmpEscRunHash = tmpRunHash.replace(/'/g, "\\'");
192
+
193
+ tmpHTML += '<div class="ultravisor-pendinginput-card">';
194
+ tmpHTML += '<div class="ultravisor-pendinginput-card-header">';
195
+ tmpHTML += '<h3>' + this.escapeHTML(tmpPending.OperationName || tmpPending.OperationHash || 'Unknown') + '</h3>';
196
+ tmpHTML += '<span class="ultravisor-manifest-status waiting">Waiting for Input</span>';
197
+ tmpHTML += '</div>';
198
+ tmpHTML += '<div class="ultravisor-pendinginput-meta">';
199
+ tmpHTML += 'Operation: <code>' + this.escapeHTML(tmpPending.OperationHash || '') + '</code>';
200
+ tmpHTML += ' &middot; Run: <code>' + this.escapeHTML(tmpRunHash) + '</code>';
201
+ if (tmpPending.StartTime)
202
+ {
203
+ tmpHTML += ' &middot; Started: ' + this.escapeHTML(tmpPending.StartTime);
204
+ }
205
+ tmpHTML += '</div>';
206
+
207
+ // Render each waiting task
208
+ let tmpWaitingTasks = tmpPending.WaitingTasks || {};
209
+ let tmpNodeHashes = Object.keys(tmpWaitingTasks);
210
+
211
+ for (let j = 0; j < tmpNodeHashes.length; j++)
212
+ {
213
+ let tmpNodeHash = tmpNodeHashes[j];
214
+ let tmpEscNodeHash = tmpNodeHash.replace(/'/g, "\\'");
215
+ let tmpTask = tmpWaitingTasks[tmpNodeHash];
216
+ let tmpInputId = 'pending-input-' + tmpRunHash + '-' + tmpNodeHash;
217
+ let tmpResultId = 'pending-result-' + tmpRunHash + '-' + tmpNodeHash;
218
+
219
+ tmpHTML += '<div class="ultravisor-pendinginput-task">';
220
+ tmpHTML += '<div class="ultravisor-pendinginput-prompt">' + this.escapeHTML(tmpTask.PromptMessage || 'Enter a value') + '</div>';
221
+ if (tmpTask.OutputAddress)
222
+ {
223
+ tmpHTML += '<div class="ultravisor-pendinginput-address">Target: <code>' + this.escapeHTML(tmpTask.OutputAddress) + '</code></div>';
224
+ }
225
+ tmpHTML += '<div class="ultravisor-pendinginput-form">';
226
+ tmpHTML += '<input type="text" id="' + tmpInputId + '" placeholder="Enter value..." />';
227
+ tmpHTML += '<button class="ultravisor-pendinginput-submit" onclick="' + tmpViewRef + '.submitInput(\'' + tmpEscRunHash + '\', \'' + tmpEscNodeHash + '\', \'' + tmpInputId + '\', \'' + tmpResultId + '\')">Submit</button>';
228
+ tmpHTML += '</div>';
229
+ tmpHTML += '<div id="' + tmpResultId + '"></div>';
230
+ tmpHTML += '</div>';
231
+ }
232
+
233
+ tmpHTML += '</div>';
234
+ }
235
+
236
+ this.pict.ContentAssignment.assignContent('#Ultravisor-PendingInput-Body', tmpHTML);
237
+ }
238
+
239
+ submitInput(pRunHash, pNodeHash, pInputId, pResultId)
240
+ {
241
+ let tmpInputEl = document.getElementById(pInputId);
242
+ if (!tmpInputEl)
243
+ {
244
+ return;
245
+ }
246
+
247
+ let tmpValue = tmpInputEl.value;
248
+
249
+ // Disable the input and button while submitting
250
+ tmpInputEl.disabled = true;
251
+ let tmpButton = tmpInputEl.parentElement.querySelector('.ultravisor-pendinginput-submit');
252
+ if (tmpButton)
253
+ {
254
+ tmpButton.disabled = true;
255
+ tmpButton.textContent = 'Submitting...';
256
+ }
257
+
258
+ this.pict.PictApplication.submitPendingInput(pRunHash, pNodeHash, tmpValue,
259
+ function (pError, pData)
260
+ {
261
+ if (pError)
262
+ {
263
+ this.pict.ContentAssignment.assignContent('#' + pResultId,
264
+ '<div class="ultravisor-pendinginput-result error">Error: ' + this.escapeHTML(pError.message || 'Request failed') + '</div>');
265
+ // Re-enable
266
+ tmpInputEl.disabled = false;
267
+ if (tmpButton)
268
+ {
269
+ tmpButton.disabled = false;
270
+ tmpButton.textContent = 'Submit';
271
+ }
272
+ return;
273
+ }
274
+
275
+ if (pData && pData.Error)
276
+ {
277
+ this.pict.ContentAssignment.assignContent('#' + pResultId,
278
+ '<div class="ultravisor-pendinginput-result error">Error: ' + this.escapeHTML(pData.Error) + '</div>');
279
+ tmpInputEl.disabled = false;
280
+ if (tmpButton)
281
+ {
282
+ tmpButton.disabled = false;
283
+ tmpButton.textContent = 'Submit';
284
+ }
285
+ return;
286
+ }
287
+
288
+ let tmpStatus = (pData && pData.Status) || 'Submitted';
289
+ this.pict.ContentAssignment.assignContent('#' + pResultId,
290
+ '<div class="ultravisor-pendinginput-result success">Input submitted — operation status: ' + this.escapeHTML(tmpStatus) + '</div>');
291
+
292
+ // Refresh the list after a brief delay so the user sees the success message
293
+ setTimeout(
294
+ function ()
295
+ {
296
+ this.pict.PictApplication.loadPendingInputs(
297
+ function ()
298
+ {
299
+ this.renderPendingInputs();
300
+ }.bind(this));
301
+ }.bind(this), 1500);
302
+ }.bind(this));
303
+ }
304
+
305
+ escapeHTML(pValue)
306
+ {
307
+ if (!pValue) return '';
308
+ return String(pValue).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
309
+ }
310
+ }
311
+
312
+ module.exports = UltravisorPendingInputView;
313
+
314
+ module.exports.default_configuration = _ViewConfiguration;
@@ -156,7 +156,7 @@ class UltravisorScheduleView extends libPictView
156
156
  }
157
157
 
158
158
  let tmpHTML = '<table class="ultravisor-schedule-table">';
159
- tmpHTML += '<thead><tr><th>GUID</th><th>Type</th><th>Target</th><th>Cron</th><th>Active</th><th>Actions</th></tr></thead>';
159
+ tmpHTML += '<thead><tr><th>GUID</th><th>Type</th><th>Target Hash</th><th>Cron</th><th>Active</th><th>Actions</th></tr></thead>';
160
160
  tmpHTML += '<tbody>';
161
161
 
162
162
  for (let i = 0; i < tmpSchedule.length; i++)
@@ -167,10 +167,10 @@ class UltravisorScheduleView extends libPictView
167
167
  let tmpActive = tmpEntry.Active ? 'yes' : 'no';
168
168
 
169
169
  tmpHTML += '<tr>';
170
- tmpHTML += '<td><code style="font-size:0.8em;">' + tmpGUID + '</code></td>';
171
- tmpHTML += '<td>' + (tmpEntry.TargetType || '') + '</td>';
172
- tmpHTML += '<td><code>' + (tmpEntry.TargetGUID || '') + '</code></td>';
173
- tmpHTML += '<td><code>' + (tmpEntry.CronExpression || tmpEntry.Parameters || '') + '</code></td>';
170
+ tmpHTML += '<td><code style="font-size:0.8em;">' + this.escapeHTML(tmpGUID) + '</code></td>';
171
+ tmpHTML += '<td>' + this.escapeHTML(tmpEntry.TargetType || '') + '</td>';
172
+ tmpHTML += '<td><code>' + this.escapeHTML(tmpEntry.TargetHash || '') + '</code></td>';
173
+ tmpHTML += '<td><code>' + this.escapeHTML(tmpEntry.CronExpression || tmpEntry.Parameters || '') + '</code></td>';
174
174
  tmpHTML += '<td><span class="ultravisor-schedule-active ' + tmpActive + '">' + (tmpEntry.Active ? 'Active' : 'Inactive') + '</span></td>';
175
175
  tmpHTML += '<td>';
176
176
  tmpHTML += '<button class="ultravisor-btn-sm ultravisor-btn-delete" onclick="if(confirm(\'Remove schedule entry?\')){ ' + tmpGlobalRef + '.PictApplication.removeScheduleEntry(\'' + tmpEscGUID + '\', function(){ ' + tmpGlobalRef + '.PictApplication.showView(\'Ultravisor-Schedule\'); }); }">Remove</button>';
@@ -189,29 +189,12 @@ class UltravisorScheduleView extends libPictView
189
189
 
190
190
  let tmpHTML = '';
191
191
 
192
- // Schedule a task
193
- tmpHTML += '<div class="ultravisor-schedule-add-section">';
194
- tmpHTML += '<h3>Schedule a Task</h3>';
195
- tmpHTML += '<div class="ultravisor-schedule-add-form">';
196
- tmpHTML += '<div class="ultravisor-form-group"><label>Task GUID</label>';
197
- tmpHTML += '<input type="text" id="Ultravisor-Schedule-TaskGUID" placeholder="e.g. MY-TASK-001"></div>';
198
- tmpHTML += '<div class="ultravisor-form-group"><label>Schedule Type</label>';
199
- tmpHTML += '<select id="Ultravisor-Schedule-TaskScheduleType">';
200
- tmpHTML += '<option value="cron">Cron</option>';
201
- tmpHTML += '<option value="daily">Daily</option>';
202
- tmpHTML += '<option value="hourly">Hourly</option>';
203
- tmpHTML += '</select></div>';
204
- tmpHTML += '<div class="ultravisor-form-group"><label>Parameters (cron expression)</label>';
205
- tmpHTML += '<input type="text" id="Ultravisor-Schedule-TaskParameters" placeholder="e.g. 0 * * * *"></div>';
206
- tmpHTML += '<button class="ultravisor-btn ultravisor-btn-primary" onclick="' + tmpViewRef + '.addTaskSchedule()">Add</button>';
207
- tmpHTML += '</div></div>';
208
-
209
192
  // Schedule an operation
210
- tmpHTML += '<div class="ultravisor-schedule-add-section" style="margin-top:1em;">';
193
+ tmpHTML += '<div class="ultravisor-schedule-add-section">';
211
194
  tmpHTML += '<h3>Schedule an Operation</h3>';
212
195
  tmpHTML += '<div class="ultravisor-schedule-add-form">';
213
- tmpHTML += '<div class="ultravisor-form-group"><label>Operation GUID</label>';
214
- tmpHTML += '<input type="text" id="Ultravisor-Schedule-OperationGUID" placeholder="e.g. MY-OP-001"></div>';
196
+ tmpHTML += '<div class="ultravisor-form-group"><label>Operation Hash</label>';
197
+ tmpHTML += '<input type="text" id="Ultravisor-Schedule-OperationHash" placeholder="e.g. OPR-0001"></div>';
215
198
  tmpHTML += '<div class="ultravisor-form-group"><label>Schedule Type</label>';
216
199
  tmpHTML += '<select id="Ultravisor-Schedule-OperationScheduleType">';
217
200
  tmpHTML += '<option value="cron">Cron</option>';
@@ -226,43 +209,19 @@ class UltravisorScheduleView extends libPictView
226
209
  this.pict.ContentAssignment.assignContent('#Ultravisor-Schedule-AddForms', tmpHTML);
227
210
  }
228
211
 
229
- addTaskSchedule()
230
- {
231
- let tmpGUID = document.getElementById('Ultravisor-Schedule-TaskGUID').value.trim();
232
- let tmpType = document.getElementById('Ultravisor-Schedule-TaskScheduleType').value;
233
- let tmpParams = document.getElementById('Ultravisor-Schedule-TaskParameters').value.trim();
234
-
235
- if (!tmpGUID)
236
- {
237
- alert('Task GUID is required.');
238
- return;
239
- }
240
-
241
- this.pict.PictApplication.scheduleTask(tmpGUID, tmpType, tmpParams,
242
- function (pError)
243
- {
244
- if (pError)
245
- {
246
- alert('Error scheduling task: ' + pError.message);
247
- return;
248
- }
249
- this.pict.PictApplication.showView('Ultravisor-Schedule');
250
- }.bind(this));
251
- }
252
-
253
212
  addOperationSchedule()
254
213
  {
255
- let tmpGUID = document.getElementById('Ultravisor-Schedule-OperationGUID').value.trim();
214
+ let tmpHash = document.getElementById('Ultravisor-Schedule-OperationHash').value.trim();
256
215
  let tmpType = document.getElementById('Ultravisor-Schedule-OperationScheduleType').value;
257
216
  let tmpParams = document.getElementById('Ultravisor-Schedule-OperationParameters').value.trim();
258
217
 
259
- if (!tmpGUID)
218
+ if (!tmpHash)
260
219
  {
261
- alert('Operation GUID is required.');
220
+ alert('Operation Hash is required.');
262
221
  return;
263
222
  }
264
223
 
265
- this.pict.PictApplication.scheduleOperation(tmpGUID, tmpType, tmpParams,
224
+ this.pict.PictApplication.scheduleOperation(tmpHash, tmpType, tmpParams,
266
225
  function (pError)
267
226
  {
268
227
  if (pError)
@@ -273,6 +232,12 @@ class UltravisorScheduleView extends libPictView
273
232
  this.pict.PictApplication.showView('Ultravisor-Schedule');
274
233
  }.bind(this));
275
234
  }
235
+
236
+ escapeHTML(pValue)
237
+ {
238
+ if (!pValue) return '';
239
+ return String(pValue).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
240
+ }
276
241
  }
277
242
 
278
243
  module.exports = UltravisorScheduleView;
@@ -235,26 +235,26 @@ class UltravisorTimingView extends libPictView
235
235
  for (let i = tmpManifests.length - 1; i >= 0; i--)
236
236
  {
237
237
  let tmpManifest = tmpManifests[i];
238
- let tmpGUIDRun = tmpManifest.GUIDRun || '';
239
- let tmpLabel = (tmpManifest.Name || tmpManifest.GUIDOperation || tmpGUIDRun);
238
+ let tmpRunHash = tmpManifest.Hash || '';
239
+ let tmpLabel = (tmpManifest.OperationHash || tmpRunHash);
240
240
  let tmpStatus = tmpManifest.Status || 'Unknown';
241
241
  let tmpTime = tmpManifest.StartTime ? tmpManifest.StartTime.replace('T', ' ').replace(/\.\d+Z$/, '') : '';
242
- tmpHTML += '<option value="' + this.escapeHTML(tmpGUIDRun) + '">' + this.escapeHTML(tmpLabel) + ' [' + tmpStatus + '] ' + tmpTime + '</option>';
242
+ tmpHTML += '<option value="' + this.escapeHTML(tmpRunHash) + '">' + this.escapeHTML(tmpLabel) + ' [' + tmpStatus + '] ' + tmpTime + '</option>';
243
243
  }
244
244
 
245
245
  tmpHTML += '</select>';
246
246
  this.pict.ContentAssignment.assignContent('#Ultravisor-Timing-Selector', tmpHTML);
247
247
  }
248
248
 
249
- onSelectManifest(pGUIDRun)
249
+ onSelectManifest(pRunHash)
250
250
  {
251
- if (!pGUIDRun)
251
+ if (!pRunHash)
252
252
  {
253
253
  this.pict.ContentAssignment.assignContent('#Ultravisor-Timing-Detail', '');
254
254
  return;
255
255
  }
256
256
 
257
- this.pict.PictApplication.loadManifest(pGUIDRun,
257
+ this.pict.PictApplication.loadManifest(pRunHash,
258
258
  function (pError, pManifest)
259
259
  {
260
260
  if (pError || !pManifest)
@@ -270,10 +270,22 @@ class UltravisorTimingView extends libPictView
270
270
 
271
271
  renderTimingVisualization(pManifest)
272
272
  {
273
- let tmpTaskResults = pManifest.TaskResults || [];
273
+ // Convert TaskManifests object to an array for visualization
274
+ let tmpTaskResults = [];
275
+ if (pManifest.TaskManifests && typeof pManifest.TaskManifests === 'object')
276
+ {
277
+ let tmpKeys = Object.keys(pManifest.TaskManifests);
278
+ for (let k = 0; k < tmpKeys.length; k++)
279
+ {
280
+ let tmpEntry = pManifest.TaskManifests[tmpKeys[k]];
281
+ tmpEntry._NodeHash = tmpKeys[k];
282
+ tmpTaskResults.push(tmpEntry);
283
+ }
284
+ }
285
+
274
286
  let tmpOperationElapsedMs = pManifest.ElapsedMs || 0;
275
- let tmpOperationElapsedFormatted = pManifest.ElapsedFormatted || this.formatMs(tmpOperationElapsedMs);
276
- let tmpAverageTaskMs = pManifest.AverageTaskMs || 0;
287
+ let tmpOperationElapsedFormatted = this.formatMs(tmpOperationElapsedMs);
288
+ let tmpAverageTaskMs = 0;
277
289
  let tmpStatus = (pManifest.Status || 'Unknown').toLowerCase();
278
290
  let tmpStatusClass = (tmpStatus === 'complete' || tmpStatus === 'error' || tmpStatus === 'running') ? tmpStatus : '';
279
291
 
@@ -287,8 +299,8 @@ class UltravisorTimingView extends libPictView
287
299
  tmpOperationElapsedFormatted = this.formatMs(tmpOperationElapsedMs);
288
300
  }
289
301
 
290
- // Compute average if not provided
291
- if (tmpAverageTaskMs <= 0 && tmpTaskResults.length > 0 && tmpOperationElapsedMs > 0)
302
+ // Compute average
303
+ if (tmpTaskResults.length > 0 && tmpOperationElapsedMs > 0)
292
304
  {
293
305
  tmpAverageTaskMs = tmpOperationElapsedMs / tmpTaskResults.length;
294
306
  }
@@ -312,7 +324,7 @@ class UltravisorTimingView extends libPictView
312
324
 
313
325
  // Summary header
314
326
  tmpHTML += '<div class="ultravisor-timing-summary">';
315
- tmpHTML += '<div class="ultravisor-timing-stat"><span class="ultravisor-timing-stat-label">Operation</span><span class="ultravisor-timing-stat-value">' + this.escapeHTML(pManifest.Name || pManifest.GUIDOperation || '') + '</span></div>';
327
+ tmpHTML += '<div class="ultravisor-timing-stat"><span class="ultravisor-timing-stat-label">Operation</span><span class="ultravisor-timing-stat-value">' + this.escapeHTML(pManifest.OperationHash || '') + '</span></div>';
316
328
  tmpHTML += '<div class="ultravisor-timing-stat"><span class="ultravisor-timing-stat-label">Status</span><span class="ultravisor-timing-stat-value ' + tmpStatusClass + '">' + this.escapeHTML(pManifest.Status || 'Unknown') + '</span></div>';
317
329
  tmpHTML += '<div class="ultravisor-timing-stat"><span class="ultravisor-timing-stat-label">Total Time</span><span class="ultravisor-timing-stat-value">' + this.escapeHTML(tmpOperationElapsedFormatted) + '</span></div>';
318
330
  tmpHTML += '<div class="ultravisor-timing-stat"><span class="ultravisor-timing-stat-label">Tasks</span><span class="ultravisor-timing-stat-value">' + tmpTaskResults.length + '</span></div>';
@@ -350,10 +362,11 @@ class UltravisorTimingView extends libPictView
350
362
  }
351
363
 
352
364
  let tmpWidthPercent = (tmpMaxTaskMs > 0) ? Math.max((tmpTaskMs / tmpMaxTaskMs) * 100, 1) : 1;
353
- let tmpBarLabel = this.escapeHTML(tmpResult.Name || tmpResult.GUIDTask || '');
365
+ let tmpNodeHash = tmpResult._NodeHash || '';
366
+ let tmpBarLabel = this.escapeHTML(tmpResult.Name || tmpNodeHash || '');
354
367
 
355
368
  tmpHTML += '<div class="ultravisor-timing-row">';
356
- tmpHTML += '<div class="ultravisor-timing-row-label" title="' + this.escapeHTML(tmpResult.GUIDTask || '') + '">' + this.escapeHTML(tmpResult.Name || tmpResult.GUIDTask || 'Task ' + (i + 1)) + '</div>';
369
+ tmpHTML += '<div class="ultravisor-timing-row-label" title="' + this.escapeHTML(tmpNodeHash) + '">' + this.escapeHTML(tmpResult.Name || tmpNodeHash || 'Task ' + (i + 1)) + '</div>';
357
370
  tmpHTML += '<div class="ultravisor-timing-row-bar-container">';
358
371
  tmpHTML += '<div class="ultravisor-timing-row-bar ' + tmpBarClass + '" style="width: ' + tmpWidthPercent.toFixed(1) + '%;">';
359
372
  if (tmpWidthPercent > 20)
@@ -82,11 +82,12 @@ const _ViewConfiguration =
82
82
  <a class="ultravisor-topbar-brand" onclick="{~P~}.PictApplication.navigateTo('/Home')">Ultravisor</a>
83
83
  <div class="ultravisor-topbar-nav">
84
84
  <a onclick="{~P~}.PictApplication.navigateTo('/Home')">Dashboard</a>
85
- <a onclick="{~P~}.PictApplication.navigateTo('/Tasks')">Tasks</a>
86
85
  <a onclick="{~P~}.PictApplication.navigateTo('/Operations')">Operations</a>
87
86
  <a onclick="{~P~}.PictApplication.navigateTo('/Schedule')">Schedule</a>
88
87
  <a onclick="{~P~}.PictApplication.navigateTo('/Manifests')">Manifests</a>
88
+ <a onclick="{~P~}.PictApplication.navigateTo('/PendingInput')">Pending Input</a>
89
89
  <a onclick="{~P~}.PictApplication.navigateTo('/Timing')">Timing</a>
90
+ <a onclick="{~P~}.PictApplication.editOperation()">Flow Editor</a>
90
91
  </div>
91
92
  <div class="ultravisor-topbar-status" id="Ultravisor-TopBar-StatusArea"></div>
92
93
  </div>
package/debug/Harness.js DELETED
@@ -1,6 +0,0 @@
1
- let libUltravisor = require(`../source/cli/Ultravisor-Run.cjs`);
2
- //let libUltravisor = require(`../source/cli/Ultravisor-CLIProgram.cjs`);
3
-
4
- //libUltravisor.run(['node', 'Harness.js', 'explain-config']);
5
-
6
- //libUltravisor.run(['node', 'Harness.js', 'start']);