@oneuptime/common 14.0.6 → 14.0.8
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/Incident.ts +267 -1
- package/Models/DatabaseModels/IncidentCustomField.ts +202 -0
- package/Models/DatabaseModels/IncidentEpisode.ts +30 -0
- package/Models/DatabaseModels/IncidentTemplate.ts +126 -1
- package/Models/DatabaseModels/InventoryItem.ts +23 -12
- package/Models/DatabaseModels/StatusPage.ts +55 -0
- package/Models/DatabaseModels/StatusPageSubscriber.ts +128 -0
- package/Server/API/IncidentAPI.ts +162 -0
- package/Server/API/StatusPageAPI.ts +487 -171
- package/Server/API/StatusPageSubscriberAPI.ts +63 -15
- package/Server/Infrastructure/Postgres/SchemaMigrations/1795200000000-AddInventoryItemProjectEntityKeyIndex.ts +217 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1795300000000-SkipHiddenIncidentCreatedNotifications.ts +49 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1795400000000-AddIncidentStatusPageScope.ts +108 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1795500000000-AddIncidentTemplateStatusPageScopeFlag.ts +33 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1795600000000-AddStatusPageSubscriberUnsubscribeToken.ts +51 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1795700000000-AddStatusPageSubscriberIsAddedByTeam.ts +33 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1795800000000-AddIncidentCustomFieldCreateAndNotificationSettings.ts +168 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1795900000000-AddSubscriberNotificationClaimedAt.ts +44 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +16 -0
- package/Server/Infrastructure/Semaphore.ts +10 -0
- package/Server/Middleware/IdentityRateLimit.ts +108 -3
- package/Server/Middleware/SubscriberNotificationPreviewRateLimit.ts +237 -0
- package/Server/Middleware/SubscriberNotificationTestSendRateLimit.ts +304 -0
- package/Server/Services/AlertService.ts +32 -36
- package/Server/Services/DatabaseService.ts +93 -10
- package/Server/Services/IncidentAlertService.ts +609 -2
- package/Server/Services/IncidentCustomFieldService.ts +276 -1
- package/Server/Services/IncidentEpisodePublicNoteService.ts +28 -0
- package/Server/Services/IncidentEpisodeService.ts +15 -0
- package/Server/Services/IncidentEpisodeStateTimelineService.ts +27 -1
- package/Server/Services/IncidentPublicNoteService.ts +30 -1
- package/Server/Services/IncidentService.ts +1663 -103
- package/Server/Services/IncidentStateTimelineService.ts +13 -0
- package/Server/Services/IncidentTemplateService.ts +109 -0
- package/Server/Services/InventoryItemService.ts +38 -0
- package/Server/Services/IoTDeviceCredentialService.ts +13 -4
- package/Server/Services/ScheduledMaintenancePublicNoteService.ts +30 -1
- package/Server/Services/ScheduledMaintenanceService.ts +118 -64
- package/Server/Services/SmsService.ts +10 -0
- package/Server/Services/StatusPageService.ts +65 -8
- package/Server/Services/StatusPageSubscriberNotificationTemplateService.ts +299 -37
- package/Server/Services/StatusPageSubscriberNotificationTemplateStatusPageService.ts +129 -0
- package/Server/Services/StatusPageSubscriberService.ts +1161 -64
- package/Server/Services/UserNotificationRuleService.ts +55 -53
- package/Server/Services/WorkspaceNotificationSummaryService.ts +38 -20
- package/Server/Types/Markdown.ts +153 -6
- package/Server/Types/Workflow/Components/Email.ts +61 -2
- package/Server/Utils/AffectedResources/LinkedAffectedResources.ts +576 -0
- package/Server/Utils/Alert/AlertStateChangeAuthorization.ts +129 -0
- package/Server/Utils/CustomField/CustomFieldRename.ts +378 -0
- package/Server/Utils/DataSource/EgressGuard.ts +66 -21
- package/Server/Utils/Inventory/InventoryOverviewAggregation.ts +111 -0
- package/Server/Utils/Mail/PinnedSmtpSocket.ts +130 -0
- package/Server/Utils/Monitor/MonitorCriteriaObservationBuilder.ts +10 -0
- package/Server/Utils/Response.ts +31 -0
- package/Server/Utils/SSRFProtection.ts +76 -16
- package/Server/Utils/StatusPage/IncidentStatusPageScope.ts +948 -0
- package/Server/Utils/StatusPage/IncidentSubscriberAudienceBuilder.ts +656 -0
- package/Server/Utils/StatusPage/IncidentTemplateVariableBuilder.ts +805 -0
- package/Server/Utils/StatusPage/StatusPageExclusion.ts +18 -0
- package/Server/Utils/StatusPage/StatusPageReadAccess.ts +125 -0
- package/Server/Utils/StatusPage/StatusPageSubscriberUnsubscribeNotice.ts +151 -0
- package/Server/Utils/StatusPage/StatusPageSubscriberUnsubscribeToken.ts +70 -0
- package/Server/Utils/StatusPage/SubscriberIncidentEmailBuilder.ts +421 -0
- package/Server/Utils/StatusPage/SubscriberNotificationClaim.ts +107 -0
- package/Server/Utils/StatusPage/SubscriberNotificationDeliveryRecord.ts +1049 -0
- package/Server/Utils/StatusPage/SubscriberNotificationFanOut.ts +180 -0
- package/Server/Utils/StatusPage/SubscriberNotificationPreviewBuilder.ts +839 -0
- package/Server/Utils/StatusPage/SubscriberNotificationResendAccess.ts +393 -0
- package/Server/Utils/StatusPage/SubscriberNotificationRunLimit.ts +246 -0
- package/Server/Utils/StatusPage/SubscriberNotificationTiming.ts +133 -0
- package/Server/Utils/StatusPage/SubscriberTemplateIncidentRecordAccess.ts +215 -0
- package/Server/Utils/StatusPageResource.ts +51 -20
- package/Server/Utils/Topology/TopologyConcurrencyLimiter.ts +229 -0
- package/Server/Utils/Topology/TopologyQueries.ts +1350 -0
- package/Server/Utils/Topology/TopologyRequest.ts +463 -0
- package/Server/Utils/Topology/TopologyResponseCache.ts +183 -0
- package/Server/Utils/Topology/TopologySql.ts +1024 -0
- package/Server/Utils/VM/VMAPI.ts +1 -0
- package/Server/Utils/VM/VMRunner.ts +10 -0
- package/Server/Utils/Workflow/OAuth2TokenClient.ts +10 -0
- package/Server/Views/Partials/SensitiveUrlToken.ejs +8 -5
- package/Tests/App/Accounts/RegisterVerifyEmail.test.tsx +748 -0
- package/Tests/App/Accounts/ResendVerificationEmail.test.tsx +1222 -0
- package/Tests/App/Accounts/VerificationEmailResendUtils.test.ts +797 -0
- package/Tests/App/Accounts/VerifyEmailPending.test.tsx +538 -0
- package/Tests/App/Accounts/VerifyEmailResend.test.tsx +779 -0
- package/Tests/App/Dashboard/AcknowledgeAlertsOnDeclare.test.ts +369 -0
- package/Tests/App/Dashboard/AffectedResourcesSlo.test.tsx +1 -1
- package/Tests/App/Dashboard/AffectedResourcesSummaryStep.test.tsx +510 -123
- package/Tests/App/Dashboard/AlertsTableAffectedResources.test.tsx +490 -0
- package/Tests/App/Dashboard/ChangeAlertStateDeclareIncident.test.tsx +886 -0
- package/Tests/App/Dashboard/CreateReviewStepRoleSummary.test.tsx +1250 -0
- package/Tests/App/Dashboard/CreateReviewStepSelectionSummary.test.tsx +738 -0
- package/Tests/App/Dashboard/CustomFieldsSettingsIncidentOptions.test.tsx +357 -0
- package/Tests/App/Dashboard/DeclareIncidentFromAlert.test.ts +417 -0
- package/Tests/App/Dashboard/EntityDetailPanel.test.tsx +1948 -229
- package/Tests/App/Dashboard/EntityDetailPanelLifecycle.test.tsx +493 -0
- package/Tests/App/Dashboard/EntityDetailPanelNavigation.test.tsx +439 -0
- package/Tests/App/Dashboard/EventNotes.test.tsx +776 -0
- package/Tests/App/Dashboard/EventNotesPages.test.tsx +119 -0
- package/Tests/App/Dashboard/EventNotesUtil.test.ts +116 -17
- package/Tests/App/Dashboard/EventOverviewPages.test.tsx +534 -6
- package/Tests/App/Dashboard/EventStatusPanel.test.tsx +798 -2
- package/Tests/App/Dashboard/FetchStateAndSeverityElements.test.tsx +669 -0
- package/Tests/App/Dashboard/FetchUsers.test.tsx +230 -0
- package/Tests/App/Dashboard/IncidentChangeStateNotifyDefault.test.tsx +91 -1
- package/Tests/App/Dashboard/IncidentCreateAcknowledgeAlerts.test.tsx +1611 -0
- package/Tests/App/Dashboard/IncidentCreateDetailsStep.test.tsx +643 -0
- package/Tests/App/Dashboard/IncidentCreateFromAlerts.test.tsx +8 -1
- package/Tests/App/Dashboard/IncidentCreateStatusPageScope.test.tsx +601 -0
- package/Tests/App/Dashboard/IncidentCustomFieldTemplateVariables.test.tsx +386 -0
- package/Tests/App/Dashboard/IncidentNoteTemplatePlaceholders.test.tsx +124 -0
- package/Tests/App/Dashboard/IncidentNoteTemplateVariablesLoader.test.ts +305 -0
- package/Tests/App/Dashboard/IncidentOverviewNotifyDefault.test.tsx +112 -0
- package/Tests/App/Dashboard/IncidentSettingsRenotifyOnPublish.test.tsx +674 -0
- package/Tests/App/Dashboard/IncidentSettingsStatusPageScope.test.tsx +1051 -0
- package/Tests/App/Dashboard/IncidentTemplateCustomFields.test.tsx +384 -0
- package/Tests/App/Dashboard/IncidentTemplateStatusPageScopeCard.test.tsx +215 -0
- package/Tests/App/Dashboard/InfrastructureExplorer.test.tsx +1365 -57
- package/Tests/App/Dashboard/InfrastructureGraph.test.tsx +964 -23
- package/Tests/App/Dashboard/InventoryRelationships.test.tsx +885 -0
- package/Tests/App/Dashboard/PublicNotePagesNotifyDefault.test.tsx +113 -1
- package/Tests/App/Dashboard/ServiceMapDatabaseLink.test.tsx +201 -15
- package/Tests/App/Dashboard/ServiceMapGraph.test.tsx +508 -36
- package/Tests/App/Dashboard/SubscriberAudienceSummary.test.tsx +512 -0
- package/Tests/App/Dashboard/SubscriberNotificationPreviewModal.test.tsx +837 -0
- package/Tests/App/Dashboard/SubscriberNotificationStatusLabel.test.tsx +88 -0
- package/Tests/App/Dashboard/SubscriberNotificationStatusResend.test.tsx +473 -0
- package/Tests/App/Dashboard/SubscriberTemplateLivePreview.test.tsx +196 -0
- package/Tests/App/Dashboard/TeamAddedSubscribersUnsubscribedNotice.test.tsx +248 -0
- package/Tests/App/Dashboard/TopologyDataLifecycle.test.tsx +583 -0
- package/Tests/App/Dashboard/TopologyDataLoading.test.tsx +982 -218
- package/Tests/App/Dashboard/TopologyPageNavigation.test.tsx +818 -114
- package/Tests/App/SensitiveUrlTokenBootstrap.test.ts +64 -3
- package/Tests/App/StatusPage/StatusPageUnsubscribePage.test.tsx +412 -0
- package/Tests/Models/IncidentCustomFieldApiSchemaContract.test.ts +217 -0
- package/Tests/Models/IncidentCustomFieldCreateSettingsColumns.test.ts +252 -0
- package/Tests/Models/StatusPageSubscriberUnsubscribeColumns.test.ts +218 -0
- package/Tests/Server/API/ExpiredSessionRouteGuards.test.ts +7 -0
- package/Tests/Server/API/IncidentSubscriberAudienceAPI.test.ts +1408 -0
- package/Tests/Server/API/StatusPageIncidentScope.test.ts +1868 -0
- package/Tests/Server/API/StatusPageIncidentScopePostgres.test.ts +790 -0
- package/Tests/Server/API/StatusPageManageSubscriptionRecipient.test.ts +10 -1
- package/Tests/Server/API/StatusPageManageSubscriptionTemplateVariables.test.ts +206 -18
- package/Tests/Server/API/StatusPagePostmortemVisibility.test.ts +14 -2
- package/Tests/Server/API/StatusPageSubscriberCreateResponse.test.ts +217 -0
- package/Tests/Server/API/StatusPageSubscriberOwnership.test.ts +103 -2
- package/Tests/Server/API/StatusPageUnsubscribeAPI.test.ts +396 -0
- package/Tests/Server/Infrastructure/Postgres/AddIncidentStatusPageScopeMigration.test.ts +395 -0
- package/Tests/Server/Infrastructure/Postgres/AddIncidentTemplateStatusPageScopeFlagMigration.test.ts +150 -0
- package/Tests/Server/Infrastructure/Postgres/AddSubscriberNotificationClaimedAtMigration.test.ts +156 -0
- package/Tests/Server/Infrastructure/Postgres/RenameInventoryItemMigration.test.ts +90 -21
- package/Tests/Server/Infrastructure/Postgres/SkipHiddenIncidentCreatedNotificationsMigration.test.ts +410 -0
- package/Tests/Server/Middleware/IdentityRateLimit.test.ts +551 -1
- package/Tests/Server/Middleware/SubscriberNotificationPreviewRateLimit.test.ts +238 -0
- package/Tests/Server/Middleware/SubscriberNotificationTestSendRateLimit.test.ts +245 -0
- package/Tests/Server/Services/AddStatusPageSubscriberUnsubscribeTokenMigration.test.ts +152 -0
- package/Tests/Server/Services/CrossProjectRelationWriteGuard.test.ts +221 -36
- package/Tests/Server/Services/DatabaseServiceCompareAndSetColumns.test.ts +191 -0
- package/Tests/Server/Services/DomainService.test.ts +525 -0
- package/Tests/Server/Services/IncidentAlertAcknowledgeOnDeclare.test.ts +2630 -0
- package/Tests/Server/Services/IncidentAlertPostgres.test.ts +1625 -1
- package/Tests/Server/Services/IncidentCreatedRenotifyOnPublish.test.ts +681 -0
- package/Tests/Server/Services/IncidentCreatedResend.test.ts +775 -0
- package/Tests/Server/Services/IncidentCustomFieldRenamePostgres.test.ts +713 -0
- package/Tests/Server/Services/IncidentCustomFieldService.test.ts +751 -0
- package/Tests/Server/Services/IncidentCustomFieldValueValidation.test.ts +556 -0
- package/Tests/Server/Services/IncidentDeclareAcknowledgeAlerts.test.ts +2189 -0
- package/Tests/Server/Services/IncidentStatusPageScope.test.ts +2971 -0
- package/Tests/Server/Services/IncidentStatusPageScopeFeed.test.ts +131 -0
- package/Tests/Server/Services/IncidentStatusPageScopePostgres.test.ts +625 -0
- package/Tests/Server/Services/IncidentTemplateCustomFieldsCopy.test.ts +311 -0
- package/Tests/Server/Services/IncidentTemplateStatusPageScope.test.ts +363 -0
- package/Tests/Server/Services/InventoryItemServiceOverviewCounts.test.ts +345 -0
- package/Tests/Server/Services/InventoryOverviewPostgres.test.ts +254 -0
- package/Tests/Server/Services/IoTDeviceCredentialService.test.ts +819 -0
- package/Tests/Server/Services/LinkedAffectedResourcesCreatedFeed.test.ts +420 -0
- package/Tests/Server/Services/PublicNoteEditFeedEventType.test.ts +213 -0
- package/Tests/Server/Services/PublicNoteResendAccess.test.ts +994 -0
- package/Tests/Server/Services/ScheduledMaintenanceSubscriberTemplateFormats.test.ts +289 -9
- package/Tests/Server/Services/SloAffectedResourceCreatedFeed.test.ts +92 -36
- package/Tests/Server/Services/SmsServiceFailIfNotSent.test.ts +67 -0
- package/Tests/Server/Services/StatusPageReportIncidentCounts.test.ts +610 -0
- package/Tests/Server/Services/StatusPageSubscriberAudienceCounts.test.ts +201 -0
- package/Tests/Server/Services/StatusPageSubscriberAudienceCountsPostgres.test.ts +271 -0
- package/Tests/Server/Services/StatusPageSubscriberConfirmationTemplateEscaping.test.ts +200 -0
- package/Tests/Server/Services/StatusPageSubscriberNotificationLogRedaction.test.ts +54 -0
- package/Tests/Server/Services/StatusPageSubscriberNotificationTemplateCompile.test.ts +37 -0
- package/Tests/Server/Services/StatusPageSubscriberNotificationTemplateIncidentRecordAccess.test.ts +772 -0
- package/Tests/Server/Services/StatusPageSubscriberNotificationTemplateLookup.test.ts +506 -0
- package/Tests/Server/Services/StatusPageSubscriberNotificationTemplateLookupPostgres.test.ts +261 -0
- package/Tests/Server/Services/StatusPageSubscriberReport.test.ts +21 -5
- package/Tests/Server/Services/StatusPageSubscriberUnsubscribe.test.ts +1618 -0
- package/Tests/Server/Services/StatusPageSubscriberUnsubscribeLinkSenders.test.ts +373 -0
- package/Tests/Server/Services/StatusPageSubscriberUnsubscribePostgres.test.ts +388 -0
- package/Tests/Server/Services/SubscriberNotificationInFlightRequeue.test.ts +500 -0
- package/Tests/Server/Types/MarkdownEmailLinks.test.ts +320 -0
- package/Tests/Server/Types/Workflow/Components/Email.test.ts +491 -1
- package/Tests/Server/Types/Workflow/Components/EmailSmtpPinning.test.ts +398 -0
- package/Tests/Server/Utils/AffectedResources/LinkedAffectedResources.test.ts +858 -0
- package/Tests/Server/Utils/Alert/AlertStateChangeAuthorization.test.ts +1172 -0
- package/Tests/Server/Utils/CustomField/CustomFieldRename.test.ts +586 -0
- package/Tests/Server/Utils/DataSource/EgressGuard.test.ts +246 -10
- package/Tests/Server/Utils/DataSource/EgressGuardDeploymentConfig.test.ts +226 -0
- package/Tests/Server/Utils/DataSource/EgressGuardPinning.test.ts +131 -0
- package/Tests/Server/Utils/DataSource/HttpFetch.test.ts +4 -0
- package/Tests/Server/Utils/EgressPolicyEnvironment.ts +45 -0
- package/Tests/Server/Utils/Mail/PinnedSmtpSocket.test.ts +409 -0
- package/Tests/Server/Utils/Monitor/MonitorCriteriaObservationBuilderUnits.test.ts +23 -0
- package/Tests/Server/Utils/SSRFProtection.test.ts +4 -0
- package/Tests/Server/Utils/SSRFProtectionCloudServiceAddresses.test.ts +4 -0
- package/Tests/Server/Utils/SSRFProtectionPrivateNetwork.test.ts +4 -0
- package/Tests/Server/Utils/SSRFProtectionResolutionDetail.test.ts +314 -0
- package/Tests/Server/Utils/StatusPage/IncidentStatusPageScope.test.ts +1699 -0
- package/Tests/Server/Utils/StatusPage/IncidentStatusPageScopeQueriesPostgres.test.ts +508 -0
- package/Tests/Server/Utils/StatusPage/IncidentSubscriberAudienceCallerPermission.test.ts +246 -0
- package/Tests/Server/Utils/StatusPage/IncidentTemplateVariableBuilder.test.ts +1348 -0
- package/Tests/Server/Utils/StatusPage/StatusPageReadAccess.test.ts +221 -0
- package/Tests/Server/Utils/StatusPage/StatusPageSubscriberUnsubscribeNotice.test.ts +132 -0
- package/Tests/Server/Utils/StatusPage/StatusPageSubscriberUnsubscribeToken.test.ts +155 -0
- package/Tests/Server/Utils/StatusPage/SubscriberIncidentEmailBuilder.test.ts +708 -0
- package/Tests/Server/Utils/StatusPage/SubscriberNotificationClaim.test.ts +255 -0
- package/Tests/Server/Utils/StatusPage/SubscriberNotificationClaimPostgres.test.ts +528 -0
- package/Tests/Server/Utils/StatusPage/SubscriberNotificationDeliveryRecord.test.ts +1238 -0
- package/Tests/Server/Utils/StatusPage/SubscriberNotificationFanOut.test.ts +472 -0
- package/Tests/Server/Utils/StatusPage/SubscriberNotificationPreviewBuilder.test.ts +1168 -0
- package/Tests/Server/Utils/StatusPage/SubscriberNotificationRunLimit.test.ts +275 -0
- package/Tests/Server/Utils/StatusPage/SubscriberNotificationTiming.test.ts +131 -0
- package/Tests/Server/Utils/StatusPageResource.test.ts +98 -0
- package/Tests/Server/Utils/Topology/InventoryItemEntityKeyIndexMigration.test.ts +386 -0
- package/Tests/Server/Utils/Topology/InventoryItemEntityKeyIndexMigrationPostgres.test.ts +430 -0
- package/Tests/Server/Utils/Topology/TopologyActivityParityPostgres.test.ts +279 -0
- package/Tests/Server/Utils/Topology/TopologyConcurrencyLimiter.test.ts +534 -0
- package/Tests/Server/Utils/Topology/TopologyEstateGenerator.ts +624 -0
- package/Tests/Server/Utils/Topology/TopologyJsonResponse.test.ts +90 -0
- package/Tests/Server/Utils/Topology/TopologyQueries.test.ts +1634 -0
- package/Tests/Server/Utils/Topology/TopologyQueriesDifferentialPostgres.test.ts +683 -0
- package/Tests/Server/Utils/Topology/TopologyQueriesPostgres.test.ts +2624 -0
- package/Tests/Server/Utils/Topology/TopologyReference.ts +1018 -0
- package/Tests/Server/Utils/Topology/TopologyRequest.test.ts +643 -0
- package/Tests/Server/Utils/Topology/TopologyResponseCache.test.ts +305 -0
- package/Tests/Server/Utils/Topology/TopologySql.test.ts +973 -0
- package/Tests/Server/Utils/VM/VMRunnerPrivateNetworkWiring.test.ts +17 -0
- package/Tests/Server/Utils/VM/VMRunnerSsrf.test.ts +75 -0
- package/Tests/Types/CustomField/CustomFieldSavedViews.test.ts +247 -0
- package/Tests/Types/CustomField/CustomFieldTemplateValues.test.ts +186 -0
- package/Tests/Types/CustomField/CustomFieldTypeCorrespondence.test.ts +48 -0
- package/Tests/Types/CustomField/CustomFieldValueFormat.test.ts +215 -0
- package/Tests/Types/CustomField/CustomFieldValueValidator.test.ts +343 -0
- package/Tests/Types/CustomField/CustomFieldVariableKey.test.ts +364 -0
- package/Tests/Types/SafeHtml.test.ts +102 -0
- package/Tests/Types/StatusPage/IncidentCreatedRenotify.test.ts +419 -0
- package/Tests/Types/StatusPage/IncidentCreatedResend.test.ts +118 -0
- package/Tests/Types/StatusPage/IncidentScopeAddedPagesNotification.test.ts +558 -0
- package/Tests/Types/StatusPage/IncidentSubscriberAudience.test.ts +284 -0
- package/Tests/Types/StatusPage/StatusPageSubscriberUnsubscribe.test.ts +341 -0
- package/Tests/Types/StatusPage/SubscriberNotificationPreview.test.ts +196 -0
- package/Tests/Types/StatusPage/SubscriberNotificationResend.test.ts +201 -0
- package/Tests/Types/StatusPage/SubscriberNotificationTemplateCompiler.test.ts +277 -0
- package/Tests/Types/StatusPage/SubscriberNotificationTemplatePreview.test.ts +179 -0
- package/Tests/Types/StatusPage/SubscriberNotificationTemplateVariables.test.ts +324 -0
- package/Tests/Types/StatusPage/SubscriberUpdateNotification.test.ts +60 -13
- package/Tests/Types/Topology/TopologyTypeRules.test.ts +176 -0
- package/Tests/UI/Components/CustomFields/CustomFieldFormFields.test.ts +432 -0
- package/Tests/UI/Components/CustomFields/CustomFieldModelFormFields.test.tsx +685 -0
- package/Tests/UI/Components/CustomFields/CustomFieldsDetailOrder.test.tsx +469 -0
- package/Tests/UI/Components/Forms/ModelFormCustomFieldInputs.test.tsx +325 -0
- package/Tests/UI/Components/Forms/ModelFormDropdownOptionsRefused.test.tsx +358 -0
- package/Tests/UI/Components/ModelTable/CustomFieldColumns.test.tsx +22 -0
- package/Tests/UI/Monitor/NetworkPathView.test.tsx +289 -0
- package/Tests/Utils/Incident/IncidentFromAlerts.test.ts +302 -0
- package/Tests/Utils/Incident/IncidentNoteTemplateVariables.test.ts +623 -0
- package/Tests/Utils/Markdown/MarkdownEscape.test.ts +89 -0
- package/Tests/Utils/ProbeNetworkFailureUtil.test.ts +992 -0
- package/Tests/Utils/RequestFailedDetails.test.ts +575 -0
- package/Types/CustomField/CustomFieldOrder.ts +55 -0
- package/Types/CustomField/CustomFieldSavedViews.ts +225 -0
- package/Types/CustomField/CustomFieldTemplateMerge.ts +71 -0
- package/Types/CustomField/CustomFieldType.ts +14 -0
- package/Types/CustomField/CustomFieldValueFormat.ts +161 -0
- package/Types/CustomField/CustomFieldValueValidator.ts +488 -0
- package/Types/CustomField/CustomFieldVariableKey.ts +211 -0
- package/Types/Incident/IncidentAlertLink.ts +19 -0
- package/Types/SafeHtml.ts +93 -0
- package/Types/StatusPage/IncidentCreatedRenotify.ts +224 -0
- package/Types/StatusPage/IncidentCreatedResend.ts +108 -0
- package/Types/StatusPage/IncidentScopeAddedPagesNotification.ts +343 -0
- package/Types/StatusPage/IncidentSubscriberAudience.ts +332 -0
- package/Types/StatusPage/StatusPageSubscriberUnsubscribe.ts +405 -0
- package/Types/StatusPage/SubscriberNotificationInterruption.ts +32 -0
- package/Types/StatusPage/SubscriberNotificationPreview.ts +322 -0
- package/Types/StatusPage/SubscriberNotificationResend.ts +132 -0
- package/Types/StatusPage/SubscriberNotificationTemplateCompiler.ts +180 -0
- package/Types/StatusPage/SubscriberNotificationTemplatePreview.ts +301 -0
- package/Types/StatusPage/SubscriberNotificationTemplateVariables.ts +217 -4
- package/Types/StatusPage/SubscriberUpdateNotification.ts +32 -11
- package/Types/Telemetry/InventoryLiveness.ts +26 -0
- package/Types/Topology/TopologyApi.ts +428 -0
- package/Types/Topology/TopologyTypeRules.ts +191 -0
- package/UI/Components/CustomFields/CustomFieldFormFields.ts +317 -0
- package/UI/Components/CustomFields/CustomFieldModelFormFields.tsx +395 -0
- package/UI/Components/CustomFields/CustomFieldsDetail.tsx +95 -55
- package/UI/Components/Forms/ModelForm.tsx +70 -8
- package/UI/Components/Forms/Validation.ts +1 -1
- package/UI/Components/ModelFormModal/ModelFormModal.tsx +2 -4
- package/UI/Components/ModelTable/AnalyticsModelTable.tsx +2 -6
- package/UI/Components/ModelTable/BaseModelTable.tsx +9 -8
- package/UI/Components/ModelTable/CustomFieldColumns.tsx +14 -1
- package/UI/Components/ModelTable/ModelTable.tsx +6 -7
- package/UI/Utils/SensitiveUrlToken.ts +10 -5
- package/Utils/API.ts +247 -2
- package/Utils/Incident/IncidentFromAlerts.ts +78 -0
- package/Utils/Incident/IncidentNoteTemplateVariables.ts +304 -0
- package/Utils/Markdown/MarkdownEscape.ts +65 -0
- package/Utils/ProbeNetworkFailureUtil.ts +673 -0
- package/build/dist/Models/DatabaseModels/Incident.js +267 -1
- package/build/dist/Models/DatabaseModels/Incident.js.map +1 -1
- package/build/dist/Models/DatabaseModels/IncidentCustomField.js +207 -1
- package/build/dist/Models/DatabaseModels/IncidentCustomField.js.map +1 -1
- package/build/dist/Models/DatabaseModels/IncidentEpisode.js +31 -0
- package/build/dist/Models/DatabaseModels/IncidentEpisode.js.map +1 -1
- package/build/dist/Models/DatabaseModels/IncidentTemplate.js +124 -1
- package/build/dist/Models/DatabaseModels/IncidentTemplate.js.map +1 -1
- package/build/dist/Models/DatabaseModels/InventoryItem.js +20 -11
- package/build/dist/Models/DatabaseModels/InventoryItem.js.map +1 -1
- package/build/dist/Models/DatabaseModels/StatusPage.js +56 -0
- package/build/dist/Models/DatabaseModels/StatusPage.js.map +1 -1
- package/build/dist/Models/DatabaseModels/StatusPageSubscriber.js +131 -0
- package/build/dist/Models/DatabaseModels/StatusPageSubscriber.js.map +1 -1
- package/build/dist/Server/API/IncidentAPI.js +100 -1
- package/build/dist/Server/API/IncidentAPI.js.map +1 -1
- package/build/dist/Server/API/StatusPageAPI.js +417 -176
- package/build/dist/Server/API/StatusPageAPI.js.map +1 -1
- package/build/dist/Server/API/StatusPageSubscriberAPI.js +52 -13
- package/build/dist/Server/API/StatusPageSubscriberAPI.js.map +1 -1
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795200000000-AddInventoryItemProjectEntityKeyIndex.js +165 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795200000000-AddInventoryItemProjectEntityKeyIndex.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795300000000-SkipHiddenIncidentCreatedNotifications.js +41 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795300000000-SkipHiddenIncidentCreatedNotifications.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795400000000-AddIncidentStatusPageScope.js +57 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795400000000-AddIncidentStatusPageScope.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795500000000-AddIncidentTemplateStatusPageScopeFlag.js +23 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795500000000-AddIncidentTemplateStatusPageScopeFlag.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795600000000-AddStatusPageSubscriberUnsubscribeToken.js +40 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795600000000-AddStatusPageSubscriberUnsubscribeToken.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795700000000-AddStatusPageSubscriberIsAddedByTeam.js +26 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795700000000-AddStatusPageSubscriberIsAddedByTeam.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795800000000-AddIncidentCustomFieldCreateAndNotificationSettings.js +89 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795800000000-AddIncidentCustomFieldCreateAndNotificationSettings.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795900000000-AddSubscriberNotificationClaimedAt.js +29 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795900000000-AddSubscriberNotificationClaimedAt.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +16 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
- package/build/dist/Server/Infrastructure/Semaphore.js +3 -0
- package/build/dist/Server/Infrastructure/Semaphore.js.map +1 -1
- package/build/dist/Server/Middleware/IdentityRateLimit.js +89 -3
- package/build/dist/Server/Middleware/IdentityRateLimit.js.map +1 -1
- package/build/dist/Server/Middleware/SubscriberNotificationPreviewRateLimit.js +149 -0
- package/build/dist/Server/Middleware/SubscriberNotificationPreviewRateLimit.js.map +1 -0
- package/build/dist/Server/Middleware/SubscriberNotificationTestSendRateLimit.js +190 -0
- package/build/dist/Server/Middleware/SubscriberNotificationTestSendRateLimit.js.map +1 -0
- package/build/dist/Server/Services/AlertService.js +21 -33
- package/build/dist/Server/Services/AlertService.js.map +1 -1
- package/build/dist/Server/Services/DatabaseService.js +56 -7
- package/build/dist/Server/Services/DatabaseService.js.map +1 -1
- package/build/dist/Server/Services/IncidentAlertService.js +457 -3
- package/build/dist/Server/Services/IncidentAlertService.js.map +1 -1
- package/build/dist/Server/Services/IncidentCustomFieldService.js +204 -8
- package/build/dist/Server/Services/IncidentCustomFieldService.js.map +1 -1
- package/build/dist/Server/Services/IncidentEpisodePublicNoteService.js +24 -0
- package/build/dist/Server/Services/IncidentEpisodePublicNoteService.js.map +1 -1
- package/build/dist/Server/Services/IncidentEpisodeService.js +14 -0
- package/build/dist/Server/Services/IncidentEpisodeService.js.map +1 -1
- package/build/dist/Server/Services/IncidentEpisodeStateTimelineService.js +26 -0
- package/build/dist/Server/Services/IncidentEpisodeStateTimelineService.js.map +1 -1
- package/build/dist/Server/Services/IncidentPublicNoteService.js +26 -1
- package/build/dist/Server/Services/IncidentPublicNoteService.js.map +1 -1
- package/build/dist/Server/Services/IncidentService.js +1148 -42
- package/build/dist/Server/Services/IncidentService.js.map +1 -1
- package/build/dist/Server/Services/IncidentStateTimelineService.js +12 -0
- package/build/dist/Server/Services/IncidentStateTimelineService.js.map +1 -1
- package/build/dist/Server/Services/IncidentTemplateService.js +83 -0
- package/build/dist/Server/Services/IncidentTemplateService.js.map +1 -1
- package/build/dist/Server/Services/InventoryItemService.js +31 -0
- package/build/dist/Server/Services/InventoryItemService.js.map +1 -1
- package/build/dist/Server/Services/IoTDeviceCredentialService.js +12 -5
- package/build/dist/Server/Services/IoTDeviceCredentialService.js.map +1 -1
- package/build/dist/Server/Services/ScheduledMaintenancePublicNoteService.js +26 -1
- package/build/dist/Server/Services/ScheduledMaintenancePublicNoteService.js.map +1 -1
- package/build/dist/Server/Services/ScheduledMaintenanceService.js +84 -57
- package/build/dist/Server/Services/ScheduledMaintenanceService.js.map +1 -1
- package/build/dist/Server/Services/SmsService.js +2 -22
- package/build/dist/Server/Services/SmsService.js.map +1 -1
- package/build/dist/Server/Services/StatusPageService.js +47 -9
- package/build/dist/Server/Services/StatusPageService.js.map +1 -1
- package/build/dist/Server/Services/StatusPageSubscriberNotificationTemplateService.js +237 -32
- package/build/dist/Server/Services/StatusPageSubscriberNotificationTemplateService.js.map +1 -1
- package/build/dist/Server/Services/StatusPageSubscriberNotificationTemplateStatusPageService.js +109 -0
- package/build/dist/Server/Services/StatusPageSubscriberNotificationTemplateStatusPageService.js.map +1 -1
- package/build/dist/Server/Services/StatusPageSubscriberService.js +925 -99
- package/build/dist/Server/Services/StatusPageSubscriberService.js.map +1 -1
- package/build/dist/Server/Services/UserNotificationRuleService.js +55 -51
- package/build/dist/Server/Services/UserNotificationRuleService.js.map +1 -1
- package/build/dist/Server/Services/WorkspaceNotificationSummaryService.js +42 -25
- package/build/dist/Server/Services/WorkspaceNotificationSummaryService.js.map +1 -1
- package/build/dist/Server/Types/Markdown.js +110 -6
- package/build/dist/Server/Types/Markdown.js.map +1 -1
- package/build/dist/Server/Types/Workflow/Components/Email.js +55 -6
- package/build/dist/Server/Types/Workflow/Components/Email.js.map +1 -1
- package/build/dist/Server/Utils/AffectedResources/LinkedAffectedResources.js +405 -0
- package/build/dist/Server/Utils/AffectedResources/LinkedAffectedResources.js.map +1 -0
- package/build/dist/Server/Utils/Alert/AlertStateChangeAuthorization.js +112 -0
- package/build/dist/Server/Utils/Alert/AlertStateChangeAuthorization.js.map +1 -0
- package/build/dist/Server/Utils/CustomField/CustomFieldRename.js +211 -0
- package/build/dist/Server/Utils/CustomField/CustomFieldRename.js.map +1 -0
- package/build/dist/Server/Utils/DataSource/EgressGuard.js +41 -12
- package/build/dist/Server/Utils/DataSource/EgressGuard.js.map +1 -1
- package/build/dist/Server/Utils/Inventory/InventoryOverviewAggregation.js +81 -0
- package/build/dist/Server/Utils/Inventory/InventoryOverviewAggregation.js.map +1 -0
- package/build/dist/Server/Utils/Mail/PinnedSmtpSocket.js +101 -0
- package/build/dist/Server/Utils/Mail/PinnedSmtpSocket.js.map +1 -0
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaObservationBuilder.js +9 -0
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaObservationBuilder.js.map +1 -1
- package/build/dist/Server/Utils/Response.js +30 -0
- package/build/dist/Server/Utils/Response.js.map +1 -1
- package/build/dist/Server/Utils/SSRFProtection.js +48 -6
- package/build/dist/Server/Utils/SSRFProtection.js.map +1 -1
- package/build/dist/Server/Utils/StatusPage/IncidentStatusPageScope.js +631 -0
- package/build/dist/Server/Utils/StatusPage/IncidentStatusPageScope.js.map +1 -0
- package/build/dist/Server/Utils/StatusPage/IncidentSubscriberAudienceBuilder.js +403 -0
- package/build/dist/Server/Utils/StatusPage/IncidentSubscriberAudienceBuilder.js.map +1 -0
- package/build/dist/Server/Utils/StatusPage/IncidentTemplateVariableBuilder.js +451 -0
- package/build/dist/Server/Utils/StatusPage/IncidentTemplateVariableBuilder.js.map +1 -0
- package/build/dist/Server/Utils/StatusPage/StatusPageExclusion.js +13 -0
- package/build/dist/Server/Utils/StatusPage/StatusPageExclusion.js.map +1 -0
- package/build/dist/Server/Utils/StatusPage/StatusPageReadAccess.js +91 -0
- package/build/dist/Server/Utils/StatusPage/StatusPageReadAccess.js.map +1 -0
- package/build/dist/Server/Utils/StatusPage/StatusPageSubscriberUnsubscribeNotice.js +101 -0
- package/build/dist/Server/Utils/StatusPage/StatusPageSubscriberUnsubscribeNotice.js.map +1 -0
- package/build/dist/Server/Utils/StatusPage/StatusPageSubscriberUnsubscribeToken.js +47 -0
- package/build/dist/Server/Utils/StatusPage/StatusPageSubscriberUnsubscribeToken.js.map +1 -0
- package/build/dist/Server/Utils/StatusPage/SubscriberIncidentEmailBuilder.js +273 -0
- package/build/dist/Server/Utils/StatusPage/SubscriberIncidentEmailBuilder.js.map +1 -0
- package/build/dist/Server/Utils/StatusPage/SubscriberNotificationClaim.js +73 -0
- package/build/dist/Server/Utils/StatusPage/SubscriberNotificationClaim.js.map +1 -0
- package/build/dist/Server/Utils/StatusPage/SubscriberNotificationDeliveryRecord.js +722 -0
- package/build/dist/Server/Utils/StatusPage/SubscriberNotificationDeliveryRecord.js.map +1 -0
- package/build/dist/Server/Utils/StatusPage/SubscriberNotificationFanOut.js +102 -0
- package/build/dist/Server/Utils/StatusPage/SubscriberNotificationFanOut.js.map +1 -0
- package/build/dist/Server/Utils/StatusPage/SubscriberNotificationPreviewBuilder.js +527 -0
- package/build/dist/Server/Utils/StatusPage/SubscriberNotificationPreviewBuilder.js.map +1 -0
- package/build/dist/Server/Utils/StatusPage/SubscriberNotificationResendAccess.js +278 -0
- package/build/dist/Server/Utils/StatusPage/SubscriberNotificationResendAccess.js.map +1 -0
- package/build/dist/Server/Utils/StatusPage/SubscriberNotificationRunLimit.js +137 -0
- package/build/dist/Server/Utils/StatusPage/SubscriberNotificationRunLimit.js.map +1 -0
- package/build/dist/Server/Utils/StatusPage/SubscriberNotificationTiming.js +103 -0
- package/build/dist/Server/Utils/StatusPage/SubscriberNotificationTiming.js.map +1 -0
- package/build/dist/Server/Utils/StatusPage/SubscriberTemplateIncidentRecordAccess.js +114 -0
- package/build/dist/Server/Utils/StatusPage/SubscriberTemplateIncidentRecordAccess.js.map +1 -0
- package/build/dist/Server/Utils/StatusPageResource.js +39 -7
- package/build/dist/Server/Utils/StatusPageResource.js.map +1 -1
- package/build/dist/Server/Utils/Topology/TopologyConcurrencyLimiter.js +178 -0
- package/build/dist/Server/Utils/Topology/TopologyConcurrencyLimiter.js.map +1 -0
- package/build/dist/Server/Utils/Topology/TopologyQueries.js +884 -0
- package/build/dist/Server/Utils/Topology/TopologyQueries.js.map +1 -0
- package/build/dist/Server/Utils/Topology/TopologyRequest.js +275 -0
- package/build/dist/Server/Utils/Topology/TopologyRequest.js.map +1 -0
- package/build/dist/Server/Utils/Topology/TopologyResponseCache.js +146 -0
- package/build/dist/Server/Utils/Topology/TopologyResponseCache.js.map +1 -0
- package/build/dist/Server/Utils/Topology/TopologySql.js +688 -0
- package/build/dist/Server/Utils/Topology/TopologySql.js.map +1 -0
- package/build/dist/Server/Utils/VM/VMAPI.js.map +1 -1
- package/build/dist/Server/Utils/VM/VMRunner.js +1 -0
- package/build/dist/Server/Utils/VM/VMRunner.js.map +1 -1
- package/build/dist/Server/Utils/Workflow/OAuth2TokenClient.js +3 -0
- package/build/dist/Server/Utils/Workflow/OAuth2TokenClient.js.map +1 -1
- package/build/dist/Types/CustomField/CustomFieldOrder.js +36 -0
- package/build/dist/Types/CustomField/CustomFieldOrder.js.map +1 -0
- package/build/dist/Types/CustomField/CustomFieldSavedViews.js +135 -0
- package/build/dist/Types/CustomField/CustomFieldSavedViews.js.map +1 -0
- package/build/dist/Types/CustomField/CustomFieldTemplateMerge.js +27 -0
- package/build/dist/Types/CustomField/CustomFieldTemplateMerge.js.map +1 -0
- package/build/dist/Types/CustomField/CustomFieldType.js +12 -0
- package/build/dist/Types/CustomField/CustomFieldType.js.map +1 -1
- package/build/dist/Types/CustomField/CustomFieldValueFormat.js +126 -0
- package/build/dist/Types/CustomField/CustomFieldValueFormat.js.map +1 -0
- package/build/dist/Types/CustomField/CustomFieldValueValidator.js +280 -0
- package/build/dist/Types/CustomField/CustomFieldValueValidator.js.map +1 -0
- package/build/dist/Types/CustomField/CustomFieldVariableKey.js +150 -0
- package/build/dist/Types/CustomField/CustomFieldVariableKey.js.map +1 -0
- package/build/dist/Types/Incident/IncidentAlertLink.js +17 -0
- package/build/dist/Types/Incident/IncidentAlertLink.js.map +1 -1
- package/build/dist/Types/SafeHtml.js +84 -0
- package/build/dist/Types/SafeHtml.js.map +1 -0
- package/build/dist/Types/StatusPage/IncidentCreatedRenotify.js +117 -0
- package/build/dist/Types/StatusPage/IncidentCreatedRenotify.js.map +1 -0
- package/build/dist/Types/StatusPage/IncidentCreatedResend.js +86 -0
- package/build/dist/Types/StatusPage/IncidentCreatedResend.js.map +1 -0
- package/build/dist/Types/StatusPage/IncidentScopeAddedPagesNotification.js +246 -0
- package/build/dist/Types/StatusPage/IncidentScopeAddedPagesNotification.js.map +1 -0
- package/build/dist/Types/StatusPage/IncidentSubscriberAudience.js +183 -0
- package/build/dist/Types/StatusPage/IncidentSubscriberAudience.js.map +1 -0
- package/build/dist/Types/StatusPage/StatusPageSubscriberUnsubscribe.js +277 -0
- package/build/dist/Types/StatusPage/StatusPageSubscriberUnsubscribe.js.map +1 -0
- package/build/dist/Types/StatusPage/SubscriberNotificationInterruption.js +27 -0
- package/build/dist/Types/StatusPage/SubscriberNotificationInterruption.js.map +1 -0
- package/build/dist/Types/StatusPage/SubscriberNotificationPreview.js +190 -0
- package/build/dist/Types/StatusPage/SubscriberNotificationPreview.js.map +1 -0
- package/build/dist/Types/StatusPage/SubscriberNotificationResend.js +102 -0
- package/build/dist/Types/StatusPage/SubscriberNotificationResend.js.map +1 -0
- package/build/dist/Types/StatusPage/SubscriberNotificationTemplateCompiler.js +97 -0
- package/build/dist/Types/StatusPage/SubscriberNotificationTemplateCompiler.js.map +1 -0
- package/build/dist/Types/StatusPage/SubscriberNotificationTemplatePreview.js +175 -0
- package/build/dist/Types/StatusPage/SubscriberNotificationTemplatePreview.js.map +1 -0
- package/build/dist/Types/StatusPage/SubscriberNotificationTemplateVariables.js +144 -4
- package/build/dist/Types/StatusPage/SubscriberNotificationTemplateVariables.js.map +1 -1
- package/build/dist/Types/StatusPage/SubscriberUpdateNotification.js +29 -9
- package/build/dist/Types/StatusPage/SubscriberUpdateNotification.js.map +1 -1
- package/build/dist/Types/Telemetry/InventoryLiveness.js +23 -0
- package/build/dist/Types/Telemetry/InventoryLiveness.js.map +1 -1
- package/build/dist/Types/Topology/TopologyApi.js +55 -0
- package/build/dist/Types/Topology/TopologyApi.js.map +1 -0
- package/build/dist/Types/Topology/TopologyTypeRules.js +165 -0
- package/build/dist/Types/Topology/TopologyTypeRules.js.map +1 -0
- package/build/dist/UI/Components/CustomFields/CustomFieldFormFields.js +169 -0
- package/build/dist/UI/Components/CustomFields/CustomFieldFormFields.js.map +1 -0
- package/build/dist/UI/Components/CustomFields/CustomFieldModelFormFields.js +212 -0
- package/build/dist/UI/Components/CustomFields/CustomFieldModelFormFields.js.map +1 -0
- package/build/dist/UI/Components/CustomFields/CustomFieldsDetail.js +64 -49
- package/build/dist/UI/Components/CustomFields/CustomFieldsDetail.js.map +1 -1
- package/build/dist/UI/Components/Forms/ModelForm.js +39 -5
- package/build/dist/UI/Components/Forms/ModelForm.js.map +1 -1
- package/build/dist/UI/Components/Forms/Validation.js +1 -1
- package/build/dist/UI/Components/Forms/Validation.js.map +1 -1
- package/build/dist/UI/Components/ModelFormModal/ModelFormModal.js.map +1 -1
- package/build/dist/UI/Components/ModelTable/AnalyticsModelTable.js.map +1 -1
- package/build/dist/UI/Components/ModelTable/BaseModelTable.js +2 -2
- package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
- package/build/dist/UI/Components/ModelTable/CustomFieldColumns.js +13 -1
- package/build/dist/UI/Components/ModelTable/CustomFieldColumns.js.map +1 -1
- package/build/dist/UI/Components/ModelTable/ModelTable.js +1 -1
- package/build/dist/UI/Components/ModelTable/ModelTable.js.map +1 -1
- package/build/dist/UI/Utils/SensitiveUrlToken.js +10 -5
- package/build/dist/UI/Utils/SensitiveUrlToken.js.map +1 -1
- package/build/dist/Utils/API.js +177 -1
- package/build/dist/Utils/API.js.map +1 -1
- package/build/dist/Utils/Incident/IncidentFromAlerts.js +38 -0
- package/build/dist/Utils/Incident/IncidentFromAlerts.js.map +1 -1
- package/build/dist/Utils/Incident/IncidentNoteTemplateVariables.js +155 -0
- package/build/dist/Utils/Incident/IncidentNoteTemplateVariables.js.map +1 -0
- package/build/dist/Utils/Markdown/MarkdownEscape.js +48 -0
- package/build/dist/Utils/Markdown/MarkdownEscape.js.map +1 -1
- package/build/dist/Utils/ProbeNetworkFailureUtil.js +460 -0
- package/build/dist/Utils/ProbeNetworkFailureUtil.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,576 @@
|
|
|
1
|
+
import FindAllBy from "../../Types/Database/FindAllBy";
|
|
2
|
+
import Query from "../../Types/Database/Query";
|
|
3
|
+
import QueryHelper from "../../Types/Database/QueryHelper";
|
|
4
|
+
import Select from "../../Types/Database/Select";
|
|
5
|
+
import Alert from "../../../Models/DatabaseModels/Alert";
|
|
6
|
+
import DatabaseBaseModel from "../../../Models/DatabaseModels/DatabaseBaseModel/DatabaseBaseModel";
|
|
7
|
+
import Incident from "../../../Models/DatabaseModels/Incident";
|
|
8
|
+
import ScheduledMaintenance from "../../../Models/DatabaseModels/ScheduledMaintenance";
|
|
9
|
+
import URL from "../../../Types/API/URL";
|
|
10
|
+
import ObjectID from "../../../Types/ObjectID";
|
|
11
|
+
import { escapeMarkdownInline } from "../../../Utils/Markdown/MarkdownEscape";
|
|
12
|
+
import {
|
|
13
|
+
getSloAffectedResourceMarkdownLines,
|
|
14
|
+
SloAffectedResourceLinkSubject,
|
|
15
|
+
} from "../../../Utils/Slo/SloAffectedResourceMarkdown";
|
|
16
|
+
|
|
17
|
+
/*
|
|
18
|
+
* What an incident, alert or scheduled maintenance event affects, for the
|
|
19
|
+
* text the server writes about it: the "Resources Affected" section of its
|
|
20
|
+
* feed items, the Resources Affected row of its emails, and the workspace
|
|
21
|
+
* summaries.
|
|
22
|
+
*
|
|
23
|
+
* The dashboard's Affected Resources cards (AffectedResourcesDisplay) list
|
|
24
|
+
* every relation the record carries - monitors, hosts, clusters, container
|
|
25
|
+
* hosts, databases, services, SLOs. The server used to name the monitors
|
|
26
|
+
* only, so an SLO burn-rate alert's card named its SLO while its on-call
|
|
27
|
+
* email read "Resources Affected: No resources identified", and an incident
|
|
28
|
+
* raised against a host named nothing at all. Every one of those writers now
|
|
29
|
+
* reads the list from here, so they name what the cards show.
|
|
30
|
+
*
|
|
31
|
+
* Reads run as root - an owner or on-call email has no user session behind
|
|
32
|
+
* it - and are held to the record's own project twice: the record is only
|
|
33
|
+
* read inside that project, and a related row of any other project is left
|
|
34
|
+
* out. The write hooks reject cross-project links now, but rows saved before
|
|
35
|
+
* that check existed may still hold one, and naming it would put another
|
|
36
|
+
* project's resource into this project's feed, Slack and email.
|
|
37
|
+
*
|
|
38
|
+
* The caller hands over the service to read with, and the dashboard URL to
|
|
39
|
+
* link from. Those services import this module, and the owner-notification
|
|
40
|
+
* workers' tests replace them wholesale; importing them here would drag the
|
|
41
|
+
* whole service graph into every one of those suites.
|
|
42
|
+
*/
|
|
43
|
+
|
|
44
|
+
export enum LinkedAffectedResourceType {
|
|
45
|
+
Monitor = "Monitor",
|
|
46
|
+
Host = "Host",
|
|
47
|
+
KubernetesCluster = "KubernetesCluster",
|
|
48
|
+
DockerHost = "DockerHost",
|
|
49
|
+
PodmanHost = "PodmanHost",
|
|
50
|
+
ProxmoxCluster = "ProxmoxCluster",
|
|
51
|
+
VMwareVCenter = "VMwareVCenter",
|
|
52
|
+
CephCluster = "CephCluster",
|
|
53
|
+
DockerSwarmCluster = "DockerSwarmCluster",
|
|
54
|
+
IoTFleet = "IoTFleet",
|
|
55
|
+
DatabaseServer = "DatabaseServer",
|
|
56
|
+
NetworkSite = "NetworkSite",
|
|
57
|
+
Service = "Service",
|
|
58
|
+
ServiceLevelObjective = "ServiceLevelObjective",
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export interface LinkedAffectedResource {
|
|
62
|
+
type: LinkedAffectedResourceType;
|
|
63
|
+
id: string;
|
|
64
|
+
name: string;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export interface LinkedAffectedResourceRelation {
|
|
68
|
+
// The relation column on Incident / Alert / ScheduledMaintenance.
|
|
69
|
+
column: string;
|
|
70
|
+
type: LinkedAffectedResourceType;
|
|
71
|
+
// Leads the feed bullet, e.g. "[Host web-01](...)".
|
|
72
|
+
label: string;
|
|
73
|
+
// The dashboard route after `/<projectId>/`, ending just before the id.
|
|
74
|
+
dashboardRoute: string;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/*
|
|
78
|
+
* The categories AffectedResourcesDisplay renders, in the order it renders
|
|
79
|
+
* them, so a feed item lists resources the way the cards beside it do. The
|
|
80
|
+
* routes are the ones each resource's own getXLinkInDashboard builds (a test
|
|
81
|
+
* pins every one that exists); IoT fleets and network sites have none on the
|
|
82
|
+
* server, so theirs follow the dashboard's RouteMap.
|
|
83
|
+
*
|
|
84
|
+
* An alert has a single `monitor`; incidents and scheduled maintenance events
|
|
85
|
+
* have `monitors`. Each record kind is read for the columns its model has.
|
|
86
|
+
*/
|
|
87
|
+
export const LINKED_AFFECTED_RESOURCE_RELATIONS: ReadonlyArray<LinkedAffectedResourceRelation> =
|
|
88
|
+
[
|
|
89
|
+
{
|
|
90
|
+
column: "monitors",
|
|
91
|
+
type: LinkedAffectedResourceType.Monitor,
|
|
92
|
+
label: "Monitor",
|
|
93
|
+
dashboardRoute: "monitors",
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
column: "monitor",
|
|
97
|
+
type: LinkedAffectedResourceType.Monitor,
|
|
98
|
+
label: "Monitor",
|
|
99
|
+
dashboardRoute: "monitors",
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
column: "hosts",
|
|
103
|
+
type: LinkedAffectedResourceType.Host,
|
|
104
|
+
label: "Host",
|
|
105
|
+
dashboardRoute: "host",
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
column: "kubernetesClusters",
|
|
109
|
+
type: LinkedAffectedResourceType.KubernetesCluster,
|
|
110
|
+
label: "Kubernetes Cluster",
|
|
111
|
+
dashboardRoute: "kubernetes",
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
column: "dockerHosts",
|
|
115
|
+
type: LinkedAffectedResourceType.DockerHost,
|
|
116
|
+
label: "Docker Host",
|
|
117
|
+
dashboardRoute: "docker",
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
column: "podmanHosts",
|
|
121
|
+
type: LinkedAffectedResourceType.PodmanHost,
|
|
122
|
+
label: "Podman Host",
|
|
123
|
+
dashboardRoute: "podman",
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
column: "proxmoxClusters",
|
|
127
|
+
type: LinkedAffectedResourceType.ProxmoxCluster,
|
|
128
|
+
label: "Proxmox Cluster",
|
|
129
|
+
dashboardRoute: "proxmox",
|
|
130
|
+
},
|
|
131
|
+
{
|
|
132
|
+
column: "vmwareVCenters",
|
|
133
|
+
type: LinkedAffectedResourceType.VMwareVCenter,
|
|
134
|
+
label: "VMware vCenter",
|
|
135
|
+
dashboardRoute: "vmware",
|
|
136
|
+
},
|
|
137
|
+
{
|
|
138
|
+
column: "cephClusters",
|
|
139
|
+
type: LinkedAffectedResourceType.CephCluster,
|
|
140
|
+
label: "Ceph Cluster",
|
|
141
|
+
dashboardRoute: "ceph",
|
|
142
|
+
},
|
|
143
|
+
{
|
|
144
|
+
column: "dockerSwarmClusters",
|
|
145
|
+
type: LinkedAffectedResourceType.DockerSwarmCluster,
|
|
146
|
+
label: "Docker Swarm Cluster",
|
|
147
|
+
dashboardRoute: "docker-swarm",
|
|
148
|
+
},
|
|
149
|
+
{
|
|
150
|
+
column: "iotFleets",
|
|
151
|
+
type: LinkedAffectedResourceType.IoTFleet,
|
|
152
|
+
label: "IoT Fleet",
|
|
153
|
+
dashboardRoute: "iot",
|
|
154
|
+
},
|
|
155
|
+
{
|
|
156
|
+
column: "databaseServers",
|
|
157
|
+
type: LinkedAffectedResourceType.DatabaseServer,
|
|
158
|
+
label: "Database",
|
|
159
|
+
dashboardRoute: "databases",
|
|
160
|
+
},
|
|
161
|
+
{
|
|
162
|
+
column: "networkSites",
|
|
163
|
+
type: LinkedAffectedResourceType.NetworkSite,
|
|
164
|
+
label: "Network Site",
|
|
165
|
+
dashboardRoute: "network-sites/view",
|
|
166
|
+
},
|
|
167
|
+
{
|
|
168
|
+
column: "services",
|
|
169
|
+
type: LinkedAffectedResourceType.Service,
|
|
170
|
+
label: "Service",
|
|
171
|
+
dashboardRoute: "service",
|
|
172
|
+
},
|
|
173
|
+
/*
|
|
174
|
+
* Last, as on the cards: an SLO is the objective measured over the
|
|
175
|
+
* resources above it rather than one of them.
|
|
176
|
+
*/
|
|
177
|
+
{
|
|
178
|
+
column: "serviceLevelObjectives",
|
|
179
|
+
type: LinkedAffectedResourceType.ServiceLevelObjective,
|
|
180
|
+
label: "SLO",
|
|
181
|
+
dashboardRoute: "slos",
|
|
182
|
+
},
|
|
183
|
+
];
|
|
184
|
+
|
|
185
|
+
// Structural, so a model instance and a plain relation row both fit.
|
|
186
|
+
interface RelatedRow {
|
|
187
|
+
_id?: string | ObjectID | undefined | null;
|
|
188
|
+
name?: string | undefined | null;
|
|
189
|
+
projectId?: ObjectID | string | undefined | null;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
type RecordWithRelations = {
|
|
193
|
+
projectId?: ObjectID | string | undefined | null;
|
|
194
|
+
} & Partial<Record<string, unknown>>;
|
|
195
|
+
|
|
196
|
+
// The one method read here - IncidentService, AlertService and so on.
|
|
197
|
+
export interface LinkedAffectedResourceReader<
|
|
198
|
+
TBaseModel extends DatabaseBaseModel,
|
|
199
|
+
> {
|
|
200
|
+
findAllBy(findAllBy: FindAllBy<TBaseModel>): Promise<Array<TBaseModel>>;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
function isSameProject(
|
|
204
|
+
projectId: ObjectID | string | undefined | null,
|
|
205
|
+
expected: ObjectID,
|
|
206
|
+
): boolean {
|
|
207
|
+
if (!projectId) {
|
|
208
|
+
return false;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
return (
|
|
212
|
+
projectId.toString().trim().toLowerCase() ===
|
|
213
|
+
expected.toString().trim().toLowerCase()
|
|
214
|
+
);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
export default class LinkedAffectedResources {
|
|
218
|
+
// The relations `model` carries, in display order.
|
|
219
|
+
public static getRelations(
|
|
220
|
+
model: DatabaseBaseModel,
|
|
221
|
+
): Array<LinkedAffectedResourceRelation> {
|
|
222
|
+
return LINKED_AFFECTED_RESOURCE_RELATIONS.filter(
|
|
223
|
+
(relation: LinkedAffectedResourceRelation) => {
|
|
224
|
+
return model.hasColumn(relation.column);
|
|
225
|
+
},
|
|
226
|
+
);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
public static async readForIncident(data: {
|
|
230
|
+
service: LinkedAffectedResourceReader<Incident>;
|
|
231
|
+
projectId: ObjectID;
|
|
232
|
+
incidentId: ObjectID;
|
|
233
|
+
}): Promise<Array<LinkedAffectedResource>> {
|
|
234
|
+
return await LinkedAffectedResources.readForIncidents({
|
|
235
|
+
service: data.service,
|
|
236
|
+
projectId: data.projectId,
|
|
237
|
+
incidentIds: [data.incidentId],
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
public static async readForIncidents(data: {
|
|
242
|
+
service: LinkedAffectedResourceReader<Incident>;
|
|
243
|
+
projectId: ObjectID;
|
|
244
|
+
incidentIds: Array<ObjectID>;
|
|
245
|
+
}): Promise<Array<LinkedAffectedResource>> {
|
|
246
|
+
return await LinkedAffectedResources.read({
|
|
247
|
+
service: data.service,
|
|
248
|
+
model: new Incident(),
|
|
249
|
+
projectId: data.projectId,
|
|
250
|
+
recordIds: data.incidentIds,
|
|
251
|
+
});
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
public static async readForAlert(data: {
|
|
255
|
+
service: LinkedAffectedResourceReader<Alert>;
|
|
256
|
+
projectId: ObjectID;
|
|
257
|
+
alertId: ObjectID;
|
|
258
|
+
}): Promise<Array<LinkedAffectedResource>> {
|
|
259
|
+
return await LinkedAffectedResources.readForAlerts({
|
|
260
|
+
service: data.service,
|
|
261
|
+
projectId: data.projectId,
|
|
262
|
+
alertIds: [data.alertId],
|
|
263
|
+
});
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
public static async readForAlerts(data: {
|
|
267
|
+
service: LinkedAffectedResourceReader<Alert>;
|
|
268
|
+
projectId: ObjectID;
|
|
269
|
+
alertIds: Array<ObjectID>;
|
|
270
|
+
}): Promise<Array<LinkedAffectedResource>> {
|
|
271
|
+
return await LinkedAffectedResources.read({
|
|
272
|
+
service: data.service,
|
|
273
|
+
model: new Alert(),
|
|
274
|
+
projectId: data.projectId,
|
|
275
|
+
recordIds: data.alertIds,
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
public static async readForScheduledMaintenance(data: {
|
|
280
|
+
service: LinkedAffectedResourceReader<ScheduledMaintenance>;
|
|
281
|
+
projectId: ObjectID;
|
|
282
|
+
scheduledMaintenanceId: ObjectID;
|
|
283
|
+
}): Promise<Array<LinkedAffectedResource>> {
|
|
284
|
+
return await LinkedAffectedResources.read({
|
|
285
|
+
service: data.service,
|
|
286
|
+
model: new ScheduledMaintenance(),
|
|
287
|
+
projectId: data.projectId,
|
|
288
|
+
recordIds: [data.scheduledMaintenanceId],
|
|
289
|
+
});
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
/*
|
|
293
|
+
* The resources linked to any of `recordIds`, merged into one list.
|
|
294
|
+
*
|
|
295
|
+
* One query per relation rather than one query selecting them all: the
|
|
296
|
+
* relations are many-to-many, and joining a dozen of them at once returns
|
|
297
|
+
* the product of their sizes - an incident on 50 monitors and 50 hosts
|
|
298
|
+
* would come back as 2,500 rows. Read one at a time, the rows add up.
|
|
299
|
+
*/
|
|
300
|
+
private static async read<TBaseModel extends DatabaseBaseModel>(data: {
|
|
301
|
+
service: LinkedAffectedResourceReader<TBaseModel>;
|
|
302
|
+
model: TBaseModel;
|
|
303
|
+
projectId: ObjectID;
|
|
304
|
+
recordIds: Array<ObjectID>;
|
|
305
|
+
}): Promise<Array<LinkedAffectedResource>> {
|
|
306
|
+
const recordIds: Array<ObjectID> = [];
|
|
307
|
+
const seenRecordIds: Set<string> = new Set<string>();
|
|
308
|
+
|
|
309
|
+
for (const recordId of data.recordIds) {
|
|
310
|
+
const key: string = recordId?.toString() || "";
|
|
311
|
+
|
|
312
|
+
if (!key || seenRecordIds.has(key)) {
|
|
313
|
+
continue;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
seenRecordIds.add(key);
|
|
317
|
+
recordIds.push(recordId);
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
if (recordIds.length === 0) {
|
|
321
|
+
return [];
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
const rowsPerRelation: Array<Array<TBaseModel> | undefined> =
|
|
325
|
+
await Promise.all(
|
|
326
|
+
LinkedAffectedResources.getRelations(data.model).map(
|
|
327
|
+
(
|
|
328
|
+
relation: LinkedAffectedResourceRelation,
|
|
329
|
+
): Promise<Array<TBaseModel>> => {
|
|
330
|
+
return data.service.findAllBy({
|
|
331
|
+
query: {
|
|
332
|
+
_id: QueryHelper.any(recordIds),
|
|
333
|
+
projectId: data.projectId,
|
|
334
|
+
} as unknown as Query<TBaseModel>,
|
|
335
|
+
select: {
|
|
336
|
+
_id: true,
|
|
337
|
+
projectId: true,
|
|
338
|
+
[relation.column]: {
|
|
339
|
+
_id: true,
|
|
340
|
+
name: true,
|
|
341
|
+
projectId: true,
|
|
342
|
+
},
|
|
343
|
+
} as unknown as Select<TBaseModel>,
|
|
344
|
+
props: {
|
|
345
|
+
isRoot: true,
|
|
346
|
+
},
|
|
347
|
+
});
|
|
348
|
+
},
|
|
349
|
+
),
|
|
350
|
+
);
|
|
351
|
+
|
|
352
|
+
return LinkedAffectedResources.collect({
|
|
353
|
+
projectId: data.projectId,
|
|
354
|
+
records: rowsPerRelation.flatMap(
|
|
355
|
+
(rows: Array<TBaseModel> | undefined): Array<TBaseModel> => {
|
|
356
|
+
return rows || [];
|
|
357
|
+
},
|
|
358
|
+
) as unknown as Array<RecordWithRelations>,
|
|
359
|
+
});
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
/*
|
|
363
|
+
* The resources on already-read records, in display order and without
|
|
364
|
+
* repeats. A related row is kept only when it has an id and belongs to
|
|
365
|
+
* `projectId`; a row whose project was not read cannot be shown to belong
|
|
366
|
+
* here, so it is left out too - which also makes a caller that drops
|
|
367
|
+
* projectId from its select fail loudly in tests rather than quietly
|
|
368
|
+
* print nothing.
|
|
369
|
+
*/
|
|
370
|
+
public static collect(data: {
|
|
371
|
+
projectId: ObjectID;
|
|
372
|
+
records: Array<RecordWithRelations | null | undefined>;
|
|
373
|
+
}): Array<LinkedAffectedResource> {
|
|
374
|
+
const resources: Array<LinkedAffectedResource> = [];
|
|
375
|
+
const seen: Set<string> = new Set<string>();
|
|
376
|
+
|
|
377
|
+
const records: Array<RecordWithRelations> = data.records.filter(
|
|
378
|
+
(record: RecordWithRelations | null | undefined): boolean => {
|
|
379
|
+
if (!record) {
|
|
380
|
+
return false;
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
// A record read without its project is taken to be the caller's.
|
|
384
|
+
return (
|
|
385
|
+
!record.projectId || isSameProject(record.projectId, data.projectId)
|
|
386
|
+
);
|
|
387
|
+
},
|
|
388
|
+
) as Array<RecordWithRelations>;
|
|
389
|
+
|
|
390
|
+
for (const relation of LINKED_AFFECTED_RESOURCE_RELATIONS) {
|
|
391
|
+
for (const record of records) {
|
|
392
|
+
const value: unknown = record[relation.column];
|
|
393
|
+
|
|
394
|
+
const rows: Array<RelatedRow | null | undefined> = Array.isArray(value)
|
|
395
|
+
? (value as Array<RelatedRow | null | undefined>)
|
|
396
|
+
: value
|
|
397
|
+
? [value as RelatedRow]
|
|
398
|
+
: [];
|
|
399
|
+
|
|
400
|
+
for (const row of rows) {
|
|
401
|
+
const id: string = row?._id?.toString() || "";
|
|
402
|
+
|
|
403
|
+
if (!row || !id || !isSameProject(row.projectId, data.projectId)) {
|
|
404
|
+
continue;
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
const key: string = `${relation.type}:${id}`;
|
|
408
|
+
|
|
409
|
+
if (seen.has(key)) {
|
|
410
|
+
continue;
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
seen.add(key);
|
|
414
|
+
|
|
415
|
+
resources.push({
|
|
416
|
+
type: relation.type,
|
|
417
|
+
id: id,
|
|
418
|
+
name: row.name?.toString() || "",
|
|
419
|
+
});
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
return resources;
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
/*
|
|
428
|
+
* The names, for plain-text surfaces: emails and workspace summaries.
|
|
429
|
+
*
|
|
430
|
+
* `seriesSummary` is an alert's series identity - the pod or container a
|
|
431
|
+
* grouped monitor raised it for (SeriesLabelDisplay.buildInlineSummary).
|
|
432
|
+
* It names what broke more precisely than the monitor does, so it takes
|
|
433
|
+
* the monitor's place at the head of the list rather than joining it.
|
|
434
|
+
*
|
|
435
|
+
* A name that repeats (a monitor and a host both called "web-01") is
|
|
436
|
+
* printed once: this is a sentence, not a table.
|
|
437
|
+
*/
|
|
438
|
+
public static getNames(data: {
|
|
439
|
+
resources: Array<LinkedAffectedResource>;
|
|
440
|
+
seriesSummary?: string | undefined;
|
|
441
|
+
}): Array<string> {
|
|
442
|
+
const names: Array<string> = [];
|
|
443
|
+
const seenNames: Set<string> = new Set<string>();
|
|
444
|
+
const seriesSummary: string = data.seriesSummary?.trim() || "";
|
|
445
|
+
|
|
446
|
+
const addName: (name: string) => void = (name: string): void => {
|
|
447
|
+
const trimmed: string = name.trim();
|
|
448
|
+
|
|
449
|
+
if (!trimmed || seenNames.has(trimmed)) {
|
|
450
|
+
return;
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
seenNames.add(trimmed);
|
|
454
|
+
names.push(trimmed);
|
|
455
|
+
};
|
|
456
|
+
|
|
457
|
+
addName(seriesSummary);
|
|
458
|
+
|
|
459
|
+
for (const resource of data.resources) {
|
|
460
|
+
if (
|
|
461
|
+
seriesSummary &&
|
|
462
|
+
resource.type === LinkedAffectedResourceType.Monitor
|
|
463
|
+
) {
|
|
464
|
+
continue;
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
addName(resource.name);
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
return names;
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
// getNames joined with ", ", or `fallback` when there are none.
|
|
474
|
+
public static getText(data: {
|
|
475
|
+
resources: Array<LinkedAffectedResource>;
|
|
476
|
+
seriesSummary?: string | undefined;
|
|
477
|
+
fallback: string;
|
|
478
|
+
}): string {
|
|
479
|
+
return (
|
|
480
|
+
LinkedAffectedResources.getNames({
|
|
481
|
+
resources: data.resources,
|
|
482
|
+
seriesSummary: data.seriesSummary,
|
|
483
|
+
}).join(", ") || data.fallback
|
|
484
|
+
);
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
public static getDashboardUrl(data: {
|
|
488
|
+
dashboardUrl: URL;
|
|
489
|
+
projectId: ObjectID;
|
|
490
|
+
resource: LinkedAffectedResource;
|
|
491
|
+
}): URL {
|
|
492
|
+
const relation: LinkedAffectedResourceRelation =
|
|
493
|
+
LinkedAffectedResources.getRelationForType(data.resource.type);
|
|
494
|
+
|
|
495
|
+
// URL.addRoute mutates, and the caller reuses its dashboard URL.
|
|
496
|
+
return URL.fromString(data.dashboardUrl.toString()).addRoute(
|
|
497
|
+
`/${data.projectId.toString()}/${relation.dashboardRoute}/${data.resource.id}`,
|
|
498
|
+
);
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
/*
|
|
502
|
+
* The bullets under a feed item's "🌎 Resources Affected" header.
|
|
503
|
+
*
|
|
504
|
+
* A monitor keeps the bullet the created feeds have always printed,
|
|
505
|
+
* `- [<name>](<monitor link>)`, and an SLO keeps `- [SLO <name>](<link>)`
|
|
506
|
+
* from getSloAffectedResourceMarkdownLines. Every other resource follows
|
|
507
|
+
* the SLO's shape, `- [Host <name>](<link>)`, so the reader can tell a host
|
|
508
|
+
* from a cluster from a service.
|
|
509
|
+
*
|
|
510
|
+
* Those names are escaped: feeds render without safe mode and the same
|
|
511
|
+
* markdown goes to Slack and Teams, and a host or cluster name can come
|
|
512
|
+
* from an agent rather than from someone typing it.
|
|
513
|
+
*/
|
|
514
|
+
public static getMarkdownLines(data: {
|
|
515
|
+
dashboardUrl: URL;
|
|
516
|
+
projectId: ObjectID;
|
|
517
|
+
resources: Array<LinkedAffectedResource>;
|
|
518
|
+
}): Array<string> {
|
|
519
|
+
const lines: Array<string> = [];
|
|
520
|
+
const slos: Array<SloAffectedResourceLinkSubject> = [];
|
|
521
|
+
|
|
522
|
+
for (const resource of data.resources) {
|
|
523
|
+
if (resource.type === LinkedAffectedResourceType.ServiceLevelObjective) {
|
|
524
|
+
slos.push({
|
|
525
|
+
_id: resource.id,
|
|
526
|
+
name: resource.name,
|
|
527
|
+
// Already held to this project by collect.
|
|
528
|
+
projectId: data.projectId,
|
|
529
|
+
});
|
|
530
|
+
continue;
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
const link: string = LinkedAffectedResources.getDashboardUrl({
|
|
534
|
+
dashboardUrl: data.dashboardUrl,
|
|
535
|
+
projectId: data.projectId,
|
|
536
|
+
resource: resource,
|
|
537
|
+
}).toString();
|
|
538
|
+
|
|
539
|
+
if (resource.type === LinkedAffectedResourceType.Monitor) {
|
|
540
|
+
lines.push(`- [${resource.name}](${link})`);
|
|
541
|
+
continue;
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
const label: string = LinkedAffectedResources.getRelationForType(
|
|
545
|
+
resource.type,
|
|
546
|
+
).label;
|
|
547
|
+
const escapedName: string = escapeMarkdownInline(resource.name).trim();
|
|
548
|
+
|
|
549
|
+
lines.push(
|
|
550
|
+
`- [${escapedName ? `${label} ${escapedName}` : label}](${link})`,
|
|
551
|
+
);
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
// SLOs are last in the table, so appending them keeps the order.
|
|
555
|
+
lines.push(
|
|
556
|
+
...getSloAffectedResourceMarkdownLines({
|
|
557
|
+
dashboardUrl: data.dashboardUrl,
|
|
558
|
+
projectId: data.projectId,
|
|
559
|
+
serviceLevelObjectives: slos,
|
|
560
|
+
}),
|
|
561
|
+
);
|
|
562
|
+
|
|
563
|
+
return lines;
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
private static getRelationForType(
|
|
567
|
+
type: LinkedAffectedResourceType,
|
|
568
|
+
): LinkedAffectedResourceRelation {
|
|
569
|
+
// Every type has at least one entry, so this always finds one.
|
|
570
|
+
return LINKED_AFFECTED_RESOURCE_RELATIONS.find(
|
|
571
|
+
(relation: LinkedAffectedResourceRelation) => {
|
|
572
|
+
return relation.type === type;
|
|
573
|
+
},
|
|
574
|
+
)!;
|
|
575
|
+
}
|
|
576
|
+
}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import Alert from "../../../Models/DatabaseModels/Alert";
|
|
2
|
+
import AlertStateTimeline from "../../../Models/DatabaseModels/AlertStateTimeline";
|
|
3
|
+
import DatabaseCommonInteractionProps from "../../../Types/BaseDatabase/DatabaseCommonInteractionProps";
|
|
4
|
+
import { LIMIT_PER_PROJECT } from "../../../Types/Database/LimitMax";
|
|
5
|
+
import NotAuthorizedException from "../../../Types/Exception/NotAuthorizedException";
|
|
6
|
+
import ObjectID from "../../../Types/ObjectID";
|
|
7
|
+
import AlertService from "../../Services/AlertService";
|
|
8
|
+
import ModelPermission from "../../Types/Database/Permissions/Index";
|
|
9
|
+
import Query from "../../Types/Database/Query";
|
|
10
|
+
import QueryHelper from "../../Types/Database/QueryHelper";
|
|
11
|
+
import { applyAlertSelfPrivacyFilter } from "./AlertPrivacyFilter";
|
|
12
|
+
import CaptureSpan from "../Telemetry/CaptureSpan";
|
|
13
|
+
|
|
14
|
+
/*
|
|
15
|
+
* Whether a caller may change the state of a set of alerts - acknowledge
|
|
16
|
+
* them, say - when that change is going to be written for them as root.
|
|
17
|
+
*
|
|
18
|
+
* Changing an alert's state from its own page takes two writes as the caller:
|
|
19
|
+
* a new AlertStateTimeline row (table and column permissions only), and then
|
|
20
|
+
* the alert's currentAlertStateId, which is an Alert UPDATE and so is narrowed
|
|
21
|
+
* by the caller's label scope, Owned scope and alert privacy. Being able to
|
|
22
|
+
* read an alert is not enough: a Viewer who is also an AlertMember for one
|
|
23
|
+
* label can read every alert but change the state of only some. A root write
|
|
24
|
+
* skips both, so this checks both, for every alert, before anything is
|
|
25
|
+
* written - the same rule the Microsoft Teams acknowledge action applies to
|
|
26
|
+
* one alert.
|
|
27
|
+
*/
|
|
28
|
+
export default class AlertStateChangeAuthorization {
|
|
29
|
+
@CaptureSpan()
|
|
30
|
+
public static async assertCanChangeStateOfAlerts(data: {
|
|
31
|
+
projectId: ObjectID;
|
|
32
|
+
alertIds: Array<ObjectID>;
|
|
33
|
+
props: DatabaseCommonInteractionProps;
|
|
34
|
+
}): Promise<void> {
|
|
35
|
+
if (data.props.isRoot || data.alertIds.length === 0) {
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const probe: AlertStateTimeline = new AlertStateTimeline();
|
|
40
|
+
probe.projectId = data.projectId;
|
|
41
|
+
probe.alertId = data.alertIds[0]!;
|
|
42
|
+
probe.alertStateId = ObjectID.generate();
|
|
43
|
+
|
|
44
|
+
ModelPermission.checkCreatePermissions(
|
|
45
|
+
AlertStateTimeline,
|
|
46
|
+
probe,
|
|
47
|
+
data.props,
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
const alertQuery: Query<Alert> = {
|
|
51
|
+
_id: QueryHelper.any(data.alertIds),
|
|
52
|
+
projectId: data.projectId,
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
/*
|
|
56
|
+
* Labelled block and allow rules are decided per record, from the
|
|
57
|
+
* record's labels.
|
|
58
|
+
*/
|
|
59
|
+
const alerts: Array<Alert> = await AlertService.findBy({
|
|
60
|
+
query: alertQuery,
|
|
61
|
+
select: {
|
|
62
|
+
_id: true,
|
|
63
|
+
labels: {
|
|
64
|
+
_id: true,
|
|
65
|
+
name: true,
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
limit: LIMIT_PER_PROJECT,
|
|
69
|
+
skip: 0,
|
|
70
|
+
props: {
|
|
71
|
+
isRoot: true,
|
|
72
|
+
},
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
for (const alert of alerts) {
|
|
76
|
+
await ModelPermission.checkUpdatePermissionByModel({
|
|
77
|
+
modelType: Alert,
|
|
78
|
+
fetchModelWithAccessControlIds: async (): Promise<Alert> => {
|
|
79
|
+
return alert;
|
|
80
|
+
},
|
|
81
|
+
props: data.props,
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/*
|
|
86
|
+
* The caller's own update scope (labels, Owned, privacy) as a query:
|
|
87
|
+
* every alert must still be in it.
|
|
88
|
+
*/
|
|
89
|
+
const permittedQuery: Query<Alert> =
|
|
90
|
+
await ModelPermission.checkUpdateQueryPermissions(
|
|
91
|
+
Alert,
|
|
92
|
+
alertQuery,
|
|
93
|
+
{
|
|
94
|
+
currentAlertStateId: ObjectID.getZeroObjectID(),
|
|
95
|
+
},
|
|
96
|
+
data.props,
|
|
97
|
+
);
|
|
98
|
+
|
|
99
|
+
const permittedAlerts: Array<Alert> = await AlertService.findBy({
|
|
100
|
+
query: applyAlertSelfPrivacyFilter(permittedQuery, data.props),
|
|
101
|
+
select: {
|
|
102
|
+
_id: true,
|
|
103
|
+
},
|
|
104
|
+
limit: LIMIT_PER_PROJECT,
|
|
105
|
+
skip: 0,
|
|
106
|
+
props: {
|
|
107
|
+
isRoot: true,
|
|
108
|
+
},
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
const permittedIds: Set<string> = new Set(
|
|
112
|
+
permittedAlerts.map((alert: Alert): string => {
|
|
113
|
+
return alert._id?.toString().toLowerCase() || "";
|
|
114
|
+
}),
|
|
115
|
+
);
|
|
116
|
+
|
|
117
|
+
const allPermitted: boolean = data.alertIds.every(
|
|
118
|
+
(alertId: ObjectID): boolean => {
|
|
119
|
+
return permittedIds.has(alertId.toString().toLowerCase());
|
|
120
|
+
},
|
|
121
|
+
);
|
|
122
|
+
|
|
123
|
+
if (!allPermitted) {
|
|
124
|
+
throw new NotAuthorizedException(
|
|
125
|
+
"You do not have permission to change the state of one or more of these alerts.",
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|