@oneuptime/common 12.0.13 → 12.0.14
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/OnCallDutyPolicySchedule.ts +14 -0
- package/Models/DatabaseModels/UserCall.ts +94 -3
- package/Models/DatabaseModels/UserEmail.ts +94 -3
- package/Models/DatabaseModels/UserIncomingCallNumber.ts +94 -3
- package/Models/DatabaseModels/UserPush.ts +37 -0
- package/Models/DatabaseModels/UserSMS.ts +94 -3
- package/Models/DatabaseModels/UserWhatsApp.ts +93 -2
- package/Server/API/BaseAPI.ts +79 -14
- package/Server/API/UserCallAPI.ts +53 -45
- package/Server/API/UserEmailAPI.ts +53 -44
- package/Server/API/UserIncomingCallNumberAPI.ts +48 -38
- package/Server/API/UserNotificationMethodAdminAPI.ts +481 -0
- package/Server/API/UserPushAPI.ts +126 -2
- package/Server/API/UserSmsAPI.ts +53 -44
- package/Server/API/UserWhatsAppAPI.ts +53 -50
- package/Server/Infrastructure/Postgres/SchemaMigrations/1787142779538-MigrationName.ts +154 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1787156982416-MigrationName.ts +17 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1787700000000-FixTotpOtpUrlAlgorithm.ts +45 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +6 -0
- package/Server/Middleware/VerificationCodeRateLimit.ts +586 -0
- package/Server/Services/AnalyticsDatabaseService.ts +169 -0
- package/Server/Services/DatabaseService.ts +101 -0
- package/Server/Services/LogAggregationService.ts +5 -0
- package/Server/Services/PushNotificationService.ts +127 -12
- package/Server/Services/TeamMemberService.ts +53 -13
- package/Server/Services/UserCallService.ts +55 -24
- package/Server/Services/UserEmailService.ts +83 -17
- package/Server/Services/UserIncomingCallNumberService.ts +49 -85
- package/Server/Services/UserNotificationMethodAdminService.ts +1527 -0
- package/Server/Services/UserNotificationRuleService.ts +26 -0
- package/Server/Services/UserPushService.ts +89 -0
- package/Server/Services/UserSmsService.ts +50 -17
- package/Server/Services/UserWhatsAppService.ts +48 -15
- package/Server/Types/Database/QueryHelper.ts +30 -0
- package/Server/Utils/AnalyticsDatabase/QuerySettingsHelper.ts +59 -0
- package/Server/Utils/ChannelVerification.ts +510 -0
- package/Server/Utils/Monitor/Criteria/IncomingRequestCriteria.ts +13 -16
- package/Server/Utils/Monitor/MonitorAlert.ts +24 -21
- package/Server/Utils/Monitor/MonitorIncident.ts +21 -18
- package/Server/Utils/Monitor/MonitorResourceContext.ts +107 -0
- package/Server/Utils/Monitor/MonitorStepResourceIdentity.ts +442 -0
- package/Server/Utils/Monitor/SeriesResourceLabels.ts +3 -3
- package/Server/Utils/Monitor/SeriesResourceLinker.ts +96 -28
- package/Server/Utils/TotpAuth.ts +137 -9
- package/Server/Utils/UserRegistrationToken.ts +182 -0
- package/Server/Utils/VerificationCode.ts +134 -0
- package/Tests/App/Dashboard/AdminNotificationRulesPage.test.tsx +173 -94
- package/Tests/App/Dashboard/AdminUserNotificationMethodsPage.test.tsx +1151 -0
- package/Tests/App/Dashboard/AdminUserOnCallPages.test.tsx +905 -0
- package/Tests/App/Dashboard/DashboardCommandPalette.test.tsx +338 -0
- package/Tests/App/Dashboard/InvestigationPanel.test.tsx +1 -1
- package/Tests/App/Dashboard/MonitorTypePicker.test.tsx +28 -0
- package/Tests/Models/UserPushCriticalAlertColumn.test.ts +172 -0
- package/Tests/Server/API/BaseAPIGetListParallel.test.ts +519 -0
- package/Tests/Server/API/NotificationChannelVerificationAPI.test.ts +543 -0
- package/Tests/Server/API/UserIncomingCallNumberApi.test.ts +108 -18
- package/Tests/Server/API/UserNotificationMethodAdminAPI.test.ts +963 -0
- package/Tests/Server/API/UserPushCriticalAlertsApi.test.ts +114 -0
- package/Tests/Server/API/UserSmsApi.test.ts +107 -14
- package/Tests/Server/API/UserTotpAuthAPI.test.ts +427 -0
- package/Tests/Server/Infrastructure/Postgres/FixTotpOtpUrlAlgorithmMigration.test.ts +315 -0
- package/Tests/Server/Middleware/VerificationCodeRateLimit.test.ts +775 -0
- package/Tests/Server/Services/AddNetworkDeviceReachabilityColumnsMigration.test.ts +10 -62
- package/Tests/Server/Services/AnalyticsDatabasePaginationStability.test.ts +33 -13
- package/Tests/Server/Services/AnalyticsDatabaseSortKeyBoundary.test.ts +658 -0
- package/Tests/Server/Services/CriticalOnCallAlertDelivery.test.ts +458 -0
- package/Tests/Server/Services/CriticalPushAlertPayload.test.ts +301 -0
- package/Tests/Server/Services/DatabaseServiceAtomicIncrement.test.ts +143 -0
- package/Tests/Server/Services/DeliverNotificationForRuleExtraction.test.ts +1 -0
- package/Tests/Server/Services/LogAggregationScanMemory.test.ts +421 -0
- package/Tests/Server/Services/LogAggregationService.test.ts +2 -2
- package/Tests/Server/Services/NotificationChannelCodeIssuance.test.ts +401 -0
- package/Tests/Server/Services/PushNotificationDeliveryOptions.test.ts +204 -0
- package/Tests/Server/Services/TeamMemberAutoAcceptInvitation.test.ts +21 -1
- package/Tests/Server/Services/TeamMemberInviteRegistrationToken.test.ts +290 -0
- package/Tests/Server/Services/UserNotificationMethodAdminService.test.ts +948 -0
- package/Tests/Server/Services/UserNotificationRuleExecuteItem.test.ts +1 -0
- package/Tests/Server/Services/UserPushCriticalAlertToggle.test.ts +255 -0
- package/Tests/Server/Services/UserTotpAuthEnrolment.test.ts +218 -0
- package/Tests/Server/TestingUtils/AuthenticatorApp.ts +248 -0
- package/Tests/Server/Types/Database/Permissions/NotificationChannelVerificationColumns.test.ts +135 -0
- package/Tests/Server/Types/Database/Permissions/OnCallScheduleRelationSelect.test.ts +504 -0
- package/Tests/Server/Types/Database/QueryHelperFindWithSameTextAnyOf.test.ts +91 -0
- package/Tests/Server/Types/Workflow/Components/JsonToText.test.ts +384 -0
- package/Tests/Server/Types/Workflow/Components/MergeJson.test.ts +403 -0
- package/Tests/Server/Utils/Browser.test.ts +162 -0
- package/Tests/Server/Utils/ChannelVerification.test.ts +689 -0
- package/Tests/Server/Utils/Express.test.ts +371 -0
- package/Tests/Server/Utils/Monitor/Criteria/CustomCodeMonitorCriteria.test.ts +707 -0
- package/Tests/Server/Utils/Monitor/Criteria/DnsMonitorCriteria.test.ts +698 -0
- package/Tests/Server/Utils/Monitor/Criteria/IncomingEmailBodyCriteria.test.ts +243 -0
- package/Tests/Server/Utils/Monitor/Criteria/IncomingRequestBodyCriteria.test.ts +278 -0
- package/Tests/Server/Utils/Monitor/MonitorAlertResourceLinking.test.ts +160 -20
- package/Tests/Server/Utils/Monitor/MonitorDependencySuppressionCreatorSkip.test.ts +13 -8
- package/Tests/Server/Utils/Monitor/MonitorIncidentResourceLinking.test.ts +162 -18
- package/Tests/Server/Utils/Monitor/MonitorResourceContext.test.ts +349 -0
- package/Tests/Server/Utils/Monitor/MonitorStepResourceIdentity.test.ts +690 -0
- package/Tests/Server/Utils/Monitor/MonitorSummaryPersistence.test.ts +7 -2
- package/Tests/Server/Utils/Monitor/SeriesResourceLinker.test.ts +92 -18
- package/Tests/Server/Utils/PushNotificationUtilCreators.test.ts +267 -0
- package/Tests/Server/Utils/Telemetry/OneuptimeLabel.test.ts +439 -0
- package/Tests/Server/Utils/TotpAuth.test.ts +719 -0
- package/Tests/Server/Utils/UserRegistrationToken.test.ts +322 -0
- package/Tests/Server/Utils/VerificationCode.test.ts +296 -0
- package/Tests/Types/AutoRemediation/AutoRemediationSuggestionStatus.test.ts +192 -0
- package/Tests/Types/Call/CallRequest.test.ts +189 -0
- package/Tests/Types/Dashboard/DashboardSize.test.ts +226 -0
- package/Tests/Types/Incident/IncidentSlaStatus.test.ts +191 -0
- package/Tests/Types/Metrics/MetricDashboardMetricType.test.ts +278 -0
- package/Tests/Types/Metrics/MetricPipelineRuleType.test.ts +517 -0
- package/Tests/Types/Monitor/IncomingMonitorDefaultCriteria.test.ts +470 -0
- package/Tests/Types/Monitor/MonitorCriteriaInstance.test.ts +6 -4
- package/Tests/Types/Monitor/Recommendation/MonitorRecommendationCatalog.test.ts +262 -5
- package/Tests/Types/Monitor/Recommendation/MonitorRecommendationCoverage.test.ts +1 -1
- package/Tests/Types/Monitor/Recommendation/MonitorRecommendationNotificationMode.test.ts +1 -1
- package/Tests/Types/Monitor/ServiceAlertTemplates.test.ts +905 -0
- package/Tests/Types/Service/ServiceLanguage.test.ts +255 -0
- package/Tests/Types/TextRandomGeneration.test.ts +211 -0
- package/Tests/UI/Components/Button.test.tsx +175 -1
- package/Tests/UI/Components/CodeBlockLanguages.test.tsx +236 -0
- package/Tests/UI/Components/CommandPalette/CommandPalette.test.tsx +568 -0
- package/Tests/UI/Components/CommandPalette/CommandPaletteKeyboard.test.tsx +239 -0
- package/Tests/UI/Components/CommandPalette/CommandPaletteProviders.test.tsx +400 -0
- package/Tests/UI/Components/CommandPalette/PaletteFilter.test.ts +234 -0
- package/Tests/UI/Components/CommandPalette/RecentCommands.test.ts +97 -0
- package/Tests/UI/Components/CountModelSideMenuItemGuard.test.tsx +198 -0
- package/Tests/UI/Components/FeedItemSafeMode.test.tsx +1 -1
- package/Tests/UI/Components/Forms/Utils/FormFieldSchemaTypeUtil.test.ts +267 -0
- package/Tests/UI/Components/List.test.tsx +9 -2
- package/Tests/UI/Components/ListLoadingStates.test.tsx +173 -0
- package/Tests/UI/Components/MarkdownLazy.test.tsx +113 -0
- package/Tests/UI/Components/MarkdownMermaidRetry.test.tsx +110 -0
- package/Tests/UI/Components/ModelTable/useCustomFieldColumns.test.tsx +8 -0
- package/Tests/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.test.ts +692 -0
- package/Tests/UI/Components/MoreMenuMotion.test.tsx +118 -0
- package/Tests/UI/Components/NavBarCommandKGating.test.tsx +178 -0
- package/Tests/UI/Components/OrderedStatesList.test.tsx +19 -2
- package/Tests/UI/Components/SideOverMotion.test.tsx +109 -0
- package/Tests/UI/Components/Skeleton.test.tsx +71 -0
- package/Tests/UI/Components/TableLoadingStates.test.tsx +279 -0
- package/Tests/UI/Components/Tabs.test.tsx +24 -0
- package/Tests/UI/Components/Toast.test.tsx +130 -7
- package/Tests/UI/Components/ToastStacking.test.tsx +198 -0
- package/Tests/UI/Utils/Dropdown.test.ts +423 -0
- package/Tests/UI/Utils/ModelAPITenantHeader.test.ts +122 -0
- package/Tests/UI/Utils/ModelListCache.test.ts +338 -0
- package/Tests/UI/Utils/ProjectListCacheInvalidation.test.ts +225 -0
- package/Tests/Utils/API.test.ts +16 -2
- package/Tests/Utils/Dashboard/Components/DashboardKubernetesResourceListShared.test.ts +347 -0
- package/Tests/Utils/Dashboard/Components/DashboardListSharedArgs.test.ts +259 -0
- package/Tests/Utils/Dashboard/Components/DashboardMonitorListComponent.test.ts +466 -0
- package/Tests/Utils/Rum/UrlScrubberSegments.test.ts +362 -0
- package/Types/Email/EmailTemplateType.ts +1 -0
- package/Types/Monitor/MonitorCriteriaInstance.ts +41 -20
- package/Types/Monitor/Recommendation/MonitorRecommendationCatalog.ts +131 -8
- package/Types/Monitor/Recommendation/MonitorRecommendationTypes.ts +48 -8
- package/Types/Monitor/ServiceAlertTemplates.ts +1352 -0
- package/Types/Permission.ts +35 -0
- package/Types/PushNotification/AndroidNotificationChannel.ts +26 -0
- package/Types/PushNotification/PushNotificationMessage.ts +15 -0
- package/Types/PushNotification/PushNotificationRequest.ts +8 -16
- package/Types/Service/ServiceLanguage.ts +144 -0
- package/Types/Text.ts +111 -19
- package/UI/Components/Button/Button.tsx +27 -14
- package/UI/Components/CodeBlock/CodeBlock.tsx +54 -7
- package/UI/Components/CodeBlock/LanguageRegistry.ts +103 -0
- package/UI/Components/CommandPalette/CommandPalette.tsx +790 -0
- package/UI/Components/CommandPalette/PaletteFilter.ts +196 -0
- package/UI/Components/CommandPalette/PaletteRow.tsx +173 -0
- package/UI/Components/CommandPalette/RecentCommands.ts +57 -0
- package/UI/Components/CommandPalette/Types.ts +49 -0
- package/UI/Components/CommandPalette/UseProviderSearch.ts +129 -0
- package/UI/Components/Dropdown/Dropdown.tsx +6 -1
- package/UI/Components/Feed/FeedItem.tsx +1 -1
- package/UI/Components/List/List.tsx +37 -5
- package/UI/Components/List/ListSkeleton.tsx +54 -0
- package/UI/Components/Markdown.tsx/LazyMarkdownViewer.tsx +6 -1
- package/UI/Components/Markdown.tsx/MarkdownViewer.tsx +71 -26
- package/UI/Components/Modal/Modal.tsx +2 -2
- package/UI/Components/ModelTable/BaseModelTable.tsx +1 -1
- package/UI/Components/ModelTable/useCustomFieldColumns.ts +11 -5
- package/UI/Components/MoreMenu/MoreMenu.tsx +39 -1
- package/UI/Components/Navbar/NavBar.tsx +14 -1
- package/UI/Components/OrderedStatesList/OrderedStatesList.tsx +50 -5
- package/UI/Components/SideMenu/CountModelSideMenuItem.tsx +40 -1
- package/UI/Components/SideOver/SideOver.tsx +37 -2
- package/UI/Components/Skeleton/Skeleton.tsx +53 -0
- package/UI/Components/Table/Table.tsx +74 -44
- package/UI/Components/Table/TableSkeletonRows.tsx +141 -0
- package/UI/Components/Tabs/Tab.tsx +1 -1
- package/UI/Components/Toast/Toast.tsx +118 -53
- package/UI/Components/Toast/ToastInit.tsx +82 -32
- package/UI/Styles/Theme.css +40 -0
- package/UI/Utils/ModelAPI/ModelAPI.ts +20 -10
- package/UI/Utils/ModelListCache.ts +188 -0
- package/UI/Utils/Project.ts +29 -0
- package/Utils/API.ts +6 -1
- package/build/dist/Models/DatabaseModels/OnCallDutyPolicySchedule.js +14 -0
- package/build/dist/Models/DatabaseModels/OnCallDutyPolicySchedule.js.map +1 -1
- package/build/dist/Models/DatabaseModels/UserCall.js +101 -3
- package/build/dist/Models/DatabaseModels/UserCall.js.map +1 -1
- package/build/dist/Models/DatabaseModels/UserEmail.js +101 -3
- package/build/dist/Models/DatabaseModels/UserEmail.js.map +1 -1
- package/build/dist/Models/DatabaseModels/UserIncomingCallNumber.js +101 -3
- package/build/dist/Models/DatabaseModels/UserIncomingCallNumber.js.map +1 -1
- package/build/dist/Models/DatabaseModels/UserPush.js +38 -0
- package/build/dist/Models/DatabaseModels/UserPush.js.map +1 -1
- package/build/dist/Models/DatabaseModels/UserSMS.js +101 -3
- package/build/dist/Models/DatabaseModels/UserSMS.js.map +1 -1
- package/build/dist/Models/DatabaseModels/UserWhatsApp.js +100 -2
- package/build/dist/Models/DatabaseModels/UserWhatsApp.js.map +1 -1
- package/build/dist/Server/API/BaseAPI.js +69 -13
- package/build/dist/Server/API/BaseAPI.js.map +1 -1
- package/build/dist/Server/API/UserCallAPI.js +42 -38
- package/build/dist/Server/API/UserCallAPI.js.map +1 -1
- package/build/dist/Server/API/UserEmailAPI.js +42 -38
- package/build/dist/Server/API/UserEmailAPI.js.map +1 -1
- package/build/dist/Server/API/UserIncomingCallNumberAPI.js +37 -32
- package/build/dist/Server/API/UserIncomingCallNumberAPI.js.map +1 -1
- package/build/dist/Server/API/UserNotificationMethodAdminAPI.js +341 -0
- package/build/dist/Server/API/UserNotificationMethodAdminAPI.js.map +1 -0
- package/build/dist/Server/API/UserPushAPI.js +95 -2
- package/build/dist/Server/API/UserPushAPI.js.map +1 -1
- package/build/dist/Server/API/UserSmsAPI.js +42 -38
- package/build/dist/Server/API/UserSmsAPI.js.map +1 -1
- package/build/dist/Server/API/UserWhatsAppAPI.js +42 -40
- package/build/dist/Server/API/UserWhatsAppAPI.js.map +1 -1
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787142779538-MigrationName.js +89 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787142779538-MigrationName.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787156982416-MigrationName.js +12 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787156982416-MigrationName.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787700000000-FixTotpOtpUrlAlgorithm.js +40 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787700000000-FixTotpOtpUrlAlgorithm.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/VerificationCodeRateLimit.js +393 -0
- package/build/dist/Server/Middleware/VerificationCodeRateLimit.js.map +1 -0
- package/build/dist/Server/Services/AnalyticsDatabaseService.js +136 -0
- package/build/dist/Server/Services/AnalyticsDatabaseService.js.map +1 -1
- package/build/dist/Server/Services/DatabaseService.js +74 -0
- package/build/dist/Server/Services/DatabaseService.js.map +1 -1
- package/build/dist/Server/Services/LogAggregationService.js +5 -0
- package/build/dist/Server/Services/LogAggregationService.js.map +1 -1
- package/build/dist/Server/Services/PushNotificationService.js +69 -30
- package/build/dist/Server/Services/PushNotificationService.js.map +1 -1
- package/build/dist/Server/Services/TeamMemberService.js +43 -7
- package/build/dist/Server/Services/TeamMemberService.js.map +1 -1
- package/build/dist/Server/Services/UserCallService.js +54 -22
- package/build/dist/Server/Services/UserCallService.js.map +1 -1
- package/build/dist/Server/Services/UserEmailService.js +78 -17
- package/build/dist/Server/Services/UserEmailService.js.map +1 -1
- package/build/dist/Server/Services/UserIncomingCallNumberService.js +45 -74
- package/build/dist/Server/Services/UserIncomingCallNumberService.js.map +1 -1
- package/build/dist/Server/Services/UserNotificationMethodAdminService.js +1117 -0
- package/build/dist/Server/Services/UserNotificationMethodAdminService.js.map +1 -0
- package/build/dist/Server/Services/UserNotificationRuleService.js +20 -0
- package/build/dist/Server/Services/UserNotificationRuleService.js.map +1 -1
- package/build/dist/Server/Services/UserPushService.js +77 -0
- package/build/dist/Server/Services/UserPushService.js.map +1 -1
- package/build/dist/Server/Services/UserSmsService.js +50 -17
- package/build/dist/Server/Services/UserSmsService.js.map +1 -1
- package/build/dist/Server/Services/UserWhatsAppService.js +48 -15
- package/build/dist/Server/Services/UserWhatsAppService.js.map +1 -1
- package/build/dist/Server/Types/Database/QueryHelper.js +27 -0
- package/build/dist/Server/Types/Database/QueryHelper.js.map +1 -1
- package/build/dist/Server/Utils/AnalyticsDatabase/QuerySettingsHelper.js +46 -0
- package/build/dist/Server/Utils/AnalyticsDatabase/QuerySettingsHelper.js.map +1 -1
- package/build/dist/Server/Utils/ChannelVerification.js +348 -0
- package/build/dist/Server/Utils/ChannelVerification.js.map +1 -0
- package/build/dist/Server/Utils/Monitor/Criteria/IncomingRequestCriteria.js +13 -12
- package/build/dist/Server/Utils/Monitor/Criteria/IncomingRequestCriteria.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorAlert.js +20 -17
- package/build/dist/Server/Utils/Monitor/MonitorAlert.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorIncident.js +17 -14
- package/build/dist/Server/Utils/Monitor/MonitorIncident.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorResourceContext.js +95 -0
- package/build/dist/Server/Utils/Monitor/MonitorResourceContext.js.map +1 -0
- package/build/dist/Server/Utils/Monitor/MonitorStepResourceIdentity.js +313 -0
- package/build/dist/Server/Utils/Monitor/MonitorStepResourceIdentity.js.map +1 -0
- package/build/dist/Server/Utils/Monitor/SeriesResourceLabels.js +3 -3
- package/build/dist/Server/Utils/Monitor/SeriesResourceLinker.js +67 -26
- package/build/dist/Server/Utils/Monitor/SeriesResourceLinker.js.map +1 -1
- package/build/dist/Server/Utils/TotpAuth.js +127 -8
- package/build/dist/Server/Utils/TotpAuth.js.map +1 -1
- package/build/dist/Server/Utils/UserRegistrationToken.js +170 -0
- package/build/dist/Server/Utils/UserRegistrationToken.js.map +1 -0
- package/build/dist/Server/Utils/VerificationCode.js +120 -0
- package/build/dist/Server/Utils/VerificationCode.js.map +1 -0
- package/build/dist/Types/Email/EmailTemplateType.js +1 -0
- package/build/dist/Types/Email/EmailTemplateType.js.map +1 -1
- package/build/dist/Types/Monitor/MonitorCriteriaInstance.js +42 -21
- package/build/dist/Types/Monitor/MonitorCriteriaInstance.js.map +1 -1
- package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationCatalog.js +77 -5
- package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationCatalog.js.map +1 -1
- package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationTypes.js +18 -6
- package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationTypes.js.map +1 -1
- package/build/dist/Types/Monitor/ServiceAlertTemplates.js +1028 -0
- package/build/dist/Types/Monitor/ServiceAlertTemplates.js.map +1 -0
- package/build/dist/Types/Permission.js +33 -0
- package/build/dist/Types/Permission.js.map +1 -1
- package/build/dist/Types/PushNotification/AndroidNotificationChannel.js +27 -0
- package/build/dist/Types/PushNotification/AndroidNotificationChannel.js.map +1 -0
- package/build/dist/Types/Service/ServiceLanguage.js +96 -0
- package/build/dist/Types/Service/ServiceLanguage.js.map +1 -0
- package/build/dist/Types/Text.js +82 -17
- package/build/dist/Types/Text.js.map +1 -1
- package/build/dist/UI/Components/Button/Button.js +22 -14
- package/build/dist/UI/Components/Button/Button.js.map +1 -1
- package/build/dist/UI/Components/CodeBlock/CodeBlock.js +35 -3
- package/build/dist/UI/Components/CodeBlock/CodeBlock.js.map +1 -1
- package/build/dist/UI/Components/CodeBlock/LanguageRegistry.js +57 -0
- package/build/dist/UI/Components/CodeBlock/LanguageRegistry.js.map +1 -0
- package/build/dist/UI/Components/CommandPalette/CommandPalette.js +439 -0
- package/build/dist/UI/Components/CommandPalette/CommandPalette.js.map +1 -0
- package/build/dist/UI/Components/CommandPalette/PaletteFilter.js +135 -0
- package/build/dist/UI/Components/CommandPalette/PaletteFilter.js.map +1 -0
- package/build/dist/UI/Components/CommandPalette/PaletteRow.js +83 -0
- package/build/dist/UI/Components/CommandPalette/PaletteRow.js.map +1 -0
- package/build/dist/UI/Components/CommandPalette/RecentCommands.js +47 -0
- package/build/dist/UI/Components/CommandPalette/RecentCommands.js.map +1 -0
- package/build/dist/UI/Components/CommandPalette/Types.js +2 -0
- package/build/dist/UI/Components/CommandPalette/Types.js.map +1 -0
- package/build/dist/UI/Components/CommandPalette/UseProviderSearch.js +88 -0
- package/build/dist/UI/Components/CommandPalette/UseProviderSearch.js.map +1 -0
- package/build/dist/UI/Components/Dropdown/Dropdown.js +6 -1
- package/build/dist/UI/Components/Dropdown/Dropdown.js.map +1 -1
- package/build/dist/UI/Components/Feed/FeedItem.js +1 -1
- package/build/dist/UI/Components/Feed/FeedItem.js.map +1 -1
- package/build/dist/UI/Components/List/List.js +19 -5
- package/build/dist/UI/Components/List/List.js.map +1 -1
- package/build/dist/UI/Components/List/ListSkeleton.js +21 -0
- package/build/dist/UI/Components/List/ListSkeleton.js.map +1 -0
- package/build/dist/UI/Components/Markdown.tsx/LazyMarkdownViewer.js.map +1 -1
- package/build/dist/UI/Components/Markdown.tsx/MarkdownViewer.js +52 -25
- package/build/dist/UI/Components/Markdown.tsx/MarkdownViewer.js.map +1 -1
- package/build/dist/UI/Components/Modal/Modal.js +2 -2
- package/build/dist/UI/Components/ModelTable/BaseModelTable.js +1 -1
- package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
- package/build/dist/UI/Components/ModelTable/useCustomFieldColumns.js +9 -2
- package/build/dist/UI/Components/ModelTable/useCustomFieldColumns.js.map +1 -1
- package/build/dist/UI/Components/MoreMenu/MoreMenu.js +32 -1
- package/build/dist/UI/Components/MoreMenu/MoreMenu.js.map +1 -1
- package/build/dist/UI/Components/Navbar/NavBar.js +5 -1
- package/build/dist/UI/Components/Navbar/NavBar.js.map +1 -1
- package/build/dist/UI/Components/OrderedStatesList/OrderedStatesList.js +29 -5
- package/build/dist/UI/Components/OrderedStatesList/OrderedStatesList.js.map +1 -1
- package/build/dist/UI/Components/SideMenu/CountModelSideMenuItem.js +23 -1
- package/build/dist/UI/Components/SideMenu/CountModelSideMenuItem.js.map +1 -1
- package/build/dist/UI/Components/SideOver/SideOver.js +23 -2
- package/build/dist/UI/Components/SideOver/SideOver.js.map +1 -1
- package/build/dist/UI/Components/Skeleton/Skeleton.js +23 -0
- package/build/dist/UI/Components/Skeleton/Skeleton.js.map +1 -0
- package/build/dist/UI/Components/Table/Table.js +35 -24
- package/build/dist/UI/Components/Table/Table.js.map +1 -1
- package/build/dist/UI/Components/Table/TableSkeletonRows.js +52 -0
- package/build/dist/UI/Components/Table/TableSkeletonRows.js.map +1 -0
- package/build/dist/UI/Components/Tabs/Tab.js +1 -1
- package/build/dist/UI/Components/Tabs/Tab.js.map +1 -1
- package/build/dist/UI/Components/Toast/Toast.js +77 -23
- package/build/dist/UI/Components/Toast/Toast.js.map +1 -1
- package/build/dist/UI/Components/Toast/ToastInit.js +37 -15
- package/build/dist/UI/Components/Toast/ToastInit.js.map +1 -1
- package/build/dist/UI/Utils/ModelAPI/ModelAPI.js +18 -9
- package/build/dist/UI/Utils/ModelAPI/ModelAPI.js.map +1 -1
- package/build/dist/UI/Utils/ModelListCache.js +126 -0
- package/build/dist/UI/Utils/ModelListCache.js.map +1 -0
- package/build/dist/UI/Utils/Project.js +24 -1
- package/build/dist/UI/Utils/Project.js.map +1 -1
- package/build/dist/Utils/API.js +6 -1
- package/build/dist/Utils/API.js.map +1 -1
- package/jest.config.json +1 -1
- package/package.json +2 -3
- package/Server/Utils/Monitor/MonitorClusterContext.ts +0 -182
- package/Tests/__mocks__/otpauth.js +0 -30
- package/build/dist/Server/Utils/Monitor/MonitorClusterContext.js +0 -141
- package/build/dist/Server/Utils/Monitor/MonitorClusterContext.js.map +0 -1
|
@@ -0,0 +1,690 @@
|
|
|
1
|
+
import Monitor from "../../../../Models/DatabaseModels/Monitor";
|
|
2
|
+
import MonitorStepResourceIdentity from "../../../../Server/Utils/Monitor/MonitorStepResourceIdentity";
|
|
3
|
+
import { SeriesResourceRefs } from "../../../../Server/Utils/Monitor/SeriesResourceLabels";
|
|
4
|
+
import { JSONObject } from "../../../../Types/JSON";
|
|
5
|
+
import MonitorStep from "../../../../Types/Monitor/MonitorStep";
|
|
6
|
+
import MonitorSteps from "../../../../Types/Monitor/MonitorSteps";
|
|
7
|
+
import MonitorType from "../../../../Types/Monitor/MonitorType";
|
|
8
|
+
import ObjectID from "../../../../Types/ObjectID";
|
|
9
|
+
import { describe, expect, test } from "@jest/globals";
|
|
10
|
+
|
|
11
|
+
/*
|
|
12
|
+
* MonitorStepResourceIdentity reads the resources a monitor's own
|
|
13
|
+
* configuration names, so an alert or incident can be attached to them
|
|
14
|
+
* even when the criteria is ungrouped and emits no series labels.
|
|
15
|
+
*
|
|
16
|
+
* The regression that motivated it: a metric monitor scoped to one
|
|
17
|
+
* service with the attribute filter
|
|
18
|
+
* `oneuptime.service.name = app-plan-starship-online-production` opened
|
|
19
|
+
* alerts whose "Affected Resources" card read "No resources affected" —
|
|
20
|
+
* the filter named the service, but nothing ever read it.
|
|
21
|
+
*
|
|
22
|
+
* Pure module: no database, no mocks.
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
const SERVICE_ID_A: string = "aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa";
|
|
26
|
+
const SERVICE_ID_B: string = "bbbbbbbb-bbbb-4bbb-8bbb-bbbbbbbbbbbb";
|
|
27
|
+
|
|
28
|
+
function monitorWithSteps(
|
|
29
|
+
monitorType: MonitorType,
|
|
30
|
+
stepDataList: Array<JSONObject>,
|
|
31
|
+
): Monitor {
|
|
32
|
+
const model: Monitor = new Monitor();
|
|
33
|
+
model.monitorType = monitorType;
|
|
34
|
+
model.projectId = new ObjectID("11111111-1111-4111-8111-111111111111");
|
|
35
|
+
|
|
36
|
+
const steps: MonitorSteps = new MonitorSteps();
|
|
37
|
+
steps.data = {
|
|
38
|
+
monitorStepsInstanceArray: stepDataList.map(
|
|
39
|
+
(stepData: JSONObject): MonitorStep => {
|
|
40
|
+
const step: MonitorStep = new MonitorStep();
|
|
41
|
+
step.data = {
|
|
42
|
+
...step.data,
|
|
43
|
+
...stepData,
|
|
44
|
+
} as MonitorStep["data"];
|
|
45
|
+
return step;
|
|
46
|
+
},
|
|
47
|
+
),
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
model.monitorSteps = steps;
|
|
51
|
+
return model;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/*
|
|
55
|
+
* A metric view config carrying one query whose filter attributes are
|
|
56
|
+
* exactly `attributes`. This is the shape every metric-backed monitor
|
|
57
|
+
* step holds, and the shape the user's reported bug lives in.
|
|
58
|
+
*/
|
|
59
|
+
function metricViewConfigWith(attributes: JSONObject): JSONObject {
|
|
60
|
+
return {
|
|
61
|
+
queryConfigs: [
|
|
62
|
+
{
|
|
63
|
+
metricQueryData: {
|
|
64
|
+
filterData: {
|
|
65
|
+
metricName: "azure_memorypercentage_maximum",
|
|
66
|
+
attributes: attributes,
|
|
67
|
+
},
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
],
|
|
71
|
+
formulaConfigs: [],
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function refsFor(monitor: Monitor): SeriesResourceRefs {
|
|
76
|
+
return MonitorStepResourceIdentity.extractResourceRefsFromMonitor({
|
|
77
|
+
monitor: monitor,
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
describe("MonitorStepResourceIdentity — the reported bug", () => {
|
|
82
|
+
test("a metric monitor filtered by oneuptime.service.name names that service", () => {
|
|
83
|
+
/*
|
|
84
|
+
* ALT-144 in the wild: a Metrics monitor whose only resource
|
|
85
|
+
* identity is an attribute filter. It is ungrouped, so the series
|
|
86
|
+
* path sees nothing; this is the only thing that can name the
|
|
87
|
+
* service.
|
|
88
|
+
*/
|
|
89
|
+
const refs: SeriesResourceRefs = refsFor(
|
|
90
|
+
monitorWithSteps(MonitorType.Metrics, [
|
|
91
|
+
{
|
|
92
|
+
metricMonitor: {
|
|
93
|
+
metricViewConfig: metricViewConfigWith({
|
|
94
|
+
"oneuptime.service.name": "app-plan-starship-online-production",
|
|
95
|
+
}),
|
|
96
|
+
},
|
|
97
|
+
},
|
|
98
|
+
]),
|
|
99
|
+
);
|
|
100
|
+
|
|
101
|
+
expect(refs.serviceNames).toEqual(["app-plan-starship-online-production"]);
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
test("every accepted service-name spelling resolves", () => {
|
|
105
|
+
for (const key of [
|
|
106
|
+
"service.name",
|
|
107
|
+
"resource.service.name",
|
|
108
|
+
"oneuptime.service.name",
|
|
109
|
+
"resource.oneuptime.service.name",
|
|
110
|
+
]) {
|
|
111
|
+
const refs: SeriesResourceRefs = refsFor(
|
|
112
|
+
monitorWithSteps(MonitorType.Metrics, [
|
|
113
|
+
{
|
|
114
|
+
metricMonitor: {
|
|
115
|
+
metricViewConfig: metricViewConfigWith({ [key]: "checkout-api" }),
|
|
116
|
+
},
|
|
117
|
+
},
|
|
118
|
+
]),
|
|
119
|
+
);
|
|
120
|
+
|
|
121
|
+
expect(refs.serviceNames).toEqual(["checkout-api"]);
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
test("a non-identifying filter attribute names nothing", () => {
|
|
126
|
+
const refs: SeriesResourceRefs = refsFor(
|
|
127
|
+
monitorWithSteps(MonitorType.Metrics, [
|
|
128
|
+
{
|
|
129
|
+
metricMonitor: {
|
|
130
|
+
metricViewConfig: metricViewConfigWith({
|
|
131
|
+
"http.response.status_code": "500",
|
|
132
|
+
}),
|
|
133
|
+
},
|
|
134
|
+
},
|
|
135
|
+
]),
|
|
136
|
+
);
|
|
137
|
+
|
|
138
|
+
expect(MonitorStepResourceIdentity.isEmpty(refs)).toBe(true);
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
test("a non-string filter (Search / Includes) names nothing", () => {
|
|
142
|
+
/*
|
|
143
|
+
* `service.name CONTAINS prod` matches a set, not one row. Treating
|
|
144
|
+
* the operator object as a name would stringify to "[object Object]"
|
|
145
|
+
* and look up a service that cannot exist.
|
|
146
|
+
*/
|
|
147
|
+
const refs: SeriesResourceRefs = refsFor(
|
|
148
|
+
monitorWithSteps(MonitorType.Metrics, [
|
|
149
|
+
{
|
|
150
|
+
metricMonitor: {
|
|
151
|
+
metricViewConfig: metricViewConfigWith({
|
|
152
|
+
"service.name": { _type: "Search", value: "prod" },
|
|
153
|
+
}),
|
|
154
|
+
},
|
|
155
|
+
},
|
|
156
|
+
]),
|
|
157
|
+
);
|
|
158
|
+
|
|
159
|
+
expect(refs.serviceNames).toEqual([]);
|
|
160
|
+
});
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
describe("MonitorStepResourceIdentity — telemetry service ids", () => {
|
|
164
|
+
test.each([
|
|
165
|
+
["logMonitor", MonitorType.Logs],
|
|
166
|
+
["traceMonitor", MonitorType.Traces],
|
|
167
|
+
["exceptionMonitor", MonitorType.Exceptions],
|
|
168
|
+
/*
|
|
169
|
+
* Profiles has no metricViewConfig and no declared identifier, so
|
|
170
|
+
* telemetryServiceIds is the ONLY identity a profile monitor has —
|
|
171
|
+
* omitting it here leaves that type with the original bug.
|
|
172
|
+
*/
|
|
173
|
+
["profileMonitor", MonitorType.Profiles],
|
|
174
|
+
["metricMonitor", MonitorType.Metrics],
|
|
175
|
+
])(
|
|
176
|
+
"%s.telemetryServiceIds names its services",
|
|
177
|
+
(stepKey: string, monitorType: MonitorType) => {
|
|
178
|
+
const refs: SeriesResourceRefs = refsFor(
|
|
179
|
+
monitorWithSteps(monitorType, [
|
|
180
|
+
{
|
|
181
|
+
[stepKey]: {
|
|
182
|
+
telemetryServiceIds: [
|
|
183
|
+
new ObjectID(SERVICE_ID_A),
|
|
184
|
+
new ObjectID(SERVICE_ID_B),
|
|
185
|
+
],
|
|
186
|
+
},
|
|
187
|
+
},
|
|
188
|
+
]),
|
|
189
|
+
);
|
|
190
|
+
|
|
191
|
+
expect(refs.serviceIds.sort()).toEqual(
|
|
192
|
+
[SERVICE_ID_A, SERVICE_ID_B].sort(),
|
|
193
|
+
);
|
|
194
|
+
},
|
|
195
|
+
);
|
|
196
|
+
|
|
197
|
+
test("a service id persisted as a bare string still resolves", () => {
|
|
198
|
+
/*
|
|
199
|
+
* Step JSON is not schema-checked, so an id can arrive as a plain
|
|
200
|
+
* string rather than a rehydrated ObjectID.
|
|
201
|
+
*/
|
|
202
|
+
const refs: SeriesResourceRefs = refsFor(
|
|
203
|
+
monitorWithSteps(MonitorType.Logs, [
|
|
204
|
+
{ logMonitor: { telemetryServiceIds: [SERVICE_ID_A] } },
|
|
205
|
+
]),
|
|
206
|
+
);
|
|
207
|
+
|
|
208
|
+
expect(refs.serviceIds).toEqual([SERVICE_ID_A]);
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
test("an empty telemetryServiceIds list names nothing", () => {
|
|
212
|
+
const refs: SeriesResourceRefs = refsFor(
|
|
213
|
+
monitorWithSteps(MonitorType.Logs, [
|
|
214
|
+
{ logMonitor: { telemetryServiceIds: [] } },
|
|
215
|
+
]),
|
|
216
|
+
);
|
|
217
|
+
|
|
218
|
+
expect(MonitorStepResourceIdentity.isEmpty(refs)).toBe(true);
|
|
219
|
+
});
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
describe("MonitorStepResourceIdentity — declared infra identifiers", () => {
|
|
223
|
+
test.each([
|
|
224
|
+
[MonitorType.Host, "hostMonitor", "hostIdentifier", "hostNames"],
|
|
225
|
+
[MonitorType.Docker, "dockerMonitor", "hostIdentifier", "dockerHostNames"],
|
|
226
|
+
[MonitorType.Podman, "podmanMonitor", "hostIdentifier", "podmanHostNames"],
|
|
227
|
+
[
|
|
228
|
+
MonitorType.Kubernetes,
|
|
229
|
+
"kubernetesMonitor",
|
|
230
|
+
"clusterIdentifier",
|
|
231
|
+
"kubernetesClusterNames",
|
|
232
|
+
],
|
|
233
|
+
[
|
|
234
|
+
MonitorType.Proxmox,
|
|
235
|
+
"proxmoxMonitor",
|
|
236
|
+
"clusterIdentifier",
|
|
237
|
+
"proxmoxClusterNames",
|
|
238
|
+
],
|
|
239
|
+
[MonitorType.Ceph, "cephMonitor", "clusterIdentifier", "cephClusterNames"],
|
|
240
|
+
[
|
|
241
|
+
MonitorType.DockerSwarm,
|
|
242
|
+
"dockerSwarmMonitor",
|
|
243
|
+
"clusterIdentifier",
|
|
244
|
+
"dockerSwarmClusterNames",
|
|
245
|
+
],
|
|
246
|
+
[MonitorType.IoTDevice, "iotMonitor", "fleetIdentifier", "iotFleetNames"],
|
|
247
|
+
])(
|
|
248
|
+
"a %s monitor names its resource via %s.%s",
|
|
249
|
+
(
|
|
250
|
+
monitorType: MonitorType,
|
|
251
|
+
stepKey: string,
|
|
252
|
+
identifierKey: string,
|
|
253
|
+
refKey: string,
|
|
254
|
+
) => {
|
|
255
|
+
const refs: SeriesResourceRefs = refsFor(
|
|
256
|
+
monitorWithSteps(monitorType, [
|
|
257
|
+
{ [stepKey]: { [identifierKey]: "prod-01" } },
|
|
258
|
+
]),
|
|
259
|
+
);
|
|
260
|
+
|
|
261
|
+
expect(refs[refKey as keyof SeriesResourceRefs]).toEqual(["prod-01"]);
|
|
262
|
+
|
|
263
|
+
/*
|
|
264
|
+
* The identifier must land in exactly one bucket. A Docker
|
|
265
|
+
* monitor that also produced `hostNames` would attach an
|
|
266
|
+
* unrelated Host row.
|
|
267
|
+
*/
|
|
268
|
+
const populated: Array<string> = Object.entries(refs)
|
|
269
|
+
.filter(([, values]: [string, Array<string>]): boolean => {
|
|
270
|
+
return values.length > 0;
|
|
271
|
+
})
|
|
272
|
+
.map(([key]: [string, Array<string>]): string => {
|
|
273
|
+
return key;
|
|
274
|
+
});
|
|
275
|
+
|
|
276
|
+
expect(populated).toEqual([refKey]);
|
|
277
|
+
},
|
|
278
|
+
);
|
|
279
|
+
|
|
280
|
+
test("a blank identifier names nothing", () => {
|
|
281
|
+
const refs: SeriesResourceRefs = refsFor(
|
|
282
|
+
monitorWithSteps(MonitorType.Host, [
|
|
283
|
+
{ hostMonitor: { hostIdentifier: " " } },
|
|
284
|
+
]),
|
|
285
|
+
);
|
|
286
|
+
|
|
287
|
+
expect(MonitorStepResourceIdentity.isEmpty(refs)).toBe(true);
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
test("an identifier is trimmed", () => {
|
|
291
|
+
const refs: SeriesResourceRefs = refsFor(
|
|
292
|
+
monitorWithSteps(MonitorType.Host, [
|
|
293
|
+
{ hostMonitor: { hostIdentifier: " prod-01 " } },
|
|
294
|
+
]),
|
|
295
|
+
);
|
|
296
|
+
|
|
297
|
+
expect(refs.hostNames).toEqual(["prod-01"]);
|
|
298
|
+
});
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
describe("MonitorStepResourceIdentity — Docker / Podman host disambiguation", () => {
|
|
302
|
+
test("a Docker monitor's resource.host.name filter does NOT name a Host", () => {
|
|
303
|
+
/*
|
|
304
|
+
* The Docker worker writes the step's hostIdentifier into
|
|
305
|
+
* `resource.host.name`, which the label key map hands to Host. That
|
|
306
|
+
* value names a DockerHost row. Honouring the map would attach an
|
|
307
|
+
* unrelated Host and surface the alert on that host's Activity tab.
|
|
308
|
+
*/
|
|
309
|
+
const refs: SeriesResourceRefs = refsFor(
|
|
310
|
+
monitorWithSteps(MonitorType.Docker, [
|
|
311
|
+
{
|
|
312
|
+
dockerMonitor: {
|
|
313
|
+
hostIdentifier: "docker-prod-01",
|
|
314
|
+
metricViewConfig: metricViewConfigWith({
|
|
315
|
+
"resource.host.name": "docker-prod-01",
|
|
316
|
+
}),
|
|
317
|
+
},
|
|
318
|
+
},
|
|
319
|
+
]),
|
|
320
|
+
);
|
|
321
|
+
|
|
322
|
+
expect(refs.hostNames).toEqual([]);
|
|
323
|
+
expect(refs.hostIds).toEqual([]);
|
|
324
|
+
expect(refs.dockerHostNames).toEqual(["docker-prod-01"]);
|
|
325
|
+
});
|
|
326
|
+
|
|
327
|
+
test("a Podman monitor's resource.host.name filter does NOT name a Host", () => {
|
|
328
|
+
const refs: SeriesResourceRefs = refsFor(
|
|
329
|
+
monitorWithSteps(MonitorType.Podman, [
|
|
330
|
+
{
|
|
331
|
+
podmanMonitor: {
|
|
332
|
+
hostIdentifier: "podman-prod-01",
|
|
333
|
+
metricViewConfig: metricViewConfigWith({
|
|
334
|
+
"resource.host.name": "podman-prod-01",
|
|
335
|
+
}),
|
|
336
|
+
},
|
|
337
|
+
},
|
|
338
|
+
]),
|
|
339
|
+
);
|
|
340
|
+
|
|
341
|
+
expect(refs.hostNames).toEqual([]);
|
|
342
|
+
expect(refs.podmanHostNames).toEqual(["podman-prod-01"]);
|
|
343
|
+
});
|
|
344
|
+
|
|
345
|
+
test("a Host monitor's resource.host.name filter DOES name a Host", () => {
|
|
346
|
+
// Same key, different monitor type — here it genuinely is a Host.
|
|
347
|
+
const refs: SeriesResourceRefs = refsFor(
|
|
348
|
+
monitorWithSteps(MonitorType.Host, [
|
|
349
|
+
{
|
|
350
|
+
hostMonitor: {
|
|
351
|
+
hostIdentifier: "prod-01",
|
|
352
|
+
metricViewConfig: metricViewConfigWith({
|
|
353
|
+
"resource.host.name": "prod-01",
|
|
354
|
+
}),
|
|
355
|
+
},
|
|
356
|
+
},
|
|
357
|
+
]),
|
|
358
|
+
);
|
|
359
|
+
|
|
360
|
+
expect(refs.hostNames).toEqual(["prod-01"]);
|
|
361
|
+
});
|
|
362
|
+
});
|
|
363
|
+
|
|
364
|
+
describe("MonitorStepResourceIdentity — monitor types with no resource identity", () => {
|
|
365
|
+
test.each([
|
|
366
|
+
MonitorType.Website,
|
|
367
|
+
MonitorType.API,
|
|
368
|
+
MonitorType.Ping,
|
|
369
|
+
MonitorType.IP,
|
|
370
|
+
MonitorType.Port,
|
|
371
|
+
MonitorType.SSLCertificate,
|
|
372
|
+
MonitorType.Domain,
|
|
373
|
+
MonitorType.DNS,
|
|
374
|
+
MonitorType.SQLQuery,
|
|
375
|
+
MonitorType.SyntheticMonitor,
|
|
376
|
+
MonitorType.CustomJavaScriptCode,
|
|
377
|
+
MonitorType.IncomingRequest,
|
|
378
|
+
MonitorType.IncomingEmail,
|
|
379
|
+
MonitorType.Server,
|
|
380
|
+
MonitorType.Manual,
|
|
381
|
+
MonitorType.NetworkDevice,
|
|
382
|
+
MonitorType.ExternalStatusPage,
|
|
383
|
+
])("%s names no resource", (monitorType: MonitorType) => {
|
|
384
|
+
const refs: SeriesResourceRefs = refsFor(
|
|
385
|
+
monitorWithSteps(monitorType, [{}]),
|
|
386
|
+
);
|
|
387
|
+
|
|
388
|
+
expect(MonitorStepResourceIdentity.isEmpty(refs)).toBe(true);
|
|
389
|
+
});
|
|
390
|
+
|
|
391
|
+
test("a monitor with no steps at all names no resource", () => {
|
|
392
|
+
const model: Monitor = new Monitor();
|
|
393
|
+
model.monitorType = MonitorType.Host;
|
|
394
|
+
|
|
395
|
+
expect(MonitorStepResourceIdentity.isEmpty(refsFor(model))).toBe(true);
|
|
396
|
+
});
|
|
397
|
+
|
|
398
|
+
test("a monitor with no monitorType names no resource", () => {
|
|
399
|
+
const model: Monitor = new Monitor();
|
|
400
|
+
|
|
401
|
+
expect(MonitorStepResourceIdentity.isEmpty(refsFor(model))).toBe(true);
|
|
402
|
+
});
|
|
403
|
+
});
|
|
404
|
+
|
|
405
|
+
describe("MonitorStepResourceIdentity — multi-query metric steps", () => {
|
|
406
|
+
test("names every service its queries filter on", () => {
|
|
407
|
+
/*
|
|
408
|
+
* A metric step can hold several queries, and the UI lets a user add
|
|
409
|
+
* them. Two queries filtering the same attribute on different
|
|
410
|
+
* services both name a real resource; collapsing them to the last
|
|
411
|
+
* one silently drops a service from Affected Resources, from its
|
|
412
|
+
* Activity tab, and from owner/label inheritance.
|
|
413
|
+
*/
|
|
414
|
+
const refs: SeriesResourceRefs = refsFor(
|
|
415
|
+
monitorWithSteps(MonitorType.Metrics, [
|
|
416
|
+
{
|
|
417
|
+
metricMonitor: {
|
|
418
|
+
metricViewConfig: {
|
|
419
|
+
queryConfigs: [
|
|
420
|
+
{
|
|
421
|
+
metricQueryData: {
|
|
422
|
+
filterData: {
|
|
423
|
+
metricName: "a",
|
|
424
|
+
attributes: { "oneuptime.service.name": "checkout-api" },
|
|
425
|
+
},
|
|
426
|
+
},
|
|
427
|
+
},
|
|
428
|
+
{
|
|
429
|
+
metricQueryData: {
|
|
430
|
+
filterData: {
|
|
431
|
+
metricName: "b",
|
|
432
|
+
attributes: { "oneuptime.service.name": "payments-api" },
|
|
433
|
+
},
|
|
434
|
+
},
|
|
435
|
+
},
|
|
436
|
+
],
|
|
437
|
+
formulaConfigs: [],
|
|
438
|
+
},
|
|
439
|
+
},
|
|
440
|
+
},
|
|
441
|
+
]),
|
|
442
|
+
);
|
|
443
|
+
|
|
444
|
+
expect(refs.serviceNames.sort()).toEqual(["checkout-api", "payments-api"]);
|
|
445
|
+
});
|
|
446
|
+
});
|
|
447
|
+
|
|
448
|
+
describe("MonitorStepResourceIdentity — malformed step configuration", () => {
|
|
449
|
+
/*
|
|
450
|
+
* Step JSON is persisted free-form and never schema-checked, so the
|
|
451
|
+
* API, a seed, an import or an older build can write shapes the types
|
|
452
|
+
* say are impossible. This module runs inside the probe and telemetry
|
|
453
|
+
* queue workers: a TypeError here would fail the whole job and retry
|
|
454
|
+
* forever, so it must degrade to "names nothing" instead of throwing.
|
|
455
|
+
*/
|
|
456
|
+
test.each([
|
|
457
|
+
["an object", {}],
|
|
458
|
+
["a number", 123],
|
|
459
|
+
["a string", "not-an-array"],
|
|
460
|
+
["null", null],
|
|
461
|
+
])(
|
|
462
|
+
"does not throw when telemetryServiceIds is %s",
|
|
463
|
+
(_label: string, value: unknown) => {
|
|
464
|
+
const monitor: Monitor = monitorWithSteps(MonitorType.Logs, [
|
|
465
|
+
{ logMonitor: { telemetryServiceIds: value } } as unknown as JSONObject,
|
|
466
|
+
]);
|
|
467
|
+
|
|
468
|
+
expect(() => {
|
|
469
|
+
return refsFor(monitor);
|
|
470
|
+
}).not.toThrow();
|
|
471
|
+
|
|
472
|
+
expect(refsFor(monitor).serviceIds).toEqual([]);
|
|
473
|
+
},
|
|
474
|
+
);
|
|
475
|
+
|
|
476
|
+
test.each([
|
|
477
|
+
["a number", 12345],
|
|
478
|
+
["an object", { name: "prod-01" }],
|
|
479
|
+
["null", null],
|
|
480
|
+
])(
|
|
481
|
+
"does not throw when a declared identifier is %s",
|
|
482
|
+
(_label: string, value: unknown) => {
|
|
483
|
+
const monitor: Monitor = monitorWithSteps(MonitorType.Host, [
|
|
484
|
+
{ hostMonitor: { hostIdentifier: value } } as unknown as JSONObject,
|
|
485
|
+
]);
|
|
486
|
+
|
|
487
|
+
expect(() => {
|
|
488
|
+
return refsFor(monitor);
|
|
489
|
+
}).not.toThrow();
|
|
490
|
+
|
|
491
|
+
expect(refsFor(monitor).hostNames).toEqual([]);
|
|
492
|
+
},
|
|
493
|
+
);
|
|
494
|
+
|
|
495
|
+
test("drops a non-scalar service id rather than stringifying it", () => {
|
|
496
|
+
/*
|
|
497
|
+
* `String({})` is "[object Object]" — a lookup key that can never
|
|
498
|
+
* match, but that would still cost a query and pollute the refs.
|
|
499
|
+
*/
|
|
500
|
+
const refs: SeriesResourceRefs = refsFor(
|
|
501
|
+
monitorWithSteps(MonitorType.Logs, [
|
|
502
|
+
{
|
|
503
|
+
logMonitor: { telemetryServiceIds: [{ nested: "object" }] },
|
|
504
|
+
} as unknown as JSONObject,
|
|
505
|
+
]),
|
|
506
|
+
);
|
|
507
|
+
|
|
508
|
+
expect(refs.serviceIds).toEqual([]);
|
|
509
|
+
});
|
|
510
|
+
|
|
511
|
+
test("does not throw when a metric view config is malformed", () => {
|
|
512
|
+
const monitor: Monitor = monitorWithSteps(MonitorType.Metrics, [
|
|
513
|
+
{
|
|
514
|
+
metricMonitor: { metricViewConfig: { queryConfigs: "nope" } },
|
|
515
|
+
} as unknown as JSONObject,
|
|
516
|
+
]);
|
|
517
|
+
|
|
518
|
+
expect(() => {
|
|
519
|
+
return refsFor(monitor);
|
|
520
|
+
}).not.toThrow();
|
|
521
|
+
});
|
|
522
|
+
});
|
|
523
|
+
|
|
524
|
+
describe("MonitorStepResourceIdentity — persisted monitors", () => {
|
|
525
|
+
/*
|
|
526
|
+
* Production never sees a hand-built MonitorSteps: it reads one that
|
|
527
|
+
* has been through toJSON on the way into Postgres and fromJSON on the
|
|
528
|
+
* way out. If an ObjectID does not survive that round trip as
|
|
529
|
+
* something String() can render, the ids become "[object Object]" and
|
|
530
|
+
* every lookup silently misses. These pin the shape that actually
|
|
531
|
+
* reaches the extractor.
|
|
532
|
+
*/
|
|
533
|
+
function roundTrip(monitorType: MonitorType, stepData: JSONObject): Monitor {
|
|
534
|
+
const built: Monitor = monitorWithSteps(monitorType, [stepData]);
|
|
535
|
+
|
|
536
|
+
const rehydrated: MonitorSteps = MonitorSteps.fromJSON(
|
|
537
|
+
JSON.parse(JSON.stringify(built.monitorSteps!.toJSON())) as JSONObject,
|
|
538
|
+
) as MonitorSteps;
|
|
539
|
+
|
|
540
|
+
const model: Monitor = new Monitor();
|
|
541
|
+
model.monitorType = monitorType;
|
|
542
|
+
model.projectId = new ObjectID("11111111-1111-4111-8111-111111111111");
|
|
543
|
+
model.monitorSteps = rehydrated;
|
|
544
|
+
return model;
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
test("telemetryServiceIds survive a persist / rehydrate round trip", () => {
|
|
548
|
+
const refs: SeriesResourceRefs = refsFor(
|
|
549
|
+
roundTrip(MonitorType.Logs, {
|
|
550
|
+
logMonitor: {
|
|
551
|
+
attributes: {},
|
|
552
|
+
body: "",
|
|
553
|
+
severityTexts: [],
|
|
554
|
+
lastXSecondsOfLogs: 60,
|
|
555
|
+
telemetryServiceIds: [new ObjectID(SERVICE_ID_A)],
|
|
556
|
+
},
|
|
557
|
+
}),
|
|
558
|
+
);
|
|
559
|
+
|
|
560
|
+
expect(refs.serviceIds).toEqual([SERVICE_ID_A]);
|
|
561
|
+
});
|
|
562
|
+
|
|
563
|
+
test("a metric filter survives a persist / rehydrate round trip", () => {
|
|
564
|
+
const refs: SeriesResourceRefs = refsFor(
|
|
565
|
+
roundTrip(MonitorType.Metrics, {
|
|
566
|
+
metricMonitor: {
|
|
567
|
+
rollingTime: "Past 1 Minute",
|
|
568
|
+
metricViewConfig: metricViewConfigWith({
|
|
569
|
+
"oneuptime.service.name": "app-plan-starship-online-production",
|
|
570
|
+
}),
|
|
571
|
+
},
|
|
572
|
+
}),
|
|
573
|
+
);
|
|
574
|
+
|
|
575
|
+
expect(refs.serviceNames).toEqual(["app-plan-starship-online-production"]);
|
|
576
|
+
});
|
|
577
|
+
|
|
578
|
+
test("a declared host identifier survives a persist / rehydrate round trip", () => {
|
|
579
|
+
const refs: SeriesResourceRefs = refsFor(
|
|
580
|
+
roundTrip(MonitorType.Host, {
|
|
581
|
+
hostMonitor: {
|
|
582
|
+
hostIdentifier: "prod-01",
|
|
583
|
+
rollingTime: "Past 1 Minute",
|
|
584
|
+
metricViewConfig: { queryConfigs: [], formulaConfigs: [] },
|
|
585
|
+
},
|
|
586
|
+
}),
|
|
587
|
+
);
|
|
588
|
+
|
|
589
|
+
expect(refs.hostNames).toEqual(["prod-01"]);
|
|
590
|
+
});
|
|
591
|
+
|
|
592
|
+
test("no id ever renders as [object Object]", () => {
|
|
593
|
+
/*
|
|
594
|
+
* The failure mode this whole describe exists to catch: a
|
|
595
|
+
* half-rehydrated ObjectID stringifies to "[object Object]" and the
|
|
596
|
+
* lookup quietly matches nothing.
|
|
597
|
+
*/
|
|
598
|
+
const refs: SeriesResourceRefs = refsFor(
|
|
599
|
+
roundTrip(MonitorType.Metrics, {
|
|
600
|
+
metricMonitor: {
|
|
601
|
+
rollingTime: "Past 1 Minute",
|
|
602
|
+
telemetryServiceIds: [new ObjectID(SERVICE_ID_A)],
|
|
603
|
+
metricViewConfig: { queryConfigs: [], formulaConfigs: [] },
|
|
604
|
+
},
|
|
605
|
+
}),
|
|
606
|
+
);
|
|
607
|
+
|
|
608
|
+
for (const values of Object.values(refs)) {
|
|
609
|
+
for (const value of values) {
|
|
610
|
+
expect(value).not.toContain("[object");
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
expect(refs.serviceIds).toEqual([SERVICE_ID_A]);
|
|
615
|
+
});
|
|
616
|
+
});
|
|
617
|
+
|
|
618
|
+
describe("MonitorStepResourceIdentity — multiple steps", () => {
|
|
619
|
+
test("names the union across steps", () => {
|
|
620
|
+
/*
|
|
621
|
+
* The creation path does not know which step fired, so a monitor
|
|
622
|
+
* watching three hosts names all three. Attributing nothing is the
|
|
623
|
+
* bug this module exists to fix.
|
|
624
|
+
*/
|
|
625
|
+
const refs: SeriesResourceRefs = refsFor(
|
|
626
|
+
monitorWithSteps(MonitorType.Host, [
|
|
627
|
+
{ hostMonitor: { hostIdentifier: "prod-01" } },
|
|
628
|
+
{ hostMonitor: { hostIdentifier: "prod-02" } },
|
|
629
|
+
]),
|
|
630
|
+
);
|
|
631
|
+
|
|
632
|
+
expect(refs.hostNames.sort()).toEqual(["prod-01", "prod-02"]);
|
|
633
|
+
});
|
|
634
|
+
|
|
635
|
+
test("dedupes a resource named by two steps", () => {
|
|
636
|
+
const refs: SeriesResourceRefs = refsFor(
|
|
637
|
+
monitorWithSteps(MonitorType.Host, [
|
|
638
|
+
{ hostMonitor: { hostIdentifier: "prod-01" } },
|
|
639
|
+
{ hostMonitor: { hostIdentifier: "prod-01" } },
|
|
640
|
+
]),
|
|
641
|
+
);
|
|
642
|
+
|
|
643
|
+
expect(refs.hostNames).toEqual(["prod-01"]);
|
|
644
|
+
});
|
|
645
|
+
|
|
646
|
+
test("dedupes a service named by both the filter and another step", () => {
|
|
647
|
+
const refs: SeriesResourceRefs = refsFor(
|
|
648
|
+
monitorWithSteps(MonitorType.Metrics, [
|
|
649
|
+
{
|
|
650
|
+
metricMonitor: {
|
|
651
|
+
metricViewConfig: metricViewConfigWith({
|
|
652
|
+
"service.name": "checkout-api",
|
|
653
|
+
}),
|
|
654
|
+
},
|
|
655
|
+
},
|
|
656
|
+
{
|
|
657
|
+
metricMonitor: {
|
|
658
|
+
metricViewConfig: metricViewConfigWith({
|
|
659
|
+
"oneuptime.service.name": "checkout-api",
|
|
660
|
+
}),
|
|
661
|
+
},
|
|
662
|
+
},
|
|
663
|
+
]),
|
|
664
|
+
);
|
|
665
|
+
|
|
666
|
+
expect(refs.serviceNames).toEqual(["checkout-api"]);
|
|
667
|
+
});
|
|
668
|
+
|
|
669
|
+
test("collects the declared identifier and the filter identity together", () => {
|
|
670
|
+
/*
|
|
671
|
+
* A Kubernetes monitor names its cluster in the step config and can
|
|
672
|
+
* additionally scope itself to a service by filter. Both are real.
|
|
673
|
+
*/
|
|
674
|
+
const refs: SeriesResourceRefs = refsFor(
|
|
675
|
+
monitorWithSteps(MonitorType.Kubernetes, [
|
|
676
|
+
{
|
|
677
|
+
kubernetesMonitor: {
|
|
678
|
+
clusterIdentifier: "prod-cluster",
|
|
679
|
+
metricViewConfig: metricViewConfigWith({
|
|
680
|
+
"service.name": "checkout-api",
|
|
681
|
+
}),
|
|
682
|
+
},
|
|
683
|
+
},
|
|
684
|
+
]),
|
|
685
|
+
);
|
|
686
|
+
|
|
687
|
+
expect(refs.kubernetesClusterNames).toEqual(["prod-cluster"]);
|
|
688
|
+
expect(refs.serviceNames).toEqual(["checkout-api"]);
|
|
689
|
+
});
|
|
690
|
+
});
|
|
@@ -5,7 +5,7 @@ import AlertService from "../../../../Server/Services/AlertService";
|
|
|
5
5
|
import IncidentService from "../../../../Server/Services/IncidentService";
|
|
6
6
|
import NetworkDeviceOwnerUserService from "../../../../Server/Services/NetworkDeviceOwnerUserService";
|
|
7
7
|
import MonitorAlert from "../../../../Server/Utils/Monitor/MonitorAlert";
|
|
8
|
-
import
|
|
8
|
+
import MonitorResourceContextUtil from "../../../../Server/Utils/Monitor/MonitorResourceContext";
|
|
9
9
|
import MonitorIncident from "../../../../Server/Utils/Monitor/MonitorIncident";
|
|
10
10
|
import ProjectScopedReferenceValidator from "../../../../Server/Utils/Database/ProjectScopedReferenceValidator";
|
|
11
11
|
import Dictionary from "../../../../Types/Dictionary";
|
|
@@ -132,8 +132,13 @@ describe("The monitor summary is stored on the incident / alert it created", ()
|
|
|
132
132
|
.mockResolvedValue(true);
|
|
133
133
|
|
|
134
134
|
jest
|
|
135
|
-
.spyOn(
|
|
135
|
+
.spyOn(MonitorResourceContextUtil, "resolveResourceContextForMonitor")
|
|
136
136
|
.mockResolvedValue({
|
|
137
|
+
hostIds: [],
|
|
138
|
+
dockerHostIds: [],
|
|
139
|
+
podmanHostIds: [],
|
|
140
|
+
kubernetesClusterIds: [],
|
|
141
|
+
serviceIds: [],
|
|
137
142
|
proxmoxClusterIds: [],
|
|
138
143
|
cephClusterIds: [],
|
|
139
144
|
dockerSwarmClusterIds: [],
|