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
@@ -1,5 +1,7 @@
1
1
  const libPictView = require('pict-view');
2
2
 
3
+ const libTimingUtils = require('../Ultravisor-TimingUtils.js');
4
+
3
5
  const _ViewConfiguration =
4
6
  {
5
7
  ViewIdentifier: "Ultravisor-TimingView",
@@ -21,13 +23,13 @@ const _ViewConfiguration =
21
23
  align-items: center;
22
24
  margin-bottom: 1.5em;
23
25
  padding-bottom: 1em;
24
- border-bottom: 1px solid #2a2a4a;
26
+ border-bottom: 1px solid var(--uv-border-subtle);
25
27
  }
26
28
  .ultravisor-timing-header h1 {
27
29
  margin: 0;
28
30
  font-size: 2em;
29
31
  font-weight: 300;
30
- color: #e0e0e0;
32
+ color: var(--uv-text);
31
33
  }
32
34
  .ultravisor-timing-selector {
33
35
  margin-bottom: 1.5em;
@@ -38,8 +40,8 @@ const _ViewConfiguration =
38
40
  padding: 0.6em 0.75em;
39
41
  }
40
42
  .ultravisor-timing-card {
41
- background: #16213e;
42
- border: 1px solid #2a2a4a;
43
+ background: var(--uv-bg-surface);
44
+ border: 1px solid var(--uv-border-subtle);
43
45
  border-radius: 8px;
44
46
  padding: 1.5em;
45
47
  margin-bottom: 1.5em;
@@ -58,19 +60,19 @@ const _ViewConfiguration =
58
60
  font-size: 0.75em;
59
61
  text-transform: uppercase;
60
62
  letter-spacing: 0.05em;
61
- color: #9e9ec0;
63
+ color: var(--uv-text-secondary);
62
64
  margin-bottom: 0.25em;
63
65
  }
64
66
  .ultravisor-timing-stat-value {
65
67
  font-size: 1.2em;
66
68
  font-weight: 600;
67
- color: #e0e0e0;
69
+ color: var(--uv-text);
68
70
  }
69
71
  .ultravisor-timing-stat-value.complete {
70
- color: #66bb6a;
72
+ color: var(--uv-success);
71
73
  }
72
74
  .ultravisor-timing-stat-value.error {
73
- color: #ef5350;
75
+ color: var(--uv-error);
74
76
  }
75
77
  .ultravisor-timing-chart {
76
78
  margin-top: 1.5em;
@@ -79,7 +81,7 @@ const _ViewConfiguration =
79
81
  font-size: 0.85em;
80
82
  text-transform: uppercase;
81
83
  letter-spacing: 0.05em;
82
- color: #9e9ec0;
84
+ color: var(--uv-text-secondary);
83
85
  margin-bottom: 1em;
84
86
  }
85
87
  .ultravisor-timing-row {
@@ -91,7 +93,7 @@ const _ViewConfiguration =
91
93
  width: 180px;
92
94
  flex-shrink: 0;
93
95
  font-size: 0.85em;
94
- color: #b0bec5;
96
+ color: var(--uv-text-secondary);
95
97
  white-space: nowrap;
96
98
  overflow: hidden;
97
99
  text-overflow: ellipsis;
@@ -100,7 +102,7 @@ const _ViewConfiguration =
100
102
  .ultravisor-timing-row-bar-container {
101
103
  flex: 1;
102
104
  height: 28px;
103
- background: #1a1a2e;
105
+ background: var(--uv-bg-base);
104
106
  border-radius: 4px;
105
107
  position: relative;
106
108
  overflow: hidden;
@@ -121,26 +123,34 @@ const _ViewConfiguration =
121
123
  background: linear-gradient(90deg, #c62828, #e53935);
122
124
  }
123
125
  .ultravisor-timing-row-bar.running {
124
- background: linear-gradient(90deg, #1565c0, #1e88e5);
126
+ background: linear-gradient(90deg, var(--uv-info), #1e88e5);
125
127
  }
126
128
  .ultravisor-timing-row-bar.other {
127
- background: linear-gradient(90deg, #37474f, #546e7a);
129
+ background: linear-gradient(90deg, var(--uv-btn-secondary-bg), #546e7a);
128
130
  }
129
131
  .ultravisor-timing-row-bar-text {
130
132
  font-size: 0.75em;
131
133
  color: #fff;
132
134
  white-space: nowrap;
133
- text-shadow: 0 1px 2px rgba(0,0,0,0.5);
135
+ text-shadow: 0 1px 2px var(--uv-shadow-heavy);
134
136
  }
135
137
  .ultravisor-timing-row-duration {
136
138
  width: 120px;
137
139
  flex-shrink: 0;
138
140
  font-size: 0.8em;
139
- color: #78909c;
141
+ color: var(--uv-text-secondary);
140
142
  text-align: right;
141
143
  padding-left: 0.75em;
142
144
  font-family: monospace;
143
145
  }
146
+ .ultravisor-timing-row-count {
147
+ width: 60px;
148
+ flex-shrink: 0;
149
+ font-size: 0.75em;
150
+ color: var(--uv-text-secondary);
151
+ text-align: right;
152
+ padding-left: 0.5em;
153
+ }
144
154
  .ultravisor-timing-axis {
145
155
  display: flex;
146
156
  align-items: center;
@@ -151,12 +161,12 @@ const _ViewConfiguration =
151
161
  flex: 1;
152
162
  display: flex;
153
163
  justify-content: space-between;
154
- border-top: 1px solid #3a3a5c;
164
+ border-top: 1px solid var(--uv-border);
155
165
  padding-top: 0.35em;
156
166
  }
157
167
  .ultravisor-timing-axis-tick {
158
168
  font-size: 0.7em;
159
- color: #616161;
169
+ color: var(--uv-text-tertiary);
160
170
  font-family: monospace;
161
171
  }
162
172
  .ultravisor-timing-axis-spacer {
@@ -166,9 +176,56 @@ const _ViewConfiguration =
166
176
  .ultravisor-timing-empty {
167
177
  text-align: center;
168
178
  padding: 3em;
169
- color: #616161;
179
+ color: var(--uv-text-tertiary);
170
180
  font-style: italic;
171
181
  }
182
+ .ultravisor-timing-verbosity-controls {
183
+ display: flex;
184
+ gap: 0.5em;
185
+ margin-bottom: 1em;
186
+ }
187
+ .ultravisor-timing-verbosity-btn {
188
+ padding: 0.35em 0.75em;
189
+ border: 1px solid var(--uv-border);
190
+ border-radius: 4px;
191
+ background: transparent;
192
+ color: var(--uv-text-secondary);
193
+ font-size: 0.8em;
194
+ cursor: pointer;
195
+ }
196
+ .ultravisor-timing-verbosity-btn.active {
197
+ background: #1e3a5f;
198
+ border-color: #42a5f5;
199
+ color: #90caf9;
200
+ }
201
+ .ultravisor-timing-eventlog-table {
202
+ width: 100%;
203
+ border-collapse: collapse;
204
+ font-size: 0.8em;
205
+ }
206
+ .ultravisor-timing-eventlog-table th {
207
+ text-align: left;
208
+ padding: 0.5em 0.75em;
209
+ background: #0d1b2a;
210
+ color: var(--uv-text-secondary);
211
+ border-bottom: 1px solid var(--uv-border-subtle);
212
+ font-weight: 600;
213
+ text-transform: uppercase;
214
+ font-size: 0.85em;
215
+ letter-spacing: 0.05em;
216
+ }
217
+ .ultravisor-timing-eventlog-table td {
218
+ padding: 0.4em 0.75em;
219
+ border-bottom: 1px solid var(--uv-bg-base);
220
+ color: var(--uv-text-secondary);
221
+ font-family: monospace;
222
+ }
223
+ .ultravisor-timing-eventlog-table tr:hover td {
224
+ background: #1a2744;
225
+ }
226
+ .ultravisor-timing-eventlog-v0 { color: var(--uv-text); }
227
+ .ultravisor-timing-eventlog-v1 { color: var(--uv-text-secondary); }
228
+ .ultravisor-timing-eventlog-v2 { color: #546e7a; }
172
229
  `,
173
230
 
174
231
  Templates:
@@ -185,6 +242,10 @@ const _ViewConfiguration =
185
242
  <div id="Ultravisor-Timing-Detail"></div>
186
243
  </div>
187
244
  `
245
+ },
246
+ {
247
+ Hash: "Ultravisor-Timing-Row-Template",
248
+ Template: /*html*/`<div class="ultravisor-timing-row"><div class="ultravisor-timing-row-label" title="{~D:Record.LabelTitle~}" style="{~D:Record.LabelStyle~}">{~D:Record.Label~}</div><div class="ultravisor-timing-row-bar-container"><div class="ultravisor-timing-row-bar {~D:Record.BarClass~}" style="width: {~D:Record.WidthPercent~}%;{~D:Record.BarStyle~}">{~D:Record.BarText~}</div></div><div class="ultravisor-timing-row-duration">{~D:Record.Duration~}</div>{~D:Record.CountHTML~}</div>`
188
249
  }
189
250
  ],
190
251
 
@@ -204,6 +265,9 @@ class UltravisorTimingView extends libPictView
204
265
  constructor(pFable, pOptions, pServiceHash)
205
266
  {
206
267
  super(pFable, pOptions, pServiceHash);
268
+
269
+ this._currentVerbosity = 0;
270
+ this._currentManifest = null;
207
271
  }
208
272
 
209
273
  onAfterRender(pRenderable, pRenderDestinationAddress, pRecord, pContent)
@@ -235,45 +299,61 @@ class UltravisorTimingView extends libPictView
235
299
  for (let i = tmpManifests.length - 1; i >= 0; i--)
236
300
  {
237
301
  let tmpManifest = tmpManifests[i];
238
- let tmpGUIDRun = tmpManifest.GUIDRun || '';
239
- let tmpLabel = (tmpManifest.Name || tmpManifest.GUIDOperation || tmpGUIDRun);
302
+ let tmpRunHash = tmpManifest.Hash || '';
303
+ let tmpLabel = (tmpManifest.OperationHash || tmpRunHash);
240
304
  let tmpStatus = tmpManifest.Status || 'Unknown';
241
305
  let tmpTime = tmpManifest.StartTime ? tmpManifest.StartTime.replace('T', ' ').replace(/\.\d+Z$/, '') : '';
242
- tmpHTML += '<option value="' + this.escapeHTML(tmpGUIDRun) + '">' + this.escapeHTML(tmpLabel) + ' [' + tmpStatus + '] ' + tmpTime + '</option>';
306
+ tmpHTML += '<option value="' + libTimingUtils.escapeHTML(tmpRunHash) + '">' + libTimingUtils.escapeHTML(tmpLabel) + ' [' + tmpStatus + '] ' + tmpTime + '</option>';
243
307
  }
244
308
 
245
309
  tmpHTML += '</select>';
246
310
  this.pict.ContentAssignment.assignContent('#Ultravisor-Timing-Selector', tmpHTML);
247
311
  }
248
312
 
249
- onSelectManifest(pGUIDRun)
313
+ onSelectManifest(pRunHash)
250
314
  {
251
- if (!pGUIDRun)
315
+ if (!pRunHash)
252
316
  {
253
317
  this.pict.ContentAssignment.assignContent('#Ultravisor-Timing-Detail', '');
254
318
  return;
255
319
  }
256
320
 
257
- this.pict.PictApplication.loadManifest(pGUIDRun,
321
+ this.pict.PictApplication.loadManifest(pRunHash,
258
322
  function (pError, pManifest)
259
323
  {
260
324
  if (pError || !pManifest)
261
325
  {
262
326
  this.pict.ContentAssignment.assignContent('#Ultravisor-Timing-Detail',
263
- '<div class="ultravisor-timing-card"><p style="color:#ef5350;">Error loading manifest details.</p></div>');
327
+ '<div class="ultravisor-timing-card"><p style="color:var(--uv-error);">Error loading manifest details.</p></div>');
264
328
  return;
265
329
  }
266
330
 
331
+ this._currentManifest = pManifest;
332
+ this._currentVerbosity = 0;
267
333
  this.renderTimingVisualization(pManifest);
268
334
  }.bind(this));
269
335
  }
270
336
 
271
337
  renderTimingVisualization(pManifest)
272
338
  {
273
- let tmpTaskResults = pManifest.TaskResults || [];
339
+ // Convert TaskManifests object to an array for visualization
340
+ let tmpTaskResults = [];
341
+ if (pManifest.TaskManifests && typeof pManifest.TaskManifests === 'object')
342
+ {
343
+ let tmpKeys = Object.keys(pManifest.TaskManifests);
344
+ for (let k = 0; k < tmpKeys.length; k++)
345
+ {
346
+ let tmpEntry = pManifest.TaskManifests[tmpKeys[k]];
347
+ tmpEntry._NodeHash = tmpKeys[k];
348
+ tmpEntry._ComputedElapsedMs = libTimingUtils.computeTaskElapsedMs(tmpEntry);
349
+ tmpEntry._ComputedStatus = libTimingUtils.computeTaskStatus(tmpEntry);
350
+ tmpTaskResults.push(tmpEntry);
351
+ }
352
+ }
353
+
274
354
  let tmpOperationElapsedMs = pManifest.ElapsedMs || 0;
275
- let tmpOperationElapsedFormatted = pManifest.ElapsedFormatted || this.formatMs(tmpOperationElapsedMs);
276
- let tmpAverageTaskMs = pManifest.AverageTaskMs || 0;
355
+ let tmpOperationElapsedFormatted = libTimingUtils.formatMs(tmpOperationElapsedMs);
356
+ let tmpAverageTaskMs = 0;
277
357
  let tmpStatus = (pManifest.Status || 'Unknown').toLowerCase();
278
358
  let tmpStatusClass = (tmpStatus === 'complete' || tmpStatus === 'error' || tmpStatus === 'running') ? tmpStatus : '';
279
359
 
@@ -282,13 +362,13 @@ class UltravisorTimingView extends libPictView
282
362
  {
283
363
  for (let i = 0; i < tmpTaskResults.length; i++)
284
364
  {
285
- tmpOperationElapsedMs += (tmpTaskResults[i].ElapsedMs || 0);
365
+ tmpOperationElapsedMs += tmpTaskResults[i]._ComputedElapsedMs;
286
366
  }
287
- tmpOperationElapsedFormatted = this.formatMs(tmpOperationElapsedMs);
367
+ tmpOperationElapsedFormatted = libTimingUtils.formatMs(tmpOperationElapsedMs);
288
368
  }
289
369
 
290
- // Compute average if not provided
291
- if (tmpAverageTaskMs <= 0 && tmpTaskResults.length > 0 && tmpOperationElapsedMs > 0)
370
+ // Compute average
371
+ if (tmpTaskResults.length > 0 && tmpOperationElapsedMs > 0)
292
372
  {
293
373
  tmpAverageTaskMs = tmpOperationElapsedMs / tmpTaskResults.length;
294
374
  }
@@ -297,7 +377,7 @@ class UltravisorTimingView extends libPictView
297
377
  let tmpMaxTaskMs = 0;
298
378
  for (let i = 0; i < tmpTaskResults.length; i++)
299
379
  {
300
- let tmpMs = tmpTaskResults[i].ElapsedMs || 0;
380
+ let tmpMs = tmpTaskResults[i]._ComputedElapsedMs;
301
381
  if (tmpMs > tmpMaxTaskMs)
302
382
  {
303
383
  tmpMaxTaskMs = tmpMs;
@@ -308,18 +388,19 @@ class UltravisorTimingView extends libPictView
308
388
  tmpMaxTaskMs = 1;
309
389
  }
310
390
 
311
- let tmpHTML = '<div class="ultravisor-timing-card">';
391
+ let tmpHTML = '';
312
392
 
313
- // Summary header
393
+ // ---- Summary Card ----
394
+ tmpHTML += '<div class="ultravisor-timing-card">';
314
395
  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>';
316
- 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
- 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>';
396
+ tmpHTML += '<div class="ultravisor-timing-stat"><span class="ultravisor-timing-stat-label">Operation</span><span class="ultravisor-timing-stat-value">' + libTimingUtils.escapeHTML(pManifest.OperationHash || '') + '</span></div>';
397
+ tmpHTML += '<div class="ultravisor-timing-stat"><span class="ultravisor-timing-stat-label">Status</span><span class="ultravisor-timing-stat-value ' + tmpStatusClass + '">' + libTimingUtils.escapeHTML(pManifest.Status || 'Unknown') + '</span></div>';
398
+ tmpHTML += '<div class="ultravisor-timing-stat"><span class="ultravisor-timing-stat-label">Total Time</span><span class="ultravisor-timing-stat-value">' + libTimingUtils.escapeHTML(tmpOperationElapsedFormatted) + '</span></div>';
318
399
  tmpHTML += '<div class="ultravisor-timing-stat"><span class="ultravisor-timing-stat-label">Tasks</span><span class="ultravisor-timing-stat-value">' + tmpTaskResults.length + '</span></div>';
319
- tmpHTML += '<div class="ultravisor-timing-stat"><span class="ultravisor-timing-stat-label">Avg per Task</span><span class="ultravisor-timing-stat-value">' + this.formatMs(tmpAverageTaskMs) + '</span></div>';
400
+ tmpHTML += '<div class="ultravisor-timing-stat"><span class="ultravisor-timing-stat-label">Avg per Task</span><span class="ultravisor-timing-stat-value">' + libTimingUtils.formatMs(tmpAverageTaskMs) + '</span></div>';
320
401
  tmpHTML += '</div>';
321
402
 
322
- // Timeline chart
403
+ // ---- Task Timeline ----
323
404
  if (tmpTaskResults.length === 0)
324
405
  {
325
406
  tmpHTML += '<div class="ultravisor-timing-empty">No task results in this manifest.</div>';
@@ -332,9 +413,9 @@ class UltravisorTimingView extends libPictView
332
413
  for (let i = 0; i < tmpTaskResults.length; i++)
333
414
  {
334
415
  let tmpResult = tmpTaskResults[i];
335
- let tmpTaskMs = tmpResult.ElapsedMs || 0;
336
- let tmpTaskFormatted = tmpResult.ElapsedFormatted || this.formatMs(tmpTaskMs);
337
- let tmpTaskStatus = (tmpResult.Status || 'Unknown').toLowerCase();
416
+ let tmpTaskMs = tmpResult._ComputedElapsedMs;
417
+ let tmpTaskFormatted = libTimingUtils.formatMs(tmpTaskMs);
418
+ let tmpTaskStatus = tmpResult._ComputedStatus.toLowerCase();
338
419
  let tmpBarClass = 'other';
339
420
  if (tmpTaskStatus === 'complete')
340
421
  {
@@ -350,20 +431,22 @@ class UltravisorTimingView extends libPictView
350
431
  }
351
432
 
352
433
  let tmpWidthPercent = (tmpMaxTaskMs > 0) ? Math.max((tmpTaskMs / tmpMaxTaskMs) * 100, 1) : 1;
353
- let tmpBarLabel = this.escapeHTML(tmpResult.Name || tmpResult.GUIDTask || '');
434
+ let tmpNodeHash = tmpResult._NodeHash || '';
435
+ let tmpDisplayName = tmpResult.TaskTypeName || tmpResult._NodeHash || 'Task ' + (i + 1);
354
436
 
355
- 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>';
357
- tmpHTML += '<div class="ultravisor-timing-row-bar-container">';
358
- tmpHTML += '<div class="ultravisor-timing-row-bar ' + tmpBarClass + '" style="width: ' + tmpWidthPercent.toFixed(1) + '%;">';
359
- if (tmpWidthPercent > 20)
437
+ let tmpRowData =
360
438
  {
361
- tmpHTML += '<span class="ultravisor-timing-row-bar-text">' + tmpBarLabel + '</span>';
362
- }
363
- tmpHTML += '</div>';
364
- tmpHTML += '</div>';
365
- tmpHTML += '<div class="ultravisor-timing-row-duration">' + this.escapeHTML(tmpTaskFormatted) + '</div>';
366
- tmpHTML += '</div>';
439
+ Label: libTimingUtils.escapeHTML(tmpDisplayName),
440
+ LabelTitle: libTimingUtils.escapeHTML(tmpNodeHash),
441
+ LabelStyle: '',
442
+ BarClass: tmpBarClass,
443
+ BarStyle: '',
444
+ WidthPercent: tmpWidthPercent.toFixed(1),
445
+ BarText: (tmpWidthPercent > 20) ? '<span class="ultravisor-timing-row-bar-text">' + libTimingUtils.escapeHTML(tmpDisplayName) + '</span>' : '',
446
+ Duration: libTimingUtils.escapeHTML(tmpTaskFormatted),
447
+ CountHTML: ''
448
+ };
449
+ tmpHTML += this.pict.parseTemplateByHash('Ultravisor-Timing-Row-Template', tmpRowData);
367
450
  }
368
451
 
369
452
  // Time axis
@@ -373,7 +456,7 @@ class UltravisorTimingView extends libPictView
373
456
  for (let t = 0; t <= tmpTickCount; t++)
374
457
  {
375
458
  let tmpTickMs = (tmpMaxTaskMs / tmpTickCount) * t;
376
- tmpHTML += '<span class="ultravisor-timing-axis-tick">' + this.formatMs(tmpTickMs) + '</span>';
459
+ tmpHTML += '<span class="ultravisor-timing-axis-tick">' + libTimingUtils.formatMs(tmpTickMs) + '</span>';
377
460
  }
378
461
  tmpHTML += '</div>';
379
462
  tmpHTML += '<div class="ultravisor-timing-axis-spacer"></div>';
@@ -384,34 +467,213 @@ class UltravisorTimingView extends libPictView
384
467
 
385
468
  tmpHTML += '</div>';
386
469
 
470
+ // ---- Category Histogram ----
471
+ if (pManifest.TimingSummary && pManifest.TimingSummary.ByCategory)
472
+ {
473
+ tmpHTML += this._renderCategoryHistogram(pManifest.TimingSummary.ByCategory);
474
+ }
475
+
476
+ // ---- Task Type Histogram ----
477
+ if (pManifest.TimingSummary && pManifest.TimingSummary.ByTaskType)
478
+ {
479
+ tmpHTML += this._renderTaskTypeHistogram(pManifest.TimingSummary.ByTaskType);
480
+ }
481
+
482
+ // ---- Event Log Panel ----
483
+ if (pManifest.EventLog && pManifest.EventLog.length > 0)
484
+ {
485
+ tmpHTML += this._renderEventLogPanel(pManifest);
486
+ }
487
+
387
488
  this.pict.ContentAssignment.assignContent('#Ultravisor-Timing-Detail', tmpHTML);
388
489
  }
389
490
 
390
- formatMs(pMs)
491
+ _renderCategoryHistogram(pByCategory)
492
+ {
493
+ let tmpCategories = Object.keys(pByCategory);
494
+ if (tmpCategories.length === 0)
495
+ {
496
+ return '';
497
+ }
498
+
499
+ // Sort by TotalMs descending
500
+ tmpCategories.sort(function (pA, pB)
501
+ {
502
+ return (pByCategory[pB].TotalMs || 0) - (pByCategory[pA].TotalMs || 0);
503
+ });
504
+
505
+ let tmpMaxMs = pByCategory[tmpCategories[0]].TotalMs || 1;
506
+
507
+ let tmpHTML = '<div class="ultravisor-timing-card">';
508
+ tmpHTML += '<div class="ultravisor-timing-chart">';
509
+ tmpHTML += '<div class="ultravisor-timing-chart-title">Time by Category</div>';
510
+
511
+ for (let i = 0; i < tmpCategories.length; i++)
512
+ {
513
+ let tmpCat = tmpCategories[i];
514
+ let tmpData = pByCategory[tmpCat];
515
+ let tmpMs = tmpData.TotalMs || 0;
516
+ let tmpWidthPercent = Math.max((tmpMs / tmpMaxMs) * 100, 1);
517
+ let tmpColors = libTimingUtils.CategoryColors[tmpCat] || libTimingUtils.CategoryColors['Uncategorized'];
518
+
519
+ let tmpRowData =
520
+ {
521
+ Label: libTimingUtils.escapeHTML(tmpCat),
522
+ LabelTitle: '',
523
+ LabelStyle: 'color:' + tmpColors.text + ';',
524
+ BarClass: '',
525
+ BarStyle: ' background: ' + tmpColors.bar + ';',
526
+ WidthPercent: tmpWidthPercent.toFixed(1),
527
+ BarText: (tmpWidthPercent > 15) ? '<span class="ultravisor-timing-row-bar-text">' + libTimingUtils.formatMs(tmpMs) + '</span>' : '',
528
+ Duration: libTimingUtils.formatMs(tmpMs),
529
+ CountHTML: '<div class="ultravisor-timing-row-count">' + tmpData.Count + 'x</div>'
530
+ };
531
+ tmpHTML += this.pict.parseTemplateByHash('Ultravisor-Timing-Row-Template', tmpRowData);
532
+ }
533
+
534
+ tmpHTML += '</div>';
535
+ tmpHTML += '</div>';
536
+ return tmpHTML;
537
+ }
538
+
539
+ _renderTaskTypeHistogram(pByTaskType)
391
540
  {
392
- if (typeof pMs !== 'number' || pMs <= 0)
541
+ let tmpTypes = Object.keys(pByTaskType);
542
+ if (tmpTypes.length === 0)
393
543
  {
394
- return '0ms';
544
+ return '';
395
545
  }
396
- if (pMs < 1000)
546
+
547
+ // Sort by TotalMs descending
548
+ tmpTypes.sort(function (pA, pB)
549
+ {
550
+ return (pByTaskType[pB].TotalMs || 0) - (pByTaskType[pA].TotalMs || 0);
551
+ });
552
+
553
+ let tmpMaxMs = pByTaskType[tmpTypes[0]].TotalMs || 1;
554
+
555
+ let tmpHTML = '<div class="ultravisor-timing-card">';
556
+ tmpHTML += '<div class="ultravisor-timing-chart">';
557
+ tmpHTML += '<div class="ultravisor-timing-chart-title">Time by Task Type</div>';
558
+
559
+ for (let i = 0; i < tmpTypes.length; i++)
397
560
  {
398
- return Math.round(pMs) + 'ms';
561
+ let tmpType = tmpTypes[i];
562
+ let tmpData = pByTaskType[tmpType];
563
+ let tmpMs = tmpData.TotalMs || 0;
564
+ let tmpWidthPercent = Math.max((tmpMs / tmpMaxMs) * 100, 1);
565
+ let tmpCategory = tmpData.Category || 'Uncategorized';
566
+ let tmpColors = libTimingUtils.CategoryColors[tmpCategory] || libTimingUtils.CategoryColors['Uncategorized'];
567
+ let tmpDisplayName = tmpData.Name || tmpType;
568
+
569
+ let tmpRowData =
570
+ {
571
+ Label: libTimingUtils.escapeHTML(tmpDisplayName),
572
+ LabelTitle: libTimingUtils.escapeHTML(tmpType),
573
+ LabelStyle: '',
574
+ BarClass: '',
575
+ BarStyle: ' background: ' + tmpColors.bar + ';',
576
+ WidthPercent: tmpWidthPercent.toFixed(1),
577
+ BarText: (tmpWidthPercent > 15) ? '<span class="ultravisor-timing-row-bar-text">' + libTimingUtils.formatMs(tmpMs) + '</span>' : '',
578
+ Duration: libTimingUtils.formatMs(tmpMs),
579
+ CountHTML: '<div class="ultravisor-timing-row-count">' + tmpData.Count + 'x</div>'
580
+ };
581
+ tmpHTML += this.pict.parseTemplateByHash('Ultravisor-Timing-Row-Template', tmpRowData);
399
582
  }
400
- if (pMs < 60000)
583
+
584
+ tmpHTML += '</div>';
585
+ tmpHTML += '</div>';
586
+ return tmpHTML;
587
+ }
588
+
589
+ _renderEventLogPanel(pManifest)
590
+ {
591
+ let tmpViewRef = "_Pict.views['Ultravisor-TimingView']";
592
+
593
+ let tmpHTML = '<div class="ultravisor-timing-card">';
594
+ tmpHTML += '<div class="ultravisor-timing-chart">';
595
+ tmpHTML += '<div class="ultravisor-timing-chart-title">Event Log</div>';
596
+
597
+ // Verbosity toggle buttons
598
+ tmpHTML += '<div class="ultravisor-timing-verbosity-controls">';
599
+ tmpHTML += '<button class="ultravisor-timing-verbosity-btn' + (this._currentVerbosity === 0 ? ' active' : '') + '" onclick="' + tmpViewRef + '.setVerbosity(0)">Normal</button>';
600
+ tmpHTML += '<button class="ultravisor-timing-verbosity-btn' + (this._currentVerbosity === 1 ? ' active' : '') + '" onclick="' + tmpViewRef + '.setVerbosity(1)">Verbose</button>';
601
+ tmpHTML += '<button class="ultravisor-timing-verbosity-btn' + (this._currentVerbosity === 2 ? ' active' : '') + '" onclick="' + tmpViewRef + '.setVerbosity(2)">Ultra-verbose</button>';
602
+ tmpHTML += '</div>';
603
+
604
+ tmpHTML += '<div id="Ultravisor-Timing-EventLog-Body">';
605
+ tmpHTML += this._renderEventLogTable(pManifest.EventLog, pManifest.StartTime);
606
+ tmpHTML += '</div>';
607
+
608
+ tmpHTML += '</div>';
609
+ tmpHTML += '</div>';
610
+ return tmpHTML;
611
+ }
612
+
613
+ _renderEventLogTable(pEventLog, pOperationStartTime)
614
+ {
615
+ let tmpStartMs = pOperationStartTime ? new Date(pOperationStartTime).getTime() : 0;
616
+ let tmpMaxVerbosity = this._currentVerbosity;
617
+
618
+ let tmpHTML = '<table class="ultravisor-timing-eventlog-table">';
619
+ tmpHTML += '<thead><tr><th>Time</th><th>Node</th><th>Event</th><th>Message</th></tr></thead>';
620
+ tmpHTML += '<tbody>';
621
+
622
+ let tmpVisibleCount = 0;
623
+
624
+ for (let i = 0; i < pEventLog.length; i++)
401
625
  {
402
- let tmpSeconds = Math.floor(pMs / 1000);
403
- let tmpMs = Math.round(pMs % 1000);
404
- return tmpSeconds + 's ' + tmpMs + 'ms';
626
+ let tmpEvent = pEventLog[i];
627
+
628
+ if (tmpEvent.Verbosity > tmpMaxVerbosity)
629
+ {
630
+ continue;
631
+ }
632
+
633
+ tmpVisibleCount++;
634
+ let tmpRelativeMs = (tmpEvent.TimestampMs && tmpStartMs) ? (tmpEvent.TimestampMs - tmpStartMs) : 0;
635
+ let tmpVerbClass = 'ultravisor-timing-eventlog-v' + (tmpEvent.Verbosity || 0);
636
+
637
+ tmpHTML += '<tr class="' + tmpVerbClass + '">';
638
+ tmpHTML += '<td>+' + libTimingUtils.formatMs(tmpRelativeMs) + '</td>';
639
+ tmpHTML += '<td>' + libTimingUtils.escapeHTML(tmpEvent.NodeHash || '-') + '</td>';
640
+ tmpHTML += '<td>' + libTimingUtils.escapeHTML(tmpEvent.EventName || '') + '</td>';
641
+ tmpHTML += '<td>' + libTimingUtils.escapeHTML(tmpEvent.Message || '') + '</td>';
642
+ tmpHTML += '</tr>';
643
+ }
644
+
645
+ if (tmpVisibleCount === 0)
646
+ {
647
+ tmpHTML += '<tr><td colspan="4" style="text-align:center; color:var(--uv-text-tertiary); font-style:italic;">No events at this verbosity level.</td></tr>';
405
648
  }
406
- let tmpMinutes = Math.floor(pMs / 60000);
407
- let tmpSeconds = Math.floor((pMs % 60000) / 1000);
408
- return tmpMinutes + 'm ' + tmpSeconds + 's';
649
+
650
+ tmpHTML += '</tbody></table>';
651
+ return tmpHTML;
409
652
  }
410
653
 
411
- escapeHTML(pValue)
654
+ setVerbosity(pLevel)
412
655
  {
413
- if (!pValue) return '';
414
- return String(pValue).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
656
+ this._currentVerbosity = pLevel;
657
+
658
+ if (this._currentManifest && this._currentManifest.EventLog)
659
+ {
660
+ // Re-render the event log table only
661
+ let tmpTableHTML = this._renderEventLogTable(this._currentManifest.EventLog, this._currentManifest.StartTime);
662
+ this.pict.ContentAssignment.assignContent('#Ultravisor-Timing-EventLog-Body', tmpTableHTML);
663
+
664
+ // Update button active states
665
+ let tmpViewRef = "_Pict.views['Ultravisor-TimingView']";
666
+ let tmpBtnHTML = '';
667
+ tmpBtnHTML += '<button class="ultravisor-timing-verbosity-btn' + (pLevel === 0 ? ' active' : '') + '" onclick="' + tmpViewRef + '.setVerbosity(0)">Normal</button>';
668
+ tmpBtnHTML += '<button class="ultravisor-timing-verbosity-btn' + (pLevel === 1 ? ' active' : '') + '" onclick="' + tmpViewRef + '.setVerbosity(1)">Verbose</button>';
669
+ tmpBtnHTML += '<button class="ultravisor-timing-verbosity-btn' + (pLevel === 2 ? ' active' : '') + '" onclick="' + tmpViewRef + '.setVerbosity(2)">Ultra-verbose</button>';
670
+
671
+ let tmpControlsEl = document.querySelector('.ultravisor-timing-verbosity-controls');
672
+ if (tmpControlsEl)
673
+ {
674
+ tmpControlsEl.innerHTML = tmpBtnHTML;
675
+ }
676
+ }
415
677
  }
416
678
  }
417
679