@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,225 @@
|
|
|
1
|
+
import { JSONObject } from "../JSON";
|
|
2
|
+
|
|
3
|
+
/*
|
|
4
|
+
* How a saved table view (TableView) refers to a custom field, and what
|
|
5
|
+
* renaming a field does to those references.
|
|
6
|
+
*
|
|
7
|
+
* Custom field values are keyed by the field's display name, and so is
|
|
8
|
+
* everything a saved view remembers about one:
|
|
9
|
+
*
|
|
10
|
+
* - TableView.columns = { order: [...ids], hidden: [...ids] }, where a
|
|
11
|
+
* custom field's column id is "customFields.<name>"
|
|
12
|
+
* (CustomFieldColumns.getCustomFieldColumns);
|
|
13
|
+
* - TableView.facets.facetSelections and .facetOperators, keyed by the
|
|
14
|
+
* facet chip's key "customField:<name>" (Dashboard CustomFieldFacets);
|
|
15
|
+
* - TableView.query, the table's own filters, which would hold a custom
|
|
16
|
+
* field under query.customFields["<name>"].
|
|
17
|
+
*
|
|
18
|
+
* A rename that moved the values but not these would leave every saved view
|
|
19
|
+
* pointing at a field that no longer exists: the column silently drops out
|
|
20
|
+
* and the filter chip is discarded as stale. Both prefixes live here so the
|
|
21
|
+
* table, the facet bar and the rename share one spelling.
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
// Column id of a custom field column: "customFields.Severity".
|
|
25
|
+
export const CUSTOM_FIELD_COLUMN_ID_PREFIX: string = "customFields.";
|
|
26
|
+
|
|
27
|
+
// Facet chip key of a custom field: "customField:Severity".
|
|
28
|
+
export const CUSTOM_FIELD_FACET_KEY_PREFIX: string = "customField:";
|
|
29
|
+
|
|
30
|
+
/*
|
|
31
|
+
* The saved views whose table shows incident custom fields. Only tables that
|
|
32
|
+
* offer saved views (a saveFilterProps.tableId) can have any; today that is
|
|
33
|
+
* the Incidents list. App/Tests/Dashboard/IncidentCustomFieldSavedViews
|
|
34
|
+
* fails if a table of incidents gains saved views without being listed.
|
|
35
|
+
*/
|
|
36
|
+
export const INCIDENT_CUSTOM_FIELD_TABLE_VIEW_IDS: Array<string> = [
|
|
37
|
+
"all-incidents-table",
|
|
38
|
+
];
|
|
39
|
+
|
|
40
|
+
export interface CustomFieldSavedViewState {
|
|
41
|
+
query?: JSONObject | null | undefined;
|
|
42
|
+
facets?: JSONObject | null | undefined;
|
|
43
|
+
columns?: JSONObject | null | undefined;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export interface RenamedCustomFieldSavedViewState {
|
|
47
|
+
/*
|
|
48
|
+
* Only the parts that changed, as the whole new value of that column.
|
|
49
|
+
* Empty when the view does not mention the field.
|
|
50
|
+
*/
|
|
51
|
+
changes: CustomFieldSavedViewState;
|
|
52
|
+
hasChanged: boolean;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
type IsObjectFunction = (value: unknown) => value is JSONObject;
|
|
56
|
+
|
|
57
|
+
const isObject: IsObjectFunction = (value: unknown): value is JSONObject => {
|
|
58
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
type RenameKeyFunction = (
|
|
62
|
+
object: JSONObject,
|
|
63
|
+
oldKey: string,
|
|
64
|
+
newKey: string,
|
|
65
|
+
) => JSONObject | null;
|
|
66
|
+
|
|
67
|
+
/*
|
|
68
|
+
* A copy of `object` with `oldKey` renamed, keeping the key's position, or
|
|
69
|
+
* null when there is no such key. The renamed value wins over anything the
|
|
70
|
+
* new key already held, as it does for the values themselves.
|
|
71
|
+
*/
|
|
72
|
+
const renameKey: RenameKeyFunction = (
|
|
73
|
+
object: JSONObject,
|
|
74
|
+
oldKey: string,
|
|
75
|
+
newKey: string,
|
|
76
|
+
): JSONObject | null => {
|
|
77
|
+
if (!Object.prototype.hasOwnProperty.call(object, oldKey)) {
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const renamed: JSONObject = {};
|
|
82
|
+
|
|
83
|
+
for (const [key, value] of Object.entries(object)) {
|
|
84
|
+
if (key === oldKey) {
|
|
85
|
+
renamed[newKey] = value;
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (key === newKey) {
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
renamed[key] = value;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return renamed;
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
type RenameInListFunction = (
|
|
100
|
+
list: unknown,
|
|
101
|
+
oldEntry: string,
|
|
102
|
+
newEntry: string,
|
|
103
|
+
) => Array<unknown> | null;
|
|
104
|
+
|
|
105
|
+
// A copy of the list with the entry renamed (and not doubled), or null.
|
|
106
|
+
const renameInList: RenameInListFunction = (
|
|
107
|
+
list: unknown,
|
|
108
|
+
oldEntry: string,
|
|
109
|
+
newEntry: string,
|
|
110
|
+
): Array<unknown> | null => {
|
|
111
|
+
if (!Array.isArray(list) || !list.includes(oldEntry)) {
|
|
112
|
+
return null;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const renamed: Array<unknown> = [];
|
|
116
|
+
|
|
117
|
+
for (const entry of list) {
|
|
118
|
+
const next: unknown = entry === oldEntry ? newEntry : entry;
|
|
119
|
+
|
|
120
|
+
if (next === newEntry && renamed.includes(newEntry)) {
|
|
121
|
+
continue;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
renamed.push(next);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
return renamed;
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
export type RenameCustomFieldInSavedViewFunction = (data: {
|
|
131
|
+
view: CustomFieldSavedViewState;
|
|
132
|
+
oldName: string;
|
|
133
|
+
newName: string;
|
|
134
|
+
}) => RenamedCustomFieldSavedViewState;
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* What a saved view has to become when a custom field it mentions is
|
|
138
|
+
* renamed from `oldName` to `newName`. Everything else in the view is kept
|
|
139
|
+
* exactly as it was.
|
|
140
|
+
*/
|
|
141
|
+
export const renameCustomFieldInSavedView: RenameCustomFieldInSavedViewFunction =
|
|
142
|
+
(data: {
|
|
143
|
+
view: CustomFieldSavedViewState;
|
|
144
|
+
oldName: string;
|
|
145
|
+
newName: string;
|
|
146
|
+
}): RenamedCustomFieldSavedViewState => {
|
|
147
|
+
const changes: CustomFieldSavedViewState = {};
|
|
148
|
+
|
|
149
|
+
if (!data.oldName || !data.newName || data.oldName === data.newName) {
|
|
150
|
+
return { changes, hasChanged: false };
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// Columns: the column ids in the viewer's order and hidden lists.
|
|
154
|
+
if (isObject(data.view.columns)) {
|
|
155
|
+
const oldId: string = `${CUSTOM_FIELD_COLUMN_ID_PREFIX}${data.oldName}`;
|
|
156
|
+
const newId: string = `${CUSTOM_FIELD_COLUMN_ID_PREFIX}${data.newName}`;
|
|
157
|
+
const columns: JSONObject = { ...data.view.columns };
|
|
158
|
+
let changed: boolean = false;
|
|
159
|
+
|
|
160
|
+
for (const listName of ["order", "hidden"]) {
|
|
161
|
+
const renamed: Array<unknown> | null = renameInList(
|
|
162
|
+
columns[listName],
|
|
163
|
+
oldId,
|
|
164
|
+
newId,
|
|
165
|
+
);
|
|
166
|
+
|
|
167
|
+
if (renamed) {
|
|
168
|
+
columns[listName] = renamed as JSONObject[string];
|
|
169
|
+
changed = true;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
if (changed) {
|
|
174
|
+
changes.columns = columns;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// Facets: the chip's selection and operator, keyed by the chip.
|
|
179
|
+
if (isObject(data.view.facets)) {
|
|
180
|
+
const oldKey: string = `${CUSTOM_FIELD_FACET_KEY_PREFIX}${data.oldName}`;
|
|
181
|
+
const newKey: string = `${CUSTOM_FIELD_FACET_KEY_PREFIX}${data.newName}`;
|
|
182
|
+
const facets: JSONObject = { ...data.view.facets };
|
|
183
|
+
let changed: boolean = false;
|
|
184
|
+
|
|
185
|
+
for (const mapName of ["facetSelections", "facetOperators"]) {
|
|
186
|
+
const map: unknown = facets[mapName];
|
|
187
|
+
|
|
188
|
+
if (!isObject(map)) {
|
|
189
|
+
continue;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
const renamed: JSONObject | null = renameKey(map, oldKey, newKey);
|
|
193
|
+
|
|
194
|
+
if (renamed) {
|
|
195
|
+
facets[mapName] = renamed;
|
|
196
|
+
changed = true;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
if (changed) {
|
|
201
|
+
changes.facets = facets;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// The table's own filters, should one ever filter on a custom field.
|
|
206
|
+
if (
|
|
207
|
+
isObject(data.view.query) &&
|
|
208
|
+
isObject(data.view.query["customFields"])
|
|
209
|
+
) {
|
|
210
|
+
const renamed: JSONObject | null = renameKey(
|
|
211
|
+
data.view.query["customFields"],
|
|
212
|
+
data.oldName,
|
|
213
|
+
data.newName,
|
|
214
|
+
);
|
|
215
|
+
|
|
216
|
+
if (renamed) {
|
|
217
|
+
changes.query = { ...data.view.query, customFields: renamed };
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
return {
|
|
222
|
+
changes: changes,
|
|
223
|
+
hasChanged: Object.keys(changes).length > 0,
|
|
224
|
+
};
|
|
225
|
+
};
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { JSONObject } from "../JSON";
|
|
2
|
+
|
|
3
|
+
/*
|
|
4
|
+
* An incident template's custom field values, copied onto an incident being
|
|
5
|
+
* declared from it.
|
|
6
|
+
*
|
|
7
|
+
* A MERGE, never a replacement: the template fills in the fields the incident
|
|
8
|
+
* does not set, and a value the incident does set - the answer someone typed
|
|
9
|
+
* on the Details step, or one an API caller sent - always wins. A key set to
|
|
10
|
+
* null or an empty string wins too: that is an explicit "no value" for that
|
|
11
|
+
* field, not a gap for the template to fill.
|
|
12
|
+
*
|
|
13
|
+
* Shared by the server, which copies a template's values when an incident is
|
|
14
|
+
* created with `createdIncidentTemplateId`, and kept pure so it is tested on
|
|
15
|
+
* its own. (The dashboard's Create page merges on the client instead, with
|
|
16
|
+
* the Details step's values on top: see packCustomFieldFormValues.)
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
type IsPlainObjectFunction = (value: unknown) => value is JSONObject;
|
|
20
|
+
|
|
21
|
+
const isPlainObject: IsPlainObjectFunction = (
|
|
22
|
+
value: unknown,
|
|
23
|
+
): value is JSONObject => {
|
|
24
|
+
return (
|
|
25
|
+
value !== null &&
|
|
26
|
+
typeof value === "object" &&
|
|
27
|
+
!Array.isArray(value) &&
|
|
28
|
+
!(value instanceof Date)
|
|
29
|
+
);
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
export type MergeTemplateCustomFieldsFunction = (data: {
|
|
33
|
+
// The template's bag, keyed by field name.
|
|
34
|
+
templateCustomFields: unknown;
|
|
35
|
+
// What the incident is being created with, if anything.
|
|
36
|
+
customFields: unknown;
|
|
37
|
+
}) => JSONObject | undefined;
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* The incident's bag with the template's values filled in, or undefined when
|
|
41
|
+
* there is nothing to change: the template has no values, or the incident's
|
|
42
|
+
* `customFields` is something other than a bag (which is left exactly as it
|
|
43
|
+
* was sent, for the caller's own mistake to surface as it would have).
|
|
44
|
+
*/
|
|
45
|
+
export const mergeTemplateCustomFields: MergeTemplateCustomFieldsFunction =
|
|
46
|
+
(data: {
|
|
47
|
+
templateCustomFields: unknown;
|
|
48
|
+
customFields: unknown;
|
|
49
|
+
}): JSONObject | undefined => {
|
|
50
|
+
if (
|
|
51
|
+
!isPlainObject(data.templateCustomFields) ||
|
|
52
|
+
Object.keys(data.templateCustomFields).length === 0
|
|
53
|
+
) {
|
|
54
|
+
return undefined;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (data.customFields === undefined || data.customFields === null) {
|
|
58
|
+
return { ...data.templateCustomFields };
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (!isPlainObject(data.customFields)) {
|
|
62
|
+
return undefined;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return {
|
|
66
|
+
...data.templateCustomFields,
|
|
67
|
+
...data.customFields,
|
|
68
|
+
};
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
export default mergeTemplateCustomFields;
|
|
@@ -32,6 +32,20 @@ enum CustomFieldType {
|
|
|
32
32
|
* decommissioned at.
|
|
33
33
|
*/
|
|
34
34
|
DateTime = "DateTime",
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Several lines of plain text — additional information, affected users or
|
|
38
|
+
* systems. Stored as a string, exactly like `Text`; only the input (a text
|
|
39
|
+
* area) and the rendering (line breaks kept) differ.
|
|
40
|
+
*/
|
|
41
|
+
LongText = "LongText",
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Rich text, written in the Markdown editor (which has a visual mode) and
|
|
45
|
+
* stored as the Markdown source string. Anything that renders it must go
|
|
46
|
+
* through the Markdown renderer, never insert it as HTML.
|
|
47
|
+
*/
|
|
48
|
+
Markdown = "Markdown",
|
|
35
49
|
}
|
|
36
50
|
|
|
37
51
|
export default CustomFieldType;
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import { isCustomFieldValueEmpty } from "./CustomFieldValueMapping";
|
|
2
|
+
|
|
3
|
+
/*
|
|
4
|
+
* How a stored custom field value reads as words, for everything that puts a
|
|
5
|
+
* value in front of a person outside the Custom Fields card: an incident
|
|
6
|
+
* note's {{customFields.<key>}} placeholder (Common/Utils/Incident/
|
|
7
|
+
* IncidentNoteTemplateVariables) and the status page subscriber messages
|
|
8
|
+
* (Common/Server/Utils/StatusPage/IncidentTemplateVariableBuilder).
|
|
9
|
+
*
|
|
10
|
+
* Only the reading is shared here. Where the words then go decides the rest:
|
|
11
|
+
* a note escapes them as Markdown, an email as HTML, an SMS takes them as
|
|
12
|
+
* they are. A date and time reads in the note author's time zone in a note,
|
|
13
|
+
* and in the status page's subscriber time zones in its emails, so that is
|
|
14
|
+
* left to the caller too.
|
|
15
|
+
*
|
|
16
|
+
* Pure, with no database or React imports, so the server and the dashboard
|
|
17
|
+
* share it and it is tested directly.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
/*
|
|
21
|
+
* A day with no time zone: "2026-09-27", or a wall-clock time on it with no
|
|
22
|
+
* offset ("2026-09-27T00:00:00"). Its day is the one it names, wherever it is
|
|
23
|
+
* read.
|
|
24
|
+
*/
|
|
25
|
+
const DAY_WITHOUT_TIME_ZONE_PATTERN: RegExp =
|
|
26
|
+
/^(\d{4}-\d{2}-\d{2})(?:[T ]\d{2}:\d{2}(?::\d{2}(?:\.\d+)?)?)?$/;
|
|
27
|
+
|
|
28
|
+
/*
|
|
29
|
+
* What a Date value's instant is moved by before its UTC day is read; see
|
|
30
|
+
* formatCustomFieldCalendarDate.
|
|
31
|
+
*/
|
|
32
|
+
const PICKED_DAY_SHIFT_MS: number = 13 * 60 * 60 * 1000;
|
|
33
|
+
|
|
34
|
+
export type CustomFieldValueToTextFunction = (value: unknown) => string;
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Plain text for a value of no particular type: a list joined with commas
|
|
38
|
+
* (its empty entries left out), a Date as its ISO string, an object as JSON,
|
|
39
|
+
* anything else as String() gives it. null and undefined are "".
|
|
40
|
+
*/
|
|
41
|
+
export const customFieldValueToText: CustomFieldValueToTextFunction = (
|
|
42
|
+
value: unknown,
|
|
43
|
+
): string => {
|
|
44
|
+
if (value === null || value === undefined) {
|
|
45
|
+
return "";
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (Array.isArray(value)) {
|
|
49
|
+
return value
|
|
50
|
+
.filter((entry: unknown): boolean => {
|
|
51
|
+
return !isCustomFieldValueEmpty(entry);
|
|
52
|
+
})
|
|
53
|
+
.map((entry: unknown): string => {
|
|
54
|
+
return customFieldValueToText(entry);
|
|
55
|
+
})
|
|
56
|
+
.join(", ");
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (value instanceof Date) {
|
|
60
|
+
return isNaN(value.getTime()) ? "" : value.toISOString();
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (typeof value === "object") {
|
|
64
|
+
try {
|
|
65
|
+
return JSON.stringify(value);
|
|
66
|
+
} catch {
|
|
67
|
+
return String(value);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return String(value);
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
export type CustomFieldValueToDateFunction = (value: unknown) => Date | null;
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* The instant a Date or DateTime value holds, or null when it holds none
|
|
78
|
+
* (an empty string, text that is not a date).
|
|
79
|
+
*/
|
|
80
|
+
export const customFieldValueToDate: CustomFieldValueToDateFunction = (
|
|
81
|
+
value: unknown,
|
|
82
|
+
): Date | null => {
|
|
83
|
+
if (value instanceof Date) {
|
|
84
|
+
return isNaN(value.getTime()) ? null : value;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if (typeof value === "string" && value.trim().length > 0) {
|
|
88
|
+
const date: Date = new Date(value.trim());
|
|
89
|
+
return isNaN(date.getTime()) ? null : date;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return null;
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
export type FormatCustomFieldBooleanFunction = (value: unknown) => string;
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Yes or No for a Boolean value, which is stored as true or false (or, from
|
|
99
|
+
* an older form, as "true" or "false"). Anything else reads as it is.
|
|
100
|
+
*/
|
|
101
|
+
export const formatCustomFieldBoolean: FormatCustomFieldBooleanFunction = (
|
|
102
|
+
value: unknown,
|
|
103
|
+
): string => {
|
|
104
|
+
if (value === true || value === "true") {
|
|
105
|
+
return "Yes";
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
if (value === false || value === "false") {
|
|
109
|
+
return "No";
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return customFieldValueToText(value);
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
export type FormatCustomFieldCalendarDateFunction = (value: unknown) => string;
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* A Date value - a calendar day with no time of day - as the day that was
|
|
119
|
+
* picked, "2026-09-27". A value that is no date reads as it is.
|
|
120
|
+
*
|
|
121
|
+
* The dashboard does not store the day itself. Its date input stores the
|
|
122
|
+
* picked day's midnight in the author's time zone, as a UTC instant: 27 Sep
|
|
123
|
+
* picked in Berlin (UTC+2) is "2026-09-26T22:00:00.000Z", in New York
|
|
124
|
+
* (UTC-4) "2026-09-27T04:00:00.000Z". So neither the UTC day of the instant
|
|
125
|
+
* (26 Sep for Berlin: every author east of UTC would get the day before) nor
|
|
126
|
+
* the reader's day (a reader in another zone than the author's) is the day
|
|
127
|
+
* that was picked, and who picked it, and where, is not stored.
|
|
128
|
+
*
|
|
129
|
+
* The instant is read as the nearest plausible local midnight instead: moved
|
|
130
|
+
* 13 hours on, its UTC day is the picked day for an author anywhere from
|
|
131
|
+
* UTC-10:59 to UTC+13:00 - Hawaii to New Zealand in summer - and for a value
|
|
132
|
+
* an API client stored as UTC midnight. Only an author in UTC-11 or UTC-12,
|
|
133
|
+
* or past UTC+13, gets the day after or the day before. It is the same day
|
|
134
|
+
* whoever reads it, so a note and an email about one incident agree.
|
|
135
|
+
*
|
|
136
|
+
* A bare day ("2026-09-27"), or a time with no offset, is the day it names.
|
|
137
|
+
*/
|
|
138
|
+
export const formatCustomFieldCalendarDate: FormatCustomFieldCalendarDateFunction =
|
|
139
|
+
(value: unknown): string => {
|
|
140
|
+
const match: RegExpMatchArray | null =
|
|
141
|
+
typeof value === "string"
|
|
142
|
+
? value.trim().match(DAY_WITHOUT_TIME_ZONE_PATTERN)
|
|
143
|
+
: null;
|
|
144
|
+
|
|
145
|
+
if (match) {
|
|
146
|
+
return match[1]!;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
const date: Date | null = customFieldValueToDate(value);
|
|
150
|
+
|
|
151
|
+
const pickedDay: Date | null = date
|
|
152
|
+
? new Date(date.getTime() + PICKED_DAY_SHIFT_MS)
|
|
153
|
+
: null;
|
|
154
|
+
|
|
155
|
+
// Invalid only at the very end of the range a Date can hold.
|
|
156
|
+
if (!pickedDay || isNaN(pickedDay.getTime())) {
|
|
157
|
+
return customFieldValueToText(value);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
return pickedDay.toISOString().slice(0, 10);
|
|
161
|
+
};
|