@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,625 @@
|
|
|
1
|
+
import Entities from "../../../Models/DatabaseModels/Index";
|
|
2
|
+
import Incident from "../../../Models/DatabaseModels/Incident";
|
|
3
|
+
import StatusPage from "../../../Models/DatabaseModels/StatusPage";
|
|
4
|
+
import PostgresAppInstance from "../../../Server/Infrastructure/PostgresDatabase";
|
|
5
|
+
import AuditLogService from "../../../Server/Services/AuditLogService";
|
|
6
|
+
import CustomFieldMappingService from "../../../Server/Services/CustomFieldMappingService";
|
|
7
|
+
import IncidentFeedService from "../../../Server/Services/IncidentFeedService";
|
|
8
|
+
import IncidentService from "../../../Server/Services/IncidentService";
|
|
9
|
+
import UpdateBy from "../../../Server/Types/Database/UpdateBy";
|
|
10
|
+
import StatusPageService from "../../../Server/Services/StatusPageService";
|
|
11
|
+
import URL from "../../../Types/API/URL";
|
|
12
|
+
import DatabaseCommonInteractionProps from "../../../Types/BaseDatabase/DatabaseCommonInteractionProps";
|
|
13
|
+
import ObjectID from "../../../Types/ObjectID";
|
|
14
|
+
import Permission, {
|
|
15
|
+
UserTenantAccessPermission,
|
|
16
|
+
} from "../../../Types/Permission";
|
|
17
|
+
import UserType from "../../../Types/UserType";
|
|
18
|
+
import { DataSource } from "typeorm";
|
|
19
|
+
|
|
20
|
+
/*
|
|
21
|
+
* Incident status page scope (Incident.statusPages) against a migrated
|
|
22
|
+
* Postgres.
|
|
23
|
+
*
|
|
24
|
+
* Opt in with RUN_POSTGRES_INCIDENT_STATUS_PAGE_SCOPE_TESTS=true against a
|
|
25
|
+
* database the registered migrations have been applied to, e.g.
|
|
26
|
+
*
|
|
27
|
+
* RUN_POSTGRES_INCIDENT_STATUS_PAGE_SCOPE_TESTS=true \
|
|
28
|
+
* INCIDENT_STATUS_PAGE_SCOPE_TEST_DATABASE_HOST=127.0.0.1 \
|
|
29
|
+
* INCIDENT_STATUS_PAGE_SCOPE_TEST_DATABASE_PORT=5400 \
|
|
30
|
+
* DATABASE_PASSWORD=... npx jest Tests/Server/Services/IncidentStatusPageScopePostgres.test.ts
|
|
31
|
+
*
|
|
32
|
+
* CI runs it in .github/workflows/postgres-schema-drift.yaml, right after that
|
|
33
|
+
* job has applied every registered migration to an empty database.
|
|
34
|
+
*
|
|
35
|
+
* What it pins down is the promise that deleting a status page never widens
|
|
36
|
+
* an incident's reach. Deletes are hard deletes (DatabaseService deletes rows
|
|
37
|
+
* with a plain DELETE), so an incident's join row to a deleted page goes with
|
|
38
|
+
* the page through the foreign key's ON DELETE CASCADE. isScopedToStatusPages
|
|
39
|
+
* stays true: nothing recomputes it from the join table. An incident whose
|
|
40
|
+
* only scoped page is deleted is therefore scoped to nothing - hidden from
|
|
41
|
+
* every page - rather than unscoped and broadcast to every page its monitors
|
|
42
|
+
* reach. Only an explicit write of the list moves it.
|
|
43
|
+
*
|
|
44
|
+
* Two halves, as in IncidentAlertPostgres.test.ts:
|
|
45
|
+
*
|
|
46
|
+
* - the migrated public tables are inspected as they are: the new columns and
|
|
47
|
+
* the ON DELETE rule of every foreign key of the two join tables;
|
|
48
|
+
* - behaviour runs in a uniquely named schema holding structure-only clones
|
|
49
|
+
* of the tables involved. The clones carry the migrated indexes (LIKE ...
|
|
50
|
+
* INCLUDING ALL), and the join tables' foreign keys are copied from the
|
|
51
|
+
* migrated tables' own definitions, so a cascade observed here is the
|
|
52
|
+
* cascade the migration declared. No row is ever written outside that
|
|
53
|
+
* schema, and the schema is dropped afterwards.
|
|
54
|
+
*
|
|
55
|
+
* The production IncidentService writes the scope through the real hooks,
|
|
56
|
+
* permission checks and join-table save, as a non-root incident member; only
|
|
57
|
+
* the feed, dashboard links, custom field mapping, audit log, realtime and
|
|
58
|
+
* workflow triggers are stubbed.
|
|
59
|
+
*/
|
|
60
|
+
const describePostgres: typeof describe =
|
|
61
|
+
process.env["RUN_POSTGRES_INCIDENT_STATUS_PAGE_SCOPE_TESTS"] === "true"
|
|
62
|
+
? describe
|
|
63
|
+
: describe.skip;
|
|
64
|
+
|
|
65
|
+
const TABLES: Array<string> = [
|
|
66
|
+
"Project",
|
|
67
|
+
"StatusPage",
|
|
68
|
+
"Incident",
|
|
69
|
+
"IncidentStatusPage",
|
|
70
|
+
"IncidentTemplate",
|
|
71
|
+
"IncidentTemplateStatusPage",
|
|
72
|
+
];
|
|
73
|
+
|
|
74
|
+
const JOIN_TABLES: Array<string> = [
|
|
75
|
+
"IncidentStatusPage",
|
|
76
|
+
"IncidentTemplateStatusPage",
|
|
77
|
+
];
|
|
78
|
+
|
|
79
|
+
interface ForeignKeyRow {
|
|
80
|
+
table: string;
|
|
81
|
+
name: string;
|
|
82
|
+
column: string;
|
|
83
|
+
referencedTable: string;
|
|
84
|
+
onDelete: string;
|
|
85
|
+
definition: string;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
describePostgres(
|
|
89
|
+
"Incident status page scope against a migrated Postgres",
|
|
90
|
+
() => {
|
|
91
|
+
const schema: string = `incident_scope_${ObjectID.generate()
|
|
92
|
+
.toString()
|
|
93
|
+
.replace(/-/g, "")}`;
|
|
94
|
+
|
|
95
|
+
const projectId: ObjectID = ObjectID.generate();
|
|
96
|
+
|
|
97
|
+
let database: DataSource;
|
|
98
|
+
let migratedForeignKeys: Array<ForeignKeyRow> = [];
|
|
99
|
+
|
|
100
|
+
beforeAll(async () => {
|
|
101
|
+
database = new DataSource({
|
|
102
|
+
type: "postgres",
|
|
103
|
+
host:
|
|
104
|
+
process.env["INCIDENT_STATUS_PAGE_SCOPE_TEST_DATABASE_HOST"] ||
|
|
105
|
+
"localhost",
|
|
106
|
+
port: Number(
|
|
107
|
+
process.env["INCIDENT_STATUS_PAGE_SCOPE_TEST_DATABASE_PORT"] ||
|
|
108
|
+
"5400",
|
|
109
|
+
),
|
|
110
|
+
username: process.env["DATABASE_USERNAME"] || "postgres",
|
|
111
|
+
password: process.env["DATABASE_PASSWORD"] || "password",
|
|
112
|
+
database:
|
|
113
|
+
process.env["INCIDENT_STATUS_PAGE_SCOPE_TEST_DATABASE_NAME"] ||
|
|
114
|
+
process.env["DATABASE_NAME"] ||
|
|
115
|
+
"oneuptimedb",
|
|
116
|
+
entities: Entities,
|
|
117
|
+
schema,
|
|
118
|
+
synchronize: false,
|
|
119
|
+
extra: { options: `-c search_path=${schema},public` },
|
|
120
|
+
});
|
|
121
|
+
await database.initialize();
|
|
122
|
+
|
|
123
|
+
/*
|
|
124
|
+
* Read the migrated foreign keys before the clones exist, so their
|
|
125
|
+
* definitions name the referenced tables without a schema.
|
|
126
|
+
*/
|
|
127
|
+
migratedForeignKeys = await database.query(
|
|
128
|
+
`SELECT t.relname AS "table",
|
|
129
|
+
c.conname AS "name",
|
|
130
|
+
a.attname AS "column",
|
|
131
|
+
r.relname AS "referencedTable",
|
|
132
|
+
c.confdeltype AS "onDelete",
|
|
133
|
+
pg_get_constraintdef(c.oid) AS "definition"
|
|
134
|
+
FROM pg_constraint c
|
|
135
|
+
JOIN pg_class t ON t.oid = c.conrelid
|
|
136
|
+
JOIN pg_namespace n ON n.oid = t.relnamespace
|
|
137
|
+
JOIN pg_class r ON r.oid = c.confrelid
|
|
138
|
+
JOIN pg_attribute a ON a.attrelid = c.conrelid AND a.attnum = c.conkey[1]
|
|
139
|
+
WHERE n.nspname = 'public' AND t.relname = ANY($1) AND c.contype = 'f'
|
|
140
|
+
ORDER BY t.relname, a.attname`,
|
|
141
|
+
[JOIN_TABLES],
|
|
142
|
+
);
|
|
143
|
+
|
|
144
|
+
await database.query(`CREATE SCHEMA "${schema}"`);
|
|
145
|
+
|
|
146
|
+
for (const table of TABLES) {
|
|
147
|
+
await database.query(
|
|
148
|
+
`CREATE TABLE "${schema}"."${table}" (LIKE public."${table}" INCLUDING ALL)`,
|
|
149
|
+
);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
for (const foreignKey of migratedForeignKeys) {
|
|
153
|
+
const definition: string = foreignKey.definition.replace(
|
|
154
|
+
/REFERENCES public\./g,
|
|
155
|
+
"REFERENCES ",
|
|
156
|
+
);
|
|
157
|
+
await database.query(
|
|
158
|
+
`ALTER TABLE "${schema}"."${foreignKey.table}" ADD CONSTRAINT "${foreignKey.name}" ${definition}`,
|
|
159
|
+
);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
const currentSchema: Array<{ current_schema: string }> =
|
|
163
|
+
await database.query("SELECT current_schema()");
|
|
164
|
+
expect(currentSchema[0]?.current_schema).toBe(schema);
|
|
165
|
+
|
|
166
|
+
jest.spyOn(PostgresAppInstance, "isConnected").mockReturnValue(true);
|
|
167
|
+
jest
|
|
168
|
+
.spyOn(PostgresAppInstance, "getDataSource")
|
|
169
|
+
.mockReturnValue(database);
|
|
170
|
+
|
|
171
|
+
jest.spyOn(IncidentService, "onTriggerWorkflow").mockResolvedValue();
|
|
172
|
+
jest.spyOn(IncidentService, "onTriggerRealtime").mockResolvedValue();
|
|
173
|
+
jest.spyOn(AuditLogService, "recordUpdate").mockResolvedValue();
|
|
174
|
+
jest
|
|
175
|
+
.spyOn(IncidentService, "getIncidentLinkInDashboard")
|
|
176
|
+
.mockResolvedValue(
|
|
177
|
+
URL.fromString("https://oneuptime.example/incident"),
|
|
178
|
+
);
|
|
179
|
+
jest
|
|
180
|
+
.spyOn(StatusPageService, "getStatusPageLinkInDashboard")
|
|
181
|
+
.mockResolvedValue(
|
|
182
|
+
URL.fromString("https://oneuptime.example/status-page"),
|
|
183
|
+
);
|
|
184
|
+
jest
|
|
185
|
+
.spyOn(IncidentFeedService, "createIncidentFeedItem")
|
|
186
|
+
.mockResolvedValue(undefined);
|
|
187
|
+
// Custom field mapping reads definition tables that are not cloned.
|
|
188
|
+
jest
|
|
189
|
+
.spyOn(CustomFieldMappingService, "applyMappingsToUpdate")
|
|
190
|
+
.mockResolvedValue(undefined);
|
|
191
|
+
jest
|
|
192
|
+
.spyOn(CustomFieldMappingService, "restampAfterMultiRowUpdate")
|
|
193
|
+
.mockReturnValue(undefined);
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
beforeEach(async () => {
|
|
197
|
+
await database.query(
|
|
198
|
+
TABLES.map((table: string): string => {
|
|
199
|
+
return `DELETE FROM "${schema}"."${table}"`;
|
|
200
|
+
})
|
|
201
|
+
.reverse()
|
|
202
|
+
.join("; "),
|
|
203
|
+
);
|
|
204
|
+
await database.query(
|
|
205
|
+
`INSERT INTO "${schema}"."Project" ("_id", "name", "slug", "version")
|
|
206
|
+
VALUES ($1, 'Status page scope test', $2, 1)`,
|
|
207
|
+
[projectId.toString(), `scope-${projectId.toString()}`],
|
|
208
|
+
);
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
afterAll(async () => {
|
|
212
|
+
jest.restoreAllMocks();
|
|
213
|
+
if (database?.isInitialized) {
|
|
214
|
+
await database.query(`DROP SCHEMA IF EXISTS "${schema}" CASCADE`);
|
|
215
|
+
await database.destroy();
|
|
216
|
+
}
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
async function seedStatusPage(name: string): Promise<ObjectID> {
|
|
220
|
+
const id: ObjectID = ObjectID.generate();
|
|
221
|
+
await database.query(
|
|
222
|
+
`INSERT INTO "${schema}"."StatusPage" ("_id", "projectId", "name", "slug", "version")
|
|
223
|
+
VALUES ($1, $2, $3, $4, 1)`,
|
|
224
|
+
[id.toString(), projectId.toString(), name, `page-${id.toString()}`],
|
|
225
|
+
);
|
|
226
|
+
return id;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
async function seedIncident(): Promise<ObjectID> {
|
|
230
|
+
const id: ObjectID = ObjectID.generate();
|
|
231
|
+
await database.query(
|
|
232
|
+
`INSERT INTO "${schema}"."Incident"
|
|
233
|
+
("_id", "projectId", "title", "slug", "currentIncidentStateId", "incidentSeverityId", "version")
|
|
234
|
+
VALUES ($1, $2, 'Shared uplink down', $3, $4, $5, 1)`,
|
|
235
|
+
[
|
|
236
|
+
id.toString(),
|
|
237
|
+
projectId.toString(),
|
|
238
|
+
`incident-${id.toString()}`,
|
|
239
|
+
ObjectID.generate().toString(),
|
|
240
|
+
ObjectID.generate().toString(),
|
|
241
|
+
],
|
|
242
|
+
);
|
|
243
|
+
return id;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
async function seedTemplate(): Promise<ObjectID> {
|
|
247
|
+
const id: ObjectID = ObjectID.generate();
|
|
248
|
+
await database.query(
|
|
249
|
+
`INSERT INTO "${schema}"."IncidentTemplate"
|
|
250
|
+
("_id", "projectId", "title", "templateName", "templateDescription", "slug", "version")
|
|
251
|
+
VALUES ($1, $2, 'Region East outage', 'Region East outage', 'East sites', $3, 1)`,
|
|
252
|
+
[id.toString(), projectId.toString(), `template-${id.toString()}`],
|
|
253
|
+
);
|
|
254
|
+
return id;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
async function deleteStatusPage(id: ObjectID): Promise<void> {
|
|
258
|
+
// What DatabaseService.deleteBy issues once a delete is permitted.
|
|
259
|
+
await database.query(
|
|
260
|
+
`DELETE FROM "${schema}"."StatusPage" WHERE "_id" = $1`,
|
|
261
|
+
[id.toString()],
|
|
262
|
+
);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
async function scopeRows(incidentId: ObjectID): Promise<Array<string>> {
|
|
266
|
+
const rows: Array<{ statusPageId: string }> = await database.query(
|
|
267
|
+
`SELECT "statusPageId" FROM "${schema}"."IncidentStatusPage" WHERE "incidentId" = $1 ORDER BY "statusPageId"`,
|
|
268
|
+
[incidentId.toString()],
|
|
269
|
+
);
|
|
270
|
+
return rows.map((row: { statusPageId: string }) => {
|
|
271
|
+
return row.statusPageId;
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
async function isScoped(incidentId: ObjectID): Promise<boolean> {
|
|
276
|
+
const rows: Array<{ isScopedToStatusPages: boolean }> =
|
|
277
|
+
await database.query(
|
|
278
|
+
`SELECT "isScopedToStatusPages" FROM "${schema}"."Incident" WHERE "_id" = $1`,
|
|
279
|
+
[incidentId.toString()],
|
|
280
|
+
);
|
|
281
|
+
return rows[0]!.isScopedToStatusPages;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
// An incident member who may also read status pages, owning nothing.
|
|
285
|
+
function memberProps(): DatabaseCommonInteractionProps {
|
|
286
|
+
const tenantPermission: UserTenantAccessPermission = {
|
|
287
|
+
projectId: projectId,
|
|
288
|
+
_type: "UserTenantAccessPermission",
|
|
289
|
+
permissions: [
|
|
290
|
+
Permission.IncidentMember,
|
|
291
|
+
Permission.StatusPageViewer,
|
|
292
|
+
].map((permission: Permission) => {
|
|
293
|
+
return {
|
|
294
|
+
_type: "UserPermission",
|
|
295
|
+
permission: permission,
|
|
296
|
+
labelIds: [],
|
|
297
|
+
isBlockPermission: false,
|
|
298
|
+
};
|
|
299
|
+
}),
|
|
300
|
+
};
|
|
301
|
+
|
|
302
|
+
return {
|
|
303
|
+
tenantId: projectId,
|
|
304
|
+
userId: ObjectID.generate(),
|
|
305
|
+
userType: UserType.User,
|
|
306
|
+
userTenantAccessPermission: {
|
|
307
|
+
[projectId.toString()]: tenantPermission,
|
|
308
|
+
},
|
|
309
|
+
};
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
async function setScope(
|
|
313
|
+
incidentId: ObjectID,
|
|
314
|
+
statusPageIds: Array<ObjectID>,
|
|
315
|
+
): Promise<void> {
|
|
316
|
+
/*
|
|
317
|
+
* Built apart from the call, so the compiler does not expand the deep
|
|
318
|
+
* partial-entity type of the literal.
|
|
319
|
+
*/
|
|
320
|
+
const data: UpdateBy<Incident>["data"] = {
|
|
321
|
+
statusPages: statusPageIds.map((id: ObjectID) => {
|
|
322
|
+
const statusPage: StatusPage = new StatusPage();
|
|
323
|
+
statusPage.id = id;
|
|
324
|
+
return statusPage;
|
|
325
|
+
}),
|
|
326
|
+
} as unknown as UpdateBy<Incident>["data"];
|
|
327
|
+
|
|
328
|
+
await IncidentService.updateOneById({
|
|
329
|
+
id: incidentId,
|
|
330
|
+
data: data,
|
|
331
|
+
props: memberProps(),
|
|
332
|
+
});
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
function sorted(ids: Array<ObjectID>): Array<string> {
|
|
336
|
+
return ids
|
|
337
|
+
.map((id: ObjectID) => {
|
|
338
|
+
return id.toString();
|
|
339
|
+
})
|
|
340
|
+
.sort();
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
describe("the migrated tables", () => {
|
|
344
|
+
test("a scope row goes with its incident or its status page, and so does a template's", () => {
|
|
345
|
+
expect(
|
|
346
|
+
migratedForeignKeys.map((foreignKey: ForeignKeyRow) => {
|
|
347
|
+
return [
|
|
348
|
+
foreignKey.table,
|
|
349
|
+
foreignKey.column,
|
|
350
|
+
foreignKey.referencedTable,
|
|
351
|
+
foreignKey.onDelete,
|
|
352
|
+
];
|
|
353
|
+
}),
|
|
354
|
+
).toEqual([
|
|
355
|
+
// confdeltype: c = CASCADE
|
|
356
|
+
["IncidentStatusPage", "incidentId", "Incident", "c"],
|
|
357
|
+
["IncidentStatusPage", "statusPageId", "StatusPage", "c"],
|
|
358
|
+
[
|
|
359
|
+
"IncidentTemplateStatusPage",
|
|
360
|
+
"incidentTemplateId",
|
|
361
|
+
"IncidentTemplate",
|
|
362
|
+
"c",
|
|
363
|
+
],
|
|
364
|
+
["IncidentTemplateStatusPage", "statusPageId", "StatusPage", "c"],
|
|
365
|
+
]);
|
|
366
|
+
});
|
|
367
|
+
|
|
368
|
+
test("every existing incident starts unscoped, and every status page shows unscoped incidents", async () => {
|
|
369
|
+
const rows: Array<{
|
|
370
|
+
table_name: string;
|
|
371
|
+
column_name: string;
|
|
372
|
+
data_type: string;
|
|
373
|
+
is_nullable: string;
|
|
374
|
+
column_default: string | null;
|
|
375
|
+
}> = await database.query(
|
|
376
|
+
`SELECT table_name, column_name, data_type, is_nullable, column_default
|
|
377
|
+
FROM information_schema.columns
|
|
378
|
+
WHERE table_schema = 'public'
|
|
379
|
+
AND ((table_name = 'Incident' AND column_name IN ('isScopedToStatusPages', 'statusPagesNotifiedOnCreation'))
|
|
380
|
+
OR (table_name = 'StatusPage' AND column_name = 'onlyShowScopedIncidents'))
|
|
381
|
+
ORDER BY table_name, column_name`,
|
|
382
|
+
);
|
|
383
|
+
|
|
384
|
+
expect(rows).toEqual([
|
|
385
|
+
{
|
|
386
|
+
table_name: "Incident",
|
|
387
|
+
column_name: "isScopedToStatusPages",
|
|
388
|
+
data_type: "boolean",
|
|
389
|
+
is_nullable: "NO",
|
|
390
|
+
column_default: "false",
|
|
391
|
+
},
|
|
392
|
+
{
|
|
393
|
+
table_name: "Incident",
|
|
394
|
+
column_name: "statusPagesNotifiedOnCreation",
|
|
395
|
+
data_type: "jsonb",
|
|
396
|
+
is_nullable: "YES",
|
|
397
|
+
column_default: null,
|
|
398
|
+
},
|
|
399
|
+
{
|
|
400
|
+
table_name: "StatusPage",
|
|
401
|
+
column_name: "onlyShowScopedIncidents",
|
|
402
|
+
data_type: "boolean",
|
|
403
|
+
is_nullable: "NO",
|
|
404
|
+
column_default: "false",
|
|
405
|
+
},
|
|
406
|
+
]);
|
|
407
|
+
});
|
|
408
|
+
|
|
409
|
+
/*
|
|
410
|
+
* The flag is false on nearly every row, so an index on it cannot help
|
|
411
|
+
* the queries that split on it; the scoped half reaches its incidents
|
|
412
|
+
* through the join table's statusPageId index. Building one in the
|
|
413
|
+
* migration that altered Incident would have held that ALTER's lock -
|
|
414
|
+
* reads included - for the whole build.
|
|
415
|
+
*/
|
|
416
|
+
test("the scope flag is not indexed, and the join table is, by status page", async () => {
|
|
417
|
+
const flagIndexes: Array<{ indexdef: string }> = await database.query(
|
|
418
|
+
`SELECT indexdef FROM pg_indexes WHERE schemaname = 'public' AND tablename = 'Incident' AND indexdef LIKE '%("isScopedToStatusPages")%'`,
|
|
419
|
+
);
|
|
420
|
+
|
|
421
|
+
expect(flagIndexes).toEqual([]);
|
|
422
|
+
|
|
423
|
+
const joinIndexes: Array<{ indexdef: string }> = await database.query(
|
|
424
|
+
`SELECT indexdef FROM pg_indexes WHERE schemaname = 'public' AND tablename = 'IncidentStatusPage' AND indexdef LIKE '%("statusPageId")%'`,
|
|
425
|
+
);
|
|
426
|
+
|
|
427
|
+
expect(joinIndexes.length).toBeGreaterThanOrEqual(1);
|
|
428
|
+
});
|
|
429
|
+
});
|
|
430
|
+
|
|
431
|
+
describe("an incident member scopes an incident through IncidentService", () => {
|
|
432
|
+
test("the join rows and the flag are written together", async () => {
|
|
433
|
+
const incidentId: ObjectID = await seedIncident();
|
|
434
|
+
const site03: ObjectID = await seedStatusPage("Site 03");
|
|
435
|
+
const site07: ObjectID = await seedStatusPage("Site 07");
|
|
436
|
+
|
|
437
|
+
expect(await isScoped(incidentId)).toBe(false);
|
|
438
|
+
|
|
439
|
+
await setScope(incidentId, [site03, site07]);
|
|
440
|
+
|
|
441
|
+
expect(await scopeRows(incidentId)).toEqual(sorted([site03, site07]));
|
|
442
|
+
expect(await isScoped(incidentId)).toBe(true);
|
|
443
|
+
|
|
444
|
+
const incident: Incident | null = await IncidentService.findOneById({
|
|
445
|
+
id: incidentId,
|
|
446
|
+
select: {
|
|
447
|
+
isScopedToStatusPages: true,
|
|
448
|
+
statusPages: { _id: true, name: true },
|
|
449
|
+
},
|
|
450
|
+
props: { isRoot: true },
|
|
451
|
+
});
|
|
452
|
+
|
|
453
|
+
expect(
|
|
454
|
+
(incident?.statusPages || [])
|
|
455
|
+
.map((page: StatusPage) => {
|
|
456
|
+
return page.name;
|
|
457
|
+
})
|
|
458
|
+
.sort(),
|
|
459
|
+
).toEqual(["Site 03", "Site 07"]);
|
|
460
|
+
expect(incident?.isScopedToStatusPages).toBe(true);
|
|
461
|
+
});
|
|
462
|
+
|
|
463
|
+
test("clearing the list is the way back to unscoped", async () => {
|
|
464
|
+
const incidentId: ObjectID = await seedIncident();
|
|
465
|
+
const site03: ObjectID = await seedStatusPage("Site 03");
|
|
466
|
+
|
|
467
|
+
await setScope(incidentId, [site03]);
|
|
468
|
+
await setScope(incidentId, []);
|
|
469
|
+
|
|
470
|
+
expect(await scopeRows(incidentId)).toEqual([]);
|
|
471
|
+
expect(await isScoped(incidentId)).toBe(false);
|
|
472
|
+
});
|
|
473
|
+
});
|
|
474
|
+
|
|
475
|
+
describe("deleting a status page never widens an incident's reach", () => {
|
|
476
|
+
test("deleting one of two scoped pages leaves the incident scoped to the other", async () => {
|
|
477
|
+
const incidentId: ObjectID = await seedIncident();
|
|
478
|
+
const site03: ObjectID = await seedStatusPage("Site 03");
|
|
479
|
+
const site07: ObjectID = await seedStatusPage("Site 07");
|
|
480
|
+
|
|
481
|
+
await setScope(incidentId, [site03, site07]);
|
|
482
|
+
await deleteStatusPage(site03);
|
|
483
|
+
|
|
484
|
+
expect(await scopeRows(incidentId)).toEqual([site07.toString()]);
|
|
485
|
+
expect(await isScoped(incidentId)).toBe(true);
|
|
486
|
+
});
|
|
487
|
+
|
|
488
|
+
test("deleting the only scoped page hides the incident instead of broadcasting it", async () => {
|
|
489
|
+
const incidentId: ObjectID = await seedIncident();
|
|
490
|
+
const site03: ObjectID = await seedStatusPage("Site 03");
|
|
491
|
+
// A page the incident was never scoped to, which must stay out of reach.
|
|
492
|
+
await seedStatusPage("Site 05");
|
|
493
|
+
|
|
494
|
+
await setScope(incidentId, [site03]);
|
|
495
|
+
await deleteStatusPage(site03);
|
|
496
|
+
|
|
497
|
+
// The join row went with the page; the flag did not follow it.
|
|
498
|
+
expect(await scopeRows(incidentId)).toEqual([]);
|
|
499
|
+
expect(await isScoped(incidentId)).toBe(true);
|
|
500
|
+
|
|
501
|
+
/*
|
|
502
|
+
* As the status page queries will read it: scoped, and to no page -
|
|
503
|
+
* so no page shows it, instead of every page that lists its monitors.
|
|
504
|
+
*/
|
|
505
|
+
const incident: Incident | null = await IncidentService.findOneById({
|
|
506
|
+
id: incidentId,
|
|
507
|
+
select: {
|
|
508
|
+
isScopedToStatusPages: true,
|
|
509
|
+
statusPages: { _id: true },
|
|
510
|
+
},
|
|
511
|
+
props: { isRoot: true },
|
|
512
|
+
});
|
|
513
|
+
|
|
514
|
+
expect(incident?.isScopedToStatusPages).toBe(true);
|
|
515
|
+
expect(incident?.statusPages || []).toEqual([]);
|
|
516
|
+
});
|
|
517
|
+
|
|
518
|
+
test("a later edit that does not touch the scope keeps the incident hidden", async () => {
|
|
519
|
+
const incidentId: ObjectID = await seedIncident();
|
|
520
|
+
const site03: ObjectID = await seedStatusPage("Site 03");
|
|
521
|
+
|
|
522
|
+
await setScope(incidentId, [site03]);
|
|
523
|
+
await deleteStatusPage(site03);
|
|
524
|
+
|
|
525
|
+
await IncidentService.updateOneById({
|
|
526
|
+
id: incidentId,
|
|
527
|
+
data: { title: "Shared uplink down - investigating" },
|
|
528
|
+
props: memberProps(),
|
|
529
|
+
});
|
|
530
|
+
|
|
531
|
+
expect(await isScoped(incidentId)).toBe(true);
|
|
532
|
+
});
|
|
533
|
+
|
|
534
|
+
test("an unscoped incident stays unscoped when a status page is deleted", async () => {
|
|
535
|
+
const incidentId: ObjectID = await seedIncident();
|
|
536
|
+
const site03: ObjectID = await seedStatusPage("Site 03");
|
|
537
|
+
|
|
538
|
+
await deleteStatusPage(site03);
|
|
539
|
+
|
|
540
|
+
expect(await isScoped(incidentId)).toBe(false);
|
|
541
|
+
});
|
|
542
|
+
|
|
543
|
+
test("deleting an incident takes its scope rows, and leaves the status pages", async () => {
|
|
544
|
+
const incidentId: ObjectID = await seedIncident();
|
|
545
|
+
const site03: ObjectID = await seedStatusPage("Site 03");
|
|
546
|
+
|
|
547
|
+
await setScope(incidentId, [site03]);
|
|
548
|
+
await database.query(
|
|
549
|
+
`DELETE FROM "${schema}"."Incident" WHERE "_id" = $1`,
|
|
550
|
+
[incidentId.toString()],
|
|
551
|
+
);
|
|
552
|
+
|
|
553
|
+
expect(await scopeRows(incidentId)).toEqual([]);
|
|
554
|
+
const pages: Array<{ count: string }> = await database.query(
|
|
555
|
+
`SELECT count(*)::text AS "count" FROM "${schema}"."StatusPage" WHERE "_id" = $1`,
|
|
556
|
+
[site03.toString()],
|
|
557
|
+
);
|
|
558
|
+
expect(pages[0]!.count).toBe("1");
|
|
559
|
+
});
|
|
560
|
+
|
|
561
|
+
test("deleting a template's status page takes the template's row with it", async () => {
|
|
562
|
+
const templateId: ObjectID = await seedTemplate();
|
|
563
|
+
const site03: ObjectID = await seedStatusPage("Site 03");
|
|
564
|
+
const site07: ObjectID = await seedStatusPage("Site 07");
|
|
565
|
+
|
|
566
|
+
for (const statusPageId of [site03, site07]) {
|
|
567
|
+
await database.query(
|
|
568
|
+
`INSERT INTO "${schema}"."IncidentTemplateStatusPage" ("incidentTemplateId", "statusPageId") VALUES ($1, $2)`,
|
|
569
|
+
[templateId.toString(), statusPageId.toString()],
|
|
570
|
+
);
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
await deleteStatusPage(site03);
|
|
574
|
+
|
|
575
|
+
const rows: Array<{ statusPageId: string }> = await database.query(
|
|
576
|
+
`SELECT "statusPageId" FROM "${schema}"."IncidentTemplateStatusPage" WHERE "incidentTemplateId" = $1`,
|
|
577
|
+
[templateId.toString()],
|
|
578
|
+
);
|
|
579
|
+
|
|
580
|
+
expect(
|
|
581
|
+
rows.map((row: { statusPageId: string }) => {
|
|
582
|
+
return row.statusPageId;
|
|
583
|
+
}),
|
|
584
|
+
).toEqual([site07.toString()]);
|
|
585
|
+
});
|
|
586
|
+
|
|
587
|
+
test("a template whose every page was deleted stays scoped, so its incidents are hidden rather than broadcast", async () => {
|
|
588
|
+
const templateId: ObjectID = await seedTemplate();
|
|
589
|
+
const site03: ObjectID = await seedStatusPage("Site 03");
|
|
590
|
+
|
|
591
|
+
await database.query(
|
|
592
|
+
`INSERT INTO "${schema}"."IncidentTemplateStatusPage" ("incidentTemplateId", "statusPageId") VALUES ($1, $2)`,
|
|
593
|
+
[templateId.toString(), site03.toString()],
|
|
594
|
+
);
|
|
595
|
+
// What IncidentTemplateService writes with the list.
|
|
596
|
+
await database.query(
|
|
597
|
+
`UPDATE "${schema}"."IncidentTemplate" SET "isScopedToStatusPages" = true WHERE "_id" = $1`,
|
|
598
|
+
[templateId.toString()],
|
|
599
|
+
);
|
|
600
|
+
|
|
601
|
+
await deleteStatusPage(site03);
|
|
602
|
+
|
|
603
|
+
const rows: Array<{ isScopedToStatusPages: boolean; pages: string }> =
|
|
604
|
+
await database.query(
|
|
605
|
+
`SELECT t."isScopedToStatusPages", (SELECT COUNT(*) FROM "${schema}"."IncidentTemplateStatusPage" j WHERE j."incidentTemplateId" = t."_id")::text AS pages FROM "${schema}"."IncidentTemplate" t WHERE t."_id" = $1`,
|
|
606
|
+
[templateId.toString()],
|
|
607
|
+
);
|
|
608
|
+
|
|
609
|
+
expect(rows).toEqual([{ isScopedToStatusPages: true, pages: "0" }]);
|
|
610
|
+
});
|
|
611
|
+
|
|
612
|
+
test("a new template starts unscoped", async () => {
|
|
613
|
+
const templateId: ObjectID = await seedTemplate();
|
|
614
|
+
|
|
615
|
+
const rows: Array<{ isScopedToStatusPages: boolean }> =
|
|
616
|
+
await database.query(
|
|
617
|
+
`SELECT "isScopedToStatusPages" FROM "${schema}"."IncidentTemplate" WHERE "_id" = $1`,
|
|
618
|
+
[templateId.toString()],
|
|
619
|
+
);
|
|
620
|
+
|
|
621
|
+
expect(rows).toEqual([{ isScopedToStatusPages: false }]);
|
|
622
|
+
});
|
|
623
|
+
});
|
|
624
|
+
},
|
|
625
|
+
);
|