@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,181 @@
|
|
|
1
|
+
import ColumnLength from "../../Types/Database/ColumnLength";
|
|
2
|
+
|
|
3
|
+
/*
|
|
4
|
+
* The optional operator-supplied name on a Network Device Discovery Scan.
|
|
5
|
+
*
|
|
6
|
+
* WHY IT EXISTS
|
|
7
|
+
*
|
|
8
|
+
* A scan used to be identified by its target alone — `10.15.128.0-255`,
|
|
9
|
+
* `10.240-249.0-254.220-226`. Half a dozen rows in, nothing on the Discovery
|
|
10
|
+
* Scans list says which one was the router sweep and which one was the switch
|
|
11
|
+
* range for a region; the only way to find out is to open each scan and read
|
|
12
|
+
* the range back against a subnet plan kept somewhere else (OneUptime issue
|
|
13
|
+
* #3391). A name is that missing sentence, stored with the scan rather than in
|
|
14
|
+
* a spreadsheet beside it.
|
|
15
|
+
*
|
|
16
|
+
* It is deliberately OPTIONAL and deliberately NOT unique: it is a label for
|
|
17
|
+
* humans, not an identifier. Every scan that existed before this column did
|
|
18
|
+
* has none, and every surface that shows a name therefore has to keep working
|
|
19
|
+
* when it is absent — which is what getScanLabel() below is for.
|
|
20
|
+
*
|
|
21
|
+
* WHY IT LIVES IN Common
|
|
22
|
+
*
|
|
23
|
+
* The same two questions — "is this name storable?" and "what do I call this
|
|
24
|
+
* scan?" — are asked by the create form (App Dashboard), the write hooks
|
|
25
|
+
* (Common server service), the recurring-scan worker (App Workers) and the
|
|
26
|
+
* sweep itself (Probe). Answering them in one module is what keeps the form's
|
|
27
|
+
* error message identical to the server's, and the probe's log line readable
|
|
28
|
+
* against the row the operator is looking at. Same reason ScanTargetUtil sits
|
|
29
|
+
* next door.
|
|
30
|
+
*/
|
|
31
|
+
|
|
32
|
+
/*
|
|
33
|
+
* The parts of a scan that answer "which scan is this?". Structural rather
|
|
34
|
+
* than the model type, so a partially-selected row — the workers and the probe
|
|
35
|
+
* both select two or three columns — satisfies it, and so this module stays
|
|
36
|
+
* importable from the Probe without dragging a database model behind it.
|
|
37
|
+
*
|
|
38
|
+
* Both are nullable: `cidr` is NOT NULL in the database, but a caller that did
|
|
39
|
+
* not select it hands over a row where it is simply missing.
|
|
40
|
+
*/
|
|
41
|
+
export interface DiscoveryScanIdentity {
|
|
42
|
+
name?: string | null | undefined;
|
|
43
|
+
cidr?: string | null | undefined;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export class ScanNameUtil {
|
|
47
|
+
/*
|
|
48
|
+
* Matches the column: NetworkDeviceDiscoveryScan.name is a ShortText, so a
|
|
49
|
+
* longer value does not truncate in Postgres — it throws, failing the whole
|
|
50
|
+
* INSERT. Read off ColumnLength rather than written as 100 so the two cannot
|
|
51
|
+
* drift apart if the column type ever changes.
|
|
52
|
+
*/
|
|
53
|
+
public static readonly MAX_SCAN_NAME_LENGTH: number = ColumnLength.ShortText;
|
|
54
|
+
|
|
55
|
+
/*
|
|
56
|
+
* ASCII control characters, including DEL. Written as escapes rather than as
|
|
57
|
+
* a literal range so the characters this guards against cannot end up inside
|
|
58
|
+
* the guard itself, and so the file stays readable in a diff.
|
|
59
|
+
*
|
|
60
|
+
* no-control-regex is disabled deliberately, the same way
|
|
61
|
+
* MetricResourceAttributeUtil disables it: a control character inside a
|
|
62
|
+
* user-typed name is precisely what this has to match in order to remove it.
|
|
63
|
+
*/
|
|
64
|
+
// eslint-disable-next-line no-control-regex
|
|
65
|
+
private static readonly CONTROL_CHARACTERS: RegExp = /[\u0000-\u001F\u007F]/g;
|
|
66
|
+
|
|
67
|
+
/*
|
|
68
|
+
* The name as it should be stored, or null when the operator supplied none.
|
|
69
|
+
*
|
|
70
|
+
* Three things happen here, in this order:
|
|
71
|
+
*
|
|
72
|
+
* - anything that is not a string becomes null. The value arrives straight
|
|
73
|
+
* from request JSON (BaseAPI assigns ShortText columns verbatim), so a
|
|
74
|
+
* client really can hand over a number, an object or an array. Callers
|
|
75
|
+
* that want to REJECT those call getValidationError() first; this
|
|
76
|
+
* function's job is only to say what would be stored.
|
|
77
|
+
* - control characters — a newline pasted out of a spreadsheet cell, a
|
|
78
|
+
* stray tab — become spaces, and every run of whitespace collapses to a
|
|
79
|
+
* single space. A name is rendered on one line in a table cell and
|
|
80
|
+
* inlined into log messages; a multi-line one breaks both, and nothing
|
|
81
|
+
* downstream would ever repair it.
|
|
82
|
+
* - the result is trimmed, and an empty result is null rather than "".
|
|
83
|
+
* "Not named" is one state, not two: an empty string in the column would
|
|
84
|
+
* read as a name everywhere `name ?` is asked, and render as a blank
|
|
85
|
+
* first line above the scan target.
|
|
86
|
+
*/
|
|
87
|
+
public static normalize(name: unknown): string | null {
|
|
88
|
+
if (typeof name !== "string") {
|
|
89
|
+
return null;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const collapsed: string = name
|
|
93
|
+
.replace(ScanNameUtil.CONTROL_CHARACTERS, " ")
|
|
94
|
+
.replace(/\s+/g, " ")
|
|
95
|
+
.trim();
|
|
96
|
+
|
|
97
|
+
return collapsed.length > 0 ? collapsed : null;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/*
|
|
101
|
+
* The single validation entry point for a scan name, shared by the create
|
|
102
|
+
* form and both write hooks. Returns null when the name is storable —
|
|
103
|
+
* INCLUDING when there is no name at all, because the field is optional and
|
|
104
|
+
* "" is a perfectly good way to say so.
|
|
105
|
+
*
|
|
106
|
+
* `name` is typed unknown for the same reason ScanTargetUtil's target is:
|
|
107
|
+
* the server hook runs before the model's own type and length checks, so it
|
|
108
|
+
* is the first thing to see whatever the client actually sent.
|
|
109
|
+
*/
|
|
110
|
+
public static getValidationError(name: unknown): string | null {
|
|
111
|
+
if (name === undefined || name === null) {
|
|
112
|
+
return null;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
if (typeof name !== "string") {
|
|
116
|
+
return "A scan name must be text.";
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const normalized: string | null = ScanNameUtil.normalize(name);
|
|
120
|
+
|
|
121
|
+
if (normalized === null) {
|
|
122
|
+
return null;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/*
|
|
126
|
+
* Measured against the NORMALIZED value, which is what would be stored:
|
|
127
|
+
* rejecting a 101-character value that is 100 characters plus a trailing
|
|
128
|
+
* newline would be refusing to save something this module was about to fix
|
|
129
|
+
* anyway.
|
|
130
|
+
*/
|
|
131
|
+
if (normalized.length > ScanNameUtil.MAX_SCAN_NAME_LENGTH) {
|
|
132
|
+
return (
|
|
133
|
+
`A scan name cannot be longer than ${ScanNameUtil.MAX_SCAN_NAME_LENGTH} characters. ` +
|
|
134
|
+
`This one is ${normalized.length}.`
|
|
135
|
+
);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
return null;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/*
|
|
142
|
+
* The name to show for a scan, or null when it has none — so a caller can
|
|
143
|
+
* render the scan target instead rather than an empty line.
|
|
144
|
+
*
|
|
145
|
+
* Normalized on the way out as well as on the way in, because rows written
|
|
146
|
+
* before this column existed, and rows written by any writer that bypasses
|
|
147
|
+
* the hooks (migrations, the probe-ingest endpoints), are not guaranteed to
|
|
148
|
+
* have been through normalize().
|
|
149
|
+
*/
|
|
150
|
+
public static getDisplayName(scan: DiscoveryScanIdentity): string | null {
|
|
151
|
+
return ScanNameUtil.normalize(scan.name);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/*
|
|
155
|
+
* How to refer to a scan in one line of running text — a log message, a
|
|
156
|
+
* modal's description, a status note.
|
|
157
|
+
*
|
|
158
|
+
* A named scan carries its target along with it (`Router Discovery — Region
|
|
159
|
+
* 1100 (10.15.128.0-255)`): the name says which scan, the target says what
|
|
160
|
+
* it sweeps, and an operator reading a log line usually wants both. An
|
|
161
|
+
* unnamed one is exactly what it was before this column existed — the target
|
|
162
|
+
* alone.
|
|
163
|
+
*
|
|
164
|
+
* Returns "" when the row has neither, which happens only when the caller
|
|
165
|
+
* selected neither column. Callers append their own fallback (the scan id)
|
|
166
|
+
* rather than having one invented for them here.
|
|
167
|
+
*/
|
|
168
|
+
public static getScanLabel(scan: DiscoveryScanIdentity): string {
|
|
169
|
+
const name: string | null = ScanNameUtil.getDisplayName(scan);
|
|
170
|
+
const target: string =
|
|
171
|
+
typeof scan.cidr === "string" ? scan.cidr.trim() : "";
|
|
172
|
+
|
|
173
|
+
if (name && target) {
|
|
174
|
+
return `${name} (${target})`;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
return name || target || "";
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
export default ScanNameUtil;
|
|
@@ -98,6 +98,9 @@ export class ScanTargetUtil {
|
|
|
98
98
|
private static readonly OCTET_TERM_PATTERN: RegExp =
|
|
99
99
|
/^(\d{1,3})(?:-(\d{1,3}))?$/;
|
|
100
100
|
|
|
101
|
+
// One octet of a bare address. Bounds are validated after parsing.
|
|
102
|
+
private static readonly IP_OCTET_PATTERN: RegExp = /^\d{1,3}$/;
|
|
103
|
+
|
|
101
104
|
private static readonly EXAMPLE_CIDR: string = "192.168.1.0/24";
|
|
102
105
|
|
|
103
106
|
private static readonly EXAMPLE_OCTET_RANGE: string = "10.16-22.0-255.51-66";
|
|
@@ -192,6 +195,54 @@ export class ScanTargetUtil {
|
|
|
192
195
|
return ScanTargetUtil.expandOctetRangeTarget(parsed);
|
|
193
196
|
}
|
|
194
197
|
|
|
198
|
+
/*
|
|
199
|
+
* True when `ip` falls inside `target`, in either notation. This is the
|
|
200
|
+
* matcher behind the auto-import rules' "Host IP is in" condition, sharing
|
|
201
|
+
* the exact parser scan targets are validated and expanded with — so a
|
|
202
|
+
* condition that saves is a condition that matches what its scan sweeps.
|
|
203
|
+
*
|
|
204
|
+
* Containment, not enumeration: a CIDR block is a mask comparison over the
|
|
205
|
+
* whole block (network and broadcast addresses INCLUDED — a rule asking
|
|
206
|
+
* "is this address in 10.0.0.0/24" means the subnet, not the sweep list),
|
|
207
|
+
* and an octet range is per-octet interval membership. The latter is NOT a
|
|
208
|
+
* single numeric interval: for `10.16-22.0-255.51-66`, the address
|
|
209
|
+
* 10.17.5.10 sits between the range's lowest and highest addresses but its
|
|
210
|
+
* fourth octet is outside 51-66, so it does not match.
|
|
211
|
+
*
|
|
212
|
+
* Malformed targets and malformed addresses match nothing.
|
|
213
|
+
*/
|
|
214
|
+
public static contains(target: string, ip: string): boolean {
|
|
215
|
+
const parsed: ScanTarget | null = ScanTargetUtil.parse(target);
|
|
216
|
+
|
|
217
|
+
if (!parsed) {
|
|
218
|
+
return false;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
const octets: Array<number> | null = ScanTargetUtil.parseIpOctets(ip);
|
|
222
|
+
|
|
223
|
+
if (!octets) {
|
|
224
|
+
return false;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
if (parsed.notation === ScanTargetNotation.Cidr) {
|
|
228
|
+
const ipLong: number =
|
|
229
|
+
(((octets[0]! * 256 + octets[1]!) * 256 + octets[2]!) * 256 +
|
|
230
|
+
octets[3]!) >>>
|
|
231
|
+
0;
|
|
232
|
+
|
|
233
|
+
return (
|
|
234
|
+
ipLong >= parsed.networkLong! &&
|
|
235
|
+
ipLong < parsed.networkLong! + parsed.blockSize!
|
|
236
|
+
);
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
return parsed.octetRanges!.every(
|
|
240
|
+
(range: OctetRange, index: number): boolean => {
|
|
241
|
+
return octets[index]! >= range.start && octets[index]! <= range.end;
|
|
242
|
+
},
|
|
243
|
+
);
|
|
244
|
+
}
|
|
245
|
+
|
|
195
246
|
/*
|
|
196
247
|
* Both notations in one sentence, for form hints and error messages. Kept
|
|
197
248
|
* here so the UI, the server-side validator and the probe all describe the
|
|
@@ -411,6 +462,37 @@ export class ScanTargetUtil {
|
|
|
411
462
|
return hosts;
|
|
412
463
|
}
|
|
413
464
|
|
|
465
|
+
// '10.0.0.1' -> [10, 0, 0, 1]; anything malformed -> null.
|
|
466
|
+
private static parseIpOctets(ip: string): Array<number> | null {
|
|
467
|
+
if (typeof ip !== "string") {
|
|
468
|
+
return null;
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
const terms: Array<string> = ip.trim().split(".");
|
|
472
|
+
|
|
473
|
+
if (terms.length !== 4) {
|
|
474
|
+
return null;
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
const octets: Array<number> = [];
|
|
478
|
+
|
|
479
|
+
for (const term of terms) {
|
|
480
|
+
if (!ScanTargetUtil.IP_OCTET_PATTERN.test(term)) {
|
|
481
|
+
return null;
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
const octet: number = parseInt(term, 10);
|
|
485
|
+
|
|
486
|
+
if (octet > 255) {
|
|
487
|
+
return null;
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
octets.push(octet);
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
return octets;
|
|
494
|
+
}
|
|
495
|
+
|
|
414
496
|
private static getMalformedTargetMessage(target: string): string {
|
|
415
497
|
const shown: string =
|
|
416
498
|
typeof target === "string" ? target.trim() : String(target);
|
|
@@ -154,6 +154,25 @@ export interface StatusPageResourceGridModel {
|
|
|
154
154
|
orphanResources: Array<StatusPageResource>;
|
|
155
155
|
}
|
|
156
156
|
|
|
157
|
+
/*
|
|
158
|
+
* How a group's checkbox column stands at the moment: whether the box at the
|
|
159
|
+
* top of the list should be ticked, half ticked, or empty.
|
|
160
|
+
*
|
|
161
|
+
* Computed over whichever resources the list is actually drawing - a filtered
|
|
162
|
+
* list's "select all" means "everything the search matched", not "everything in
|
|
163
|
+
* the group", because those are the only rows the operator can see.
|
|
164
|
+
*/
|
|
165
|
+
export interface StatusPageResourceSelectionState {
|
|
166
|
+
/* Every resource on offer is selected, and there is at least one. */
|
|
167
|
+
isAllSelected: boolean;
|
|
168
|
+
/* Some but not all - the half-filled box. */
|
|
169
|
+
isIndeterminate: boolean;
|
|
170
|
+
/* How many of the resources on offer are selected. */
|
|
171
|
+
selectedCount: number;
|
|
172
|
+
/* How many resources were on offer at all. */
|
|
173
|
+
selectableCount: number;
|
|
174
|
+
}
|
|
175
|
+
|
|
157
176
|
export default class StatusPageResourceExplorerUtil {
|
|
158
177
|
/*
|
|
159
178
|
* How many navigator rows are drawn before the list stops and offers to draw
|
|
@@ -622,6 +641,245 @@ export default class StatusPageResourceExplorerUtil {
|
|
|
622
641
|
);
|
|
623
642
|
}
|
|
624
643
|
|
|
644
|
+
/* ------------------------------------------------------------------ */
|
|
645
|
+
/* Selecting resources */
|
|
646
|
+
/* ------------------------------------------------------------------ */
|
|
647
|
+
|
|
648
|
+
/*
|
|
649
|
+
* Removing monitors from a status page used to be a row at a time: open the
|
|
650
|
+
* row's menu, confirm, wait for the refetch, and do it again for the next of
|
|
651
|
+
* twenty seven (issue #3419). The list carries a checkbox column instead, and
|
|
652
|
+
* everything below is the model behind it.
|
|
653
|
+
*
|
|
654
|
+
* A selection is a set of id STRINGS rather than of resources. Resources are
|
|
655
|
+
* re-fetched constantly here - every create, delete, reorder and refresh
|
|
656
|
+
* replaces the whole array - so holding the objects would mean holding rows
|
|
657
|
+
* that no longer exist, compared by identity against their own replacements.
|
|
658
|
+
*/
|
|
659
|
+
|
|
660
|
+
/*
|
|
661
|
+
* A resource's id as a selection holds it.
|
|
662
|
+
*
|
|
663
|
+
* Null when there is nothing to hold on to. The server never returns such a
|
|
664
|
+
* row, but a list drawn from local state briefly can, and a set containing
|
|
665
|
+
* `""` would silently make every id-less row the same row.
|
|
666
|
+
*/
|
|
667
|
+
public static getResourceId(
|
|
668
|
+
statusPageResource: StatusPageResource,
|
|
669
|
+
): string | null {
|
|
670
|
+
const id: string = statusPageResource._id?.toString() || "";
|
|
671
|
+
|
|
672
|
+
return id.length > 0 ? id : null;
|
|
673
|
+
}
|
|
674
|
+
|
|
675
|
+
/*
|
|
676
|
+
* The ids of everything in the list that can be selected at all, in the order
|
|
677
|
+
* the list draws them and without repeats.
|
|
678
|
+
*/
|
|
679
|
+
public static getResourceIds(
|
|
680
|
+
statusPageResources: Array<StatusPageResource>,
|
|
681
|
+
): Array<string> {
|
|
682
|
+
const ids: Array<string> = [];
|
|
683
|
+
const seen: Set<string> = new Set<string>();
|
|
684
|
+
|
|
685
|
+
for (const statusPageResource of statusPageResources) {
|
|
686
|
+
const id: string | null =
|
|
687
|
+
StatusPageResourceExplorerUtil.getResourceId(statusPageResource);
|
|
688
|
+
|
|
689
|
+
if (!id || seen.has(id)) {
|
|
690
|
+
continue;
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
seen.add(id);
|
|
694
|
+
ids.push(id);
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
return ids;
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
/*
|
|
701
|
+
* One row's box, ticked or unticked. Always a new set, because it always
|
|
702
|
+
* changes something.
|
|
703
|
+
*/
|
|
704
|
+
public static toggleSelectedResourceId(data: {
|
|
705
|
+
selectedResourceIds: Set<string>;
|
|
706
|
+
resourceId: string;
|
|
707
|
+
}): Set<string> {
|
|
708
|
+
const next: Set<string> = new Set<string>(data.selectedResourceIds);
|
|
709
|
+
|
|
710
|
+
if (next.has(data.resourceId)) {
|
|
711
|
+
next.delete(data.resourceId);
|
|
712
|
+
} else {
|
|
713
|
+
next.add(data.resourceId);
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
return next;
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
/*
|
|
720
|
+
* The box at the top of the list: every resource handed in is selected, or
|
|
721
|
+
* none of them is.
|
|
722
|
+
*
|
|
723
|
+
* Only the resources handed in are touched. A search is on while this is
|
|
724
|
+
* pressed as often as not, and un-ticking "select all" over four matching
|
|
725
|
+
* rows must not quietly drop the twenty the operator selected before they
|
|
726
|
+
* started typing.
|
|
727
|
+
*
|
|
728
|
+
* Returns the set it was given when nothing would change, so a component
|
|
729
|
+
* holding it in state does not re-render itself for a no-op.
|
|
730
|
+
*/
|
|
731
|
+
public static setResourcesSelected(data: {
|
|
732
|
+
selectedResourceIds: Set<string>;
|
|
733
|
+
statusPageResources: Array<StatusPageResource>;
|
|
734
|
+
isSelected: boolean;
|
|
735
|
+
}): Set<string> {
|
|
736
|
+
const ids: Array<string> = StatusPageResourceExplorerUtil.getResourceIds(
|
|
737
|
+
data.statusPageResources,
|
|
738
|
+
);
|
|
739
|
+
|
|
740
|
+
const next: Set<string> = new Set<string>(data.selectedResourceIds);
|
|
741
|
+
|
|
742
|
+
let hasChanged: boolean = false;
|
|
743
|
+
|
|
744
|
+
for (const id of ids) {
|
|
745
|
+
if (data.isSelected) {
|
|
746
|
+
if (!next.has(id)) {
|
|
747
|
+
next.add(id);
|
|
748
|
+
hasChanged = true;
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
continue;
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
if (next.delete(id)) {
|
|
755
|
+
hasChanged = true;
|
|
756
|
+
}
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
return hasChanged ? next : data.selectedResourceIds;
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
/*
|
|
763
|
+
* What the box at the top of the list should look like, over whichever
|
|
764
|
+
* resources are being drawn.
|
|
765
|
+
*
|
|
766
|
+
* An empty list is never "all selected": a ticked box over nothing to tick
|
|
767
|
+
* reads as a selection that was lost.
|
|
768
|
+
*/
|
|
769
|
+
public static getSelectionState(data: {
|
|
770
|
+
statusPageResources: Array<StatusPageResource>;
|
|
771
|
+
selectedResourceIds: Set<string>;
|
|
772
|
+
}): StatusPageResourceSelectionState {
|
|
773
|
+
const ids: Array<string> = StatusPageResourceExplorerUtil.getResourceIds(
|
|
774
|
+
data.statusPageResources,
|
|
775
|
+
);
|
|
776
|
+
|
|
777
|
+
let selectedCount: number = 0;
|
|
778
|
+
|
|
779
|
+
for (const id of ids) {
|
|
780
|
+
if (data.selectedResourceIds.has(id)) {
|
|
781
|
+
selectedCount++;
|
|
782
|
+
}
|
|
783
|
+
}
|
|
784
|
+
|
|
785
|
+
const isAllSelected: boolean =
|
|
786
|
+
ids.length > 0 && selectedCount === ids.length;
|
|
787
|
+
|
|
788
|
+
return {
|
|
789
|
+
isAllSelected: isAllSelected,
|
|
790
|
+
isIndeterminate: selectedCount > 0 && !isAllSelected,
|
|
791
|
+
selectedCount: selectedCount,
|
|
792
|
+
selectableCount: ids.length,
|
|
793
|
+
};
|
|
794
|
+
}
|
|
795
|
+
|
|
796
|
+
/*
|
|
797
|
+
* The selected resources themselves, in the order the list holds them, so a
|
|
798
|
+
* bulk action reports its progress in the order the operator is looking at.
|
|
799
|
+
*
|
|
800
|
+
* Ids in the selection that match nothing in the list are dropped rather than
|
|
801
|
+
* guessed at - see retainSelectedResourceIds for where they come from.
|
|
802
|
+
*/
|
|
803
|
+
public static getSelectedResources(data: {
|
|
804
|
+
statusPageResources: Array<StatusPageResource>;
|
|
805
|
+
selectedResourceIds: Set<string>;
|
|
806
|
+
}): Array<StatusPageResource> {
|
|
807
|
+
const seen: Set<string> = new Set<string>();
|
|
808
|
+
|
|
809
|
+
return data.statusPageResources.filter(
|
|
810
|
+
(statusPageResource: StatusPageResource): boolean => {
|
|
811
|
+
const id: string | null =
|
|
812
|
+
StatusPageResourceExplorerUtil.getResourceId(statusPageResource);
|
|
813
|
+
|
|
814
|
+
if (!id || seen.has(id) || !data.selectedResourceIds.has(id)) {
|
|
815
|
+
return false;
|
|
816
|
+
}
|
|
817
|
+
|
|
818
|
+
seen.add(id);
|
|
819
|
+
|
|
820
|
+
return true;
|
|
821
|
+
},
|
|
822
|
+
);
|
|
823
|
+
}
|
|
824
|
+
|
|
825
|
+
/*
|
|
826
|
+
* The selection, minus anything the list no longer holds.
|
|
827
|
+
*
|
|
828
|
+
* Every write on this pane ends in a refetch, and a resource that was removed
|
|
829
|
+
* - by this operator's own bulk action, or by somebody else's - must not stay
|
|
830
|
+
* in the selection: the bulk bar would go on counting it, and the next action
|
|
831
|
+
* would try to delete a row that is already gone.
|
|
832
|
+
*
|
|
833
|
+
* Returns the set it was given when nothing was dropped, for the same reason
|
|
834
|
+
* setResourcesSelected does.
|
|
835
|
+
*/
|
|
836
|
+
public static retainSelectedResourceIds(data: {
|
|
837
|
+
selectedResourceIds: Set<string>;
|
|
838
|
+
statusPageResources: Array<StatusPageResource>;
|
|
839
|
+
}): Set<string> {
|
|
840
|
+
if (data.selectedResourceIds.size === 0) {
|
|
841
|
+
return data.selectedResourceIds;
|
|
842
|
+
}
|
|
843
|
+
|
|
844
|
+
const present: Set<string> = new Set<string>(
|
|
845
|
+
StatusPageResourceExplorerUtil.getResourceIds(data.statusPageResources),
|
|
846
|
+
);
|
|
847
|
+
|
|
848
|
+
const next: Set<string> = new Set<string>();
|
|
849
|
+
|
|
850
|
+
for (const id of data.selectedResourceIds) {
|
|
851
|
+
if (present.has(id)) {
|
|
852
|
+
next.add(id);
|
|
853
|
+
}
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
return next.size === data.selectedResourceIds.size
|
|
857
|
+
? data.selectedResourceIds
|
|
858
|
+
: next;
|
|
859
|
+
}
|
|
860
|
+
|
|
861
|
+
/*
|
|
862
|
+
* What the confirmation for a bulk removal is called, and what it says.
|
|
863
|
+
*
|
|
864
|
+
* It says the monitors survive, for the same reason the single-row confirm
|
|
865
|
+
* does: "remove" on a status page means "stop publishing this", and an
|
|
866
|
+
* operator clearing twenty seven rows deserves to be told that once, loudly,
|
|
867
|
+
* rather than to wonder afterwards.
|
|
868
|
+
*/
|
|
869
|
+
public static getBulkRemoveConfirmTitle(data: { count: number }): string {
|
|
870
|
+
return `Remove ${data.count.toLocaleString()} ${
|
|
871
|
+
data.count === 1 ? "resource" : "resources"
|
|
872
|
+
}`;
|
|
873
|
+
}
|
|
874
|
+
|
|
875
|
+
public static getBulkRemoveConfirmMessage(data: { count: number }): string {
|
|
876
|
+
if (data.count === 1) {
|
|
877
|
+
return "Are you sure you want to remove 1 resource from this status page? The monitor itself is not deleted.";
|
|
878
|
+
}
|
|
879
|
+
|
|
880
|
+
return `Are you sure you want to remove ${data.count.toLocaleString()} resources from this status page? The monitors themselves are not deleted.`;
|
|
881
|
+
}
|
|
882
|
+
|
|
625
883
|
/*
|
|
626
884
|
* The `order` to write when a resource is dragged from one position to
|
|
627
885
|
* another.
|