@oneuptime/common 12.0.22 → 12.0.24
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/DatabaseModels/DetectionRule.ts +55 -0
- package/Models/DatabaseModels/Index.ts +2 -0
- package/Models/DatabaseModels/NetworkDevice.ts +44 -0
- package/Models/DatabaseModels/NetworkDeviceAutoImportRule.ts +584 -0
- package/Models/DatabaseModels/NetworkDeviceDiscoveryScan.ts +105 -0
- package/Models/DatabaseModels/Project.ts +68 -0
- package/Models/DatabaseModels/User.ts +68 -0
- package/Server/API/TelemetryAPI.ts +29 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1789100000000-AddNetworkDeviceAutoImportRule.ts +60 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1789200000000-AddSysObjectIdPatternToAutoImportRule.ts +26 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1789300000000-AddAutoApplyVendorHealthTemplate.ts +26 -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 +12 -0
- package/Server/Middleware/GzipRequestBody.ts +311 -0
- package/Server/Middleware/MultipartFormData.ts +87 -3
- package/Server/Services/DetectionRuleService.ts +73 -6
- package/Server/Services/Index.ts +207 -0
- package/Server/Services/NetworkDeviceAutoImportRuleEngineService.ts +917 -0
- package/Server/Services/NetworkDeviceAutoImportRuleService.ts +181 -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/Monitor/NetworkInventoryUtil.ts +39 -1
- 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 +130 -0
- 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/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/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/Services/AddDetectionRuleDistinctCountColumnsMigration.test.ts +311 -0
- package/Tests/Server/Services/AutoImportScanCredentialSelect.test.ts +205 -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/NetworkDeviceAutoImportRuleEngineService.test.ts +933 -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/Monitor/NetworkInventoryUtil.test.ts +97 -1
- 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 +368 -4
- package/Tests/Server/Utils/Telemetry/LlmMetricSpend.test.ts +245 -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 +193 -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/AutoImportRuleMatcher.test.ts +516 -0
- package/Tests/Utils/NetworkDiscovery/DiscoveredDeviceBuilder.test.ts +272 -0
- package/Tests/Utils/NetworkDiscovery/DiscoveredHostUtil.test.ts +221 -0
- package/Tests/Utils/NetworkDiscovery/ScanNameUtil.test.ts +312 -0
- package/Tests/Utils/NetworkDiscovery/ScanTargetUtil.test.ts +164 -0
- package/Tests/Utils/StatusPage/ResourceExplorer.test.ts +468 -0
- package/Tests/Utils/Telemetry/LlmMetricQuery.test.ts +472 -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/NetworkAutomation/RuleRunResult.ts +84 -0
- package/Types/Permission.ts +47 -0
- package/Types/SecurityEvent/DetectionFindingConstants.ts +11 -0
- package/Types/Telemetry/LlmMetricConventions.ts +124 -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/AutoImportRuleMatcher.ts +257 -0
- package/Utils/NetworkDiscovery/DiscoveredDeviceBuilder.ts +183 -0
- package/Utils/NetworkDiscovery/DiscoveredHostUtil.ts +95 -0
- package/Utils/NetworkDiscovery/DiscoveryImportEligibility.ts +66 -0
- package/Utils/NetworkDiscovery/ScanNameUtil.ts +181 -0
- package/Utils/NetworkDiscovery/ScanTargetUtil.ts +82 -0
- package/Utils/StatusPage/ResourceExplorer.ts +258 -0
- package/Utils/Telemetry/LlmMetricQuery.ts +204 -0
- package/build/dist/Models/DatabaseModels/DetectionRule.js +57 -0
- package/build/dist/Models/DatabaseModels/DetectionRule.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Index.js +2 -0
- package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
- package/build/dist/Models/DatabaseModels/NetworkDevice.js +45 -0
- package/build/dist/Models/DatabaseModels/NetworkDevice.js.map +1 -1
- package/build/dist/Models/DatabaseModels/NetworkDeviceAutoImportRule.js +609 -0
- package/build/dist/Models/DatabaseModels/NetworkDeviceAutoImportRule.js.map +1 -0
- package/build/dist/Models/DatabaseModels/NetworkDeviceDiscoveryScan.js +97 -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/TelemetryAPI.js +17 -0
- package/build/dist/Server/API/TelemetryAPI.js.map +1 -1
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1789100000000-AddNetworkDeviceAutoImportRule.js +35 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1789100000000-AddNetworkDeviceAutoImportRule.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1789200000000-AddSysObjectIdPatternToAutoImportRule.js +19 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1789200000000-AddSysObjectIdPatternToAutoImportRule.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1789300000000-AddAutoApplyVendorHealthTemplate.js +19 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1789300000000-AddAutoApplyVendorHealthTemplate.js.map +1 -0
- 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 +12 -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/Services/DetectionRuleService.js +49 -4
- package/build/dist/Server/Services/DetectionRuleService.js.map +1 -1
- package/build/dist/Server/Services/Index.js +206 -0
- package/build/dist/Server/Services/Index.js.map +1 -1
- package/build/dist/Server/Services/NetworkDeviceAutoImportRuleEngineService.js +711 -0
- package/build/dist/Server/Services/NetworkDeviceAutoImportRuleEngineService.js.map +1 -0
- package/build/dist/Server/Services/NetworkDeviceAutoImportRuleService.js +155 -0
- package/build/dist/Server/Services/NetworkDeviceAutoImportRuleService.js.map +1 -0
- 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/Monitor/NetworkInventoryUtil.js +26 -0
- package/build/dist/Server/Utils/Monitor/NetworkInventoryUtil.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 +102 -0
- package/build/dist/Server/Utils/Telemetry/LlmMetricSpend.js.map +1 -0
- 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/NetworkAutomation/RuleRunResult.js +24 -0
- package/build/dist/Types/NetworkAutomation/RuleRunResult.js.map +1 -1
- package/build/dist/Types/Permission.js +41 -0
- package/build/dist/Types/Permission.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/LlmMetricConventions.js +98 -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/AutoImportRuleMatcher.js +149 -0
- package/build/dist/Utils/NetworkDiscovery/AutoImportRuleMatcher.js.map +1 -0
- package/build/dist/Utils/NetworkDiscovery/DiscoveredDeviceBuilder.js +121 -0
- package/build/dist/Utils/NetworkDiscovery/DiscoveredDeviceBuilder.js.map +1 -0
- package/build/dist/Utils/NetworkDiscovery/DiscoveredHostUtil.js +75 -0
- package/build/dist/Utils/NetworkDiscovery/DiscoveredHostUtil.js.map +1 -0
- package/build/dist/Utils/NetworkDiscovery/DiscoveryImportEligibility.js +59 -0
- package/build/dist/Utils/NetworkDiscovery/DiscoveryImportEligibility.js.map +1 -0
- package/build/dist/Utils/NetworkDiscovery/ScanNameUtil.js +120 -0
- package/build/dist/Utils/NetworkDiscovery/ScanNameUtil.js.map +1 -0
- package/build/dist/Utils/NetworkDiscovery/ScanTargetUtil.js +60 -0
- package/build/dist/Utils/NetworkDiscovery/ScanTargetUtil.js.map +1 -1
- 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 +119 -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,460 @@
|
|
|
1
|
+
import "@testing-library/jest-dom";
|
|
2
|
+
import {
|
|
3
|
+
afterEach,
|
|
4
|
+
beforeEach,
|
|
5
|
+
describe,
|
|
6
|
+
expect,
|
|
7
|
+
jest,
|
|
8
|
+
test,
|
|
9
|
+
} from "@jest/globals";
|
|
10
|
+
import { cleanup, render, screen, waitFor } from "@testing-library/react";
|
|
11
|
+
import React from "react";
|
|
12
|
+
import getJestMockFunction, { MockFunction } from "../../MockType";
|
|
13
|
+
|
|
14
|
+
/*
|
|
15
|
+
* https://github.com/OneUptime/oneuptime/issues/3411
|
|
16
|
+
*
|
|
17
|
+
* The schedule preview (the "Final schedule" calendar and the "On call right
|
|
18
|
+
* now" card above it) is the screen an on-call engineer opens to answer "who is
|
|
19
|
+
* covering?". Alert routing answers the same question through
|
|
20
|
+
* OnCallDutyPolicyEscalationRuleService -> getCurrentUserIdInSchedule, which is
|
|
21
|
+
* handed the escalating policy's id and therefore applies BOTH global and
|
|
22
|
+
* policy-scoped user overrides.
|
|
23
|
+
*
|
|
24
|
+
* The preview used to hard-code `onCallDutyPolicyId: IsNull()` on its override
|
|
25
|
+
* fetch, so an override created from the on-call policy's own "User Overrides"
|
|
26
|
+
* tab - the obvious place to add a shift override, and the one that stamps
|
|
27
|
+
* onCallDutyPolicyId - never reached the calendar. The page then contradicted
|
|
28
|
+
* itself: the banner at the top of the same screen reads the persisted roster,
|
|
29
|
+
* which the server resolves in the single attached policy's context and which
|
|
30
|
+
* therefore DID show the substitute, while the calendar underneath kept showing
|
|
31
|
+
* the original user.
|
|
32
|
+
*
|
|
33
|
+
* These tests drive the real component with a mocked ModelAPI that filters the
|
|
34
|
+
* override list exactly the way the server's query would, so an assertion here
|
|
35
|
+
* fails if the component stops asking for the right rows OR stops passing the
|
|
36
|
+
* policy context into UserOverrideUtil - the two independent halves of the bug.
|
|
37
|
+
*/
|
|
38
|
+
|
|
39
|
+
const getListMock: MockFunction = getJestMockFunction();
|
|
40
|
+
|
|
41
|
+
/*
|
|
42
|
+
* The arrow wrappers matter: jest.mock is hoisted above the compiled requires,
|
|
43
|
+
* so the consts above are still in their temporal dead zone when the factory
|
|
44
|
+
* body runs. Dereferencing lazily, at call time, is what works.
|
|
45
|
+
*/
|
|
46
|
+
jest.mock("../../../UI/Utils/ModelAPI/ModelAPI", () => {
|
|
47
|
+
return {
|
|
48
|
+
__esModule: true,
|
|
49
|
+
default: {
|
|
50
|
+
getList: (...args: Array<any>) => {
|
|
51
|
+
return getListMock(...args);
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
};
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
jest.mock("../../../UI/Utils/Project", () => {
|
|
58
|
+
return {
|
|
59
|
+
__esModule: true,
|
|
60
|
+
default: {
|
|
61
|
+
getCurrentProjectId: () => {
|
|
62
|
+
return {
|
|
63
|
+
toString: (): string => {
|
|
64
|
+
return PROJECT_ID;
|
|
65
|
+
},
|
|
66
|
+
};
|
|
67
|
+
},
|
|
68
|
+
},
|
|
69
|
+
};
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
/*
|
|
73
|
+
* react-big-calendar renders a grid that is awkward to assert against and slow
|
|
74
|
+
* to mount. What matters here is the event list the preview hands it, so the
|
|
75
|
+
* calendar is replaced by a plain list of event titles. The substitution is
|
|
76
|
+
* visible in the DOM either way, so a regression that stops relabelling events
|
|
77
|
+
* still fails.
|
|
78
|
+
*/
|
|
79
|
+
jest.mock("../../../UI/Components/Calendar/Calendar", () => {
|
|
80
|
+
return {
|
|
81
|
+
__esModule: true,
|
|
82
|
+
default: (props: any) => {
|
|
83
|
+
return (
|
|
84
|
+
<ul data-testid="calendar-events">
|
|
85
|
+
{(props.events || []).map((event: any, index: number) => {
|
|
86
|
+
return (
|
|
87
|
+
<li key={index} data-testid="calendar-event">
|
|
88
|
+
{event.title}
|
|
89
|
+
</li>
|
|
90
|
+
);
|
|
91
|
+
})}
|
|
92
|
+
</ul>
|
|
93
|
+
);
|
|
94
|
+
},
|
|
95
|
+
DefaultCalendarView: {
|
|
96
|
+
Month: "month",
|
|
97
|
+
Week: "week",
|
|
98
|
+
Day: "day",
|
|
99
|
+
Agenda: "agenda",
|
|
100
|
+
},
|
|
101
|
+
};
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
import LayersPreview from "../../../../App/FeatureSet/Dashboard/src/Components/OnCallPolicy/OnCallScheduleLayer/LayersPreview";
|
|
105
|
+
import OnCallDutyPolicyEscalationRuleSchedule from "../../../Models/DatabaseModels/OnCallDutyPolicyEscalationRuleSchedule";
|
|
106
|
+
import OnCallDutyPolicyScheduleLayer from "../../../Models/DatabaseModels/OnCallDutyPolicyScheduleLayer";
|
|
107
|
+
import OnCallDutyPolicyScheduleLayerUser from "../../../Models/DatabaseModels/OnCallDutyPolicyScheduleLayerUser";
|
|
108
|
+
import OnCallDutyPolicyUserOverride from "../../../Models/DatabaseModels/OnCallDutyPolicyUserOverride";
|
|
109
|
+
import User from "../../../Models/DatabaseModels/User";
|
|
110
|
+
import IsNull from "../../../Types/BaseDatabase/IsNull";
|
|
111
|
+
import EqualToOrNull from "../../../Types/BaseDatabase/EqualToOrNull";
|
|
112
|
+
import Dictionary from "../../../Types/Dictionary";
|
|
113
|
+
import OneUptimeDate from "../../../Types/Date";
|
|
114
|
+
import EventInterval from "../../../Types/Events/EventInterval";
|
|
115
|
+
import Recurring from "../../../Types/Events/Recurring";
|
|
116
|
+
import ObjectID from "../../../Types/ObjectID";
|
|
117
|
+
import RestrictionTimes, {
|
|
118
|
+
RestrictionType,
|
|
119
|
+
} from "../../../Types/OnCallDutyPolicy/RestrictionTimes";
|
|
120
|
+
|
|
121
|
+
const PROJECT_ID: string = "11111111-1111-4111-8111-111111111111";
|
|
122
|
+
const SCHEDULE_ID: string = "22222222-2222-4222-8222-222222222222";
|
|
123
|
+
const LAYER_ID: string = "33333333-3333-4333-8333-333333333333";
|
|
124
|
+
const POLICY_ID: string = "44444444-4444-4444-8444-444444444444";
|
|
125
|
+
const OTHER_POLICY_ID: string = "55555555-5555-4555-8555-555555555555";
|
|
126
|
+
|
|
127
|
+
const USER_A_ID: string = "aaaaaaaa-1111-4111-8111-111111111111";
|
|
128
|
+
const USER_B_ID: string = "bbbbbbbb-2222-4222-8222-222222222222";
|
|
129
|
+
const USER_C_ID: string = "cccccccc-3333-4333-8333-333333333333";
|
|
130
|
+
|
|
131
|
+
const USER_A_NAME: string = "Alice Scheduled";
|
|
132
|
+
const USER_B_NAME: string = "Bob Covering";
|
|
133
|
+
const USER_C_NAME: string = "Carol Elsewhere";
|
|
134
|
+
|
|
135
|
+
const objectId: (id: string) => ObjectID = (id: string): ObjectID => {
|
|
136
|
+
return new ObjectID(id);
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
function makeUser(id: string, name: string): User {
|
|
140
|
+
const user: User = new User();
|
|
141
|
+
user.id = objectId(id);
|
|
142
|
+
user.name = name as any;
|
|
143
|
+
user.email = `${id}@example.com` as any;
|
|
144
|
+
return user;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/*
|
|
148
|
+
* A single 24/7 layer that started well in the past and rotates daily, so
|
|
149
|
+
* exactly one user - the only one assigned - is on call at "now" no matter when
|
|
150
|
+
* the suite runs. That makes "who does the preview show right now" a question
|
|
151
|
+
* with one correct answer, which is the whole point.
|
|
152
|
+
*/
|
|
153
|
+
function makeLayer(): OnCallDutyPolicyScheduleLayer {
|
|
154
|
+
const layer: OnCallDutyPolicyScheduleLayer =
|
|
155
|
+
new OnCallDutyPolicyScheduleLayer();
|
|
156
|
+
layer.id = objectId(LAYER_ID);
|
|
157
|
+
layer.projectId = objectId(PROJECT_ID);
|
|
158
|
+
layer.onCallDutyPolicyScheduleId = objectId(SCHEDULE_ID);
|
|
159
|
+
layer.order = 1;
|
|
160
|
+
layer.name = "Primary" as any;
|
|
161
|
+
|
|
162
|
+
const now: Date = OneUptimeDate.getCurrentDate();
|
|
163
|
+
layer.startsAt = OneUptimeDate.addRemoveDays(now, -30);
|
|
164
|
+
layer.handOffTime = OneUptimeDate.addRemoveDays(now, -30);
|
|
165
|
+
|
|
166
|
+
layer.rotation = Recurring.fromJSON({
|
|
167
|
+
_type: "Recurring",
|
|
168
|
+
value: {
|
|
169
|
+
intervalType: EventInterval.Day,
|
|
170
|
+
intervalCount: { _type: "PositiveNumber", value: 1 },
|
|
171
|
+
},
|
|
172
|
+
} as any) as any;
|
|
173
|
+
|
|
174
|
+
const restrictionTimes: RestrictionTimes = new RestrictionTimes();
|
|
175
|
+
restrictionTimes.restictionType = RestrictionType.None;
|
|
176
|
+
restrictionTimes.dayRestrictionTimes = null;
|
|
177
|
+
layer.restrictionTimes = restrictionTimes as any;
|
|
178
|
+
|
|
179
|
+
return layer;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
function makeLayerUsers(): Dictionary<
|
|
183
|
+
Array<OnCallDutyPolicyScheduleLayerUser>
|
|
184
|
+
> {
|
|
185
|
+
const layerUser: OnCallDutyPolicyScheduleLayerUser =
|
|
186
|
+
new OnCallDutyPolicyScheduleLayerUser();
|
|
187
|
+
layerUser.id = objectId("66666666-6666-4666-8666-666666666666");
|
|
188
|
+
layerUser.onCallDutyPolicyScheduleLayerId = objectId(LAYER_ID);
|
|
189
|
+
layerUser.onCallDutyPolicyScheduleId = objectId(SCHEDULE_ID);
|
|
190
|
+
layerUser.projectId = objectId(PROJECT_ID);
|
|
191
|
+
layerUser.order = 1;
|
|
192
|
+
layerUser.userId = objectId(USER_A_ID);
|
|
193
|
+
layerUser.user = makeUser(USER_A_ID, USER_A_NAME);
|
|
194
|
+
|
|
195
|
+
return { [LAYER_ID]: [layerUser] };
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
interface OverrideFixture {
|
|
199
|
+
overrideUserId: string;
|
|
200
|
+
routeAlertsToUserId: string;
|
|
201
|
+
routeAlertsToUserName: string;
|
|
202
|
+
onCallDutyPolicyId: string | null;
|
|
203
|
+
startsAt: Date;
|
|
204
|
+
endsAt: Date;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
function activeOverride(
|
|
208
|
+
onCallDutyPolicyId: string | null,
|
|
209
|
+
routeAlertsToUserId: string = USER_B_ID,
|
|
210
|
+
routeAlertsToUserName: string = USER_B_NAME,
|
|
211
|
+
): OverrideFixture {
|
|
212
|
+
const now: Date = OneUptimeDate.getCurrentDate();
|
|
213
|
+
return {
|
|
214
|
+
overrideUserId: USER_A_ID,
|
|
215
|
+
routeAlertsToUserId,
|
|
216
|
+
routeAlertsToUserName,
|
|
217
|
+
onCallDutyPolicyId,
|
|
218
|
+
startsAt: OneUptimeDate.addRemoveHours(now, -1),
|
|
219
|
+
endsAt: OneUptimeDate.addRemoveHours(now, 1),
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
function toModel(fixture: OverrideFixture): OnCallDutyPolicyUserOverride {
|
|
224
|
+
const model: OnCallDutyPolicyUserOverride =
|
|
225
|
+
new OnCallDutyPolicyUserOverride();
|
|
226
|
+
model.id = objectId("77777777-7777-4777-8777-777777777777");
|
|
227
|
+
model.projectId = objectId(PROJECT_ID);
|
|
228
|
+
model.overrideUserId = objectId(fixture.overrideUserId);
|
|
229
|
+
model.routeAlertsToUserId = objectId(fixture.routeAlertsToUserId);
|
|
230
|
+
model.startsAt = fixture.startsAt;
|
|
231
|
+
model.endsAt = fixture.endsAt;
|
|
232
|
+
model.onCallDutyPolicyId = fixture.onCallDutyPolicyId
|
|
233
|
+
? objectId(fixture.onCallDutyPolicyId)
|
|
234
|
+
: (null as any);
|
|
235
|
+
model.overrideUser = makeUser(fixture.overrideUserId, USER_A_NAME);
|
|
236
|
+
model.routeAlertsToUser = makeUser(
|
|
237
|
+
fixture.routeAlertsToUserId,
|
|
238
|
+
fixture.routeAlertsToUserName,
|
|
239
|
+
);
|
|
240
|
+
return model;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
/*
|
|
244
|
+
* Stands in for the server's WHERE clause on onCallDutyPolicyId. Without this
|
|
245
|
+
* the mock would hand back every override regardless of what the component
|
|
246
|
+
* asked for, and the test could not tell a component that asks for the right
|
|
247
|
+
* rows apart from one that asks for the wrong rows and gets lucky.
|
|
248
|
+
*/
|
|
249
|
+
function matchesPolicyQuery(
|
|
250
|
+
fixture: OverrideFixture,
|
|
251
|
+
queryValue: unknown,
|
|
252
|
+
): boolean {
|
|
253
|
+
if (queryValue instanceof IsNull) {
|
|
254
|
+
return fixture.onCallDutyPolicyId === null;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
if (queryValue instanceof EqualToOrNull) {
|
|
258
|
+
return (
|
|
259
|
+
fixture.onCallDutyPolicyId === null ||
|
|
260
|
+
fixture.onCallDutyPolicyId === queryValue.toString()
|
|
261
|
+
);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
if (queryValue === undefined || queryValue === null) {
|
|
265
|
+
// No filter at all - the server would return every row in the project.
|
|
266
|
+
return true;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
return fixture.onCallDutyPolicyId === String(queryValue);
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
interface ScenarioOptions {
|
|
273
|
+
overrides: Array<OverrideFixture>;
|
|
274
|
+
attachedPolicyIds: Array<string>;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
function setupApi(options: ScenarioOptions): void {
|
|
278
|
+
getListMock.mockImplementation((args: any) => {
|
|
279
|
+
const modelName: string = args?.modelType?.name || "";
|
|
280
|
+
|
|
281
|
+
if (modelName === "OnCallDutyPolicyUserOverride") {
|
|
282
|
+
const matched: Array<OverrideFixture> = options.overrides.filter(
|
|
283
|
+
(fixture: OverrideFixture) => {
|
|
284
|
+
return matchesPolicyQuery(fixture, args?.query?.onCallDutyPolicyId);
|
|
285
|
+
},
|
|
286
|
+
);
|
|
287
|
+
|
|
288
|
+
return Promise.resolve({
|
|
289
|
+
data: matched.map(toModel),
|
|
290
|
+
count: matched.length,
|
|
291
|
+
skip: 0,
|
|
292
|
+
limit: matched.length,
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
if (modelName === "OnCallDutyPolicyEscalationRuleSchedule") {
|
|
297
|
+
const joins: Array<OnCallDutyPolicyEscalationRuleSchedule> =
|
|
298
|
+
options.attachedPolicyIds.map((policyId: string, index: number) => {
|
|
299
|
+
const join: OnCallDutyPolicyEscalationRuleSchedule =
|
|
300
|
+
new OnCallDutyPolicyEscalationRuleSchedule();
|
|
301
|
+
join.id = objectId(
|
|
302
|
+
`8888888${index}-8888-4888-8888-888888888888`.slice(0, 36),
|
|
303
|
+
);
|
|
304
|
+
join.projectId = objectId(PROJECT_ID);
|
|
305
|
+
join.onCallDutyPolicyScheduleId = objectId(SCHEDULE_ID);
|
|
306
|
+
join.onCallDutyPolicyId = objectId(policyId);
|
|
307
|
+
return join;
|
|
308
|
+
});
|
|
309
|
+
|
|
310
|
+
return Promise.resolve({
|
|
311
|
+
data: joins,
|
|
312
|
+
count: joins.length,
|
|
313
|
+
skip: 0,
|
|
314
|
+
limit: joins.length,
|
|
315
|
+
});
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
return Promise.resolve({ data: [], count: 0, skip: 0, limit: 0 });
|
|
319
|
+
});
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
function renderPreview(): void {
|
|
323
|
+
render(
|
|
324
|
+
<LayersPreview
|
|
325
|
+
layers={[makeLayer()]}
|
|
326
|
+
allLayerUsers={makeLayerUsers()}
|
|
327
|
+
timezone="UTC"
|
|
328
|
+
onCallDutyPolicyScheduleId={objectId(SCHEDULE_ID)}
|
|
329
|
+
/>,
|
|
330
|
+
);
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
/*
|
|
334
|
+
* The "On call right now" hero card. Reading the name out of that specific card
|
|
335
|
+
* (rather than out of the whole document) is what makes the assertion about the
|
|
336
|
+
* question the user asked - "who is covering right now" - and not about whether
|
|
337
|
+
* a name appears anywhere on a screen that also lists a whole week of shifts.
|
|
338
|
+
*/
|
|
339
|
+
async function getOnCallNowText(): Promise<string> {
|
|
340
|
+
const heading: HTMLElement = await screen.findByText(/On call right now/i);
|
|
341
|
+
const card: HTMLElement | null = heading.closest("div.rounded-xl");
|
|
342
|
+
if (!card) {
|
|
343
|
+
throw new Error("Could not find the 'On call right now' card");
|
|
344
|
+
}
|
|
345
|
+
return card.textContent || "";
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
describe("Schedule preview reflects the overrides that alert routing applies (issue #3411)", () => {
|
|
349
|
+
beforeEach(() => {
|
|
350
|
+
getListMock.mockReset();
|
|
351
|
+
});
|
|
352
|
+
|
|
353
|
+
afterEach(() => {
|
|
354
|
+
cleanup();
|
|
355
|
+
});
|
|
356
|
+
|
|
357
|
+
test("a POLICY-SCOPED override is shown when the schedule is attached to exactly one policy", async () => {
|
|
358
|
+
setupApi({
|
|
359
|
+
overrides: [activeOverride(POLICY_ID)],
|
|
360
|
+
attachedPolicyIds: [POLICY_ID],
|
|
361
|
+
});
|
|
362
|
+
|
|
363
|
+
renderPreview();
|
|
364
|
+
|
|
365
|
+
await waitFor(
|
|
366
|
+
async () => {
|
|
367
|
+
expect(await getOnCallNowText()).toContain(USER_B_NAME);
|
|
368
|
+
},
|
|
369
|
+
{ timeout: 10000 },
|
|
370
|
+
);
|
|
371
|
+
|
|
372
|
+
expect(await getOnCallNowText()).not.toContain(USER_A_NAME);
|
|
373
|
+
});
|
|
374
|
+
|
|
375
|
+
test("the calendar grid relabels the overridden window to the substitute", async () => {
|
|
376
|
+
setupApi({
|
|
377
|
+
overrides: [activeOverride(POLICY_ID)],
|
|
378
|
+
attachedPolicyIds: [POLICY_ID],
|
|
379
|
+
});
|
|
380
|
+
|
|
381
|
+
renderPreview();
|
|
382
|
+
|
|
383
|
+
/*
|
|
384
|
+
* A longer budget than the 1s default on purpose. The grid is painted from a
|
|
385
|
+
* useEffect, so it lands one commit after the summary (a useMemo) - plus two
|
|
386
|
+
* awaited round trips before that, for the policy context and the overrides.
|
|
387
|
+
*/
|
|
388
|
+
await waitFor(
|
|
389
|
+
() => {
|
|
390
|
+
const titles: Array<string> = screen
|
|
391
|
+
.getAllByTestId("calendar-event")
|
|
392
|
+
.map((node: HTMLElement) => {
|
|
393
|
+
return node.textContent || "";
|
|
394
|
+
});
|
|
395
|
+
|
|
396
|
+
expect(
|
|
397
|
+
titles.some((title: string) => {
|
|
398
|
+
return (
|
|
399
|
+
title.includes(USER_B_NAME) &&
|
|
400
|
+
title.includes(`covering ${USER_A_NAME}`)
|
|
401
|
+
);
|
|
402
|
+
}),
|
|
403
|
+
).toBe(true);
|
|
404
|
+
},
|
|
405
|
+
{ timeout: 10000 },
|
|
406
|
+
);
|
|
407
|
+
});
|
|
408
|
+
|
|
409
|
+
test("a GLOBAL override is still shown (the behaviour that already worked must not regress)", async () => {
|
|
410
|
+
setupApi({
|
|
411
|
+
overrides: [activeOverride(null)],
|
|
412
|
+
attachedPolicyIds: [POLICY_ID],
|
|
413
|
+
});
|
|
414
|
+
|
|
415
|
+
renderPreview();
|
|
416
|
+
|
|
417
|
+
await waitFor(
|
|
418
|
+
async () => {
|
|
419
|
+
expect(await getOnCallNowText()).toContain(USER_B_NAME);
|
|
420
|
+
},
|
|
421
|
+
{ timeout: 10000 },
|
|
422
|
+
);
|
|
423
|
+
});
|
|
424
|
+
|
|
425
|
+
test("an override scoped to a DIFFERENT policy is not shown", async () => {
|
|
426
|
+
setupApi({
|
|
427
|
+
overrides: [activeOverride(OTHER_POLICY_ID, USER_C_ID, USER_C_NAME)],
|
|
428
|
+
attachedPolicyIds: [POLICY_ID],
|
|
429
|
+
});
|
|
430
|
+
|
|
431
|
+
renderPreview();
|
|
432
|
+
|
|
433
|
+
await waitFor(
|
|
434
|
+
async () => {
|
|
435
|
+
expect(await getOnCallNowText()).toContain(USER_A_NAME);
|
|
436
|
+
},
|
|
437
|
+
{ timeout: 10000 },
|
|
438
|
+
);
|
|
439
|
+
|
|
440
|
+
expect(await getOnCallNowText()).not.toContain(USER_C_NAME);
|
|
441
|
+
});
|
|
442
|
+
|
|
443
|
+
test("with the schedule attached to TWO policies only global overrides apply, matching the persisted roster", async () => {
|
|
444
|
+
setupApi({
|
|
445
|
+
overrides: [activeOverride(POLICY_ID, USER_C_ID, USER_C_NAME)],
|
|
446
|
+
attachedPolicyIds: [POLICY_ID, OTHER_POLICY_ID],
|
|
447
|
+
});
|
|
448
|
+
|
|
449
|
+
renderPreview();
|
|
450
|
+
|
|
451
|
+
await waitFor(
|
|
452
|
+
async () => {
|
|
453
|
+
expect(await getOnCallNowText()).toContain(USER_A_NAME);
|
|
454
|
+
},
|
|
455
|
+
{ timeout: 10000 },
|
|
456
|
+
);
|
|
457
|
+
|
|
458
|
+
expect(await getOnCallNowText()).not.toContain(USER_C_NAME);
|
|
459
|
+
});
|
|
460
|
+
});
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import {
|
|
2
|
+
afterEach,
|
|
3
|
+
beforeEach,
|
|
4
|
+
describe,
|
|
5
|
+
expect,
|
|
6
|
+
jest,
|
|
7
|
+
test,
|
|
8
|
+
} from "@jest/globals";
|
|
9
|
+
|
|
10
|
+
import SecurityEventAttributeUtil from "../../../../App/FeatureSet/Dashboard/src/Components/SecurityEvents/SecurityEventAttributeUtil";
|
|
11
|
+
import API from "../../../UI/Utils/API/API";
|
|
12
|
+
import AnalyticsModelAPI from "../../../UI/Utils/AnalyticsModelAPI/AnalyticsModelAPI";
|
|
13
|
+
import HTTPErrorResponse from "../../../Types/API/HTTPErrorResponse";
|
|
14
|
+
import HTTPResponse from "../../../Types/API/HTTPResponse";
|
|
15
|
+
import URL from "../../../Types/API/URL";
|
|
16
|
+
import { JSONObject } from "../../../Types/JSON";
|
|
17
|
+
import Dictionary from "../../../Types/Dictionary";
|
|
18
|
+
|
|
19
|
+
/*
|
|
20
|
+
* The security events table's "Add Attribute Column" search is fed from this
|
|
21
|
+
* one request. Three things about it are worth pinning, because each fails
|
|
22
|
+
* quietly rather than loudly:
|
|
23
|
+
*
|
|
24
|
+
* - the route. A wrong path 404s, which the picker renders as an error the
|
|
25
|
+
* user cannot act on.
|
|
26
|
+
* - the tenant headers. AnalyticsModelAPI.getCommonHeaders carries the
|
|
27
|
+
* project id these bespoke telemetry routes read the tenant from; without
|
|
28
|
+
* it the request is rejected as having no project.
|
|
29
|
+
* - the shape of what comes back. It is JSON off the wire, so a non-array
|
|
30
|
+
* (or an array with junk in it) has to degrade to "no attributes" rather
|
|
31
|
+
* than generating columns titled "null" that read nothing off any row.
|
|
32
|
+
*/
|
|
33
|
+
|
|
34
|
+
type PostArgs = {
|
|
35
|
+
url: URL;
|
|
36
|
+
data: JSONObject;
|
|
37
|
+
headers?: Dictionary<string> | undefined;
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
type MockPostFunction = (
|
|
41
|
+
response: HTTPResponse<JSONObject> | HTTPErrorResponse,
|
|
42
|
+
) => jest.SpiedFunction<typeof API.post>;
|
|
43
|
+
|
|
44
|
+
const mockPost: MockPostFunction = (
|
|
45
|
+
response: HTTPResponse<JSONObject> | HTTPErrorResponse,
|
|
46
|
+
): jest.SpiedFunction<typeof API.post> => {
|
|
47
|
+
return jest
|
|
48
|
+
.spyOn(API, "post")
|
|
49
|
+
.mockResolvedValue(response as never) as unknown as jest.SpiedFunction<
|
|
50
|
+
typeof API.post
|
|
51
|
+
>;
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
type FirstPostArgsFunction = (
|
|
55
|
+
spy: jest.SpiedFunction<typeof API.post>,
|
|
56
|
+
) => PostArgs;
|
|
57
|
+
|
|
58
|
+
const firstPostArgs: FirstPostArgsFunction = (
|
|
59
|
+
spy: jest.SpiedFunction<typeof API.post>,
|
|
60
|
+
): PostArgs => {
|
|
61
|
+
return (spy.mock.calls[0] as Array<unknown>)[0] as PostArgs;
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
type OkFunction = (data: JSONObject) => HTTPResponse<JSONObject>;
|
|
65
|
+
|
|
66
|
+
const ok: OkFunction = (data: JSONObject): HTTPResponse<JSONObject> => {
|
|
67
|
+
return new HTTPResponse<JSONObject>(200, data, {});
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
describe("SecurityEventAttributeUtil.getAttributeKeys", () => {
|
|
71
|
+
beforeEach(() => {
|
|
72
|
+
jest
|
|
73
|
+
.spyOn(AnalyticsModelAPI, "getCommonHeaders")
|
|
74
|
+
.mockReturnValue({ tenantid: "project-1" } as Dictionary<string>);
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
afterEach(() => {
|
|
78
|
+
jest.restoreAllMocks();
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
test("posts to the security events attribute route", async () => {
|
|
82
|
+
const spy: jest.SpiedFunction<typeof API.post> = mockPost(
|
|
83
|
+
ok({ attributes: [] }),
|
|
84
|
+
);
|
|
85
|
+
|
|
86
|
+
await SecurityEventAttributeUtil.getAttributeKeys();
|
|
87
|
+
|
|
88
|
+
expect(firstPostArgs(spy).url.toString()).toContain(
|
|
89
|
+
"/telemetry/security-events/get-attributes",
|
|
90
|
+
);
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
test("carries the tenant headers the route reads the project from", async () => {
|
|
94
|
+
const spy: jest.SpiedFunction<typeof API.post> = mockPost(
|
|
95
|
+
ok({ attributes: [] }),
|
|
96
|
+
);
|
|
97
|
+
|
|
98
|
+
await SecurityEventAttributeUtil.getAttributeKeys();
|
|
99
|
+
|
|
100
|
+
expect(firstPostArgs(spy).headers).toMatchObject({
|
|
101
|
+
tenantid: "project-1",
|
|
102
|
+
});
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
test("returns the keys the server sent", async () => {
|
|
106
|
+
mockPost(
|
|
107
|
+
ok({
|
|
108
|
+
attributes: ["device.hostname", "class_uid", "finding_info.title"],
|
|
109
|
+
}),
|
|
110
|
+
);
|
|
111
|
+
|
|
112
|
+
await expect(
|
|
113
|
+
SecurityEventAttributeUtil.getAttributeKeys(),
|
|
114
|
+
).resolves.toEqual(["device.hostname", "class_uid", "finding_info.title"]);
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
test("an empty list is an empty list, not an error", async () => {
|
|
118
|
+
mockPost(ok({ attributes: [] }));
|
|
119
|
+
|
|
120
|
+
await expect(
|
|
121
|
+
SecurityEventAttributeUtil.getAttributeKeys(),
|
|
122
|
+
).resolves.toEqual([]);
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
test("a missing attributes field degrades to no attributes", async () => {
|
|
126
|
+
mockPost(ok({ someOtherField: true }));
|
|
127
|
+
|
|
128
|
+
await expect(
|
|
129
|
+
SecurityEventAttributeUtil.getAttributeKeys(),
|
|
130
|
+
).resolves.toEqual([]);
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
test("a non-array attributes field degrades to no attributes", async () => {
|
|
134
|
+
mockPost(ok({ attributes: "device.hostname" }));
|
|
135
|
+
|
|
136
|
+
await expect(
|
|
137
|
+
SecurityEventAttributeUtil.getAttributeKeys(),
|
|
138
|
+
).resolves.toEqual([]);
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
test("non-string entries are dropped rather than turned into columns", async () => {
|
|
142
|
+
mockPost(
|
|
143
|
+
ok({
|
|
144
|
+
attributes: ["device.hostname", null, 42, { a: 1 }, "class_uid"],
|
|
145
|
+
} as unknown as JSONObject),
|
|
146
|
+
);
|
|
147
|
+
|
|
148
|
+
await expect(
|
|
149
|
+
SecurityEventAttributeUtil.getAttributeKeys(),
|
|
150
|
+
).resolves.toEqual(["device.hostname", "class_uid"]);
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
/*
|
|
154
|
+
* The caller turns a rejection into the picker's error message. Swallowing
|
|
155
|
+
* it here would show an empty search box instead, which reads as "this
|
|
156
|
+
* project has no attributes".
|
|
157
|
+
*/
|
|
158
|
+
test("an error response is thrown, not swallowed", async () => {
|
|
159
|
+
const error: HTTPErrorResponse = new HTTPErrorResponse(
|
|
160
|
+
500,
|
|
161
|
+
{ message: "clickhouse said no" },
|
|
162
|
+
{},
|
|
163
|
+
);
|
|
164
|
+
|
|
165
|
+
mockPost(error);
|
|
166
|
+
|
|
167
|
+
await expect(SecurityEventAttributeUtil.getAttributeKeys()).rejects.toBe(
|
|
168
|
+
error,
|
|
169
|
+
);
|
|
170
|
+
});
|
|
171
|
+
});
|