@oneuptime/common 12.0.23 → 12.0.25

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 (323) hide show
  1. package/Models/AnalyticsModels/Span.ts +101 -0
  2. package/Models/DatabaseModels/DetectionRule.ts +55 -0
  3. package/Models/DatabaseModels/NetworkDeviceAutoImportRule.ts +27 -7
  4. package/Models/DatabaseModels/NetworkDeviceDiscoveryScan.ts +67 -0
  5. package/Models/DatabaseModels/Project.ts +68 -0
  6. package/Models/DatabaseModels/User.ts +68 -0
  7. package/Server/API/BaseAPI.ts +0 -24
  8. package/Server/API/SlackAPI.ts +0 -2
  9. package/Server/API/TelemetryAPI.ts +29 -0
  10. package/Server/Infrastructure/Postgres/SchemaMigrations/1789400000000-AddNameToNetworkDeviceDiscoveryScan.ts +28 -0
  11. package/Server/Infrastructure/Postgres/SchemaMigrations/1789500000000-AddCampaignUtmFields.ts +49 -0
  12. package/Server/Infrastructure/Postgres/SchemaMigrations/1789512000000-AddDetectionRuleDistinctCountColumns.ts +33 -0
  13. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +6 -0
  14. package/Server/Middleware/GzipRequestBody.ts +311 -0
  15. package/Server/Middleware/MultipartFormData.ts +87 -3
  16. package/Server/Middleware/SlackAuthorization.ts +96 -18
  17. package/Server/Services/DetectionRuleService.ts +73 -6
  18. package/Server/Services/Index.ts +205 -0
  19. package/Server/Services/NetworkDeviceDiscoveryScanService.ts +59 -0
  20. package/Server/Services/NetworkDeviceService.ts +148 -0
  21. package/Server/Services/OnCallDutyPolicyEscalationRuleScheduleService.ts +65 -0
  22. package/Server/Services/OnCallDutyPolicyFeedService.ts +1 -1
  23. package/Server/Services/ProjectService.ts +29 -19
  24. package/Server/Services/SecurityEventService.ts +90 -13
  25. package/Server/Services/StatusPageResourceService.ts +223 -0
  26. package/Server/Services/TelemetryAttributeService.ts +17 -0
  27. package/Server/Services/UserService.ts +4 -6
  28. package/Server/Types/Markdown.ts +161 -67
  29. package/Server/Utils/AI/Toolbox/OnCallTools.ts +12 -4
  30. package/Server/Utils/AnalyticsDatabase/Statement.ts +13 -1
  31. package/Server/Utils/AnalyticsDatabase/StatementGenerator.ts +297 -6
  32. package/Server/Utils/Attribution.ts +4 -0
  33. package/Server/Utils/Marketing/MarketingEventUtil.ts +45 -7
  34. package/Server/Utils/SecurityEvent/DetectionRuleEvaluator.ts +55 -3
  35. package/Server/Utils/SecurityEvent/Sigma/SigmaClickhouseCompiler.ts +21 -0
  36. package/Server/Utils/StartServer.ts +12 -32
  37. package/Server/Utils/Telemetry/LlmCostBudgetEvaluator.ts +101 -4
  38. package/Server/Utils/Telemetry/LlmMetricSpend.ts +181 -0
  39. package/Server/Utils/Telemetry/LlmSpan.ts +46 -0
  40. package/Server/Utils/Workspace/Slack/Actions/Auth.ts +0 -12
  41. package/Server/Views/Partials/AnalyticsConsent.ejs +159 -102
  42. package/Server/Views/Partials/Head.ejs +2 -1
  43. package/Tests/App/Dashboard/AdminUserNotificationMethodsPage.test.tsx +776 -38
  44. package/Tests/App/Dashboard/CorrelateFilterBuilder.test.tsx +359 -0
  45. package/Tests/App/Dashboard/CorrelateGraph.test.tsx +865 -0
  46. package/Tests/App/Dashboard/CorrelationGraph.test.ts +346 -0
  47. package/Tests/App/Dashboard/CriteriaFilterConditionDropdown.test.tsx +256 -0
  48. package/Tests/App/Dashboard/CriteriaFilterDefaults.test.ts +738 -0
  49. package/Tests/App/Dashboard/CriteriaFilterMonitorTypeChange.test.ts +1122 -0
  50. package/Tests/App/Dashboard/DiscoveryScanWizardValidation.test.tsx +283 -0
  51. package/Tests/App/Dashboard/ExternalStatusPageCriteriaFilter.test.ts +407 -0
  52. package/Tests/App/Dashboard/LlmCallsTableIdentity.test.tsx +322 -0
  53. package/Tests/App/Dashboard/LlmOverview.test.tsx +335 -0
  54. package/Tests/App/Dashboard/LlmSpanDisplay.test.ts +391 -0
  55. package/Tests/App/Dashboard/LlmUsageBreakdown.test.tsx +1007 -0
  56. package/Tests/App/Dashboard/MetricSeriesInvestigateMenu.test.tsx +5 -14
  57. package/Tests/App/Dashboard/MonitorCriteriaActionToggles.test.tsx +426 -0
  58. package/Tests/App/Dashboard/MonitorStepsCriteriaAlignmentWiring.test.tsx +352 -0
  59. package/Tests/App/Dashboard/OnCallLayerCardOverrides.test.tsx +278 -0
  60. package/Tests/App/Dashboard/OnCallLayerShiftPreviewOverrides.test.ts +237 -0
  61. package/Tests/App/Dashboard/OnCallReadinessSurfaces.test.tsx +2 -2
  62. package/Tests/App/Dashboard/OnCallSchedulePreviewOverrides.test.tsx +460 -0
  63. package/Tests/App/Dashboard/SecurityEventAttributeUtil.test.ts +171 -0
  64. package/Tests/App/Dashboard/SecurityEventCorrelation.test.ts +857 -0
  65. package/Tests/App/Dashboard/SecurityEventDetailObservables.test.tsx +194 -0
  66. package/Tests/App/Dashboard/SecurityEventsDetectionRulesPage.test.tsx +124 -0
  67. package/Tests/App/Dashboard/SecurityEventsMonitorStepForm.test.tsx +79 -19
  68. package/Tests/App/Dashboard/SecurityEventsTableColumns.test.tsx +382 -0
  69. package/Tests/App/StatusPage/BulkAddStatusPageMonitors.test.ts +216 -0
  70. package/Tests/App/StatusPage/BulkAddStatusPageMonitorsModal.test.tsx +590 -11
  71. package/Tests/App/StatusPage/StatusPageResourceExplorer.test.tsx +757 -0
  72. package/Tests/Models/DiscoveryScanNameColumn.test.ts +293 -0
  73. package/Tests/Server/API/BaseAPI.test.ts +41 -0
  74. package/Tests/Server/API/BaseAPIUpdatePayloadValidation.test.ts +9 -16
  75. package/Tests/Server/API/SecurityEventAttributesAPI.test.ts +564 -0
  76. package/Tests/Server/Infrastructure/Postgres/SchemaMigrationsOrdering.test.ts +120 -4
  77. package/Tests/Server/Middleware/GzipRequestBody.test.ts +725 -0
  78. package/Tests/Server/Middleware/MultipartFormData.test.ts +298 -0
  79. package/Tests/Server/Middleware/SlackAuthorization.test.ts +262 -5
  80. package/Tests/Server/Services/AddDetectionRuleDistinctCountColumnsMigration.test.ts +311 -0
  81. package/Tests/Server/Services/DetectionRuleService.test.ts +134 -2
  82. package/Tests/Server/Services/DiscoveryScanClaimHookFreeSafety.test.ts +7 -1
  83. package/Tests/Server/Services/FeedRetentionConsistency.test.ts +131 -0
  84. package/Tests/Server/Services/NetworkDeviceDiscoveryScanService.test.ts +194 -0
  85. package/Tests/Server/Services/NetworkDeviceMonitorStatusStamp.test.ts +800 -0
  86. package/Tests/Server/Services/OnCallScheduleAttachRosterRefresh.test.ts +244 -0
  87. package/Tests/Server/Services/SecurityEventService.test.ts +376 -0
  88. package/Tests/Server/Services/StatusPageResourceDuplicates.test.ts +703 -0
  89. package/Tests/Server/Services/TelemetryAttributeServiceSecurityEvent.test.ts +256 -0
  90. package/Tests/Server/Types/Workflow/Components/ComponentRegistryParity.test.ts +417 -0
  91. package/Tests/Server/Utils/AnalyticsDatabase/StatementGeneratorWhereOperators.test.ts +677 -0
  92. package/Tests/Server/Utils/Marketing/MarketingEventUtil.test.ts +43 -0
  93. package/Tests/Server/Utils/Monitor/Criteria/ProfileMonitorCriteria.test.ts +15 -11
  94. package/Tests/Server/Utils/SecurityEvent/DetectionRuleEvaluator.test.ts +369 -8
  95. package/Tests/Server/Utils/SecurityEvent/SigmaClickhouseCompiler.test.ts +35 -0
  96. package/Tests/Server/Utils/Telemetry/LlmCostBudgetEvaluator.test.ts +387 -4
  97. package/Tests/Server/Utils/Telemetry/LlmMetricSpend.test.ts +386 -0
  98. package/Tests/Server/Utils/Telemetry/LlmSpan.test.ts +804 -0
  99. package/Tests/Server/Views/AnalyticsConsentPartial.test.ts +48 -5
  100. package/Tests/Types/Code/YamlSyntax.test.ts +396 -0
  101. package/Tests/Types/Monitor/MetricAndProfileDefaultCriteria.test.ts +957 -0
  102. package/Tests/Types/Monitor/MonitorCriteriaActionValidation.test.ts +598 -0
  103. package/Tests/Types/Monitor/MonitorCriteriaInstance.test.ts +49 -0
  104. package/Tests/Types/Monitor/Recommendation/MonitorRecommendationNotificationMode.test.ts +6 -6
  105. package/Tests/Types/Monitor/Recommendation/MonitorRecommendationSeverityMapper.test.ts +4 -4
  106. package/Tests/Types/Monitor/Recommendation/MonitorRecommendationUtil.test.ts +4 -3
  107. package/Tests/Types/Telemetry/LlmMetricConventions.test.ts +584 -0
  108. package/Tests/UI/Components/AiInvestigationSettingsCard.test.tsx +0 -12
  109. package/Tests/UI/Components/CardModelDetailEdit.test.tsx +1 -17
  110. package/Tests/UI/Components/CodeEditor.test.tsx +474 -10
  111. package/Tests/UI/Components/Detail/YamlField.test.tsx +105 -0
  112. package/Tests/UI/Components/EntityDropdownLabelsBulkAdd.test.tsx +319 -0
  113. package/Tests/UI/Components/Forms/FormFieldYaml.test.tsx +231 -0
  114. package/Tests/UI/Components/Forms/Utils/FormFieldSchemaTypeUtil.test.ts +1 -0
  115. package/Tests/UI/Components/Forms/ValidationYAML.test.ts +234 -0
  116. package/Tests/UI/Components/ModelTable/AttributeColumns.test.tsx +573 -0
  117. package/Tests/UI/Components/ModelTable/BaseModelTableAttributeColumns.test.tsx +824 -0
  118. package/Tests/UI/Components/ModelTable/ColumnCustomizationModalAddableColumns.test.tsx +707 -0
  119. package/Tests/UI/Components/SideOver.test.tsx +1 -1
  120. package/Tests/UI/Components/StatusPage/ResourceGridSelection.test.tsx +294 -0
  121. package/Tests/UI/Components/StatusPage/ResourceListSelection.test.tsx +436 -0
  122. package/Tests/UI/Components/TableBulkCsvExport.test.tsx +6 -2
  123. package/Tests/UI/Components/Toggle.test.tsx +25 -0
  124. package/Tests/UI/Components/YamlEditor.test.tsx +847 -0
  125. package/Tests/Utils/NetworkDevice/DeviceReachabilityUtil.test.ts +252 -0
  126. package/Tests/Utils/NetworkDiscovery/DiscoveredHostUtil.test.ts +221 -0
  127. package/Tests/Utils/NetworkDiscovery/ScanNameUtil.test.ts +312 -0
  128. package/Tests/Utils/StatusPage/ResourceExplorer.test.ts +468 -0
  129. package/Tests/Utils/Telemetry/LlmMetricQuery.test.ts +770 -0
  130. package/Types/Code/YamlSyntax.ts +396 -0
  131. package/Types/Exception/ExceptionCode.ts +1 -0
  132. package/Types/Exception/PayloadTooLargeException.ts +8 -0
  133. package/Types/Marketing/Attribution.ts +10 -0
  134. package/Types/Marketing/MarketingEvent.ts +4 -0
  135. package/Types/Monitor/MonitorCriteriaInstance.ts +116 -56
  136. package/Types/Monitor/Recommendation/MonitorRecommendationSeverityMapper.ts +2 -1
  137. package/Types/SecurityEvent/DetectionFindingConstants.ts +11 -0
  138. package/Types/Telemetry/LlmConventions.ts +255 -0
  139. package/Types/Telemetry/LlmMetricConventions.ts +329 -0
  140. package/UI/Components/AutocompleteTextInput/AutocompleteTextInput.tsx +3 -0
  141. package/UI/Components/BulkUpdate/BulkUpdateForm.tsx +10 -1
  142. package/UI/Components/CodeEditor/CodeEditor.tsx +241 -79
  143. package/UI/Components/CodeEditor/YamlEditor.tsx +369 -0
  144. package/UI/Components/Detail/Detail.tsx +10 -0
  145. package/UI/Components/EntityDropdown/EntityDropdown.tsx +33 -0
  146. package/UI/Components/Forms/Fields/FormField.tsx +31 -0
  147. package/UI/Components/Forms/Types/Field.ts +8 -0
  148. package/UI/Components/Forms/Types/FormFieldSchemaType.ts +1 -0
  149. package/UI/Components/Forms/Utils/FormFieldSchemaTypeUtil.ts +2 -0
  150. package/UI/Components/Forms/Validation.ts +46 -0
  151. package/UI/Components/Input/Input.tsx +3 -0
  152. package/UI/Components/ModelTable/AttributeColumns.tsx +321 -0
  153. package/UI/Components/ModelTable/BaseModelTable.tsx +263 -14
  154. package/UI/Components/ModelTable/Column.ts +8 -0
  155. package/UI/Components/ModelTable/ColumnCustomizationModal.tsx +310 -0
  156. package/UI/Components/ModelTable/ColumnPreference.ts +13 -1
  157. package/UI/Components/MonitorTemplateVariables/TemplateVariablesModal.tsx +2 -2
  158. package/UI/Components/SideOver/SideOver.tsx +5 -5
  159. package/UI/Components/StatusPage/ResourceGrid.tsx +82 -2
  160. package/UI/Components/StatusPage/ResourceList.tsx +197 -38
  161. package/UI/Components/Toggle/Toggle.tsx +9 -1
  162. package/UI/Components/Types/FieldType.ts +1 -0
  163. package/Utils/NetworkDevice/DeviceReachabilityUtil.ts +73 -1
  164. package/Utils/NetworkDiscovery/ScanNameUtil.ts +181 -0
  165. package/Utils/StatusPage/ResourceExplorer.ts +258 -0
  166. package/Utils/Telemetry/LlmMetricQuery.ts +287 -0
  167. package/build/dist/Models/AnalyticsModels/Span.js +89 -0
  168. package/build/dist/Models/AnalyticsModels/Span.js.map +1 -1
  169. package/build/dist/Models/DatabaseModels/DetectionRule.js +57 -0
  170. package/build/dist/Models/DatabaseModels/DetectionRule.js.map +1 -1
  171. package/build/dist/Models/DatabaseModels/NetworkDeviceAutoImportRule.js +27 -7
  172. package/build/dist/Models/DatabaseModels/NetworkDeviceAutoImportRule.js.map +1 -1
  173. package/build/dist/Models/DatabaseModels/NetworkDeviceDiscoveryScan.js +69 -0
  174. package/build/dist/Models/DatabaseModels/NetworkDeviceDiscoveryScan.js.map +1 -1
  175. package/build/dist/Models/DatabaseModels/Project.js +76 -0
  176. package/build/dist/Models/DatabaseModels/Project.js.map +1 -1
  177. package/build/dist/Models/DatabaseModels/User.js +76 -0
  178. package/build/dist/Models/DatabaseModels/User.js.map +1 -1
  179. package/build/dist/Server/API/BaseAPI.js +3 -19
  180. package/build/dist/Server/API/BaseAPI.js.map +1 -1
  181. package/build/dist/Server/API/SlackAPI.js +0 -2
  182. package/build/dist/Server/API/SlackAPI.js.map +1 -1
  183. package/build/dist/Server/API/TelemetryAPI.js +17 -0
  184. package/build/dist/Server/API/TelemetryAPI.js.map +1 -1
  185. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1789400000000-AddNameToNetworkDeviceDiscoveryScan.js +21 -0
  186. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1789400000000-AddNameToNetworkDeviceDiscoveryScan.js.map +1 -0
  187. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1789500000000-AddCampaignUtmFields.js +42 -0
  188. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1789500000000-AddCampaignUtmFields.js.map +1 -0
  189. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1789512000000-AddDetectionRuleDistinctCountColumns.js +22 -0
  190. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1789512000000-AddDetectionRuleDistinctCountColumns.js.map +1 -0
  191. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +6 -0
  192. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  193. package/build/dist/Server/Middleware/GzipRequestBody.js +224 -0
  194. package/build/dist/Server/Middleware/GzipRequestBody.js.map +1 -0
  195. package/build/dist/Server/Middleware/MultipartFormData.js +71 -2
  196. package/build/dist/Server/Middleware/MultipartFormData.js.map +1 -1
  197. package/build/dist/Server/Middleware/SlackAuthorization.js +58 -7
  198. package/build/dist/Server/Middleware/SlackAuthorization.js.map +1 -1
  199. package/build/dist/Server/Services/DetectionRuleService.js +49 -4
  200. package/build/dist/Server/Services/DetectionRuleService.js.map +1 -1
  201. package/build/dist/Server/Services/Index.js +204 -0
  202. package/build/dist/Server/Services/Index.js.map +1 -1
  203. package/build/dist/Server/Services/NetworkDeviceDiscoveryScanService.js +50 -0
  204. package/build/dist/Server/Services/NetworkDeviceDiscoveryScanService.js.map +1 -1
  205. package/build/dist/Server/Services/NetworkDeviceService.js +124 -0
  206. package/build/dist/Server/Services/NetworkDeviceService.js.map +1 -1
  207. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleScheduleService.js +68 -13
  208. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleScheduleService.js.map +1 -1
  209. package/build/dist/Server/Services/OnCallDutyPolicyFeedService.js +1 -1
  210. package/build/dist/Server/Services/OnCallDutyPolicyFeedService.js.map +1 -1
  211. package/build/dist/Server/Services/ProjectService.js +25 -45
  212. package/build/dist/Server/Services/ProjectService.js.map +1 -1
  213. package/build/dist/Server/Services/SecurityEventService.js +57 -5
  214. package/build/dist/Server/Services/SecurityEventService.js.map +1 -1
  215. package/build/dist/Server/Services/StatusPageResourceService.js +140 -0
  216. package/build/dist/Server/Services/StatusPageResourceService.js.map +1 -1
  217. package/build/dist/Server/Services/TelemetryAttributeService.js +17 -0
  218. package/build/dist/Server/Services/TelemetryAttributeService.js.map +1 -1
  219. package/build/dist/Server/Services/UserService.js +2 -12
  220. package/build/dist/Server/Services/UserService.js.map +1 -1
  221. package/build/dist/Server/Types/Markdown.js +147 -61
  222. package/build/dist/Server/Types/Markdown.js.map +1 -1
  223. package/build/dist/Server/Utils/AI/Toolbox/OnCallTools.js +12 -4
  224. package/build/dist/Server/Utils/AI/Toolbox/OnCallTools.js.map +1 -1
  225. package/build/dist/Server/Utils/AnalyticsDatabase/Statement.js +12 -1
  226. package/build/dist/Server/Utils/AnalyticsDatabase/Statement.js.map +1 -1
  227. package/build/dist/Server/Utils/AnalyticsDatabase/StatementGenerator.js +246 -9
  228. package/build/dist/Server/Utils/AnalyticsDatabase/StatementGenerator.js.map +1 -1
  229. package/build/dist/Server/Utils/Attribution.js.map +1 -1
  230. package/build/dist/Server/Utils/Marketing/MarketingEventUtil.js +27 -7
  231. package/build/dist/Server/Utils/Marketing/MarketingEventUtil.js.map +1 -1
  232. package/build/dist/Server/Utils/SecurityEvent/DetectionRuleEvaluator.js +42 -7
  233. package/build/dist/Server/Utils/SecurityEvent/DetectionRuleEvaluator.js.map +1 -1
  234. package/build/dist/Server/Utils/SecurityEvent/Sigma/SigmaClickhouseCompiler.js +18 -0
  235. package/build/dist/Server/Utils/SecurityEvent/Sigma/SigmaClickhouseCompiler.js.map +1 -1
  236. package/build/dist/Server/Utils/StartServer.js +12 -21
  237. package/build/dist/Server/Utils/StartServer.js.map +1 -1
  238. package/build/dist/Server/Utils/Telemetry/LlmCostBudgetEvaluator.js +76 -5
  239. package/build/dist/Server/Utils/Telemetry/LlmCostBudgetEvaluator.js.map +1 -1
  240. package/build/dist/Server/Utils/Telemetry/LlmMetricSpend.js +151 -0
  241. package/build/dist/Server/Utils/Telemetry/LlmMetricSpend.js.map +1 -0
  242. package/build/dist/Server/Utils/Telemetry/LlmSpan.js +24 -1
  243. package/build/dist/Server/Utils/Telemetry/LlmSpan.js.map +1 -1
  244. package/build/dist/Server/Utils/Workspace/Slack/Actions/Auth.js +0 -10
  245. package/build/dist/Server/Utils/Workspace/Slack/Actions/Auth.js.map +1 -1
  246. package/build/dist/Types/Code/YamlSyntax.js +212 -0
  247. package/build/dist/Types/Code/YamlSyntax.js.map +1 -0
  248. package/build/dist/Types/Exception/ExceptionCode.js +1 -0
  249. package/build/dist/Types/Exception/ExceptionCode.js.map +1 -1
  250. package/build/dist/Types/Exception/PayloadTooLargeException.js +8 -0
  251. package/build/dist/Types/Exception/PayloadTooLargeException.js.map +1 -0
  252. package/build/dist/Types/Marketing/Attribution.js +10 -0
  253. package/build/dist/Types/Marketing/Attribution.js.map +1 -1
  254. package/build/dist/Types/Monitor/MonitorCriteriaInstance.js +112 -51
  255. package/build/dist/Types/Monitor/MonitorCriteriaInstance.js.map +1 -1
  256. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationSeverityMapper.js +2 -1
  257. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationSeverityMapper.js.map +1 -1
  258. package/build/dist/Types/SecurityEvent/DetectionFindingConstants.js +9 -0
  259. package/build/dist/Types/SecurityEvent/DetectionFindingConstants.js.map +1 -1
  260. package/build/dist/Types/Telemetry/LlmConventions.js +236 -0
  261. package/build/dist/Types/Telemetry/LlmConventions.js.map +1 -1
  262. package/build/dist/Types/Telemetry/LlmMetricConventions.js +290 -0
  263. package/build/dist/Types/Telemetry/LlmMetricConventions.js.map +1 -0
  264. package/build/dist/UI/Components/AutocompleteTextInput/AutocompleteTextInput.js +1 -1
  265. package/build/dist/UI/Components/AutocompleteTextInput/AutocompleteTextInput.js.map +1 -1
  266. package/build/dist/UI/Components/BulkUpdate/BulkUpdateForm.js +5 -2
  267. package/build/dist/UI/Components/BulkUpdate/BulkUpdateForm.js.map +1 -1
  268. package/build/dist/UI/Components/CodeEditor/CodeEditor.js +206 -76
  269. package/build/dist/UI/Components/CodeEditor/CodeEditor.js.map +1 -1
  270. package/build/dist/UI/Components/CodeEditor/YamlEditor.js +201 -0
  271. package/build/dist/UI/Components/CodeEditor/YamlEditor.js.map +1 -0
  272. package/build/dist/UI/Components/Detail/Detail.js +9 -0
  273. package/build/dist/UI/Components/Detail/Detail.js.map +1 -1
  274. package/build/dist/UI/Components/EntityDropdown/EntityDropdown.js +16 -1
  275. package/build/dist/UI/Components/EntityDropdown/EntityDropdown.js.map +1 -1
  276. package/build/dist/UI/Components/Forms/Fields/FormField.js +14 -1
  277. package/build/dist/UI/Components/Forms/Fields/FormField.js.map +1 -1
  278. package/build/dist/UI/Components/Forms/Types/Field.js.map +1 -1
  279. package/build/dist/UI/Components/Forms/Types/FormFieldSchemaType.js +1 -0
  280. package/build/dist/UI/Components/Forms/Types/FormFieldSchemaType.js.map +1 -1
  281. package/build/dist/UI/Components/Forms/Utils/FormFieldSchemaTypeUtil.js +2 -0
  282. package/build/dist/UI/Components/Forms/Utils/FormFieldSchemaTypeUtil.js.map +1 -1
  283. package/build/dist/UI/Components/Forms/Validation.js +27 -0
  284. package/build/dist/UI/Components/Forms/Validation.js.map +1 -1
  285. package/build/dist/UI/Components/Input/Input.js +1 -1
  286. package/build/dist/UI/Components/Input/Input.js.map +1 -1
  287. package/build/dist/UI/Components/ModelTable/AttributeColumns.js +159 -0
  288. package/build/dist/UI/Components/ModelTable/AttributeColumns.js.map +1 -0
  289. package/build/dist/UI/Components/ModelTable/BaseModelTable.js +179 -17
  290. package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
  291. package/build/dist/UI/Components/ModelTable/ColumnCustomizationModal.js +133 -2
  292. package/build/dist/UI/Components/ModelTable/ColumnCustomizationModal.js.map +1 -1
  293. package/build/dist/UI/Components/ModelTable/ColumnPreference.js +7 -1
  294. package/build/dist/UI/Components/ModelTable/ColumnPreference.js.map +1 -1
  295. package/build/dist/UI/Components/MonitorTemplateVariables/TemplateVariablesModal.js +2 -2
  296. package/build/dist/UI/Components/SideOver/SideOver.js +5 -5
  297. package/build/dist/UI/Components/StatusPage/ResourceGrid.js +28 -2
  298. package/build/dist/UI/Components/StatusPage/ResourceGrid.js.map +1 -1
  299. package/build/dist/UI/Components/StatusPage/ResourceList.js +87 -20
  300. package/build/dist/UI/Components/StatusPage/ResourceList.js.map +1 -1
  301. package/build/dist/UI/Components/Toggle/Toggle.js +9 -1
  302. package/build/dist/UI/Components/Toggle/Toggle.js.map +1 -1
  303. package/build/dist/UI/Components/Types/FieldType.js +1 -0
  304. package/build/dist/UI/Components/Types/FieldType.js.map +1 -1
  305. package/build/dist/Utils/NetworkDevice/DeviceReachabilityUtil.js +37 -1
  306. package/build/dist/Utils/NetworkDevice/DeviceReachabilityUtil.js.map +1 -1
  307. package/build/dist/Utils/NetworkDiscovery/ScanNameUtil.js +120 -0
  308. package/build/dist/Utils/NetworkDiscovery/ScanNameUtil.js.map +1 -0
  309. package/build/dist/Utils/StatusPage/ResourceExplorer.js +171 -0
  310. package/build/dist/Utils/StatusPage/ResourceExplorer.js.map +1 -1
  311. package/build/dist/Utils/Telemetry/LlmMetricQuery.js +175 -0
  312. package/build/dist/Utils/Telemetry/LlmMetricQuery.js.map +1 -0
  313. package/jest.config.json +2 -0
  314. package/package.json +1 -1
  315. package/tsconfig.json +2 -1
  316. package/Tests/UI/Components/Toast.test.tsx +0 -197
  317. package/Tests/UI/Components/ToastStacking.test.tsx +0 -198
  318. package/UI/Components/Toast/Toast.tsx +0 -189
  319. package/UI/Components/Toast/ToastInit.tsx +0 -110
  320. package/build/dist/UI/Components/Toast/Toast.js +0 -123
  321. package/build/dist/UI/Components/Toast/Toast.js.map +0 -1
  322. package/build/dist/UI/Components/Toast/ToastInit.js +0 -53
  323. package/build/dist/UI/Components/Toast/ToastInit.js.map +0 -1
@@ -0,0 +1,369 @@
1
+ import CodeEditor from "./CodeEditor";
2
+ import Icon from "../Icon/Icon";
3
+ import CodeType from "../../../Types/Code/CodeType";
4
+ import IconProp from "../../../Types/Icon/IconProp";
5
+ import {
6
+ YamlSyntaxCheckResult,
7
+ checkYamlSyntax,
8
+ describeYamlSyntaxError,
9
+ } from "../../../Types/Code/YamlSyntax";
10
+ import React, {
11
+ FunctionComponent,
12
+ ReactElement,
13
+ useEffect,
14
+ useId,
15
+ useMemo,
16
+ useRef,
17
+ useState,
18
+ } from "react";
19
+
20
+ export interface ComponentProps {
21
+ initialValue?: string | undefined;
22
+ value?: string | undefined;
23
+ onChange?: ((value: string) => void) | undefined;
24
+ onBlur?: (() => void) | undefined;
25
+ onFocus?: (() => void) | undefined;
26
+ /** Shown in the header bar as a hint. Never written into the document. */
27
+ placeholder?: string | undefined;
28
+ error?: string | undefined;
29
+ readOnly?: boolean | undefined;
30
+ tabIndex?: number | undefined;
31
+ dataTestId?: string | undefined;
32
+ ariaLabelledby?: string | undefined;
33
+ height?: string | undefined;
34
+ className?: string | undefined;
35
+ }
36
+
37
+ /** How long the document sits still before it is parsed again. */
38
+ export const YAML_VALIDATION_DEBOUNCE_MS: number = 250;
39
+
40
+ const DEFAULT_HINT: string =
41
+ "Indentation is significant — use 2 spaces per level. Tabs are not valid YAML.";
42
+
43
+ const MAC_PLATFORM_PATTERN: RegExp = /Mac|iPhone|iPad|iPod/i;
44
+
45
+ type IsMacFunction = () => boolean;
46
+
47
+ /*
48
+ * Monaco binds toggleTabFocusMode to Ctrl+M everywhere except macOS, where the
49
+ * `mac` override in its keybinding makes it Ctrl+Shift+M. Naming the wrong key
50
+ * turns the keyboard-trap advisory (WCAG 2.1.2) into a false one.
51
+ */
52
+ const isMac: IsMacFunction = (): boolean => {
53
+ if (typeof navigator === "undefined") {
54
+ return false;
55
+ }
56
+
57
+ const platform: string =
58
+ (navigator as { platform?: string }).platform || navigator.userAgent || "";
59
+
60
+ return MAC_PLATFORM_PATTERN.test(platform);
61
+ };
62
+
63
+ /*
64
+ * Callers reach us through Form's currentValues, which is `any`, so a
65
+ * non-string can arrive on a prop typed as string. CodeEditor stringifies for
66
+ * display; we mirror that so the status bar judges the same text the user
67
+ * sees.
68
+ */
69
+ type ToTextFunction = (value: string | undefined) => string;
70
+
71
+ const toText: ToTextFunction = (value: string | undefined): string => {
72
+ if (value === undefined || value === null) {
73
+ return "";
74
+ }
75
+
76
+ if (typeof value !== "string") {
77
+ return JSON.stringify(value, null, 4);
78
+ }
79
+
80
+ return value;
81
+ };
82
+
83
+ type CountLinesFunction = (text: string) => number;
84
+
85
+ const countLines: CountLinesFunction = (text: string): number => {
86
+ return text.split("\n").length;
87
+ };
88
+
89
+ /**
90
+ * A YAML document editor: Monaco with the YAML grammar and YAML-safe
91
+ * indentation, wrapped in chrome that names the language, copies the document
92
+ * and reports - as you type - whether what is in the box actually parses.
93
+ *
94
+ * Exists because YAML fields used to render the rich-text Markdown editor.
95
+ * That was not only the wrong affordance (a Bold button over a Sigma rule);
96
+ * the Markdown editor round-trips its value through HTML and back, and
97
+ * indentation-sensitive YAML does not survive that intact.
98
+ */
99
+ const YamlEditor: FunctionComponent<ComponentProps> = (
100
+ props: ComponentProps,
101
+ ): ReactElement => {
102
+ const [text, setText] = useState<string>(() => {
103
+ return toText(props.value ?? props.initialValue);
104
+ });
105
+
106
+ /*
107
+ * The parse runs on a timer so it does not re-run on every keystroke, and
108
+ * so a half-typed line is not judged the instant it is typed.
109
+ */
110
+ const [checkedText, setCheckedText] = useState<string>(() => {
111
+ return toText(props.value ?? props.initialValue);
112
+ });
113
+
114
+ const instanceId: string = useId();
115
+ const hintId: string = `${instanceId}-yaml-hint`;
116
+ const statusId: string = `${instanceId}-yaml-status`;
117
+ const escapeHintId: string = `${instanceId}-yaml-escape`;
118
+
119
+ const [copied, setCopied] = useState<boolean>(false);
120
+ const copyResetTimer: React.MutableRefObject<ReturnType<
121
+ typeof setTimeout
122
+ > | null> = useRef<ReturnType<typeof setTimeout> | null>(null);
123
+
124
+ // `value` is the controlled prop; `initialValue` only seeds it.
125
+ useEffect(() => {
126
+ setText(
127
+ toText(props.value === undefined ? props.initialValue : props.value),
128
+ );
129
+ }, [props.value, props.initialValue]);
130
+
131
+ useEffect(() => {
132
+ const timer: ReturnType<typeof setTimeout> = setTimeout(() => {
133
+ setCheckedText(text);
134
+ }, YAML_VALIDATION_DEBOUNCE_MS);
135
+
136
+ return () => {
137
+ clearTimeout(timer);
138
+ };
139
+ }, [text]);
140
+
141
+ useEffect(() => {
142
+ return () => {
143
+ if (copyResetTimer.current) {
144
+ clearTimeout(copyResetTimer.current);
145
+ }
146
+ };
147
+ }, []);
148
+
149
+ const syntax: YamlSyntaxCheckResult = useMemo(() => {
150
+ return checkYamlSyntax(checkedText);
151
+ }, [checkedText]);
152
+
153
+ const isEmpty: boolean = text.trim() === "";
154
+
155
+ type HandleCopyFunction = () => void;
156
+
157
+ const handleCopy: HandleCopyFunction = (): void => {
158
+ if (
159
+ typeof navigator === "undefined" ||
160
+ !navigator.clipboard ||
161
+ typeof navigator.clipboard.writeText !== "function"
162
+ ) {
163
+ return;
164
+ }
165
+
166
+ void Promise.resolve(navigator.clipboard.writeText(text)).catch(() => {
167
+ /* A denied clipboard permission is not worth an error state. */
168
+ });
169
+
170
+ setCopied(true);
171
+
172
+ if (copyResetTimer.current) {
173
+ clearTimeout(copyResetTimer.current);
174
+ }
175
+
176
+ copyResetTimer.current = setTimeout(() => {
177
+ setCopied(false);
178
+ }, 2000);
179
+ };
180
+
181
+ /*
182
+ * One line, one message, five states. Whichever arm wins, the status bar is
183
+ * the only place the field says anything - the editor below is not given
184
+ * the error, so nothing is printed twice.
185
+ */
186
+ type StatusShape = {
187
+ tone: "error" | "valid" | "invalid" | "empty";
188
+ icon: IconProp;
189
+ message: string;
190
+ };
191
+
192
+ const status: StatusShape = useMemo(() => {
193
+ /*
194
+ * The form re-validates synchronously on every keystroke and the field is
195
+ * marked touched from the first one, so props.error arrives undebounced.
196
+ * Deferring to it only once the parse has caught up with the text keeps a
197
+ * red message off a half-typed line - and the moment they agree, the
198
+ * form's sentence wins, because it is the one blocking Save.
199
+ */
200
+ if (props.error && checkedText === text) {
201
+ return {
202
+ tone: "error",
203
+ icon: IconProp.Error,
204
+ message: props.error,
205
+ };
206
+ }
207
+
208
+ if (isEmpty) {
209
+ return {
210
+ tone: "empty",
211
+ icon: IconProp.Info,
212
+ message: "Nothing entered yet.",
213
+ };
214
+ }
215
+
216
+ /*
217
+ * checkYamlSyntax declines to judge a document whose shape is only known
218
+ * at run time. Saying "Valid YAML" about text nobody parsed would be a
219
+ * claim this component cannot make.
220
+ */
221
+ if (syntax.wasSkipped) {
222
+ return {
223
+ tone: "empty",
224
+ icon: IconProp.Info,
225
+ message: "Contains template expressions — syntax not checked.",
226
+ };
227
+ }
228
+
229
+ if (syntax.isValid) {
230
+ const lines: number = countLines(text);
231
+
232
+ return {
233
+ tone: "valid",
234
+ icon: IconProp.CheckCircle,
235
+ message: `Valid YAML · ${lines} ${lines === 1 ? "line" : "lines"}`,
236
+ };
237
+ }
238
+
239
+ return {
240
+ tone: "invalid",
241
+ icon: IconProp.Alert,
242
+ message: describeYamlSyntaxError(syntax),
243
+ };
244
+ }, [props.error, isEmpty, syntax, text, checkedText]);
245
+
246
+ /*
247
+ * Light-theme values only, one step darker than the obvious choice so the
248
+ * 12px status text clears 4.5:1 on bg-gray-50 (WCAG 1.4.3). Dark mode is
249
+ * not written here: Styles/Theme.css remaps these very classes globally
250
+ * under html.dark, at a specificity that beats any dark: variant a
251
+ * component could add - which is why no sibling component uses them.
252
+ */
253
+ const statusToneClassName: string = {
254
+ error: "text-red-700",
255
+ invalid: "text-amber-700",
256
+ valid: "text-green-700",
257
+ empty: "text-gray-500",
258
+ }[status.tone];
259
+
260
+ const borderClassName: string = props.error
261
+ ? "border-red-300 focus-within:border-red-500 focus-within:ring-red-500"
262
+ : "border-gray-300 focus-within:border-indigo-500 focus-within:ring-indigo-500";
263
+
264
+ const escapeHint: string = isMac()
265
+ ? "Press Control plus Shift plus M to toggle whether the Tab key indents or moves focus out of this editor."
266
+ : "Press Control plus M to toggle whether the Tab key indents or moves focus out of this editor.";
267
+
268
+ return (
269
+ <div
270
+ data-testid="yaml-editor"
271
+ className={
272
+ props.className ||
273
+ `overflow-hidden rounded-md border bg-white shadow-sm transition-shadow focus-within:ring-1 ${borderClassName}`
274
+ }
275
+ >
276
+ <div className="flex items-center justify-between gap-3 border-b border-gray-200 bg-gray-50 px-3 py-1">
277
+ <div className="flex min-w-0 items-center gap-2">
278
+ <span className="inline-flex shrink-0 items-center rounded border border-indigo-100 bg-indigo-50 px-1.5 py-0.5 text-[10px] font-semibold uppercase tracking-wide text-indigo-700">
279
+ YAML
280
+ </span>
281
+ <span
282
+ id={hintId}
283
+ data-testid="yaml-editor-hint"
284
+ className="truncate text-xs text-gray-500"
285
+ >
286
+ {props.placeholder || DEFAULT_HINT}
287
+ </span>
288
+ </div>
289
+
290
+ <button
291
+ type="button"
292
+ data-testid="yaml-editor-copy-button"
293
+ aria-label={
294
+ copied ? "YAML copied to clipboard" : "Copy YAML to clipboard"
295
+ }
296
+ disabled={isEmpty}
297
+ onClick={handleCopy}
298
+ className="inline-flex shrink-0 items-center gap-1 rounded px-2 py-1 text-xs text-gray-500 transition-colors hover:bg-gray-100 hover:text-gray-900 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-40 disabled:hover:bg-transparent disabled:hover:text-gray-500"
299
+ >
300
+ <Icon
301
+ icon={copied ? IconProp.Check : IconProp.Copy}
302
+ className="h-3.5 w-3.5"
303
+ />
304
+ {copied ? "Copied" : "Copy"}
305
+ </button>
306
+ </div>
307
+
308
+ {/*
309
+ * Ahead of the editor in reading order, and referenced from Monaco's own
310
+ * input through aria-describedby - Monaco takes Tab to indent, so this
311
+ * is the only way out, and it has to be heard on the way in rather than
312
+ * discovered on the way past.
313
+ */}
314
+ <span id={escapeHintId} className="sr-only">
315
+ {escapeHint}
316
+ </span>
317
+
318
+ <CodeEditor
319
+ type={CodeType.YAML}
320
+ ariaLabelledby={props.ariaLabelledby}
321
+ ariaDescribedby={`${escapeHintId} ${hintId} ${statusId}`}
322
+ ariaInvalid={Boolean(props.error)}
323
+ dataTestId={props.dataTestId}
324
+ tabIndex={props.tabIndex}
325
+ readOnly={props.readOnly}
326
+ height={props.height || "22rem"}
327
+ /*
328
+ * The chrome above owns the border, the background and the focus ring,
329
+ * so the editor contributes none of its own. `error` is deliberately
330
+ * not forwarded either - it would paint a second red border and print
331
+ * the message a second time under the box; the status bar below says
332
+ * it once.
333
+ */
334
+ className="block w-full text-sm"
335
+ value={text}
336
+ onChange={(value: string) => {
337
+ setText(value);
338
+
339
+ if (props.onChange) {
340
+ props.onChange(value);
341
+ }
342
+ }}
343
+ onBlur={props.onBlur}
344
+ onFocus={props.onFocus}
345
+ />
346
+
347
+ <div
348
+ id={statusId}
349
+ data-testid="yaml-editor-status"
350
+ role="status"
351
+ aria-live="polite"
352
+ className={`flex items-center gap-1.5 border-t border-gray-200 bg-gray-50 px-3 py-1.5 text-xs ${statusToneClassName}`}
353
+ >
354
+ <Icon icon={status.icon} className="h-3.5 w-3.5 shrink-0" />
355
+ <span className="min-w-0 break-words">{status.message}</span>
356
+ </div>
357
+
358
+ {/*
359
+ * The copy button's own name changes, but a button name is not a live
360
+ * region - nothing would speak the confirmation. This does.
361
+ */}
362
+ <span role="status" aria-live="polite" className="sr-only">
363
+ {copied ? "YAML copied to clipboard" : ""}
364
+ </span>
365
+ </div>
366
+ );
367
+ };
368
+
369
+ export default YamlEditor;
@@ -631,6 +631,7 @@ const Detail: DetailFunction = <T extends GenericObject>(
631
631
  field.fieldType === FieldType.CSS ||
632
632
  field.fieldType === FieldType.JSON ||
633
633
  field.fieldType === FieldType.JavaScript ||
634
+ field.fieldType === FieldType.YAML ||
634
635
  field.fieldType === FieldType.Code)
635
636
  ) {
636
637
  let language: string = "html";
@@ -682,6 +683,15 @@ const Detail: DetailFunction = <T extends GenericObject>(
682
683
  language = "plaintext";
683
684
  }
684
685
 
686
+ /*
687
+ * Rendered verbatim, unlike the JSON arm above: re-emitting YAML through
688
+ * a parser would drop the comments, anchors and key ordering that a hand
689
+ * written document (a Sigma rule, a collector config) is written with.
690
+ */
691
+ if (field.fieldType === FieldType.YAML) {
692
+ language = "yaml";
693
+ }
694
+
685
695
  data = (
686
696
  <CodeBlock
687
697
  code={data as string}
@@ -65,6 +65,12 @@ export type EntityDropdownValue =
65
65
  | null
66
66
  | undefined;
67
67
 
68
+ /** A label the Labels tab expanded, as handed to onLabelsBulkAdded. */
69
+ export interface BulkAddedLabel {
70
+ id: string;
71
+ name: string;
72
+ }
73
+
68
74
  export interface EntityDropdownProps {
69
75
  /*
70
76
  * Static options (enum-like). Used as initial cache when modelType is set;
@@ -104,6 +110,15 @@ export interface EntityDropdownProps {
104
110
  * labeled entity, or force-show it.
105
111
  */
106
112
  enableLabelsTab?: boolean | undefined;
113
+ /*
114
+ * Fired when the Labels tab actually expands a label into entries, with the
115
+ * labels that were applied. Bulk-add by tag is a one-time expansion - the
116
+ * labels are dropped the moment the entries land in the selection - so a
117
+ * caller that wants to remember which label a selection came from (to keep
118
+ * it in sync later, say) has no other way to find out. Names come along
119
+ * because the caller has no cheap way back from an id to one.
120
+ */
121
+ onLabelsBulkAdded?: ((labels: Array<BulkAddedLabel>) => void) | undefined;
107
122
  }
108
123
 
109
124
  const SEARCH_DEBOUNCE_MS: number = 250;
@@ -969,6 +984,24 @@ const EntityDropdown: FunctionComponent<EntityDropdownProps> = (
969
984
  additions.push(key);
970
985
  }
971
986
  }
987
+ /*
988
+ * Tell the caller which labels the user applied. Reported before the
989
+ * empty check below, and before the selection is cleared further down:
990
+ * the interesting case is a label whose entries are ALL already
991
+ * selected, which adds nothing here but is still a label the user asked
992
+ * this selection to be built from.
993
+ */
994
+ props.onLabelsBulkAdded?.(
995
+ selectedLabelIds.map((labelId: string): BulkAddedLabel => {
996
+ const label: Label | undefined = allLabels.find(
997
+ (candidate: Label): boolean => {
998
+ return candidate._id?.toString() === labelId;
999
+ },
1000
+ );
1001
+
1002
+ return { id: labelId, name: label?.name || "" };
1003
+ }),
1004
+ );
972
1005
  if (additions.length === 0) {
973
1006
  setLabelError(
974
1007
  "No new entries matched the selected labels (or you don't have read access).",
@@ -40,6 +40,7 @@ import Radio, { RadioValue } from "../../Radio/Radio";
40
40
  import { BasicRadioButtonOption } from "../../RadioButtons/BasicRadioButtons";
41
41
  import HorizontalRule from "../../HorizontalRule/HorizontalRule";
42
42
  import MarkdownEditor from "../../Markdown.tsx/MarkdownEditor";
43
+ import YamlEditor from "../../CodeEditor/YamlEditor";
43
44
  import useTranslateValue from "../../../Utils/Translation";
44
45
 
45
46
  export interface ComponentProps<T extends GenericObject> {
@@ -474,6 +475,7 @@ const FormField: <T extends GenericObject>(
474
475
  modelType={props.field.dropdownModal.type}
475
476
  labelField={props.field.dropdownModal.labelField}
476
477
  valueField={props.field.dropdownModal.valueField}
478
+ onLabelsBulkAdded={props.field.onLabelsBulkAdded}
477
479
  options={props.field.dropdownOptions || []}
478
480
  placeholder={translatedPlaceholder || ""}
479
481
  value={
@@ -688,6 +690,35 @@ const FormField: <T extends GenericObject>(
688
690
  />
689
691
  )}
690
692
 
693
+ {props.field.fieldType === FormFieldSchemaType.YAML && (
694
+ <YamlEditor
695
+ ariaLabelledby={fieldLabelId}
696
+ error={props.touched && props.error ? props.error : undefined}
697
+ tabIndex={0}
698
+ dataTestId={props.field.dataTestId}
699
+ onChange={async (value: string) => {
700
+ onChange(value);
701
+ props.setFieldValue(props.fieldName, value);
702
+ }}
703
+ onBlur={async () => {
704
+ props.setFieldTouched(props.fieldName, true);
705
+ }}
706
+ initialValue={
707
+ props.currentValues &&
708
+ (props.currentValues as any)[props.fieldName]
709
+ ? (props.currentValues as any)[props.fieldName]
710
+ : ""
711
+ }
712
+ value={
713
+ props.currentValues &&
714
+ (props.currentValues as any)[props.fieldName]
715
+ ? (props.currentValues as any)[props.fieldName]
716
+ : ""
717
+ }
718
+ placeholder={translatedPlaceholder || ""}
719
+ />
720
+ )}
721
+
691
722
  {props.field.fieldType === FormFieldSchemaType.Markdown && (
692
723
  <MarkdownEditor
693
724
  ariaLabelledby={fieldLabelId}
@@ -8,6 +8,7 @@ import {
8
8
  CardSelectOptionGroup,
9
9
  } from "../../CardSelect/CardSelect";
10
10
  import { DropdownOption, DropdownOptionGroup } from "../../Dropdown/Dropdown";
11
+ import { BulkAddedLabel } from "../../EntityDropdown/EntityDropdown";
11
12
  import { RadioButton } from "../../RadioButtons/GroupRadioButtons";
12
13
  import FormFieldSchemaType from "./FormFieldSchemaType";
13
14
  import FormValues from "./FormValues";
@@ -78,6 +79,13 @@ export default interface Field<TEntity> {
78
79
  labelField: string;
79
80
  valueField: string;
80
81
  };
82
+ /*
83
+ * Entity dropdowns can bulk-add every entry carrying a label. That is a
84
+ * one-time expansion and the label is not part of the field's value, so a
85
+ * form that needs to know which label a selection came from asks for it
86
+ * here.
87
+ */
88
+ onLabelsBulkAdded?: ((labels: Array<BulkAddedLabel>) => void) | undefined;
81
89
  selectByAccessControlProps?: {
82
90
  categoryCheckboxProps: CategoryCheckboxProps;
83
91
  accessControlColumnTitle: string;
@@ -31,6 +31,7 @@ enum FormFieldSchemaType {
31
31
  HTML = "HTML",
32
32
  RadioButton = "RadioButton",
33
33
  JSON = "JSON",
34
+ YAML = "YAML",
34
35
  Query = "Query",
35
36
  CustomComponent = "CustomComponent",
36
37
  Checkbox = "Checkbox",
@@ -68,6 +68,8 @@ export default class FormFieldSchemaTypeUtil {
68
68
  return FieldType.Element;
69
69
  case FormFieldSchemaType.JSON:
70
70
  return FieldType.JSON;
71
+ case FormFieldSchemaType.YAML:
72
+ return FieldType.YAML;
71
73
  case FormFieldSchemaType.Query:
72
74
  return FieldType.Element;
73
75
  case FormFieldSchemaType.CustomComponent:
@@ -18,6 +18,11 @@ import {
18
18
  JSONSyntaxCheckResult,
19
19
  checkJSONSyntax,
20
20
  } from "../../../Types/Workflow/TemplateSyntax";
21
+ import {
22
+ YamlSyntaxCheckResult,
23
+ checkYamlSyntax,
24
+ describeYamlSyntaxError,
25
+ } from "../../../Types/Code/YamlSyntax";
21
26
  import { Logger } from "../../Utils/Logger";
22
27
  import Port from "../../../Types/Port";
23
28
  import Typeof from "../../../Types/Typeof";
@@ -368,6 +373,37 @@ export default class Validation {
368
373
  );
369
374
  }
370
375
 
376
+ /**
377
+ * Reject a YAML-typed field whose text does not parse.
378
+ *
379
+ * The server validates too (a Sigma rule is compiled on save), but a round
380
+ * trip to hear "bad indentation on line 4" is a poor way to find out. Like
381
+ * validateJSONSyntax this takes the raw value rather than the stringified
382
+ * `content`, and defers to checkYamlSyntax for what it declines to judge.
383
+ */
384
+ public static validateYAMLSyntax<T extends GenericObject>(
385
+ value: JSONValue | undefined,
386
+ field: Field<T>,
387
+ ): string | null {
388
+ if (field.fieldType !== FormFieldSchemaType.YAML) {
389
+ return null;
390
+ }
391
+
392
+ const result: YamlSyntaxCheckResult = checkYamlSyntax(value);
393
+
394
+ if (result.isValid) {
395
+ return null;
396
+ }
397
+
398
+ return translateValidationMessage(
399
+ "{{field}} is not valid YAML. {{parserMessage}}",
400
+ {
401
+ field: field.title || field.name || "",
402
+ parserMessage: describeYamlSyntaxError(result),
403
+ },
404
+ );
405
+ }
406
+
371
407
  public static validate<T extends GenericObject>(args: {
372
408
  formFields: Array<Field<T>>;
373
409
  values: FormValues<T>;
@@ -437,6 +473,16 @@ export default class Validation {
437
473
  errors[name] = resultJSONSyntax;
438
474
  }
439
475
 
476
+ // Fed the raw value for the same reason validateJSONSyntax is.
477
+ const resultYAMLSyntax: string | null = this.validateYAMLSyntax(
478
+ (entries as JSONObject)[name] as JSONValue | undefined,
479
+ field,
480
+ );
481
+
482
+ if (resultYAMLSyntax) {
483
+ errors[name] = resultYAMLSyntax;
484
+ }
485
+
440
486
  const resultMatch: string | null = this.validateMatchField(
441
487
  content,
442
488
  field,
@@ -30,6 +30,8 @@ export interface ComponentProps {
30
30
  ariaHasPopup?: "dialog" | "listbox" | "menu" | "grid" | "tree" | undefined;
31
31
  ariaExpanded?: boolean | undefined;
32
32
  ariaControls?: string | undefined;
33
+ // For inputs with no visible label element to point ariaLabelledby at.
34
+ ariaLabel?: string | undefined;
33
35
  /*
34
36
  * For fields that render their own error text - a picker whose message sits
35
37
  * below the whole control rather than below this input.
@@ -177,6 +179,7 @@ const Input: FunctionComponent<ComponentProps> = (
177
179
  data-testid={props.dataTestId}
178
180
  spellCheck={!props.disableSpellCheck}
179
181
  autoComplete={props.autoComplete}
182
+ aria-label={props.ariaLabel}
180
183
  aria-labelledby={props.ariaLabelledby}
181
184
  aria-haspopup={props.ariaHasPopup}
182
185
  aria-expanded={props.ariaExpanded}