ultravisor 1.0.2 → 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 (121) 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/docs/README.md +63 -0
  5. package/package.json +12 -8
  6. package/source/Ultravisor.cjs +22 -3
  7. package/source/cli/Ultravisor-CLIProgram.cjs +35 -23
  8. package/source/cli/commands/Ultravisor-Command-SingleOperation.cjs +29 -18
  9. package/source/cli/commands/Ultravisor-Command-SingleTask.cjs +62 -19
  10. package/source/cli/commands/Ultravisor-Command-UpdateTask.cjs +27 -15
  11. package/source/config/Ultravisor-Default-Command-Configuration.cjs +5 -3
  12. package/source/services/Ultravisor-ExecutionEngine.cjs +1039 -0
  13. package/source/services/Ultravisor-ExecutionManifest.cjs +399 -0
  14. package/source/services/Ultravisor-Hypervisor-State.cjs +270 -97
  15. package/source/services/Ultravisor-Hypervisor.cjs +38 -83
  16. package/source/services/Ultravisor-StateManager.cjs +241 -0
  17. package/source/services/Ultravisor-TaskTypeRegistry.cjs +143 -0
  18. package/source/services/tasks/Ultravisor-TaskType-Base.cjs +105 -0
  19. package/source/services/tasks/control/Ultravisor-TaskType-IfConditional.cjs +148 -0
  20. package/source/services/tasks/control/Ultravisor-TaskType-LaunchOperation.cjs +187 -0
  21. package/source/services/tasks/control/Ultravisor-TaskType-SplitExecute.cjs +184 -0
  22. package/source/services/tasks/data/Ultravisor-TaskType-ReplaceString.cjs +82 -0
  23. package/source/services/tasks/data/Ultravisor-TaskType-SetValues.cjs +81 -0
  24. package/source/services/tasks/data/Ultravisor-TaskType-StringAppender.cjs +101 -0
  25. package/source/services/tasks/file-io/Ultravisor-TaskType-ReadFile.cjs +103 -0
  26. package/source/services/tasks/file-io/Ultravisor-TaskType-WriteFile.cjs +117 -0
  27. package/source/services/tasks/interaction/Ultravisor-TaskType-ErrorMessage.cjs +54 -0
  28. package/source/services/tasks/interaction/Ultravisor-TaskType-ValueInput.cjs +62 -0
  29. package/source/web_server/Ultravisor-API-Server.cjs +237 -124
  30. package/test/Ultravisor_browser_tests.js +2226 -0
  31. package/test/Ultravisor_tests.js +1143 -5830
  32. package/webinterface/css/ultravisor.css +23 -0
  33. package/webinterface/package.json +6 -3
  34. package/webinterface/source/Pict-Application-Ultravisor.js +93 -73
  35. package/webinterface/source/cards/FlowCard-CSVTransform.js +43 -0
  36. package/webinterface/source/cards/FlowCard-Command.js +86 -0
  37. package/webinterface/source/cards/FlowCard-ComprehensionIntersect.js +40 -0
  38. package/webinterface/source/cards/FlowCard-Conditional.js +87 -0
  39. package/webinterface/source/cards/FlowCard-CopyFile.js +55 -0
  40. package/webinterface/source/cards/FlowCard-End.js +29 -0
  41. package/webinterface/source/cards/FlowCard-GetJSON.js +55 -0
  42. package/webinterface/source/cards/FlowCard-GetText.js +54 -0
  43. package/webinterface/source/cards/FlowCard-Histogram.js +176 -0
  44. package/webinterface/source/cards/FlowCard-LaunchOperation.js +82 -0
  45. package/webinterface/source/cards/FlowCard-ListFiles.js +55 -0
  46. package/webinterface/source/cards/FlowCard-MeadowCount.js +44 -0
  47. package/webinterface/source/cards/FlowCard-MeadowCreate.js +44 -0
  48. package/webinterface/source/cards/FlowCard-MeadowDelete.js +45 -0
  49. package/webinterface/source/cards/FlowCard-MeadowRead.js +46 -0
  50. package/webinterface/source/cards/FlowCard-MeadowReads.js +46 -0
  51. package/webinterface/source/cards/FlowCard-MeadowUpdate.js +44 -0
  52. package/webinterface/source/cards/FlowCard-ParseCSV.js +85 -0
  53. package/webinterface/source/cards/FlowCard-ReadJSON.js +54 -0
  54. package/webinterface/source/cards/FlowCard-ReadText.js +54 -0
  55. package/webinterface/source/cards/FlowCard-RestRequest.js +59 -0
  56. package/webinterface/source/cards/FlowCard-SendJSON.js +57 -0
  57. package/webinterface/source/cards/FlowCard-Solver.js +77 -0
  58. package/webinterface/source/cards/FlowCard-Start.js +29 -0
  59. package/webinterface/source/cards/FlowCard-TemplateString.js +77 -0
  60. package/webinterface/source/cards/FlowCard-WriteJSON.js +54 -0
  61. package/webinterface/source/cards/FlowCard-WriteText.js +54 -0
  62. package/webinterface/source/data/ExampleFlow-CSVPipeline.js +231 -0
  63. package/webinterface/source/data/ExampleFlow-FileProcessor.js +315 -0
  64. package/webinterface/source/data/ExampleFlow-MeadowPipeline.js +328 -0
  65. package/webinterface/source/providers/PictRouter-Ultravisor-Configuration.json +8 -8
  66. package/webinterface/source/views/PictView-Ultravisor-Dashboard.js +6 -6
  67. package/webinterface/source/views/PictView-Ultravisor-FlowEditor.js +436 -0
  68. package/webinterface/source/views/PictView-Ultravisor-ManifestList.js +45 -43
  69. package/webinterface/source/views/PictView-Ultravisor-OperationEdit.js +34 -89
  70. package/webinterface/source/views/PictView-Ultravisor-OperationList.js +128 -13
  71. package/webinterface/source/views/PictView-Ultravisor-PendingInput.js +314 -0
  72. package/webinterface/source/views/PictView-Ultravisor-Schedule.js +18 -53
  73. package/webinterface/source/views/PictView-Ultravisor-TimingView.js +27 -14
  74. package/webinterface/source/views/PictView-Ultravisor-TopBar.js +2 -1
  75. package/.babelrc +0 -6
  76. package/.browserslistrc +0 -1
  77. package/.browserslistrc-BACKUP +0 -1
  78. package/.gulpfile-quackage-config.json +0 -7
  79. package/.gulpfile-quackage.js +0 -2
  80. package/debug/Harness.js +0 -5
  81. package/source/services/Ultravisor-Operation-Manifest.cjs +0 -160
  82. package/source/services/Ultravisor-Operation.cjs +0 -200
  83. package/source/services/Ultravisor-Task.cjs +0 -349
  84. package/source/services/events/Ultravisor-Hypervisor-Event-Solver.cjs +0 -11
  85. package/source/services/tasks/Ultravisor-Task-Base.cjs +0 -264
  86. package/source/services/tasks/Ultravisor-Task-CollectValues.cjs +0 -188
  87. package/source/services/tasks/Ultravisor-Task-Command.cjs +0 -65
  88. package/source/services/tasks/Ultravisor-Task-CommandEach.cjs +0 -190
  89. package/source/services/tasks/Ultravisor-Task-Conditional.cjs +0 -104
  90. package/source/services/tasks/Ultravisor-Task-DateWindow.cjs +0 -72
  91. package/source/services/tasks/Ultravisor-Task-GeneratePagedOperation.cjs +0 -336
  92. package/source/services/tasks/Ultravisor-Task-LaunchOperation.cjs +0 -143
  93. package/source/services/tasks/Ultravisor-Task-LaunchTask.cjs +0 -146
  94. package/source/services/tasks/Ultravisor-Task-LineMatch.cjs +0 -158
  95. package/source/services/tasks/Ultravisor-Task-Request.cjs +0 -56
  96. package/source/services/tasks/Ultravisor-Task-Solver.cjs +0 -89
  97. package/source/services/tasks/Ultravisor-Task-TemplateString.cjs +0 -93
  98. package/source/services/tasks/rest/Ultravisor-Task-GetBinary.cjs +0 -127
  99. package/source/services/tasks/rest/Ultravisor-Task-GetJSON.cjs +0 -119
  100. package/source/services/tasks/rest/Ultravisor-Task-GetText.cjs +0 -109
  101. package/source/services/tasks/rest/Ultravisor-Task-GetXML.cjs +0 -112
  102. package/source/services/tasks/rest/Ultravisor-Task-RestRequest.cjs +0 -499
  103. package/source/services/tasks/rest/Ultravisor-Task-SendJSON.cjs +0 -150
  104. package/source/services/tasks/stagingfiles/Ultravisor-Task-CopyFile.cjs +0 -110
  105. package/source/services/tasks/stagingfiles/Ultravisor-Task-ListFiles.cjs +0 -89
  106. package/source/services/tasks/stagingfiles/Ultravisor-Task-ReadBinary.cjs +0 -87
  107. package/source/services/tasks/stagingfiles/Ultravisor-Task-ReadJSON.cjs +0 -67
  108. package/source/services/tasks/stagingfiles/Ultravisor-Task-ReadText.cjs +0 -66
  109. package/source/services/tasks/stagingfiles/Ultravisor-Task-ReadXML.cjs +0 -69
  110. package/source/services/tasks/stagingfiles/Ultravisor-Task-WriteBinary.cjs +0 -95
  111. package/source/services/tasks/stagingfiles/Ultravisor-Task-WriteJSON.cjs +0 -96
  112. package/source/services/tasks/stagingfiles/Ultravisor-Task-WriteText.cjs +0 -99
  113. package/source/services/tasks/stagingfiles/Ultravisor-Task-WriteXML.cjs +0 -102
  114. package/webinterface/.babelrc +0 -6
  115. package/webinterface/.browserslistrc +0 -1
  116. package/webinterface/.browserslistrc-BACKUP +0 -1
  117. package/webinterface/.gulpfile-quackage-config.json +0 -7
  118. package/webinterface/.gulpfile-quackage.js +0 -2
  119. package/webinterface/source/views/PictView-Ultravisor-TaskEdit.js +0 -220
  120. package/webinterface/source/views/PictView-Ultravisor-TaskList.js +0 -248
  121. /package/docs/{cover.md → _cover.md} +0 -0
@@ -26,33 +26,6 @@ const _ViewConfiguration =
26
26
  font-weight: 300;
27
27
  color: #e0e0e0;
28
28
  }
29
- .ultravisor-task-list-editor {
30
- background: #16213e;
31
- border: 1px solid #2a2a4a;
32
- border-radius: 6px;
33
- padding: 1em;
34
- }
35
- .ultravisor-task-list-item {
36
- display: flex;
37
- align-items: center;
38
- justify-content: space-between;
39
- padding: 0.5em 0.75em;
40
- background: #1a1a2e;
41
- border-radius: 4px;
42
- margin-bottom: 0.5em;
43
- }
44
- .ultravisor-task-list-item code {
45
- color: #4fc3f7;
46
- font-size: 0.9em;
47
- }
48
- .ultravisor-task-list-add {
49
- display: flex;
50
- gap: 0.5em;
51
- margin-top: 0.75em;
52
- }
53
- .ultravisor-task-list-add input {
54
- flex: 1;
55
- }
56
29
  `,
57
30
 
58
31
  Templates:
@@ -93,15 +66,19 @@ class UltravisorOperationEditView extends libPictView
93
66
  let tmpOp = this.pict.AppData.Ultravisor.CurrentEditOperation;
94
67
  if (!tmpOp)
95
68
  {
96
- tmpOp = { GUIDOperation: '', Name: '', Description: '', Tasks: [] };
69
+ tmpOp =
70
+ {
71
+ Hash: '', Name: '', Description: '',
72
+ Graph: { Nodes: [], Connections: [], ViewState: {} }
73
+ };
97
74
  this.pict.AppData.Ultravisor.CurrentEditOperation = tmpOp;
98
75
  }
99
76
 
100
- let tmpIsNew = !tmpOp.GUIDOperation;
77
+ let tmpIsNew = !tmpOp.Hash;
101
78
  let tmpTitleEl = document.getElementById('Ultravisor-OperationEdit-Title');
102
79
  if (tmpTitleEl)
103
80
  {
104
- tmpTitleEl.textContent = tmpIsNew ? 'New Operation' : ('Edit Operation: ' + (tmpOp.Name || tmpOp.GUIDOperation));
81
+ tmpTitleEl.textContent = tmpIsNew ? 'New Operation' : ('Edit Operation: ' + (tmpOp.Name || tmpOp.Hash));
105
82
  }
106
83
 
107
84
  this.renderForm();
@@ -124,13 +101,19 @@ class UltravisorOperationEditView extends libPictView
124
101
  renderForm()
125
102
  {
126
103
  let tmpOp = this.pict.AppData.Ultravisor.CurrentEditOperation;
127
- let tmpIsNew = !tmpOp.GUIDOperation;
104
+ let tmpIsNew = !tmpOp.Hash;
128
105
  let tmpGlobalRef = '_Pict';
129
106
  let tmpViewRef = tmpGlobalRef + ".views['Ultravisor-OperationEdit']";
130
107
 
108
+ let tmpNodeCount = (tmpOp.Graph && tmpOp.Graph.Nodes) ? tmpOp.Graph.Nodes.length : 0;
109
+
131
110
  let tmpHTML = '';
132
- tmpHTML += '<div class="ultravisor-form-group"><label>GUID Operation</label>';
133
- tmpHTML += '<input type="text" id="Ultravisor-OperationEdit-GUIDOperation" value="' + this.escapeAttr(tmpOp.GUIDOperation) + '" ' + (tmpIsNew ? '' : 'readonly') + '></div>';
111
+
112
+ if (!tmpIsNew)
113
+ {
114
+ tmpHTML += '<div class="ultravisor-form-group"><label>Hash</label>';
115
+ tmpHTML += '<input type="text" id="Ultravisor-OperationEdit-Hash" value="' + this.escapeAttr(tmpOp.Hash) + '" readonly></div>';
116
+ }
134
117
 
135
118
  tmpHTML += '<div class="ultravisor-form-group"><label>Name</label>';
136
119
  tmpHTML += '<input type="text" id="Ultravisor-OperationEdit-Name" value="' + this.escapeAttr(tmpOp.Name || '') + '"></div>';
@@ -138,91 +121,53 @@ class UltravisorOperationEditView extends libPictView
138
121
  tmpHTML += '<div class="ultravisor-form-group"><label>Description</label>';
139
122
  tmpHTML += '<textarea id="Ultravisor-OperationEdit-Description">' + this.escapeHTML(tmpOp.Description || '') + '</textarea></div>';
140
123
 
141
- tmpHTML += '<div class="ultravisor-form-group"><label>Tasks (executed in order)</label>';
142
- tmpHTML += '<div class="ultravisor-task-list-editor">';
143
-
144
- let tmpTasks = tmpOp.Tasks || [];
145
- if (tmpTasks.length === 0)
146
- {
147
- tmpHTML += '<div style="color: #607d8b; font-size: 0.9em; padding: 0.5em;">No tasks added yet.</div>';
148
- }
149
- else
124
+ if (!tmpIsNew)
150
125
  {
151
- for (let i = 0; i < tmpTasks.length; i++)
152
- {
153
- let tmpEscTask = tmpTasks[i].replace(/'/g, "\\'");
154
- tmpHTML += '<div class="ultravisor-task-list-item">';
155
- tmpHTML += '<code>' + this.escapeHTML(tmpTasks[i]) + '</code>';
156
- tmpHTML += '<button class="ultravisor-btn-sm ultravisor-btn-delete" onclick="' + tmpViewRef + '.removeTaskFromOperation(' + i + ')">Remove</button>';
157
- tmpHTML += '</div>';
158
- }
126
+ tmpHTML += '<div class="ultravisor-form-group"><label>Graph</label>';
127
+ tmpHTML += '<p style="color:#78909c;">' + tmpNodeCount + ' node' + (tmpNodeCount !== 1 ? 's' : '') + ' in graph. Use the Flow Editor to modify the operation graph.</p>';
128
+ tmpHTML += '</div>';
159
129
  }
160
130
 
161
- tmpHTML += '<div class="ultravisor-task-list-add">';
162
- tmpHTML += '<input type="text" id="Ultravisor-OperationEdit-NewTaskGUID" placeholder="Task GUID to add...">';
163
- tmpHTML += '<button class="ultravisor-btn ultravisor-btn-secondary" onclick="' + tmpViewRef + '.addTaskToOperation()">Add</button>';
164
- tmpHTML += '</div>';
165
- tmpHTML += '</div></div>';
166
-
167
131
  tmpHTML += '<div class="ultravisor-form-actions">';
168
- tmpHTML += '<button class="ultravisor-btn ultravisor-btn-primary" onclick="' + tmpViewRef + '.saveOperation()">Save Operation</button>';
132
+ tmpHTML += '<button class="ultravisor-btn ultravisor-btn-primary" onclick="' + tmpViewRef + '.saveOperation()">Save Metadata</button>';
133
+ tmpHTML += '<button class="ultravisor-btn ultravisor-btn-primary" onclick="' + tmpViewRef + '.openFlowEditor()">Open in Flow Editor</button>';
169
134
  tmpHTML += '<button class="ultravisor-btn ultravisor-btn-secondary" onclick="' + tmpGlobalRef + '.PictApplication.navigateTo(\'/Operations\')">Cancel</button>';
170
135
  tmpHTML += '</div>';
171
136
 
172
137
  this.pict.ContentAssignment.assignContent('#Ultravisor-OperationEdit-Form', tmpHTML);
173
138
  }
174
139
 
175
- addTaskToOperation()
140
+ openFlowEditor()
176
141
  {
177
- let tmpInput = document.getElementById('Ultravisor-OperationEdit-NewTaskGUID');
178
- let tmpGUID = tmpInput ? tmpInput.value.trim() : '';
179
- if (!tmpGUID) return;
180
-
142
+ // Sync form values back to the model before navigating
181
143
  let tmpOp = this.pict.AppData.Ultravisor.CurrentEditOperation;
182
- if (!tmpOp.Tasks)
183
- {
184
- tmpOp.Tasks = [];
185
- }
186
- tmpOp.Tasks.push(tmpGUID);
187
-
188
- // Preserve current form field values before re-render
189
- tmpOp.GUIDOperation = document.getElementById('Ultravisor-OperationEdit-GUIDOperation').value.trim();
190
144
  tmpOp.Name = document.getElementById('Ultravisor-OperationEdit-Name').value.trim();
191
145
  tmpOp.Description = document.getElementById('Ultravisor-OperationEdit-Description').value.trim();
192
146
 
193
- this.renderForm();
194
- }
195
-
196
- removeTaskFromOperation(pIndex)
197
- {
198
- let tmpOp = this.pict.AppData.Ultravisor.CurrentEditOperation;
199
- if (tmpOp.Tasks && pIndex >= 0 && pIndex < tmpOp.Tasks.length)
147
+ // Load the graph into FlowEditor data
148
+ if (tmpOp.Graph)
200
149
  {
201
- tmpOp.Tasks.splice(pIndex, 1);
150
+ this.pict.AppData.Ultravisor.Flows.Current = JSON.parse(JSON.stringify(tmpOp.Graph));
202
151
  }
203
152
 
204
- // Preserve current form field values before re-render
205
- tmpOp.GUIDOperation = document.getElementById('Ultravisor-OperationEdit-GUIDOperation').value.trim();
206
- tmpOp.Name = document.getElementById('Ultravisor-OperationEdit-Name').value.trim();
207
- tmpOp.Description = document.getElementById('Ultravisor-OperationEdit-Description').value.trim();
208
-
209
- this.renderForm();
153
+ this.pict.PictApplication.navigateTo('/FlowEditor');
210
154
  }
211
155
 
212
156
  saveOperation()
213
157
  {
158
+ let tmpOp = this.pict.AppData.Ultravisor.CurrentEditOperation;
159
+
214
160
  let tmpOpData =
215
161
  {
216
- GUIDOperation: document.getElementById('Ultravisor-OperationEdit-GUIDOperation').value.trim(),
217
162
  Name: document.getElementById('Ultravisor-OperationEdit-Name').value.trim(),
218
163
  Description: document.getElementById('Ultravisor-OperationEdit-Description').value.trim(),
219
- Tasks: this.pict.AppData.Ultravisor.CurrentEditOperation.Tasks || []
164
+ Graph: tmpOp.Graph || { Nodes: [], Connections: [], ViewState: {} }
220
165
  };
221
166
 
222
- if (!tmpOpData.GUIDOperation)
167
+ let tmpHashEl = document.getElementById('Ultravisor-OperationEdit-Hash');
168
+ if (tmpHashEl)
223
169
  {
224
- alert('GUID Operation is required.');
225
- return;
170
+ tmpOpData.Hash = tmpHashEl.value.trim();
226
171
  }
227
172
 
228
173
  this.pict.PictApplication.saveOperation(tmpOpData,
@@ -1,5 +1,9 @@
1
1
  const libPictView = require('pict-view');
2
2
 
3
+ const libExampleCSVPipeline = require('../data/ExampleFlow-CSVPipeline.js');
4
+ const libExampleMeadowPipeline = require('../data/ExampleFlow-MeadowPipeline.js');
5
+ const libExampleFileProcessor = require('../data/ExampleFlow-FileProcessor.js');
6
+
3
7
  const _ViewConfiguration =
4
8
  {
5
9
  ViewIdentifier: "Ultravisor-OperationList",
@@ -39,7 +43,7 @@ const _ViewConfiguration =
39
43
  .ultravisor-operation-table tr:hover td {
40
44
  background-color: #1a2744;
41
45
  }
42
- .ultravisor-operation-task-count {
46
+ .ultravisor-operation-node-count {
43
47
  display: inline-block;
44
48
  padding: 0.15em 0.5em;
45
49
  border-radius: 3px;
@@ -58,9 +62,15 @@ const _ViewConfiguration =
58
62
  <div class="ultravisor-operationlist">
59
63
  <div class="ultravisor-operationlist-header">
60
64
  <h1>Operations</h1>
61
- <button class="ultravisor-btn ultravisor-btn-primary" onclick="{~P~}.PictApplication.editOperation()">New Operation</button>
65
+ <div>
66
+ <button class="ultravisor-btn ultravisor-btn-primary" onclick="{~P~}.PictApplication.editOperation()">New Operation</button>
67
+ <button class="ultravisor-btn ultravisor-btn-secondary" onclick="{~P~}.views['Ultravisor-OperationList'].createExampleOperation('CSVPipeline')">+ Config Processor</button>
68
+ <button class="ultravisor-btn ultravisor-btn-secondary" onclick="{~P~}.views['Ultravisor-OperationList'].createExampleOperation('MeadowPipeline')">+ Template Processor</button>
69
+ <button class="ultravisor-btn ultravisor-btn-secondary" onclick="{~P~}.views['Ultravisor-OperationList'].createExampleOperation('FileProcessor')">+ File Processor</button>
70
+ </div>
62
71
  </div>
63
72
  <div id="Ultravisor-OperationList-Body"></div>
73
+ <div id="Ultravisor-OperationList-Result"></div>
64
74
  </div>
65
75
  `
66
76
  }
@@ -108,25 +118,25 @@ class UltravisorOperationListView extends libPictView
108
118
  }
109
119
 
110
120
  let tmpHTML = '<table class="ultravisor-operation-table">';
111
- tmpHTML += '<thead><tr><th>GUID</th><th>Name</th><th>Tasks</th><th>Actions</th></tr></thead>';
121
+ tmpHTML += '<thead><tr><th>Hash</th><th>Name</th><th>Nodes</th><th>Actions</th></tr></thead>';
112
122
  tmpHTML += '<tbody>';
113
123
 
114
124
  for (let i = 0; i < tmpOpList.length; i++)
115
125
  {
116
126
  let tmpOp = tmpOpList[i];
117
- let tmpGUID = tmpOp.GUIDOperation || '';
118
- let tmpName = tmpOp.Name || tmpGUID;
119
- let tmpTaskCount = (tmpOp.Tasks && Array.isArray(tmpOp.Tasks)) ? tmpOp.Tasks.length : 0;
120
- let tmpEscGUID = tmpGUID.replace(/'/g, "\\'");
127
+ let tmpHash = tmpOp.Hash || '';
128
+ let tmpName = tmpOp.Name || tmpHash;
129
+ let tmpNodeCount = (tmpOp.Graph && tmpOp.Graph.Nodes) ? tmpOp.Graph.Nodes.length : 0;
130
+ let tmpEscHash = tmpHash.replace(/'/g, "\\'");
121
131
 
122
132
  tmpHTML += '<tr>';
123
- tmpHTML += '<td><code>' + tmpGUID + '</code></td>';
124
- tmpHTML += '<td>' + tmpName + '</td>';
125
- tmpHTML += '<td><span class="ultravisor-operation-task-count">' + tmpTaskCount + ' task' + (tmpTaskCount !== 1 ? 's' : '') + '</span></td>';
133
+ tmpHTML += '<td><code>' + this.escapeHTML(tmpHash) + '</code></td>';
134
+ tmpHTML += '<td>' + this.escapeHTML(tmpName) + '</td>';
135
+ tmpHTML += '<td><span class="ultravisor-operation-node-count">' + tmpNodeCount + ' node' + (tmpNodeCount !== 1 ? 's' : '') + '</span></td>';
126
136
  tmpHTML += '<td><div class="ultravisor-task-actions">';
127
- tmpHTML += '<button class="ultravisor-btn-sm ultravisor-btn-execute" onclick="' + tmpGlobalRef + '.PictApplication.executeOperation(\'' + tmpEscGUID + '\', function(pErr, pData){ alert(pErr ? \'Error: \'+pErr.message : \'Operation executed. Status: \'+(pData&&pData.Status||\'Done\')); })">Run</button>';
128
- tmpHTML += '<button class="ultravisor-btn-sm ultravisor-btn-edit" onclick="' + tmpGlobalRef + '.PictApplication.editOperation(\'' + tmpEscGUID + '\')">Edit</button>';
129
- tmpHTML += '<button class="ultravisor-btn-sm ultravisor-btn-delete" onclick="if(confirm(\'Delete operation ' + tmpEscGUID + '?\')){ ' + tmpGlobalRef + '.PictApplication.deleteOperation(\'' + tmpEscGUID + '\', function(){ ' + tmpGlobalRef + '.PictApplication.showView(\'Ultravisor-OperationList\'); }); }">Delete</button>';
137
+ tmpHTML += '<button class="ultravisor-btn-sm ultravisor-btn-execute" onclick="' + tmpGlobalRef + '.views[\'Ultravisor-OperationList\'].runOperation(\'' + tmpEscHash + '\')">Run</button>';
138
+ tmpHTML += '<button class="ultravisor-btn-sm ultravisor-btn-edit" onclick="' + tmpGlobalRef + '.PictApplication.editOperation(\'' + tmpEscHash + '\')">Edit</button>';
139
+ tmpHTML += '<button class="ultravisor-btn-sm ultravisor-btn-delete" onclick="if(confirm(\'Delete operation ' + tmpEscHash + '?\')){ ' + tmpGlobalRef + '.PictApplication.deleteOperation(\'' + tmpEscHash + '\', function(){ ' + tmpGlobalRef + '.PictApplication.showView(\'Ultravisor-OperationList\'); }); }">Delete</button>';
130
140
  tmpHTML += '</div></td>';
131
141
  tmpHTML += '</tr>';
132
142
  }
@@ -134,6 +144,111 @@ class UltravisorOperationListView extends libPictView
134
144
  tmpHTML += '</tbody></table>';
135
145
  this.pict.ContentAssignment.assignContent('#Ultravisor-OperationList-Body', tmpHTML);
136
146
  }
147
+
148
+ runOperation(pHash)
149
+ {
150
+ this.pict.ContentAssignment.assignContent('#Ultravisor-OperationList-Result',
151
+ '<div class="ultravisor-task-result-panel"><h3>Running operation ' + this.escapeHTML(pHash) + '...</h3></div>');
152
+
153
+ this.pict.PictApplication.executeOperation(pHash,
154
+ function (pError, pData)
155
+ {
156
+ if (pError)
157
+ {
158
+ this.pict.ContentAssignment.assignContent('#Ultravisor-OperationList-Result',
159
+ '<div class="ultravisor-task-result-panel"><h3>Error</h3><p style="color:#ef5350;">' + this.escapeHTML(pError.message) + '</p></div>');
160
+ return;
161
+ }
162
+
163
+ let tmpHTML = '<div class="ultravisor-task-result-panel">';
164
+ tmpHTML += '<h3>Operation Result: ' + this.escapeHTML(pHash) + '</h3>';
165
+ tmpHTML += '<p><strong>Status:</strong> <span class="ultravisor-manifest-status ' + (pData.Status || '').toLowerCase() + '">' + this.escapeHTML(pData.Status || '') + '</span></p>';
166
+ tmpHTML += '<p><strong>Start:</strong> ' + this.escapeHTML(pData.StartTime || '') + ' &middot; <strong>Stop:</strong> ' + this.escapeHTML(pData.StopTime || '') + '</p>';
167
+ tmpHTML += '<p><strong>Elapsed:</strong> ' + (pData.ElapsedMs || 0) + 'ms</p>';
168
+
169
+ if (pData.TaskOutputs)
170
+ {
171
+ tmpHTML += '<h4 style="color:#b0bec5; margin:0.75em 0 0.25em 0;">Task Outputs</h4>';
172
+ tmpHTML += '<div class="ultravisor-task-result-output">' + this.escapeHTML(JSON.stringify(pData.TaskOutputs, null, 2)) + '</div>';
173
+ }
174
+
175
+ if (pData.Log && pData.Log.length > 0)
176
+ {
177
+ tmpHTML += '<h4 style="color:#b0bec5; margin:0.75em 0 0.25em 0;">Log</h4>';
178
+ tmpHTML += '<div class="ultravisor-task-result-output">' + this.escapeHTML(pData.Log.join('\n')) + '</div>';
179
+ }
180
+
181
+ tmpHTML += '</div>';
182
+ this.pict.ContentAssignment.assignContent('#Ultravisor-OperationList-Result', tmpHTML);
183
+ }.bind(this));
184
+ }
185
+
186
+ createExampleOperation(pExampleName)
187
+ {
188
+ let tmpFlowData = null;
189
+ let tmpName = '';
190
+ let tmpDescription = '';
191
+
192
+ if (pExampleName === 'CSVPipeline')
193
+ {
194
+ tmpFlowData = libExampleCSVPipeline;
195
+ tmpName = 'Example: Config Processor';
196
+ tmpDescription = 'File-based config processing with branching and error handling.';
197
+ }
198
+ else if (pExampleName === 'MeadowPipeline')
199
+ {
200
+ tmpFlowData = libExampleMeadowPipeline;
201
+ tmpName = 'Example: Template Processor';
202
+ tmpDescription = 'Multi-step text processing with chained replacements and conditional validation.';
203
+ }
204
+ else if (pExampleName === 'FileProcessor')
205
+ {
206
+ tmpFlowData = libExampleFileProcessor;
207
+ tmpName = 'Example: File Processor';
208
+ tmpDescription = 'Search and replace pipeline with user input, looping, and file I/O.';
209
+ }
210
+
211
+ if (!tmpFlowData)
212
+ {
213
+ return;
214
+ }
215
+
216
+ let tmpOpData =
217
+ {
218
+ Name: tmpName,
219
+ Description: tmpDescription,
220
+ Graph:
221
+ {
222
+ Nodes: JSON.parse(JSON.stringify(tmpFlowData.Nodes)),
223
+ Connections: JSON.parse(JSON.stringify(tmpFlowData.Connections)),
224
+ ViewState: tmpFlowData.ViewState ? JSON.parse(JSON.stringify(tmpFlowData.ViewState)) : {}
225
+ }
226
+ };
227
+
228
+ this.pict.PictApplication.saveOperation(tmpOpData,
229
+ function (pError, pData)
230
+ {
231
+ if (pError)
232
+ {
233
+ this.pict.ContentAssignment.assignContent('#Ultravisor-OperationList-Result',
234
+ '<div class="ultravisor-task-result-panel"><p style="color:#ef5350;">Error creating example: ' + this.escapeHTML(pError.message) + '</p></div>');
235
+ return;
236
+ }
237
+
238
+ // Reload the operation list
239
+ this.pict.PictApplication.loadOperations(
240
+ function ()
241
+ {
242
+ this.renderOperationTable();
243
+ }.bind(this));
244
+ }.bind(this));
245
+ }
246
+
247
+ escapeHTML(pValue)
248
+ {
249
+ if (!pValue) return '';
250
+ return String(pValue).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
251
+ }
137
252
  }
138
253
 
139
254
  module.exports = UltravisorOperationListView;