@oneuptime/common 12.0.23 → 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/NetworkDeviceAutoImportRule.ts +27 -7
- package/Models/DatabaseModels/NetworkDeviceDiscoveryScan.ts +67 -0
- package/Models/DatabaseModels/Project.ts +68 -0
- package/Models/DatabaseModels/User.ts +68 -0
- package/Server/API/TelemetryAPI.ts +29 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1789400000000-AddNameToNetworkDeviceDiscoveryScan.ts +28 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1789500000000-AddCampaignUtmFields.ts +49 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1789512000000-AddDetectionRuleDistinctCountColumns.ts +33 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +6 -0
- package/Server/Middleware/GzipRequestBody.ts +311 -0
- package/Server/Middleware/MultipartFormData.ts +87 -3
- package/Server/Services/DetectionRuleService.ts +73 -6
- package/Server/Services/Index.ts +205 -0
- package/Server/Services/NetworkDeviceDiscoveryScanService.ts +59 -0
- package/Server/Services/NetworkDeviceService.ts +148 -0
- package/Server/Services/OnCallDutyPolicyEscalationRuleScheduleService.ts +65 -0
- package/Server/Services/OnCallDutyPolicyFeedService.ts +1 -1
- package/Server/Services/ProjectService.ts +29 -19
- package/Server/Services/SecurityEventService.ts +90 -13
- package/Server/Services/StatusPageResourceService.ts +223 -0
- package/Server/Services/TelemetryAttributeService.ts +17 -0
- package/Server/Services/UserService.ts +4 -6
- package/Server/Types/Markdown.ts +161 -67
- package/Server/Utils/AI/Toolbox/OnCallTools.ts +12 -4
- package/Server/Utils/AnalyticsDatabase/Statement.ts +13 -1
- package/Server/Utils/AnalyticsDatabase/StatementGenerator.ts +297 -6
- package/Server/Utils/Attribution.ts +4 -0
- package/Server/Utils/Marketing/MarketingEventUtil.ts +45 -7
- package/Server/Utils/SecurityEvent/DetectionRuleEvaluator.ts +55 -3
- package/Server/Utils/SecurityEvent/Sigma/SigmaClickhouseCompiler.ts +21 -0
- package/Server/Utils/StartServer.ts +12 -32
- package/Server/Utils/Telemetry/LlmCostBudgetEvaluator.ts +101 -4
- package/Server/Utils/Telemetry/LlmMetricSpend.ts +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/DetectionRuleService.test.ts +134 -2
- package/Tests/Server/Services/DiscoveryScanClaimHookFreeSafety.test.ts +7 -1
- package/Tests/Server/Services/FeedRetentionConsistency.test.ts +131 -0
- package/Tests/Server/Services/NetworkDeviceDiscoveryScanService.test.ts +194 -0
- package/Tests/Server/Services/NetworkDeviceMonitorStatusStamp.test.ts +800 -0
- package/Tests/Server/Services/OnCallScheduleAttachRosterRefresh.test.ts +244 -0
- package/Tests/Server/Services/SecurityEventService.test.ts +376 -0
- package/Tests/Server/Services/StatusPageResourceDuplicates.test.ts +703 -0
- package/Tests/Server/Services/TelemetryAttributeServiceSecurityEvent.test.ts +256 -0
- package/Tests/Server/Types/Workflow/Components/ComponentRegistryParity.test.ts +417 -0
- package/Tests/Server/Utils/AnalyticsDatabase/StatementGeneratorWhereOperators.test.ts +677 -0
- package/Tests/Server/Utils/Marketing/MarketingEventUtil.test.ts +43 -0
- package/Tests/Server/Utils/Monitor/Criteria/ProfileMonitorCriteria.test.ts +15 -11
- package/Tests/Server/Utils/SecurityEvent/DetectionRuleEvaluator.test.ts +369 -8
- package/Tests/Server/Utils/SecurityEvent/SigmaClickhouseCompiler.test.ts +35 -0
- package/Tests/Server/Utils/Telemetry/LlmCostBudgetEvaluator.test.ts +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/DiscoveredHostUtil.test.ts +221 -0
- package/Tests/Utils/NetworkDiscovery/ScanNameUtil.test.ts +312 -0
- package/Tests/Utils/StatusPage/ResourceExplorer.test.ts +468 -0
- package/Tests/Utils/Telemetry/LlmMetricQuery.test.ts +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/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/ScanNameUtil.ts +181 -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/NetworkDeviceAutoImportRule.js +27 -7
- package/build/dist/Models/DatabaseModels/NetworkDeviceAutoImportRule.js.map +1 -1
- package/build/dist/Models/DatabaseModels/NetworkDeviceDiscoveryScan.js +69 -0
- package/build/dist/Models/DatabaseModels/NetworkDeviceDiscoveryScan.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Project.js +76 -0
- package/build/dist/Models/DatabaseModels/Project.js.map +1 -1
- package/build/dist/Models/DatabaseModels/User.js +76 -0
- package/build/dist/Models/DatabaseModels/User.js.map +1 -1
- package/build/dist/Server/API/TelemetryAPI.js +17 -0
- package/build/dist/Server/API/TelemetryAPI.js.map +1 -1
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1789400000000-AddNameToNetworkDeviceDiscoveryScan.js +21 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1789400000000-AddNameToNetworkDeviceDiscoveryScan.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1789500000000-AddCampaignUtmFields.js +42 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1789500000000-AddCampaignUtmFields.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1789512000000-AddDetectionRuleDistinctCountColumns.js +22 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1789512000000-AddDetectionRuleDistinctCountColumns.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +6 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
- package/build/dist/Server/Middleware/GzipRequestBody.js +224 -0
- package/build/dist/Server/Middleware/GzipRequestBody.js.map +1 -0
- package/build/dist/Server/Middleware/MultipartFormData.js +71 -2
- package/build/dist/Server/Middleware/MultipartFormData.js.map +1 -1
- package/build/dist/Server/Services/DetectionRuleService.js +49 -4
- package/build/dist/Server/Services/DetectionRuleService.js.map +1 -1
- package/build/dist/Server/Services/Index.js +204 -0
- package/build/dist/Server/Services/Index.js.map +1 -1
- package/build/dist/Server/Services/NetworkDeviceDiscoveryScanService.js +50 -0
- package/build/dist/Server/Services/NetworkDeviceDiscoveryScanService.js.map +1 -1
- package/build/dist/Server/Services/NetworkDeviceService.js +124 -0
- package/build/dist/Server/Services/NetworkDeviceService.js.map +1 -1
- package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleScheduleService.js +68 -13
- package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleScheduleService.js.map +1 -1
- package/build/dist/Server/Services/OnCallDutyPolicyFeedService.js +1 -1
- package/build/dist/Server/Services/OnCallDutyPolicyFeedService.js.map +1 -1
- package/build/dist/Server/Services/ProjectService.js +25 -45
- package/build/dist/Server/Services/ProjectService.js.map +1 -1
- package/build/dist/Server/Services/SecurityEventService.js +57 -5
- package/build/dist/Server/Services/SecurityEventService.js.map +1 -1
- package/build/dist/Server/Services/StatusPageResourceService.js +140 -0
- package/build/dist/Server/Services/StatusPageResourceService.js.map +1 -1
- package/build/dist/Server/Services/TelemetryAttributeService.js +17 -0
- package/build/dist/Server/Services/TelemetryAttributeService.js.map +1 -1
- package/build/dist/Server/Services/UserService.js +2 -12
- package/build/dist/Server/Services/UserService.js.map +1 -1
- package/build/dist/Server/Types/Markdown.js +147 -61
- package/build/dist/Server/Types/Markdown.js.map +1 -1
- package/build/dist/Server/Utils/AI/Toolbox/OnCallTools.js +12 -4
- package/build/dist/Server/Utils/AI/Toolbox/OnCallTools.js.map +1 -1
- package/build/dist/Server/Utils/AnalyticsDatabase/Statement.js +12 -1
- package/build/dist/Server/Utils/AnalyticsDatabase/Statement.js.map +1 -1
- package/build/dist/Server/Utils/AnalyticsDatabase/StatementGenerator.js +246 -9
- package/build/dist/Server/Utils/AnalyticsDatabase/StatementGenerator.js.map +1 -1
- package/build/dist/Server/Utils/Attribution.js.map +1 -1
- package/build/dist/Server/Utils/Marketing/MarketingEventUtil.js +27 -7
- package/build/dist/Server/Utils/Marketing/MarketingEventUtil.js.map +1 -1
- package/build/dist/Server/Utils/SecurityEvent/DetectionRuleEvaluator.js +42 -7
- package/build/dist/Server/Utils/SecurityEvent/DetectionRuleEvaluator.js.map +1 -1
- package/build/dist/Server/Utils/SecurityEvent/Sigma/SigmaClickhouseCompiler.js +18 -0
- package/build/dist/Server/Utils/SecurityEvent/Sigma/SigmaClickhouseCompiler.js.map +1 -1
- package/build/dist/Server/Utils/StartServer.js +12 -21
- package/build/dist/Server/Utils/StartServer.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/LlmCostBudgetEvaluator.js +76 -5
- package/build/dist/Server/Utils/Telemetry/LlmCostBudgetEvaluator.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/LlmMetricSpend.js +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/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/ScanNameUtil.js +120 -0
- package/build/dist/Utils/NetworkDiscovery/ScanNameUtil.js.map +1 -0
- package/build/dist/Utils/StatusPage/ResourceExplorer.js +171 -0
- package/build/dist/Utils/StatusPage/ResourceExplorer.js.map +1 -1
- package/build/dist/Utils/Telemetry/LlmMetricQuery.js +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
|
@@ -10,6 +10,7 @@ import StatusPageResourceExplorerUtil, {
|
|
|
10
10
|
StatusPageResourceNavigatorResult,
|
|
11
11
|
StatusPageResourceNavigatorRow,
|
|
12
12
|
StatusPageResourceSelection,
|
|
13
|
+
StatusPageResourceSelectionState,
|
|
13
14
|
StatusPageResourceSelectionType,
|
|
14
15
|
} from "../../../Utils/StatusPage/ResourceExplorer";
|
|
15
16
|
import { describe, expect, test } from "@jest/globals";
|
|
@@ -928,4 +929,471 @@ describe("StatusPageResourceExplorerUtil", () => {
|
|
|
928
929
|
).toBe("12 sub groups");
|
|
929
930
|
});
|
|
930
931
|
});
|
|
932
|
+
|
|
933
|
+
/*
|
|
934
|
+
* Ticking rows, so that clearing a group is one decision rather than twenty
|
|
935
|
+
* seven (issue #3419).
|
|
936
|
+
*
|
|
937
|
+
* A selection is a set of id strings held by the pane, and the pane re-fetches
|
|
938
|
+
* the group after every write - so the two properties worth pinning down are
|
|
939
|
+
* that an operation only ever touches the resources it was handed, and that a
|
|
940
|
+
* no-op hands back the very set it was given rather than an equal copy. The
|
|
941
|
+
* second one is not tidiness: the set is React state, and returning a new
|
|
942
|
+
* instance for a no-op is a re-render of the whole pane per keystroke.
|
|
943
|
+
*/
|
|
944
|
+
describe("selecting resources", () => {
|
|
945
|
+
type MakeSelectionFunction = (ids: Array<string>) => Set<string>;
|
|
946
|
+
|
|
947
|
+
const makeSelection: MakeSelectionFunction = (
|
|
948
|
+
ids: Array<string>,
|
|
949
|
+
): Set<string> => {
|
|
950
|
+
return new Set<string>(ids);
|
|
951
|
+
};
|
|
952
|
+
|
|
953
|
+
/* A resource the server would never return: no id at all. */
|
|
954
|
+
type MakeIdlessResourceFunction = (name: string) => StatusPageResource;
|
|
955
|
+
|
|
956
|
+
const makeIdlessResource: MakeIdlessResourceFunction = (
|
|
957
|
+
name: string,
|
|
958
|
+
): StatusPageResource => {
|
|
959
|
+
const resource: StatusPageResource = new StatusPageResource();
|
|
960
|
+
resource.displayName = name;
|
|
961
|
+
|
|
962
|
+
return resource;
|
|
963
|
+
};
|
|
964
|
+
|
|
965
|
+
describe("reading a resource's id", () => {
|
|
966
|
+
test("hands back the id as a string", () => {
|
|
967
|
+
expect(
|
|
968
|
+
StatusPageResourceExplorerUtil.getResourceId(
|
|
969
|
+
makeResource({ id: "a" }),
|
|
970
|
+
),
|
|
971
|
+
).toBe("a");
|
|
972
|
+
});
|
|
973
|
+
|
|
974
|
+
test("is null for a resource with no id", () => {
|
|
975
|
+
expect(
|
|
976
|
+
StatusPageResourceExplorerUtil.getResourceId(
|
|
977
|
+
makeIdlessResource("Nameless"),
|
|
978
|
+
),
|
|
979
|
+
).toBeNull();
|
|
980
|
+
});
|
|
981
|
+
|
|
982
|
+
test("is null rather than the empty string, which would collide", () => {
|
|
983
|
+
const resource: StatusPageResource = new StatusPageResource();
|
|
984
|
+
resource._id = "";
|
|
985
|
+
|
|
986
|
+
expect(
|
|
987
|
+
StatusPageResourceExplorerUtil.getResourceId(resource),
|
|
988
|
+
).toBeNull();
|
|
989
|
+
});
|
|
990
|
+
});
|
|
991
|
+
|
|
992
|
+
describe("the ids a list offers", () => {
|
|
993
|
+
test("are in the order the list draws them", () => {
|
|
994
|
+
expect(
|
|
995
|
+
StatusPageResourceExplorerUtil.getResourceIds([
|
|
996
|
+
makeResource({ id: "c" }),
|
|
997
|
+
makeResource({ id: "a" }),
|
|
998
|
+
makeResource({ id: "b" }),
|
|
999
|
+
]),
|
|
1000
|
+
).toEqual(["c", "a", "b"]);
|
|
1001
|
+
});
|
|
1002
|
+
|
|
1003
|
+
test("skip anything that cannot be held on to", () => {
|
|
1004
|
+
expect(
|
|
1005
|
+
StatusPageResourceExplorerUtil.getResourceIds([
|
|
1006
|
+
makeResource({ id: "a" }),
|
|
1007
|
+
makeIdlessResource("Nameless"),
|
|
1008
|
+
makeResource({ id: "b" }),
|
|
1009
|
+
]),
|
|
1010
|
+
).toEqual(["a", "b"]);
|
|
1011
|
+
});
|
|
1012
|
+
|
|
1013
|
+
test("say each id once, however many rows carry it", () => {
|
|
1014
|
+
expect(
|
|
1015
|
+
StatusPageResourceExplorerUtil.getResourceIds([
|
|
1016
|
+
makeResource({ id: "a" }),
|
|
1017
|
+
makeResource({ id: "a" }),
|
|
1018
|
+
makeResource({ id: "b" }),
|
|
1019
|
+
]),
|
|
1020
|
+
).toEqual(["a", "b"]);
|
|
1021
|
+
});
|
|
1022
|
+
|
|
1023
|
+
test("are empty for an empty list", () => {
|
|
1024
|
+
expect(StatusPageResourceExplorerUtil.getResourceIds([])).toEqual([]);
|
|
1025
|
+
});
|
|
1026
|
+
});
|
|
1027
|
+
|
|
1028
|
+
describe("ticking one row", () => {
|
|
1029
|
+
test("adds an id that was not selected", () => {
|
|
1030
|
+
const next: Set<string> =
|
|
1031
|
+
StatusPageResourceExplorerUtil.toggleSelectedResourceId({
|
|
1032
|
+
selectedResourceIds: makeSelection(["a"]),
|
|
1033
|
+
resourceId: "b",
|
|
1034
|
+
});
|
|
1035
|
+
|
|
1036
|
+
expect([...next].sort()).toEqual(["a", "b"]);
|
|
1037
|
+
});
|
|
1038
|
+
|
|
1039
|
+
test("removes an id that was", () => {
|
|
1040
|
+
const next: Set<string> =
|
|
1041
|
+
StatusPageResourceExplorerUtil.toggleSelectedResourceId({
|
|
1042
|
+
selectedResourceIds: makeSelection(["a", "b"]),
|
|
1043
|
+
resourceId: "a",
|
|
1044
|
+
});
|
|
1045
|
+
|
|
1046
|
+
expect([...next]).toEqual(["b"]);
|
|
1047
|
+
});
|
|
1048
|
+
|
|
1049
|
+
test("leaves the set it was given alone", () => {
|
|
1050
|
+
const current: Set<string> = makeSelection(["a"]);
|
|
1051
|
+
|
|
1052
|
+
const next: Set<string> =
|
|
1053
|
+
StatusPageResourceExplorerUtil.toggleSelectedResourceId({
|
|
1054
|
+
selectedResourceIds: current,
|
|
1055
|
+
resourceId: "b",
|
|
1056
|
+
});
|
|
1057
|
+
|
|
1058
|
+
expect(next).not.toBe(current);
|
|
1059
|
+
expect([...current]).toEqual(["a"]);
|
|
1060
|
+
});
|
|
1061
|
+
});
|
|
1062
|
+
|
|
1063
|
+
describe("the box at the top of the list", () => {
|
|
1064
|
+
test("selects every resource it was handed", () => {
|
|
1065
|
+
const next: Set<string> =
|
|
1066
|
+
StatusPageResourceExplorerUtil.setResourcesSelected({
|
|
1067
|
+
selectedResourceIds: makeSelection([]),
|
|
1068
|
+
statusPageResources: [
|
|
1069
|
+
makeResource({ id: "a" }),
|
|
1070
|
+
makeResource({ id: "b" }),
|
|
1071
|
+
],
|
|
1072
|
+
isSelected: true,
|
|
1073
|
+
});
|
|
1074
|
+
|
|
1075
|
+
expect([...next].sort()).toEqual(["a", "b"]);
|
|
1076
|
+
});
|
|
1077
|
+
|
|
1078
|
+
/*
|
|
1079
|
+
* The list is filtered as often as not, and the rows the search hid are
|
|
1080
|
+
* still selected. Un-ticking over four matches must not drop the twenty
|
|
1081
|
+
* that were selected before the operator started typing.
|
|
1082
|
+
*/
|
|
1083
|
+
test("leaves selected rows it was not handed alone, in both directions", () => {
|
|
1084
|
+
const selected: Set<string> =
|
|
1085
|
+
StatusPageResourceExplorerUtil.setResourcesSelected({
|
|
1086
|
+
selectedResourceIds: makeSelection(["hidden"]),
|
|
1087
|
+
statusPageResources: [makeResource({ id: "shown" })],
|
|
1088
|
+
isSelected: true,
|
|
1089
|
+
});
|
|
1090
|
+
|
|
1091
|
+
expect([...selected].sort()).toEqual(["hidden", "shown"]);
|
|
1092
|
+
|
|
1093
|
+
const deselected: Set<string> =
|
|
1094
|
+
StatusPageResourceExplorerUtil.setResourcesSelected({
|
|
1095
|
+
selectedResourceIds: selected,
|
|
1096
|
+
statusPageResources: [makeResource({ id: "shown" })],
|
|
1097
|
+
isSelected: false,
|
|
1098
|
+
});
|
|
1099
|
+
|
|
1100
|
+
expect([...deselected]).toEqual(["hidden"]);
|
|
1101
|
+
});
|
|
1102
|
+
|
|
1103
|
+
test("ignores rows that cannot be selected at all", () => {
|
|
1104
|
+
const next: Set<string> =
|
|
1105
|
+
StatusPageResourceExplorerUtil.setResourcesSelected({
|
|
1106
|
+
selectedResourceIds: makeSelection([]),
|
|
1107
|
+
statusPageResources: [
|
|
1108
|
+
makeResource({ id: "a" }),
|
|
1109
|
+
makeIdlessResource("Nameless"),
|
|
1110
|
+
],
|
|
1111
|
+
isSelected: true,
|
|
1112
|
+
});
|
|
1113
|
+
|
|
1114
|
+
expect([...next]).toEqual(["a"]);
|
|
1115
|
+
});
|
|
1116
|
+
|
|
1117
|
+
test("hands back the same set when everything was already selected", () => {
|
|
1118
|
+
const current: Set<string> = makeSelection(["a", "b"]);
|
|
1119
|
+
|
|
1120
|
+
expect(
|
|
1121
|
+
StatusPageResourceExplorerUtil.setResourcesSelected({
|
|
1122
|
+
selectedResourceIds: current,
|
|
1123
|
+
statusPageResources: [
|
|
1124
|
+
makeResource({ id: "a" }),
|
|
1125
|
+
makeResource({ id: "b" }),
|
|
1126
|
+
],
|
|
1127
|
+
isSelected: true,
|
|
1128
|
+
}),
|
|
1129
|
+
).toBe(current);
|
|
1130
|
+
});
|
|
1131
|
+
|
|
1132
|
+
test("hands back the same set when nothing handed in was selected", () => {
|
|
1133
|
+
const current: Set<string> = makeSelection(["other"]);
|
|
1134
|
+
|
|
1135
|
+
expect(
|
|
1136
|
+
StatusPageResourceExplorerUtil.setResourcesSelected({
|
|
1137
|
+
selectedResourceIds: current,
|
|
1138
|
+
statusPageResources: [makeResource({ id: "a" })],
|
|
1139
|
+
isSelected: false,
|
|
1140
|
+
}),
|
|
1141
|
+
).toBe(current);
|
|
1142
|
+
});
|
|
1143
|
+
|
|
1144
|
+
test("hands back the same set for an empty list", () => {
|
|
1145
|
+
const current: Set<string> = makeSelection(["a"]);
|
|
1146
|
+
|
|
1147
|
+
expect(
|
|
1148
|
+
StatusPageResourceExplorerUtil.setResourcesSelected({
|
|
1149
|
+
selectedResourceIds: current,
|
|
1150
|
+
statusPageResources: [],
|
|
1151
|
+
isSelected: true,
|
|
1152
|
+
}),
|
|
1153
|
+
).toBe(current);
|
|
1154
|
+
});
|
|
1155
|
+
});
|
|
1156
|
+
|
|
1157
|
+
describe("what the box at the top of the list looks like", () => {
|
|
1158
|
+
type StateFunction = (
|
|
1159
|
+
resources: Array<StatusPageResource>,
|
|
1160
|
+
ids: Array<string>,
|
|
1161
|
+
) => StatusPageResourceSelectionState;
|
|
1162
|
+
|
|
1163
|
+
const state: StateFunction = (
|
|
1164
|
+
resources: Array<StatusPageResource>,
|
|
1165
|
+
ids: Array<string>,
|
|
1166
|
+
): StatusPageResourceSelectionState => {
|
|
1167
|
+
return StatusPageResourceExplorerUtil.getSelectionState({
|
|
1168
|
+
statusPageResources: resources,
|
|
1169
|
+
selectedResourceIds: makeSelection(ids),
|
|
1170
|
+
});
|
|
1171
|
+
};
|
|
1172
|
+
|
|
1173
|
+
test("is empty when nothing is selected", () => {
|
|
1174
|
+
expect(
|
|
1175
|
+
state([makeResource({ id: "a" }), makeResource({ id: "b" })], []),
|
|
1176
|
+
).toEqual({
|
|
1177
|
+
isAllSelected: false,
|
|
1178
|
+
isIndeterminate: false,
|
|
1179
|
+
selectedCount: 0,
|
|
1180
|
+
selectableCount: 2,
|
|
1181
|
+
});
|
|
1182
|
+
});
|
|
1183
|
+
|
|
1184
|
+
test("is half filled when some of them are", () => {
|
|
1185
|
+
expect(
|
|
1186
|
+
state([makeResource({ id: "a" }), makeResource({ id: "b" })], ["a"]),
|
|
1187
|
+
).toEqual({
|
|
1188
|
+
isAllSelected: false,
|
|
1189
|
+
isIndeterminate: true,
|
|
1190
|
+
selectedCount: 1,
|
|
1191
|
+
selectableCount: 2,
|
|
1192
|
+
});
|
|
1193
|
+
});
|
|
1194
|
+
|
|
1195
|
+
test("is filled when all of them are", () => {
|
|
1196
|
+
expect(
|
|
1197
|
+
state(
|
|
1198
|
+
[makeResource({ id: "a" }), makeResource({ id: "b" })],
|
|
1199
|
+
["a", "b"],
|
|
1200
|
+
),
|
|
1201
|
+
).toEqual({
|
|
1202
|
+
isAllSelected: true,
|
|
1203
|
+
isIndeterminate: false,
|
|
1204
|
+
selectedCount: 2,
|
|
1205
|
+
selectableCount: 2,
|
|
1206
|
+
});
|
|
1207
|
+
});
|
|
1208
|
+
|
|
1209
|
+
/*
|
|
1210
|
+
* A ticked box over nothing to tick reads as a selection that was lost -
|
|
1211
|
+
* which is exactly what an operator sees when a search matches nothing.
|
|
1212
|
+
*/
|
|
1213
|
+
test("is never filled over an empty list", () => {
|
|
1214
|
+
expect(state([], ["a"])).toEqual({
|
|
1215
|
+
isAllSelected: false,
|
|
1216
|
+
isIndeterminate: false,
|
|
1217
|
+
selectedCount: 0,
|
|
1218
|
+
selectableCount: 0,
|
|
1219
|
+
});
|
|
1220
|
+
});
|
|
1221
|
+
|
|
1222
|
+
/*
|
|
1223
|
+
* The selection outlives the filter, so it routinely holds ids that the
|
|
1224
|
+
* rows on screen know nothing about. They must not make the box on screen
|
|
1225
|
+
* look fuller than it is.
|
|
1226
|
+
*/
|
|
1227
|
+
test("counts only the rows it was handed", () => {
|
|
1228
|
+
expect(state([makeResource({ id: "a" })], ["a", "elsewhere"])).toEqual({
|
|
1229
|
+
isAllSelected: true,
|
|
1230
|
+
isIndeterminate: false,
|
|
1231
|
+
selectedCount: 1,
|
|
1232
|
+
selectableCount: 1,
|
|
1233
|
+
});
|
|
1234
|
+
});
|
|
1235
|
+
|
|
1236
|
+
test("is filled when every selectable row is selected, id-less ones aside", () => {
|
|
1237
|
+
expect(
|
|
1238
|
+
state(
|
|
1239
|
+
[makeResource({ id: "a" }), makeIdlessResource("Nameless")],
|
|
1240
|
+
["a"],
|
|
1241
|
+
),
|
|
1242
|
+
).toEqual({
|
|
1243
|
+
isAllSelected: true,
|
|
1244
|
+
isIndeterminate: false,
|
|
1245
|
+
selectedCount: 1,
|
|
1246
|
+
selectableCount: 1,
|
|
1247
|
+
});
|
|
1248
|
+
});
|
|
1249
|
+
});
|
|
1250
|
+
|
|
1251
|
+
describe("resolving a selection to resources", () => {
|
|
1252
|
+
test("hands them back in the order the list holds them", () => {
|
|
1253
|
+
const resources: Array<StatusPageResource> = [
|
|
1254
|
+
makeResource({ id: "a", monitorName: "API" }),
|
|
1255
|
+
makeResource({ id: "b", monitorName: "Database" }),
|
|
1256
|
+
makeResource({ id: "c", monitorName: "Cache" }),
|
|
1257
|
+
];
|
|
1258
|
+
|
|
1259
|
+
const selected: Array<StatusPageResource> =
|
|
1260
|
+
StatusPageResourceExplorerUtil.getSelectedResources({
|
|
1261
|
+
statusPageResources: resources,
|
|
1262
|
+
/* Ticked bottom up; reported top down. */
|
|
1263
|
+
selectedResourceIds: makeSelection(["c", "a"]),
|
|
1264
|
+
});
|
|
1265
|
+
|
|
1266
|
+
expect(
|
|
1267
|
+
selected.map((resource: StatusPageResource) => {
|
|
1268
|
+
return StatusPageResourceExplorerUtil.getResourceName(resource);
|
|
1269
|
+
}),
|
|
1270
|
+
).toEqual(["API", "Cache"]);
|
|
1271
|
+
});
|
|
1272
|
+
|
|
1273
|
+
test("drops ids that match nothing on screen", () => {
|
|
1274
|
+
expect(
|
|
1275
|
+
StatusPageResourceExplorerUtil.getSelectedResources({
|
|
1276
|
+
statusPageResources: [makeResource({ id: "a" })],
|
|
1277
|
+
selectedResourceIds: makeSelection(["a", "gone"]),
|
|
1278
|
+
}).length,
|
|
1279
|
+
).toBe(1);
|
|
1280
|
+
});
|
|
1281
|
+
|
|
1282
|
+
test("hands back one resource per id", () => {
|
|
1283
|
+
expect(
|
|
1284
|
+
StatusPageResourceExplorerUtil.getSelectedResources({
|
|
1285
|
+
statusPageResources: [
|
|
1286
|
+
makeResource({ id: "a" }),
|
|
1287
|
+
makeResource({ id: "a" }),
|
|
1288
|
+
],
|
|
1289
|
+
selectedResourceIds: makeSelection(["a"]),
|
|
1290
|
+
}).length,
|
|
1291
|
+
).toBe(1);
|
|
1292
|
+
});
|
|
1293
|
+
|
|
1294
|
+
test("is empty when nothing is selected", () => {
|
|
1295
|
+
expect(
|
|
1296
|
+
StatusPageResourceExplorerUtil.getSelectedResources({
|
|
1297
|
+
statusPageResources: [makeResource({ id: "a" })],
|
|
1298
|
+
selectedResourceIds: makeSelection([]),
|
|
1299
|
+
}),
|
|
1300
|
+
).toEqual([]);
|
|
1301
|
+
});
|
|
1302
|
+
});
|
|
1303
|
+
|
|
1304
|
+
describe("keeping a selection honest across a refetch", () => {
|
|
1305
|
+
test("drops whatever the group no longer holds", () => {
|
|
1306
|
+
const next: Set<string> =
|
|
1307
|
+
StatusPageResourceExplorerUtil.retainSelectedResourceIds({
|
|
1308
|
+
selectedResourceIds: makeSelection(["a", "b", "c"]),
|
|
1309
|
+
statusPageResources: [
|
|
1310
|
+
makeResource({ id: "a" }),
|
|
1311
|
+
makeResource({ id: "c" }),
|
|
1312
|
+
],
|
|
1313
|
+
});
|
|
1314
|
+
|
|
1315
|
+
expect([...next].sort()).toEqual(["a", "c"]);
|
|
1316
|
+
});
|
|
1317
|
+
|
|
1318
|
+
test("hands back the same set when nothing was dropped", () => {
|
|
1319
|
+
const current: Set<string> = makeSelection(["a", "b"]);
|
|
1320
|
+
|
|
1321
|
+
expect(
|
|
1322
|
+
StatusPageResourceExplorerUtil.retainSelectedResourceIds({
|
|
1323
|
+
selectedResourceIds: current,
|
|
1324
|
+
statusPageResources: [
|
|
1325
|
+
makeResource({ id: "a" }),
|
|
1326
|
+
makeResource({ id: "b" }),
|
|
1327
|
+
],
|
|
1328
|
+
}),
|
|
1329
|
+
).toBe(current);
|
|
1330
|
+
});
|
|
1331
|
+
|
|
1332
|
+
test("hands back the same empty set rather than a new one", () => {
|
|
1333
|
+
const current: Set<string> = makeSelection([]);
|
|
1334
|
+
|
|
1335
|
+
expect(
|
|
1336
|
+
StatusPageResourceExplorerUtil.retainSelectedResourceIds({
|
|
1337
|
+
selectedResourceIds: current,
|
|
1338
|
+
statusPageResources: [makeResource({ id: "a" })],
|
|
1339
|
+
}),
|
|
1340
|
+
).toBe(current);
|
|
1341
|
+
});
|
|
1342
|
+
|
|
1343
|
+
test("empties a selection whose group came back empty", () => {
|
|
1344
|
+
expect(
|
|
1345
|
+
StatusPageResourceExplorerUtil.retainSelectedResourceIds({
|
|
1346
|
+
selectedResourceIds: makeSelection(["a"]),
|
|
1347
|
+
statusPageResources: [],
|
|
1348
|
+
}).size,
|
|
1349
|
+
).toBe(0);
|
|
1350
|
+
});
|
|
1351
|
+
});
|
|
1352
|
+
|
|
1353
|
+
describe("what the confirmation says", () => {
|
|
1354
|
+
test("uses the singular for one resource, and says the monitor survives", () => {
|
|
1355
|
+
expect(
|
|
1356
|
+
StatusPageResourceExplorerUtil.getBulkRemoveConfirmTitle({
|
|
1357
|
+
count: 1,
|
|
1358
|
+
}),
|
|
1359
|
+
).toBe("Remove 1 resource");
|
|
1360
|
+
|
|
1361
|
+
expect(
|
|
1362
|
+
StatusPageResourceExplorerUtil.getBulkRemoveConfirmMessage({
|
|
1363
|
+
count: 1,
|
|
1364
|
+
}),
|
|
1365
|
+
).toBe(
|
|
1366
|
+
"Are you sure you want to remove 1 resource from this status page? The monitor itself is not deleted.",
|
|
1367
|
+
);
|
|
1368
|
+
});
|
|
1369
|
+
|
|
1370
|
+
test("uses the plural for several, and says the monitors survive", () => {
|
|
1371
|
+
expect(
|
|
1372
|
+
StatusPageResourceExplorerUtil.getBulkRemoveConfirmTitle({
|
|
1373
|
+
count: 27,
|
|
1374
|
+
}),
|
|
1375
|
+
).toBe("Remove 27 resources");
|
|
1376
|
+
|
|
1377
|
+
expect(
|
|
1378
|
+
StatusPageResourceExplorerUtil.getBulkRemoveConfirmMessage({
|
|
1379
|
+
count: 27,
|
|
1380
|
+
}),
|
|
1381
|
+
).toContain("remove 27 resources from this status page");
|
|
1382
|
+
|
|
1383
|
+
expect(
|
|
1384
|
+
StatusPageResourceExplorerUtil.getBulkRemoveConfirmMessage({
|
|
1385
|
+
count: 27,
|
|
1386
|
+
}),
|
|
1387
|
+
).toContain("The monitors themselves are not deleted.");
|
|
1388
|
+
});
|
|
1389
|
+
|
|
1390
|
+
test("groups the thousands, because the number is the whole warning", () => {
|
|
1391
|
+
expect(
|
|
1392
|
+
StatusPageResourceExplorerUtil.getBulkRemoveConfirmTitle({
|
|
1393
|
+
count: 1506,
|
|
1394
|
+
}),
|
|
1395
|
+
).toBe(`Remove ${(1506).toLocaleString()} resources`);
|
|
1396
|
+
});
|
|
1397
|
+
});
|
|
1398
|
+
});
|
|
931
1399
|
});
|