@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.
- package/Models/AnalyticsModels/Span.ts +101 -0
- package/Models/DatabaseModels/DetectionRule.ts +55 -0
- package/Models/DatabaseModels/NetworkDeviceAutoImportRule.ts +27 -7
- package/Models/DatabaseModels/NetworkDeviceDiscoveryScan.ts +67 -0
- package/Models/DatabaseModels/Project.ts +68 -0
- package/Models/DatabaseModels/User.ts +68 -0
- package/Server/API/BaseAPI.ts +0 -24
- package/Server/API/SlackAPI.ts +0 -2
- package/Server/API/TelemetryAPI.ts +29 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1789400000000-AddNameToNetworkDeviceDiscoveryScan.ts +28 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1789500000000-AddCampaignUtmFields.ts +49 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1789512000000-AddDetectionRuleDistinctCountColumns.ts +33 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +6 -0
- package/Server/Middleware/GzipRequestBody.ts +311 -0
- package/Server/Middleware/MultipartFormData.ts +87 -3
- package/Server/Middleware/SlackAuthorization.ts +96 -18
- package/Server/Services/DetectionRuleService.ts +73 -6
- package/Server/Services/Index.ts +205 -0
- package/Server/Services/NetworkDeviceDiscoveryScanService.ts +59 -0
- package/Server/Services/NetworkDeviceService.ts +148 -0
- package/Server/Services/OnCallDutyPolicyEscalationRuleScheduleService.ts +65 -0
- package/Server/Services/OnCallDutyPolicyFeedService.ts +1 -1
- package/Server/Services/ProjectService.ts +29 -19
- package/Server/Services/SecurityEventService.ts +90 -13
- package/Server/Services/StatusPageResourceService.ts +223 -0
- package/Server/Services/TelemetryAttributeService.ts +17 -0
- package/Server/Services/UserService.ts +4 -6
- package/Server/Types/Markdown.ts +161 -67
- package/Server/Utils/AI/Toolbox/OnCallTools.ts +12 -4
- package/Server/Utils/AnalyticsDatabase/Statement.ts +13 -1
- package/Server/Utils/AnalyticsDatabase/StatementGenerator.ts +297 -6
- package/Server/Utils/Attribution.ts +4 -0
- package/Server/Utils/Marketing/MarketingEventUtil.ts +45 -7
- package/Server/Utils/SecurityEvent/DetectionRuleEvaluator.ts +55 -3
- package/Server/Utils/SecurityEvent/Sigma/SigmaClickhouseCompiler.ts +21 -0
- package/Server/Utils/StartServer.ts +12 -32
- package/Server/Utils/Telemetry/LlmCostBudgetEvaluator.ts +101 -4
- package/Server/Utils/Telemetry/LlmMetricSpend.ts +181 -0
- package/Server/Utils/Telemetry/LlmSpan.ts +46 -0
- package/Server/Utils/Workspace/Slack/Actions/Auth.ts +0 -12
- package/Server/Views/Partials/AnalyticsConsent.ejs +159 -102
- package/Server/Views/Partials/Head.ejs +2 -1
- package/Tests/App/Dashboard/AdminUserNotificationMethodsPage.test.tsx +776 -38
- package/Tests/App/Dashboard/CorrelateFilterBuilder.test.tsx +359 -0
- package/Tests/App/Dashboard/CorrelateGraph.test.tsx +865 -0
- package/Tests/App/Dashboard/CorrelationGraph.test.ts +346 -0
- package/Tests/App/Dashboard/CriteriaFilterConditionDropdown.test.tsx +256 -0
- package/Tests/App/Dashboard/CriteriaFilterDefaults.test.ts +738 -0
- package/Tests/App/Dashboard/CriteriaFilterMonitorTypeChange.test.ts +1122 -0
- package/Tests/App/Dashboard/DiscoveryScanWizardValidation.test.tsx +283 -0
- package/Tests/App/Dashboard/ExternalStatusPageCriteriaFilter.test.ts +407 -0
- package/Tests/App/Dashboard/LlmCallsTableIdentity.test.tsx +322 -0
- package/Tests/App/Dashboard/LlmOverview.test.tsx +335 -0
- package/Tests/App/Dashboard/LlmSpanDisplay.test.ts +391 -0
- package/Tests/App/Dashboard/LlmUsageBreakdown.test.tsx +1007 -0
- package/Tests/App/Dashboard/MetricSeriesInvestigateMenu.test.tsx +5 -14
- package/Tests/App/Dashboard/MonitorCriteriaActionToggles.test.tsx +426 -0
- package/Tests/App/Dashboard/MonitorStepsCriteriaAlignmentWiring.test.tsx +352 -0
- package/Tests/App/Dashboard/OnCallLayerCardOverrides.test.tsx +278 -0
- package/Tests/App/Dashboard/OnCallLayerShiftPreviewOverrides.test.ts +237 -0
- package/Tests/App/Dashboard/OnCallReadinessSurfaces.test.tsx +2 -2
- package/Tests/App/Dashboard/OnCallSchedulePreviewOverrides.test.tsx +460 -0
- package/Tests/App/Dashboard/SecurityEventAttributeUtil.test.ts +171 -0
- package/Tests/App/Dashboard/SecurityEventCorrelation.test.ts +857 -0
- package/Tests/App/Dashboard/SecurityEventDetailObservables.test.tsx +194 -0
- package/Tests/App/Dashboard/SecurityEventsDetectionRulesPage.test.tsx +124 -0
- package/Tests/App/Dashboard/SecurityEventsMonitorStepForm.test.tsx +79 -19
- package/Tests/App/Dashboard/SecurityEventsTableColumns.test.tsx +382 -0
- package/Tests/App/StatusPage/BulkAddStatusPageMonitors.test.ts +216 -0
- package/Tests/App/StatusPage/BulkAddStatusPageMonitorsModal.test.tsx +590 -11
- package/Tests/App/StatusPage/StatusPageResourceExplorer.test.tsx +757 -0
- package/Tests/Models/DiscoveryScanNameColumn.test.ts +293 -0
- package/Tests/Server/API/BaseAPI.test.ts +41 -0
- package/Tests/Server/API/BaseAPIUpdatePayloadValidation.test.ts +9 -16
- package/Tests/Server/API/SecurityEventAttributesAPI.test.ts +564 -0
- package/Tests/Server/Infrastructure/Postgres/SchemaMigrationsOrdering.test.ts +120 -4
- package/Tests/Server/Middleware/GzipRequestBody.test.ts +725 -0
- package/Tests/Server/Middleware/MultipartFormData.test.ts +298 -0
- package/Tests/Server/Middleware/SlackAuthorization.test.ts +262 -5
- package/Tests/Server/Services/AddDetectionRuleDistinctCountColumnsMigration.test.ts +311 -0
- package/Tests/Server/Services/DetectionRuleService.test.ts +134 -2
- package/Tests/Server/Services/DiscoveryScanClaimHookFreeSafety.test.ts +7 -1
- package/Tests/Server/Services/FeedRetentionConsistency.test.ts +131 -0
- package/Tests/Server/Services/NetworkDeviceDiscoveryScanService.test.ts +194 -0
- package/Tests/Server/Services/NetworkDeviceMonitorStatusStamp.test.ts +800 -0
- package/Tests/Server/Services/OnCallScheduleAttachRosterRefresh.test.ts +244 -0
- package/Tests/Server/Services/SecurityEventService.test.ts +376 -0
- package/Tests/Server/Services/StatusPageResourceDuplicates.test.ts +703 -0
- package/Tests/Server/Services/TelemetryAttributeServiceSecurityEvent.test.ts +256 -0
- package/Tests/Server/Types/Workflow/Components/ComponentRegistryParity.test.ts +417 -0
- package/Tests/Server/Utils/AnalyticsDatabase/StatementGeneratorWhereOperators.test.ts +677 -0
- package/Tests/Server/Utils/Marketing/MarketingEventUtil.test.ts +43 -0
- package/Tests/Server/Utils/Monitor/Criteria/ProfileMonitorCriteria.test.ts +15 -11
- package/Tests/Server/Utils/SecurityEvent/DetectionRuleEvaluator.test.ts +369 -8
- package/Tests/Server/Utils/SecurityEvent/SigmaClickhouseCompiler.test.ts +35 -0
- package/Tests/Server/Utils/Telemetry/LlmCostBudgetEvaluator.test.ts +387 -4
- package/Tests/Server/Utils/Telemetry/LlmMetricSpend.test.ts +386 -0
- package/Tests/Server/Utils/Telemetry/LlmSpan.test.ts +804 -0
- package/Tests/Server/Views/AnalyticsConsentPartial.test.ts +48 -5
- package/Tests/Types/Code/YamlSyntax.test.ts +396 -0
- package/Tests/Types/Monitor/MetricAndProfileDefaultCriteria.test.ts +957 -0
- package/Tests/Types/Monitor/MonitorCriteriaActionValidation.test.ts +598 -0
- package/Tests/Types/Monitor/MonitorCriteriaInstance.test.ts +49 -0
- package/Tests/Types/Monitor/Recommendation/MonitorRecommendationNotificationMode.test.ts +6 -6
- package/Tests/Types/Monitor/Recommendation/MonitorRecommendationSeverityMapper.test.ts +4 -4
- package/Tests/Types/Monitor/Recommendation/MonitorRecommendationUtil.test.ts +4 -3
- package/Tests/Types/Telemetry/LlmMetricConventions.test.ts +584 -0
- package/Tests/UI/Components/AiInvestigationSettingsCard.test.tsx +0 -12
- package/Tests/UI/Components/CardModelDetailEdit.test.tsx +1 -17
- package/Tests/UI/Components/CodeEditor.test.tsx +474 -10
- package/Tests/UI/Components/Detail/YamlField.test.tsx +105 -0
- package/Tests/UI/Components/EntityDropdownLabelsBulkAdd.test.tsx +319 -0
- package/Tests/UI/Components/Forms/FormFieldYaml.test.tsx +231 -0
- package/Tests/UI/Components/Forms/Utils/FormFieldSchemaTypeUtil.test.ts +1 -0
- package/Tests/UI/Components/Forms/ValidationYAML.test.ts +234 -0
- package/Tests/UI/Components/ModelTable/AttributeColumns.test.tsx +573 -0
- package/Tests/UI/Components/ModelTable/BaseModelTableAttributeColumns.test.tsx +824 -0
- package/Tests/UI/Components/ModelTable/ColumnCustomizationModalAddableColumns.test.tsx +707 -0
- package/Tests/UI/Components/SideOver.test.tsx +1 -1
- package/Tests/UI/Components/StatusPage/ResourceGridSelection.test.tsx +294 -0
- package/Tests/UI/Components/StatusPage/ResourceListSelection.test.tsx +436 -0
- package/Tests/UI/Components/TableBulkCsvExport.test.tsx +6 -2
- package/Tests/UI/Components/Toggle.test.tsx +25 -0
- package/Tests/UI/Components/YamlEditor.test.tsx +847 -0
- package/Tests/Utils/NetworkDevice/DeviceReachabilityUtil.test.ts +252 -0
- package/Tests/Utils/NetworkDiscovery/DiscoveredHostUtil.test.ts +221 -0
- package/Tests/Utils/NetworkDiscovery/ScanNameUtil.test.ts +312 -0
- package/Tests/Utils/StatusPage/ResourceExplorer.test.ts +468 -0
- package/Tests/Utils/Telemetry/LlmMetricQuery.test.ts +770 -0
- package/Types/Code/YamlSyntax.ts +396 -0
- package/Types/Exception/ExceptionCode.ts +1 -0
- package/Types/Exception/PayloadTooLargeException.ts +8 -0
- package/Types/Marketing/Attribution.ts +10 -0
- package/Types/Marketing/MarketingEvent.ts +4 -0
- package/Types/Monitor/MonitorCriteriaInstance.ts +116 -56
- package/Types/Monitor/Recommendation/MonitorRecommendationSeverityMapper.ts +2 -1
- package/Types/SecurityEvent/DetectionFindingConstants.ts +11 -0
- package/Types/Telemetry/LlmConventions.ts +255 -0
- package/Types/Telemetry/LlmMetricConventions.ts +329 -0
- package/UI/Components/AutocompleteTextInput/AutocompleteTextInput.tsx +3 -0
- package/UI/Components/BulkUpdate/BulkUpdateForm.tsx +10 -1
- package/UI/Components/CodeEditor/CodeEditor.tsx +241 -79
- package/UI/Components/CodeEditor/YamlEditor.tsx +369 -0
- package/UI/Components/Detail/Detail.tsx +10 -0
- package/UI/Components/EntityDropdown/EntityDropdown.tsx +33 -0
- package/UI/Components/Forms/Fields/FormField.tsx +31 -0
- package/UI/Components/Forms/Types/Field.ts +8 -0
- package/UI/Components/Forms/Types/FormFieldSchemaType.ts +1 -0
- package/UI/Components/Forms/Utils/FormFieldSchemaTypeUtil.ts +2 -0
- package/UI/Components/Forms/Validation.ts +46 -0
- package/UI/Components/Input/Input.tsx +3 -0
- package/UI/Components/ModelTable/AttributeColumns.tsx +321 -0
- package/UI/Components/ModelTable/BaseModelTable.tsx +263 -14
- package/UI/Components/ModelTable/Column.ts +8 -0
- package/UI/Components/ModelTable/ColumnCustomizationModal.tsx +310 -0
- package/UI/Components/ModelTable/ColumnPreference.ts +13 -1
- package/UI/Components/MonitorTemplateVariables/TemplateVariablesModal.tsx +2 -2
- package/UI/Components/SideOver/SideOver.tsx +5 -5
- package/UI/Components/StatusPage/ResourceGrid.tsx +82 -2
- package/UI/Components/StatusPage/ResourceList.tsx +197 -38
- package/UI/Components/Toggle/Toggle.tsx +9 -1
- package/UI/Components/Types/FieldType.ts +1 -0
- package/Utils/NetworkDevice/DeviceReachabilityUtil.ts +73 -1
- package/Utils/NetworkDiscovery/ScanNameUtil.ts +181 -0
- package/Utils/StatusPage/ResourceExplorer.ts +258 -0
- package/Utils/Telemetry/LlmMetricQuery.ts +287 -0
- package/build/dist/Models/AnalyticsModels/Span.js +89 -0
- package/build/dist/Models/AnalyticsModels/Span.js.map +1 -1
- package/build/dist/Models/DatabaseModels/DetectionRule.js +57 -0
- package/build/dist/Models/DatabaseModels/DetectionRule.js.map +1 -1
- package/build/dist/Models/DatabaseModels/NetworkDeviceAutoImportRule.js +27 -7
- package/build/dist/Models/DatabaseModels/NetworkDeviceAutoImportRule.js.map +1 -1
- package/build/dist/Models/DatabaseModels/NetworkDeviceDiscoveryScan.js +69 -0
- package/build/dist/Models/DatabaseModels/NetworkDeviceDiscoveryScan.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Project.js +76 -0
- package/build/dist/Models/DatabaseModels/Project.js.map +1 -1
- package/build/dist/Models/DatabaseModels/User.js +76 -0
- package/build/dist/Models/DatabaseModels/User.js.map +1 -1
- package/build/dist/Server/API/BaseAPI.js +3 -19
- package/build/dist/Server/API/BaseAPI.js.map +1 -1
- package/build/dist/Server/API/SlackAPI.js +0 -2
- package/build/dist/Server/API/SlackAPI.js.map +1 -1
- package/build/dist/Server/API/TelemetryAPI.js +17 -0
- package/build/dist/Server/API/TelemetryAPI.js.map +1 -1
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1789400000000-AddNameToNetworkDeviceDiscoveryScan.js +21 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1789400000000-AddNameToNetworkDeviceDiscoveryScan.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1789500000000-AddCampaignUtmFields.js +42 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1789500000000-AddCampaignUtmFields.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1789512000000-AddDetectionRuleDistinctCountColumns.js +22 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1789512000000-AddDetectionRuleDistinctCountColumns.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +6 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
- package/build/dist/Server/Middleware/GzipRequestBody.js +224 -0
- package/build/dist/Server/Middleware/GzipRequestBody.js.map +1 -0
- package/build/dist/Server/Middleware/MultipartFormData.js +71 -2
- package/build/dist/Server/Middleware/MultipartFormData.js.map +1 -1
- package/build/dist/Server/Middleware/SlackAuthorization.js +58 -7
- package/build/dist/Server/Middleware/SlackAuthorization.js.map +1 -1
- package/build/dist/Server/Services/DetectionRuleService.js +49 -4
- package/build/dist/Server/Services/DetectionRuleService.js.map +1 -1
- package/build/dist/Server/Services/Index.js +204 -0
- package/build/dist/Server/Services/Index.js.map +1 -1
- package/build/dist/Server/Services/NetworkDeviceDiscoveryScanService.js +50 -0
- package/build/dist/Server/Services/NetworkDeviceDiscoveryScanService.js.map +1 -1
- package/build/dist/Server/Services/NetworkDeviceService.js +124 -0
- package/build/dist/Server/Services/NetworkDeviceService.js.map +1 -1
- package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleScheduleService.js +68 -13
- package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleScheduleService.js.map +1 -1
- package/build/dist/Server/Services/OnCallDutyPolicyFeedService.js +1 -1
- package/build/dist/Server/Services/OnCallDutyPolicyFeedService.js.map +1 -1
- package/build/dist/Server/Services/ProjectService.js +25 -45
- package/build/dist/Server/Services/ProjectService.js.map +1 -1
- package/build/dist/Server/Services/SecurityEventService.js +57 -5
- package/build/dist/Server/Services/SecurityEventService.js.map +1 -1
- package/build/dist/Server/Services/StatusPageResourceService.js +140 -0
- package/build/dist/Server/Services/StatusPageResourceService.js.map +1 -1
- package/build/dist/Server/Services/TelemetryAttributeService.js +17 -0
- package/build/dist/Server/Services/TelemetryAttributeService.js.map +1 -1
- package/build/dist/Server/Services/UserService.js +2 -12
- package/build/dist/Server/Services/UserService.js.map +1 -1
- package/build/dist/Server/Types/Markdown.js +147 -61
- package/build/dist/Server/Types/Markdown.js.map +1 -1
- package/build/dist/Server/Utils/AI/Toolbox/OnCallTools.js +12 -4
- package/build/dist/Server/Utils/AI/Toolbox/OnCallTools.js.map +1 -1
- package/build/dist/Server/Utils/AnalyticsDatabase/Statement.js +12 -1
- package/build/dist/Server/Utils/AnalyticsDatabase/Statement.js.map +1 -1
- package/build/dist/Server/Utils/AnalyticsDatabase/StatementGenerator.js +246 -9
- package/build/dist/Server/Utils/AnalyticsDatabase/StatementGenerator.js.map +1 -1
- package/build/dist/Server/Utils/Attribution.js.map +1 -1
- package/build/dist/Server/Utils/Marketing/MarketingEventUtil.js +27 -7
- package/build/dist/Server/Utils/Marketing/MarketingEventUtil.js.map +1 -1
- package/build/dist/Server/Utils/SecurityEvent/DetectionRuleEvaluator.js +42 -7
- package/build/dist/Server/Utils/SecurityEvent/DetectionRuleEvaluator.js.map +1 -1
- package/build/dist/Server/Utils/SecurityEvent/Sigma/SigmaClickhouseCompiler.js +18 -0
- package/build/dist/Server/Utils/SecurityEvent/Sigma/SigmaClickhouseCompiler.js.map +1 -1
- package/build/dist/Server/Utils/StartServer.js +12 -21
- package/build/dist/Server/Utils/StartServer.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/LlmCostBudgetEvaluator.js +76 -5
- package/build/dist/Server/Utils/Telemetry/LlmCostBudgetEvaluator.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/LlmMetricSpend.js +151 -0
- package/build/dist/Server/Utils/Telemetry/LlmMetricSpend.js.map +1 -0
- package/build/dist/Server/Utils/Telemetry/LlmSpan.js +24 -1
- package/build/dist/Server/Utils/Telemetry/LlmSpan.js.map +1 -1
- package/build/dist/Server/Utils/Workspace/Slack/Actions/Auth.js +0 -10
- package/build/dist/Server/Utils/Workspace/Slack/Actions/Auth.js.map +1 -1
- package/build/dist/Types/Code/YamlSyntax.js +212 -0
- package/build/dist/Types/Code/YamlSyntax.js.map +1 -0
- package/build/dist/Types/Exception/ExceptionCode.js +1 -0
- package/build/dist/Types/Exception/ExceptionCode.js.map +1 -1
- package/build/dist/Types/Exception/PayloadTooLargeException.js +8 -0
- package/build/dist/Types/Exception/PayloadTooLargeException.js.map +1 -0
- package/build/dist/Types/Marketing/Attribution.js +10 -0
- package/build/dist/Types/Marketing/Attribution.js.map +1 -1
- package/build/dist/Types/Monitor/MonitorCriteriaInstance.js +112 -51
- package/build/dist/Types/Monitor/MonitorCriteriaInstance.js.map +1 -1
- package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationSeverityMapper.js +2 -1
- package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationSeverityMapper.js.map +1 -1
- package/build/dist/Types/SecurityEvent/DetectionFindingConstants.js +9 -0
- package/build/dist/Types/SecurityEvent/DetectionFindingConstants.js.map +1 -1
- package/build/dist/Types/Telemetry/LlmConventions.js +236 -0
- package/build/dist/Types/Telemetry/LlmConventions.js.map +1 -1
- package/build/dist/Types/Telemetry/LlmMetricConventions.js +290 -0
- package/build/dist/Types/Telemetry/LlmMetricConventions.js.map +1 -0
- package/build/dist/UI/Components/AutocompleteTextInput/AutocompleteTextInput.js +1 -1
- package/build/dist/UI/Components/AutocompleteTextInput/AutocompleteTextInput.js.map +1 -1
- package/build/dist/UI/Components/BulkUpdate/BulkUpdateForm.js +5 -2
- package/build/dist/UI/Components/BulkUpdate/BulkUpdateForm.js.map +1 -1
- package/build/dist/UI/Components/CodeEditor/CodeEditor.js +206 -76
- package/build/dist/UI/Components/CodeEditor/CodeEditor.js.map +1 -1
- package/build/dist/UI/Components/CodeEditor/YamlEditor.js +201 -0
- package/build/dist/UI/Components/CodeEditor/YamlEditor.js.map +1 -0
- package/build/dist/UI/Components/Detail/Detail.js +9 -0
- package/build/dist/UI/Components/Detail/Detail.js.map +1 -1
- package/build/dist/UI/Components/EntityDropdown/EntityDropdown.js +16 -1
- package/build/dist/UI/Components/EntityDropdown/EntityDropdown.js.map +1 -1
- package/build/dist/UI/Components/Forms/Fields/FormField.js +14 -1
- package/build/dist/UI/Components/Forms/Fields/FormField.js.map +1 -1
- package/build/dist/UI/Components/Forms/Types/Field.js.map +1 -1
- package/build/dist/UI/Components/Forms/Types/FormFieldSchemaType.js +1 -0
- package/build/dist/UI/Components/Forms/Types/FormFieldSchemaType.js.map +1 -1
- package/build/dist/UI/Components/Forms/Utils/FormFieldSchemaTypeUtil.js +2 -0
- package/build/dist/UI/Components/Forms/Utils/FormFieldSchemaTypeUtil.js.map +1 -1
- package/build/dist/UI/Components/Forms/Validation.js +27 -0
- package/build/dist/UI/Components/Forms/Validation.js.map +1 -1
- package/build/dist/UI/Components/Input/Input.js +1 -1
- package/build/dist/UI/Components/Input/Input.js.map +1 -1
- package/build/dist/UI/Components/ModelTable/AttributeColumns.js +159 -0
- package/build/dist/UI/Components/ModelTable/AttributeColumns.js.map +1 -0
- package/build/dist/UI/Components/ModelTable/BaseModelTable.js +179 -17
- package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
- package/build/dist/UI/Components/ModelTable/ColumnCustomizationModal.js +133 -2
- package/build/dist/UI/Components/ModelTable/ColumnCustomizationModal.js.map +1 -1
- package/build/dist/UI/Components/ModelTable/ColumnPreference.js +7 -1
- package/build/dist/UI/Components/ModelTable/ColumnPreference.js.map +1 -1
- package/build/dist/UI/Components/MonitorTemplateVariables/TemplateVariablesModal.js +2 -2
- package/build/dist/UI/Components/SideOver/SideOver.js +5 -5
- package/build/dist/UI/Components/StatusPage/ResourceGrid.js +28 -2
- package/build/dist/UI/Components/StatusPage/ResourceGrid.js.map +1 -1
- package/build/dist/UI/Components/StatusPage/ResourceList.js +87 -20
- package/build/dist/UI/Components/StatusPage/ResourceList.js.map +1 -1
- package/build/dist/UI/Components/Toggle/Toggle.js +9 -1
- package/build/dist/UI/Components/Toggle/Toggle.js.map +1 -1
- package/build/dist/UI/Components/Types/FieldType.js +1 -0
- package/build/dist/UI/Components/Types/FieldType.js.map +1 -1
- package/build/dist/Utils/NetworkDevice/DeviceReachabilityUtil.js +37 -1
- package/build/dist/Utils/NetworkDevice/DeviceReachabilityUtil.js.map +1 -1
- package/build/dist/Utils/NetworkDiscovery/ScanNameUtil.js +120 -0
- package/build/dist/Utils/NetworkDiscovery/ScanNameUtil.js.map +1 -0
- package/build/dist/Utils/StatusPage/ResourceExplorer.js +171 -0
- package/build/dist/Utils/StatusPage/ResourceExplorer.js.map +1 -1
- package/build/dist/Utils/Telemetry/LlmMetricQuery.js +175 -0
- package/build/dist/Utils/Telemetry/LlmMetricQuery.js.map +1 -0
- package/jest.config.json +2 -0
- package/package.json +1 -1
- package/tsconfig.json +2 -1
- package/Tests/UI/Components/Toast.test.tsx +0 -197
- package/Tests/UI/Components/ToastStacking.test.tsx +0 -198
- package/UI/Components/Toast/Toast.tsx +0 -189
- package/UI/Components/Toast/ToastInit.tsx +0 -110
- package/build/dist/UI/Components/Toast/Toast.js +0 -123
- package/build/dist/UI/Components/Toast/Toast.js.map +0 -1
- package/build/dist/UI/Components/Toast/ToastInit.js +0 -53
- package/build/dist/UI/Components/Toast/ToastInit.js.map +0 -1
|
@@ -0,0 +1,319 @@
|
|
|
1
|
+
import Label from "../../../Models/DatabaseModels/Label";
|
|
2
|
+
import Monitor from "../../../Models/DatabaseModels/Monitor";
|
|
3
|
+
import EntityDropdown from "../../../UI/Components/EntityDropdown/EntityDropdown";
|
|
4
|
+
import getJestMockFunction, { MockFunction } from "../../../Tests/MockType";
|
|
5
|
+
import {
|
|
6
|
+
afterEach,
|
|
7
|
+
beforeEach,
|
|
8
|
+
describe,
|
|
9
|
+
expect,
|
|
10
|
+
jest,
|
|
11
|
+
test,
|
|
12
|
+
} from "@jest/globals";
|
|
13
|
+
import {
|
|
14
|
+
cleanup,
|
|
15
|
+
fireEvent,
|
|
16
|
+
render,
|
|
17
|
+
screen,
|
|
18
|
+
waitFor,
|
|
19
|
+
} from "@testing-library/react";
|
|
20
|
+
import React from "react";
|
|
21
|
+
|
|
22
|
+
/*
|
|
23
|
+
* Contract under test - what the Labels tab ("Bulk-add by tag") tells its
|
|
24
|
+
* caller.
|
|
25
|
+
*
|
|
26
|
+
* Bulk-add by tag is a ONE-TIME expansion: the label is turned into a list of
|
|
27
|
+
* entries and then discarded, which is exactly why a status page group
|
|
28
|
+
* populated from a label stopped tracking that label (#3418). onLabelsBulkAdded
|
|
29
|
+
* is the only record that a selection came from a label at all, so what it
|
|
30
|
+
* reports, and when, is the whole basis of keeping that group in sync.
|
|
31
|
+
*
|
|
32
|
+
* Two properties, both easy to lose:
|
|
33
|
+
*
|
|
34
|
+
* - it reports the label NAMES, not just ids. The caller has no cheap way
|
|
35
|
+
* back from an id to a name, and the name is what the rule is titled with.
|
|
36
|
+
*
|
|
37
|
+
* - it reports a label whose entries were ALL already selected. That adds
|
|
38
|
+
* nothing to the picker, but it is still a label the user asked this
|
|
39
|
+
* selection to be built from, and dropping it there would silently leave
|
|
40
|
+
* it out of the sync.
|
|
41
|
+
*/
|
|
42
|
+
|
|
43
|
+
const getListMock: MockFunction = getJestMockFunction();
|
|
44
|
+
|
|
45
|
+
jest.mock("../../../UI/Utils/ModelAPI/ModelAPI", () => {
|
|
46
|
+
return {
|
|
47
|
+
__esModule: true,
|
|
48
|
+
default: {
|
|
49
|
+
getList: (...args: Array<any>) => {
|
|
50
|
+
return getListMock(...args);
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
type MakeLabelFunction = (id: string, name: string) => Label;
|
|
57
|
+
|
|
58
|
+
const makeLabel: MakeLabelFunction = (id: string, name: string): Label => {
|
|
59
|
+
return { _id: id, name: name } as unknown as Label;
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
type MakeMonitorFunction = (id: string, name: string) => Monitor;
|
|
63
|
+
|
|
64
|
+
const makeMonitor: MakeMonitorFunction = (
|
|
65
|
+
id: string,
|
|
66
|
+
name: string,
|
|
67
|
+
): Monitor => {
|
|
68
|
+
return { _id: id, name: name } as unknown as Monitor;
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
const LABEL_A: Label = makeLabel(
|
|
72
|
+
"dddddddd-dddd-4ddd-8ddd-dddddddddddd",
|
|
73
|
+
"WB Digital",
|
|
74
|
+
);
|
|
75
|
+
const LABEL_B: Label = makeLabel(
|
|
76
|
+
"eeeeeeee-eeee-4eee-8eee-eeeeeeeeeeee",
|
|
77
|
+
"WB Digital Service",
|
|
78
|
+
);
|
|
79
|
+
const MONITOR_A: Monitor = makeMonitor(
|
|
80
|
+
"aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa",
|
|
81
|
+
"Mobile App - Payment",
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
describe("EntityDropdown Labels tab - what it tells the caller", () => {
|
|
85
|
+
let onLabelsBulkAdded: MockFunction;
|
|
86
|
+
let onChange: MockFunction;
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* One mock for every list the dropdown makes: the option search, the label
|
|
90
|
+
* list, and the by-label expansion. `monitorsForLabels` is what the
|
|
91
|
+
* expansion finds.
|
|
92
|
+
*/
|
|
93
|
+
type SetUpFunction = (options?: {
|
|
94
|
+
monitorsForLabels?: Array<Monitor> | undefined;
|
|
95
|
+
labels?: Array<Label> | undefined;
|
|
96
|
+
failLabelExpansion?: boolean | undefined;
|
|
97
|
+
}) => void;
|
|
98
|
+
|
|
99
|
+
const setUp: SetUpFunction = (options?: {
|
|
100
|
+
monitorsForLabels?: Array<Monitor> | undefined;
|
|
101
|
+
labels?: Array<Label> | undefined;
|
|
102
|
+
failLabelExpansion?: boolean | undefined;
|
|
103
|
+
}): void => {
|
|
104
|
+
getListMock.mockImplementation((request: any) => {
|
|
105
|
+
if (request?.modelType === Label) {
|
|
106
|
+
return Promise.resolve({
|
|
107
|
+
data:
|
|
108
|
+
options?.labels === undefined ? [LABEL_A, LABEL_B] : options.labels,
|
|
109
|
+
count: 0,
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// The by-label expansion is the only monitor list that queries labels.
|
|
114
|
+
if (request?.query?.labels) {
|
|
115
|
+
if (options?.failLabelExpansion) {
|
|
116
|
+
return Promise.reject(new Error("no read access"));
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return Promise.resolve({
|
|
120
|
+
data:
|
|
121
|
+
options?.monitorsForLabels === undefined
|
|
122
|
+
? [MONITOR_A]
|
|
123
|
+
: options.monitorsForLabels,
|
|
124
|
+
count: 0,
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// The plain option search behind the Results tab.
|
|
129
|
+
return Promise.resolve({ data: [], count: 0 });
|
|
130
|
+
});
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
type OpenLabelsTabFunction = (value?: Array<string> | undefined) => void;
|
|
134
|
+
|
|
135
|
+
const openLabelsTab: OpenLabelsTabFunction = (
|
|
136
|
+
value?: Array<string> | undefined,
|
|
137
|
+
): void => {
|
|
138
|
+
render(
|
|
139
|
+
<EntityDropdown
|
|
140
|
+
isMultiSelect={true}
|
|
141
|
+
modelType={Monitor}
|
|
142
|
+
labelField="name"
|
|
143
|
+
valueField="_id"
|
|
144
|
+
enableLabelsTab={true}
|
|
145
|
+
value={value}
|
|
146
|
+
placeholder="Select Monitors"
|
|
147
|
+
onChange={onChange as never}
|
|
148
|
+
onLabelsBulkAdded={onLabelsBulkAdded as never}
|
|
149
|
+
/>,
|
|
150
|
+
);
|
|
151
|
+
|
|
152
|
+
fireEvent.focus(screen.getByRole("combobox"));
|
|
153
|
+
fireEvent.click(screen.getByRole("tab", { name: /Labels/ }));
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
type ApplyLabelFunction = (labelName: string) => Promise<void>;
|
|
157
|
+
|
|
158
|
+
const applyLabel: ApplyLabelFunction = async (
|
|
159
|
+
labelName: string,
|
|
160
|
+
): Promise<void> => {
|
|
161
|
+
const labelRow: HTMLElement = await screen.findByRole("option", {
|
|
162
|
+
name: new RegExp(`^${labelName}$`),
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
fireEvent.click(labelRow);
|
|
166
|
+
fireEvent.click(screen.getByRole("button", { name: /Add entries from/ }));
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
beforeEach(() => {
|
|
170
|
+
onLabelsBulkAdded = getJestMockFunction();
|
|
171
|
+
onChange = getJestMockFunction();
|
|
172
|
+
getListMock.mockReset();
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
afterEach(() => {
|
|
176
|
+
cleanup();
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
test("reports the label that produced the entries, with its name", async () => {
|
|
180
|
+
setUp();
|
|
181
|
+
openLabelsTab();
|
|
182
|
+
await applyLabel("WB Digital");
|
|
183
|
+
|
|
184
|
+
await waitFor(() => {
|
|
185
|
+
expect(onLabelsBulkAdded).toHaveBeenCalled();
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
expect(onLabelsBulkAdded.mock.calls[0]![0]).toEqual([
|
|
189
|
+
{ id: LABEL_A._id, name: "WB Digital" },
|
|
190
|
+
]);
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
/*
|
|
194
|
+
* #3418's durable half. Two labels can sit on the same monitors, and the
|
|
195
|
+
* second one adds nothing to the picker - but the user picked it, and a
|
|
196
|
+
* monitor given only that label later is exactly what should still arrive.
|
|
197
|
+
*/
|
|
198
|
+
test("reports a label whose entries were all already selected", async () => {
|
|
199
|
+
setUp({ monitorsForLabels: [MONITOR_A] });
|
|
200
|
+
openLabelsTab([MONITOR_A._id!]);
|
|
201
|
+
await applyLabel("WB Digital");
|
|
202
|
+
|
|
203
|
+
await waitFor(() => {
|
|
204
|
+
expect(onLabelsBulkAdded).toHaveBeenCalled();
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
expect(onLabelsBulkAdded.mock.calls[0]![0]).toEqual([
|
|
208
|
+
{ id: LABEL_A._id, name: "WB Digital" },
|
|
209
|
+
]);
|
|
210
|
+
|
|
211
|
+
// And the user is still told nothing new landed in the picker.
|
|
212
|
+
expect(await screen.findByText(/No new entries matched/)).toBeTruthy();
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
test("reports a label that matches nothing at all yet", async () => {
|
|
216
|
+
setUp({ monitorsForLabels: [] });
|
|
217
|
+
openLabelsTab();
|
|
218
|
+
await applyLabel("WB Digital");
|
|
219
|
+
|
|
220
|
+
await waitFor(() => {
|
|
221
|
+
expect(onLabelsBulkAdded).toHaveBeenCalled();
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
expect(onLabelsBulkAdded.mock.calls[0]![0]).toEqual([
|
|
225
|
+
{ id: LABEL_A._id, name: "WB Digital" },
|
|
226
|
+
]);
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
/*
|
|
230
|
+
* A failed expansion means the picker does not know what the label covers.
|
|
231
|
+
* Reporting it would keep a group in sync with a label the user never got
|
|
232
|
+
* to see the contents of.
|
|
233
|
+
*/
|
|
234
|
+
test("reports nothing when the expansion itself failed", async () => {
|
|
235
|
+
setUp({ failLabelExpansion: true });
|
|
236
|
+
openLabelsTab();
|
|
237
|
+
await applyLabel("WB Digital");
|
|
238
|
+
|
|
239
|
+
expect(await screen.findByText(/Failed to fetch entries/)).toBeTruthy();
|
|
240
|
+
expect(onLabelsBulkAdded).not.toHaveBeenCalled();
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
test("reports every label when more than one was applied at once", async () => {
|
|
244
|
+
setUp();
|
|
245
|
+
openLabelsTab();
|
|
246
|
+
|
|
247
|
+
fireEvent.click(
|
|
248
|
+
await screen.findByRole("option", { name: /^WB Digital$/ }),
|
|
249
|
+
);
|
|
250
|
+
fireEvent.click(
|
|
251
|
+
await screen.findByRole("option", { name: /^WB Digital Service$/ }),
|
|
252
|
+
);
|
|
253
|
+
fireEvent.click(screen.getByRole("button", { name: /Add entries from/ }));
|
|
254
|
+
|
|
255
|
+
await waitFor(() => {
|
|
256
|
+
expect(onLabelsBulkAdded).toHaveBeenCalled();
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
expect(onLabelsBulkAdded.mock.calls[0]![0]).toEqual([
|
|
260
|
+
{ id: LABEL_A._id, name: "WB Digital" },
|
|
261
|
+
{ id: LABEL_B._id, name: "WB Digital Service" },
|
|
262
|
+
]);
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
/*
|
|
266
|
+
* The prop is optional and every other caller of this component leaves it
|
|
267
|
+
* off. Bulk-add by tag has to keep working there exactly as it did.
|
|
268
|
+
*/
|
|
269
|
+
test("still adds the entries when nobody is listening for the labels", async () => {
|
|
270
|
+
setUp();
|
|
271
|
+
|
|
272
|
+
render(
|
|
273
|
+
<EntityDropdown
|
|
274
|
+
isMultiSelect={true}
|
|
275
|
+
modelType={Monitor}
|
|
276
|
+
labelField="name"
|
|
277
|
+
valueField="_id"
|
|
278
|
+
enableLabelsTab={true}
|
|
279
|
+
placeholder="Select Monitors"
|
|
280
|
+
onChange={onChange as never}
|
|
281
|
+
/>,
|
|
282
|
+
);
|
|
283
|
+
|
|
284
|
+
fireEvent.focus(screen.getByRole("combobox"));
|
|
285
|
+
fireEvent.click(screen.getByRole("tab", { name: /Labels/ }));
|
|
286
|
+
await applyLabel("WB Digital");
|
|
287
|
+
|
|
288
|
+
await waitFor(() => {
|
|
289
|
+
expect(onChange).toHaveBeenCalled();
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
expect(onChange.mock.calls[0]![0]).toEqual([MONITOR_A._id]);
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
/*
|
|
296
|
+
* The names come off the label list the tab already loaded. A label the list
|
|
297
|
+
* does not carry must still be reported - a rule with a duller title is far
|
|
298
|
+
* better than a group that silently stops tracking the label.
|
|
299
|
+
*/
|
|
300
|
+
test("reports a label it has no name for rather than dropping it", async () => {
|
|
301
|
+
const namelessLabel: Label = makeLabel(LABEL_A._id!, "");
|
|
302
|
+
|
|
303
|
+
setUp({ labels: [namelessLabel] });
|
|
304
|
+
openLabelsTab();
|
|
305
|
+
|
|
306
|
+
fireEvent.click(
|
|
307
|
+
await screen.findByRole("option", { name: /^Unnamed Label$/ }),
|
|
308
|
+
);
|
|
309
|
+
fireEvent.click(screen.getByRole("button", { name: /Add entries from/ }));
|
|
310
|
+
|
|
311
|
+
await waitFor(() => {
|
|
312
|
+
expect(onLabelsBulkAdded).toHaveBeenCalled();
|
|
313
|
+
});
|
|
314
|
+
|
|
315
|
+
expect(onLabelsBulkAdded.mock.calls[0]![0]).toEqual([
|
|
316
|
+
{ id: LABEL_A._id, name: "" },
|
|
317
|
+
]);
|
|
318
|
+
});
|
|
319
|
+
});
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
import "@testing-library/jest-dom";
|
|
2
|
+
import React from "react";
|
|
3
|
+
import { cleanup, render, screen } from "@testing-library/react";
|
|
4
|
+
import { afterEach, describe, expect, jest, test } from "@jest/globals";
|
|
5
|
+
|
|
6
|
+
/*
|
|
7
|
+
* Monaco stand-in. Needed because FormField reaches CodeEditor through
|
|
8
|
+
* YamlEditor, and CodeEditor calls configureMonacoLoader() at module scope.
|
|
9
|
+
*/
|
|
10
|
+
jest.mock("@monaco-editor/react", () => {
|
|
11
|
+
return {
|
|
12
|
+
__esModule: true,
|
|
13
|
+
loader: { config: jest.fn() },
|
|
14
|
+
default: (editorProps: {
|
|
15
|
+
value?: string | undefined;
|
|
16
|
+
defaultLanguage?: string | undefined;
|
|
17
|
+
onChange?: ((value: string | undefined) => void) | undefined;
|
|
18
|
+
onMount?: ((editor: unknown, monaco: unknown) => void) | undefined;
|
|
19
|
+
}) => {
|
|
20
|
+
const hostRef: React.MutableRefObject<HTMLDivElement | null> =
|
|
21
|
+
React.useRef<HTMLDivElement | null>(null);
|
|
22
|
+
|
|
23
|
+
React.useEffect(() => {
|
|
24
|
+
if (!editorProps.onMount) {
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
editorProps.onMount(
|
|
29
|
+
{
|
|
30
|
+
getDomNode: () => {
|
|
31
|
+
return hostRef.current;
|
|
32
|
+
},
|
|
33
|
+
getModel: () => {
|
|
34
|
+
return {
|
|
35
|
+
updateOptions: () => {
|
|
36
|
+
return undefined;
|
|
37
|
+
},
|
|
38
|
+
};
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
{},
|
|
42
|
+
);
|
|
43
|
+
// eslint-disable-next-line
|
|
44
|
+
}, []);
|
|
45
|
+
|
|
46
|
+
return (
|
|
47
|
+
<div ref={hostRef}>
|
|
48
|
+
<textarea
|
|
49
|
+
data-testid="monaco"
|
|
50
|
+
data-language={editorProps.defaultLanguage}
|
|
51
|
+
value={editorProps.value || ""}
|
|
52
|
+
readOnly={true}
|
|
53
|
+
/>
|
|
54
|
+
</div>
|
|
55
|
+
);
|
|
56
|
+
},
|
|
57
|
+
};
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
import FormField from "../../../../UI/Components/Forms/Fields/FormField";
|
|
61
|
+
import Field from "../../../../UI/Components/Forms/Types/Field";
|
|
62
|
+
import FormFieldSchemaType from "../../../../UI/Components/Forms/Types/FormFieldSchemaType";
|
|
63
|
+
import FormValues from "../../../../UI/Components/Forms/Types/FormValues";
|
|
64
|
+
import { JSONObject } from "../../../../Types/JSON";
|
|
65
|
+
|
|
66
|
+
/*
|
|
67
|
+
* A FormFieldSchemaType member with no render branch in FormField.tsx is a
|
|
68
|
+
* silent failure: the field draws its label and description above empty
|
|
69
|
+
* space, and neither the compiler nor the linter says a word. (Query is in
|
|
70
|
+
* the enum today and does exactly that.) These tests are the guard for YAML.
|
|
71
|
+
*/
|
|
72
|
+
|
|
73
|
+
interface TestEntity extends JSONObject {
|
|
74
|
+
sigmaRuleYaml?: string;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const VALID_SIGMA_RULE: string = "title: Failed logon burst\nlevel: high\n";
|
|
78
|
+
|
|
79
|
+
type RenderFieldFunction = (
|
|
80
|
+
overrides?: Partial<Field<TestEntity>>,
|
|
81
|
+
values?: FormValues<TestEntity>,
|
|
82
|
+
) => void;
|
|
83
|
+
|
|
84
|
+
const renderField: RenderFieldFunction = (
|
|
85
|
+
overrides?: Partial<Field<TestEntity>>,
|
|
86
|
+
values?: FormValues<TestEntity>,
|
|
87
|
+
): void => {
|
|
88
|
+
const field: Field<TestEntity> = {
|
|
89
|
+
title: "Sigma Rule (YAML)",
|
|
90
|
+
description: "The Sigma rule to evaluate, in YAML.",
|
|
91
|
+
name: "sigmaRuleYaml",
|
|
92
|
+
field: { sigmaRuleYaml: true },
|
|
93
|
+
fieldType: FormFieldSchemaType.YAML,
|
|
94
|
+
required: true,
|
|
95
|
+
...overrides,
|
|
96
|
+
} as Field<TestEntity>;
|
|
97
|
+
|
|
98
|
+
render(
|
|
99
|
+
<FormField<TestEntity>
|
|
100
|
+
field={field}
|
|
101
|
+
fieldName="sigmaRuleYaml"
|
|
102
|
+
index={0}
|
|
103
|
+
isDisabled={false}
|
|
104
|
+
error=""
|
|
105
|
+
touched={false}
|
|
106
|
+
currentValues={
|
|
107
|
+
(values || {
|
|
108
|
+
sigmaRuleYaml: VALID_SIGMA_RULE,
|
|
109
|
+
}) as FormValues<TestEntity>
|
|
110
|
+
}
|
|
111
|
+
setFieldTouched={() => {}}
|
|
112
|
+
setFieldValue={() => {}}
|
|
113
|
+
/>,
|
|
114
|
+
);
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
afterEach(() => {
|
|
118
|
+
cleanup();
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
describe("FormField — a YAML field renders a YAML editor", () => {
|
|
122
|
+
test("an editor is rendered at all, not a label above empty space", () => {
|
|
123
|
+
renderField();
|
|
124
|
+
|
|
125
|
+
expect(screen.getByTestId("yaml-editor")).toBeInTheDocument();
|
|
126
|
+
expect(screen.getByTestId("monaco")).toBeInTheDocument();
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
test("Monaco is given the yaml grammar, not html or markdown", () => {
|
|
130
|
+
renderField();
|
|
131
|
+
|
|
132
|
+
expect(screen.getByTestId("monaco")).toHaveAttribute(
|
|
133
|
+
"data-language",
|
|
134
|
+
"yaml",
|
|
135
|
+
);
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
/*
|
|
139
|
+
* The bug: a Sigma rule field rendered the rich-text Markdown editor, so it
|
|
140
|
+
* carried a Bold button and an H1 button.
|
|
141
|
+
*/
|
|
142
|
+
test("no rich-text toolbar comes with it", () => {
|
|
143
|
+
renderField();
|
|
144
|
+
|
|
145
|
+
for (const label of ["Bold", "Italic", "Heading 1", "Heading 2"]) {
|
|
146
|
+
expect(screen.queryByTitle(label)).toBeNull();
|
|
147
|
+
}
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
test("the current value is shown in the editor", () => {
|
|
151
|
+
renderField();
|
|
152
|
+
|
|
153
|
+
expect((screen.getByTestId("monaco") as HTMLTextAreaElement).value).toBe(
|
|
154
|
+
VALID_SIGMA_RULE,
|
|
155
|
+
);
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
test("an empty field renders an empty editor rather than crashing", () => {
|
|
159
|
+
renderField(undefined, {} as FormValues<TestEntity>);
|
|
160
|
+
|
|
161
|
+
expect((screen.getByTestId("monaco") as HTMLTextAreaElement).value).toBe(
|
|
162
|
+
"",
|
|
163
|
+
);
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
test("the field's label is still rendered above it", () => {
|
|
167
|
+
renderField();
|
|
168
|
+
|
|
169
|
+
expect(screen.getByText("Sigma Rule (YAML)")).toBeInTheDocument();
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
/*
|
|
173
|
+
* Monaco renders nothing carrying the generated field id, so the label
|
|
174
|
+
* cannot use htmlFor without dangling (WCAG 1.3.1). It names the editor
|
|
175
|
+
* through aria-labelledby instead — and that has to land on Monaco's own
|
|
176
|
+
* focusable textarea, because the wrapper around it is a bare <div> and
|
|
177
|
+
* ARIA does not name a role=generic element.
|
|
178
|
+
*/
|
|
179
|
+
test("the field's label names Monaco's textarea", () => {
|
|
180
|
+
renderField();
|
|
181
|
+
|
|
182
|
+
const labelId: string =
|
|
183
|
+
screen.getByTestId("monaco").getAttribute("aria-labelledby") || "";
|
|
184
|
+
|
|
185
|
+
expect(labelId).not.toBe("");
|
|
186
|
+
expect(document.getElementById(labelId)?.textContent).toContain(
|
|
187
|
+
"Sigma Rule (YAML)",
|
|
188
|
+
);
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
test("the editor is described by the hint and the status bar", () => {
|
|
192
|
+
renderField();
|
|
193
|
+
|
|
194
|
+
const describedBy: string =
|
|
195
|
+
screen.getByTestId("monaco").getAttribute("aria-describedby") || "";
|
|
196
|
+
|
|
197
|
+
expect(describedBy.split(" ").length).toBeGreaterThanOrEqual(2);
|
|
198
|
+
|
|
199
|
+
for (const id of describedBy.split(" ")) {
|
|
200
|
+
expect(document.getElementById(id)).not.toBeNull();
|
|
201
|
+
}
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
test("no <label for> points at an element that does not exist", () => {
|
|
205
|
+
renderField();
|
|
206
|
+
|
|
207
|
+
const labels: Array<HTMLLabelElement> = Array.from(
|
|
208
|
+
document.querySelectorAll("label[for]"),
|
|
209
|
+
);
|
|
210
|
+
|
|
211
|
+
for (const label of labels) {
|
|
212
|
+
expect(document.getElementById(label.htmlFor)).not.toBeNull();
|
|
213
|
+
}
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
test("the dataTestId the page sets reaches the editor", () => {
|
|
217
|
+
renderField({ dataTestId: "sigma-rule-yaml" });
|
|
218
|
+
|
|
219
|
+
expect(screen.getByTestId("sigma-rule-yaml")).toBeInTheDocument();
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
test("a hidden field (showIf false) renders nothing", () => {
|
|
223
|
+
renderField({
|
|
224
|
+
showIf: (): boolean => {
|
|
225
|
+
return false;
|
|
226
|
+
},
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
expect(screen.queryByTestId("yaml-editor")).toBeNull();
|
|
230
|
+
});
|
|
231
|
+
});
|
|
@@ -69,6 +69,7 @@ const expectations: Array<SchemaToFieldExpectation> = [
|
|
|
69
69
|
{ schemaType: FormFieldSchemaType.HTML, expected: FieldType.HTML },
|
|
70
70
|
{ schemaType: FormFieldSchemaType.RadioButton, expected: FieldType.Text },
|
|
71
71
|
{ schemaType: FormFieldSchemaType.JSON, expected: FieldType.JSON },
|
|
72
|
+
{ schemaType: FormFieldSchemaType.YAML, expected: FieldType.YAML },
|
|
72
73
|
{ schemaType: FormFieldSchemaType.Query, expected: FieldType.Element },
|
|
73
74
|
{
|
|
74
75
|
schemaType: FormFieldSchemaType.CustomComponent,
|