@oneuptime/common 12.0.29 → 12.0.31
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/AnalyticsModels/SecurityEvent.ts +48 -16
- package/Models/AnalyticsModels/ThreatIntelIndicator.ts +10 -5
- package/Models/DatabaseModels/AlertSeverity.ts +44 -0
- package/Models/DatabaseModels/DetectionRule.ts +16 -5
- package/Models/DatabaseModels/GoogleSecOpsConnection.ts +14 -5
- package/Models/DatabaseModels/IncidentSeverity.ts +44 -0
- package/Models/DatabaseModels/Index.ts +13 -0
- package/Models/DatabaseModels/NetworkDevice.ts +113 -3
- package/Models/DatabaseModels/NetworkDeviceAutoImportRule.ts +88 -0
- package/Models/DatabaseModels/NetworkDeviceDiscoveryScan.ts +22 -0
- package/Models/DatabaseModels/NetworkDeviceOidTemplate.ts +499 -0
- package/Models/DatabaseModels/OnCallDutyPolicySchedule.ts +43 -0
- package/Models/DatabaseModels/OnCallDutyPolicyScheduleCalendarFeed.ts +662 -0
- package/Models/DatabaseModels/ProjectOnCallCalendarFeed.ts +584 -0
- package/Models/DatabaseModels/ThreatIntelFeed.ts +16 -5
- package/Models/DatabaseModels/UserOnCallCalendarFeed.ts +546 -0
- package/Models/DatabaseModels/UserOnCallShiftReminder.ts +231 -0
- package/Models/DatabaseModels/UserOnCallShiftReminderLog.ts +331 -0
- package/Server/API/GlobalConfigAPI.ts +362 -183
- package/Server/API/OnCallCalendarAPI.ts +2194 -0
- package/Server/API/TelemetryAPI.ts +42 -4
- package/Server/EnvironmentConfig.ts +250 -0
- package/Server/Infrastructure/OnCallCalendarFeedCache.ts +1050 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1790400000000-AddOnCallCalendarFeeds.ts +253 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1790500000000-AddNetworkDeviceOidTemplate.ts +59 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1790600000000-AddAutoImportRuleOidTemplate.ts +25 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +6 -0
- package/Server/Middleware/MultipartFormData.ts +118 -32
- package/Server/Middleware/OnCallCalendarFeedRateLimit.ts +487 -0
- package/Server/Services/AlertEpisodeLabelRuleEngineService.ts +9 -1
- package/Server/Services/AlertEpisodeOnCallRuleEngineService.ts +9 -1
- package/Server/Services/AlertEpisodeOwnerRuleEngineService.ts +9 -1
- package/Server/Services/AlertEpisodePrivacyRuleEngineService.ts +9 -1
- package/Server/Services/AlertGroupingEngineService.ts +9 -1
- package/Server/Services/AlertLabelRuleEngineService.ts +9 -1
- package/Server/Services/AlertOnCallRuleEngineService.ts +9 -1
- package/Server/Services/AlertOwnerRuleEngineService.ts +9 -1
- package/Server/Services/AlertPrivacyRuleEngineService.ts +9 -1
- package/Server/Services/AlertReminderRuleService.ts +9 -1
- package/Server/Services/AutoRemediationRuleEngineService.ts +9 -1
- package/Server/Services/CephClusterLabelRuleEngineService.ts +9 -1
- package/Server/Services/CephClusterOwnerRuleEngineService.ts +9 -1
- package/Server/Services/CloudResourceLabelRuleEngineService.ts +9 -1
- package/Server/Services/CloudResourceOwnerRuleEngineService.ts +9 -1
- package/Server/Services/DashboardLabelRuleEngineService.ts +9 -1
- package/Server/Services/DashboardOwnerRuleEngineService.ts +9 -1
- package/Server/Services/DockerHostLabelRuleEngineService.ts +9 -1
- package/Server/Services/DockerHostOwnerRuleEngineService.ts +9 -1
- package/Server/Services/DockerSwarmClusterLabelRuleEngineService.ts +9 -1
- package/Server/Services/DockerSwarmClusterOwnerRuleEngineService.ts +9 -1
- package/Server/Services/HostLabelRuleEngineService.ts +9 -1
- package/Server/Services/HostOwnerRuleEngineService.ts +9 -1
- package/Server/Services/IncidentEpisodeLabelRuleEngineService.ts +9 -1
- package/Server/Services/IncidentEpisodeOnCallRuleEngineService.ts +9 -1
- package/Server/Services/IncidentEpisodeOwnerRuleEngineService.ts +9 -1
- package/Server/Services/IncidentEpisodePrivacyRuleEngineService.ts +9 -1
- package/Server/Services/IncidentGroupingEngineService.ts +9 -1
- package/Server/Services/IncidentLabelRuleEngineService.ts +9 -1
- package/Server/Services/IncidentOnCallRuleEngineService.ts +9 -1
- package/Server/Services/IncidentOwnerRuleEngineService.ts +9 -1
- package/Server/Services/IncidentPrivacyRuleEngineService.ts +9 -1
- package/Server/Services/IncidentReminderRuleService.ts +9 -1
- package/Server/Services/IncidentSlaRuleService.ts +9 -1
- package/Server/Services/IncomingCallPolicyLabelRuleEngineService.ts +9 -1
- package/Server/Services/IncomingCallPolicyOwnerRuleEngineService.ts +9 -1
- package/Server/Services/Index.ts +14 -0
- package/Server/Services/IoTFleetLabelRuleEngineService.ts +9 -1
- package/Server/Services/IoTFleetOwnerRuleEngineService.ts +9 -1
- package/Server/Services/KubernetesClusterLabelRuleEngineService.ts +9 -1
- package/Server/Services/KubernetesClusterOwnerRuleEngineService.ts +9 -1
- package/Server/Services/KubernetesResourceService.ts +5 -1
- package/Server/Services/MonitorLabelRuleEngineService.ts +9 -1
- package/Server/Services/MonitorOwnerRuleEngineService.ts +9 -1
- package/Server/Services/NetworkDeviceAutoImportRuleEngineService.ts +35 -0
- package/Server/Services/NetworkDeviceAutoImportRuleService.ts +96 -0
- package/Server/Services/NetworkDeviceLabelRuleEngineService.ts +9 -1
- package/Server/Services/NetworkDeviceOidTemplateService.ts +201 -0
- package/Server/Services/NetworkDeviceOwnerRuleEngineService.ts +9 -1
- package/Server/Services/NetworkDeviceService.ts +209 -1
- package/Server/Services/OnCallDutyPolicyEscalationRuleScheduleService.ts +32 -0
- package/Server/Services/OnCallDutyPolicyLabelRuleEngineService.ts +9 -1
- package/Server/Services/OnCallDutyPolicyOwnerRuleEngineService.ts +9 -1
- package/Server/Services/OnCallDutyPolicyScheduleCalendarFeedService.ts +260 -0
- package/Server/Services/OnCallDutyPolicyScheduleLabelRuleEngineService.ts +9 -1
- package/Server/Services/OnCallDutyPolicyScheduleLayerService.ts +70 -3
- package/Server/Services/OnCallDutyPolicyScheduleLayerUserService.ts +138 -3
- package/Server/Services/OnCallDutyPolicyScheduleOwnerRuleEngineService.ts +9 -1
- package/Server/Services/OnCallDutyPolicyScheduleService.ts +1465 -134
- package/Server/Services/OnCallDutyPolicyUserOverrideService.ts +167 -31
- package/Server/Services/PodmanHostLabelRuleEngineService.ts +9 -1
- package/Server/Services/PodmanHostOwnerRuleEngineService.ts +9 -1
- package/Server/Services/ProjectOnCallCalendarFeedService.ts +192 -0
- package/Server/Services/ProxmoxClusterLabelRuleEngineService.ts +9 -1
- package/Server/Services/ProxmoxClusterOwnerRuleEngineService.ts +9 -1
- package/Server/Services/RumApplicationLabelRuleEngineService.ts +9 -1
- package/Server/Services/RumApplicationOwnerRuleEngineService.ts +9 -1
- package/Server/Services/RunbookLabelRuleEngineService.ts +9 -1
- package/Server/Services/RunbookOwnerRuleEngineService.ts +9 -1
- package/Server/Services/RunbookRuleEngineService.ts +9 -1
- package/Server/Services/ScheduledMaintenanceLabelRuleEngineService.ts +9 -1
- package/Server/Services/ScheduledMaintenanceOwnerRuleEngineService.ts +9 -1
- package/Server/Services/ScheduledMaintenanceReminderRuleService.ts +9 -1
- package/Server/Services/ServerlessFunctionLabelRuleEngineService.ts +9 -1
- package/Server/Services/ServerlessFunctionOwnerRuleEngineService.ts +9 -1
- package/Server/Services/ServiceLabelRuleEngineService.ts +9 -1
- package/Server/Services/ServiceOwnerRuleEngineService.ts +9 -1
- package/Server/Services/StatusPageLabelRuleEngineService.ts +9 -1
- package/Server/Services/StatusPageMonitorRuleEngineService.ts +7 -0
- package/Server/Services/StatusPageOwnerRuleEngineService.ts +9 -1
- package/Server/Services/TeamMemberService.ts +489 -1
- package/Server/Services/TeamService.ts +50 -0
- package/Server/Services/TelemetrySourceMapService.ts +266 -23
- package/Server/Services/UserNotificationSettingService.ts +44 -1
- package/Server/Services/UserOnCallCalendarFeedService.ts +159 -0
- package/Server/Services/UserOnCallShiftReminderLogService.ts +151 -0
- package/Server/Services/UserOnCallShiftReminderService.ts +112 -0
- package/Server/Services/UserService.ts +27 -0
- package/Server/Services/WorkflowLabelRuleEngineService.ts +9 -1
- package/Server/Services/WorkflowOwnerRuleEngineService.ts +9 -1
- package/Server/Utils/EnterpriseLicense/EnterpriseLicenseSeatUtil.ts +186 -0
- package/Server/Utils/Monitor/CapturedMetricAttributeUtil.ts +245 -0
- package/Server/Utils/Monitor/Criteria/SnmpMonitorCriteria.ts +21 -2
- package/Server/Utils/Monitor/MonitorMetricUtil.ts +55 -21
- package/Server/Utils/Monitor/MonitorTemplateUtil.ts +32 -0
- package/Server/Utils/Monitor/NetworkDeviceMetricUtil.ts +15 -2
- package/Server/Utils/Monitor/NetworkDeviceWalkUtil.ts +18 -1
- package/Server/Utils/Monitor/NetworkInventoryUtil.ts +10 -0
- package/Server/Utils/Monitor/SeriesResourceLabels.ts +34 -0
- package/Server/Utils/OnCall/CalendarFeedToken.ts +241 -0
- package/Server/Utils/OnCall/OnCallCalendarFeedRenderer.ts +1488 -0
- package/Server/Utils/OnCall/OnCallCalendarFeedUrls.ts +230 -0
- package/Server/Utils/OnCall/OnCallShiftChangeListeners.ts +227 -0
- package/Server/Utils/OnCall/OnCallShiftMaterializer.ts +1127 -0
- package/Server/Utils/OnCall/OnCallShiftReminderListener.ts +174 -0
- package/Server/Utils/OnCall/OnCallShiftReminderRunner.ts +2584 -0
- package/Server/Utils/Response.ts +134 -0
- package/Server/Utils/Rules/RuleEngineRuleRead.ts +48 -0
- package/Server/Utils/StartServer.ts +10 -0
- package/Server/Utils/Telemetry/AppMetrics.ts +51 -0
- package/Server/Utils/Telemetry/ExceptionSanitizer.ts +14 -1
- package/Server/Utils/Telemetry/LogExceptionExtractor.ts +14 -2
- package/Server/Utils/Telemetry/SourceMapResolver.ts +16 -5
- package/Server/Utils/Telemetry/StackTraceParser.ts +399 -0
- package/Tests/App/Dashboard/EventOverlayHook.test.tsx +125 -0
- package/Tests/App/Dashboard/HeaderImageAssets.test.tsx +93 -0
- package/Tests/App/Dashboard/OnCallCalendarFeedLinks.test.tsx +229 -0
- package/Tests/App/Dashboard/OnCallCalendarFeedPlanGate.test.tsx +489 -0
- package/Tests/App/Dashboard/OnCallCalendarFeedSideMenus.test.tsx +149 -0
- package/Tests/App/Dashboard/OnCallCalendarFeedUtil.test.ts +855 -0
- package/Tests/App/Dashboard/OnCallPersonalCalendarFeed.test.tsx +1209 -0
- package/Tests/App/Dashboard/OnCallReadinessSurfaces.test.tsx +3 -3
- package/Tests/App/Dashboard/OnCallSharedCalendarFeedCard.test.tsx +1019 -0
- package/Tests/App/Dashboard/OnCallShiftRemindersAndUpcomingShifts.test.tsx +655 -0
- package/Tests/App/Dashboard/UserElementEmail.test.tsx +12 -4
- package/Tests/App/Dashboard/UserEmailCallSites.test.tsx +1 -1
- package/Tests/App/Dashboard/UserSettingsSetupChecklistModel.test.ts +73 -0
- package/Tests/Models/DatabaseModels/DomainRoleTierCoverage.test.ts +14 -0
- package/Tests/Models/DatabaseModels/ModelRegistryInvariants.test.ts +469 -0
- package/Tests/Models/OnCallCalendarFeedModels.test.ts +642 -0
- package/Tests/Models/OnCallDutyPolicyScheduleCalendarFeed.test.ts +288 -0
- package/Tests/Models/OnCallDutyPolicyScheduleShiftConfigVersion.test.ts +88 -0
- package/Tests/Models/SecurityDomainAccessControl.test.ts +429 -0
- package/Tests/Models/UserOnCallShiftReminderModels.test.ts +368 -0
- package/Tests/Server/API/GlobalConfigLicense.test.ts +657 -0
- package/Tests/Server/API/Helpers.ts +8 -0
- package/Tests/Server/API/OnCallCalendarAPI.test.ts +4461 -0
- package/Tests/Server/API/SecurityEventAttributesAPI.test.ts +84 -6
- package/Tests/Server/API/TelemetryResolveStackTraceAPI.test.ts +805 -0
- package/Tests/Server/EnvironmentConfigOnCallCalendarFeed.test.ts +357 -0
- package/Tests/Server/Infrastructure/OnCallCalendarFeedCache.test.ts +1589 -0
- package/Tests/Server/Infrastructure/Postgres/AddOnCallCalendarFeedsMigration.test.ts +394 -0
- package/Tests/Server/Middleware/IdentityRateLimit.test.ts +1144 -0
- package/Tests/Server/Middleware/MultipartFormData.test.ts +618 -3
- package/Tests/Server/Middleware/OnCallCalendarFeedRateLimit.test.ts +1365 -0
- package/Tests/Server/Services/FeedRetentionConsistency.test.ts +70 -0
- package/Tests/Server/Services/MonitorLabelRuleEngineScale.test.ts +520 -0
- package/Tests/Server/Services/NetworkDeviceOidTemplateService.test.ts +332 -0
- package/Tests/Server/Services/NetworkDeviceOidTemplateWriteGuards.test.ts +409 -0
- package/Tests/Server/Services/OnCallCalendarFeedServices.test.ts +1103 -0
- package/Tests/Server/Services/OnCallDutyPolicyScheduleResolver.test.ts +1037 -0
- package/Tests/Server/Services/OnCallShiftConfigPropagation.test.ts +1270 -0
- package/Tests/Server/Services/RuleEngineRuleFetchLimit.test.ts +239 -0
- package/Tests/Server/Services/TeamDeleteMemberCleanup.test.ts +156 -0
- package/Tests/Server/Services/TeamMemberOnCallCleanup.test.ts +755 -0
- package/Tests/Server/Services/TelemetrySourceMapService.test.ts +1210 -2
- package/Tests/Server/Services/UserNotificationSettingShiftReminderDefaults.test.ts +267 -0
- package/Tests/Server/Services/UserOnCallShiftReminderServices.test.ts +583 -0
- package/Tests/Server/Services/UserServiceSeatLimit.test.ts +182 -0
- package/Tests/Server/Types/AnalyticsDatabase/SecurityEventModelPermission.test.ts +255 -0
- package/Tests/Server/Types/Database/Permissions/OnCallCalendarFeedPermissions.test.ts +254 -0
- package/Tests/Server/Types/Database/Permissions/ReadBlockPermission.test.ts +212 -0
- package/Tests/Server/Types/Database/Permissions/SecurityRoleAccess.test.ts +413 -0
- package/Tests/Server/Utils/CodeRepository.test.ts +689 -0
- package/Tests/Server/Utils/EnterpriseLicense/EnterpriseLicenseSeatUtil.test.ts +495 -0
- package/Tests/Server/Utils/ExceptionSanitizer.test.ts +77 -0
- package/Tests/Server/Utils/Monitor/CapturedMetricAttributeUtil.test.ts +284 -0
- package/Tests/Server/Utils/Monitor/MonitorCustomMetricAttributes.test.ts +503 -0
- package/Tests/Server/Utils/Monitor/MonitorTemplatePrototypePollution.test.ts +106 -0
- package/Tests/Server/Utils/Monitor/NetworkDeviceWalkLogWritePath.test.ts +33 -4
- package/Tests/Server/Utils/Monitor/NetworkDeviceWalkUtil.test.ts +14 -4
- package/Tests/Server/Utils/Monitor/NetworkInventoryUtil.test.ts +44 -0
- package/Tests/Server/Utils/OnCall/CalendarFeedToken.test.ts +467 -0
- package/Tests/Server/Utils/OnCall/OnCallCalendarFeedRenderer.test.ts +2142 -0
- package/Tests/Server/Utils/OnCall/OnCallCalendarFeedUrls.test.ts +278 -0
- package/Tests/Server/Utils/OnCall/OnCallResolverTestHarness.ts +440 -0
- package/Tests/Server/Utils/OnCall/OnCallShiftChangeListeners.test.ts +314 -0
- package/Tests/Server/Utils/OnCall/OnCallShiftMaterializer.test.ts +1502 -0
- package/Tests/Server/Utils/OnCall/OnCallShiftReminderListener.test.ts +491 -0
- package/Tests/Server/Utils/OnCall/OnCallShiftReminderRunner.test.ts +3088 -0
- package/Tests/Server/Utils/OnCall/OnCallShiftReminderTestHarness.ts +910 -0
- package/Tests/Server/Utils/OpenAPISpec.test.ts +536 -0
- package/Tests/Server/Utils/ResponseSendCalendarResponse.test.ts +561 -0
- package/Tests/Server/Utils/Rules/RuleEngineRuleRead.test.ts +115 -0
- package/Tests/Server/Utils/StackTraceParser.test.ts +610 -0
- package/Tests/Server/Utils/StartServerEncryptionSecretWarning.test.ts +64 -0
- package/Tests/Server/Utils/Telemetry/AppMetrics.test.ts +29 -0
- package/Tests/Server/Utils/Telemetry/LogExceptionExtractor.test.ts +0 -0
- package/Tests/Server/Utils/Telemetry/SourceMapLimits.test.ts +656 -0
- package/Tests/Server/Utils/Telemetry/SourceMapResolver.test.ts +100 -0
- package/Tests/Types/Calendar/ICalendar.test.ts +488 -0
- package/Tests/Types/Monitor/SnmpMonitor/SnmpOidListUtil.test.ts +454 -0
- package/Tests/Types/NotificationSetting/NotificationSettingEventType.test.ts +53 -0
- package/Tests/Types/OnCallDutyPolicy/CalendarFeedTestFixtures.ts +310 -0
- package/Tests/Types/OnCallDutyPolicy/CalendarFeedWindow.test.ts +205 -0
- package/Tests/Types/OnCallDutyPolicy/LayerUtilLayerMetaAndIterationCap.test.ts +458 -0
- package/Tests/Types/OnCallDutyPolicy/MaterializedShift.test.ts +197 -0
- package/Tests/Types/OnCallDutyPolicy/OnCallCalendarFeedUtil.test.ts +1986 -0
- package/Tests/Types/OnCallDutyPolicy/ScheduleShiftUtilGroupKey.test.ts +678 -0
- package/Tests/Types/OnCallDutyPolicy/ShiftSeamUtil.test.ts +417 -0
- package/Tests/Types/SecurityRolePermissions.test.ts +193 -0
- package/Tests/UI/Components/Charts/AnnotationLayout.test.ts +773 -0
- package/Tests/UI/Components/Charts/ChartAnnotationRail.test.tsx +789 -0
- package/Tests/UI/Components/Charts/ChartBucketIdentity.test.ts +254 -0
- package/Tests/UI/Components/Charts/TimeAnnotation.test.ts +471 -0
- package/Tests/UI/Components/EditionLabelLicenseRefresh.test.tsx +405 -0
- package/Tests/UI/Components/ErrorMessageRefreshControl.test.tsx +83 -0
- package/Tests/UI/Components/MarkdownConverters.test.ts +686 -0
- package/Tests/UI/Components/ModelTable/BaseModelTableDeleteAndEmptyStates.test.tsx +341 -0
- package/Tests/UI/Components/OrderedStatesList.test.tsx +5 -5
- package/Tests/UI/Components/PendingProjectInvitations.test.tsx +1 -1
- package/Tests/UI/Components/TableSortAndMobileColumns.test.tsx +195 -0
- package/Tests/UI/Components/XAxis.test.ts +270 -5
- package/Tests/UI/Components/XAxisDaylightSaving.test.ts +113 -0
- package/Tests/UI/Styles/ChartFocusRing.test.ts +153 -0
- package/Tests/UI/Styles/ChartFocusRingCoverage.test.tsx +377 -0
- package/Tests/UI/Styles/ThemeStylesheet.ts +162 -0
- package/Tests/UI/Utils/Breadcrumb/fixtures/RealBreadcrumbTrails.ts +10 -0
- package/Tests/UI/Utils/Breadcrumb/fixtures/RealRoutePatterns.ts +2 -0
- package/Tests/Utils/EnterpriseLicenseSeats.test.ts +507 -0
- package/Tests/Utils/NetworkDiscovery/DiscoveredDeviceBuilder.test.ts +951 -1
- package/Tests/Utils/NetworkDiscovery/DiscoveredHostUtil.test.ts +238 -0
- package/Tests/Utils/NetworkDiscovery/DiscoveryReverseDnsChain.test.ts +1056 -0
- package/Tests/Utils/NetworkDiscovery/ReverseDnsNameUtil.test.ts +882 -0
- package/Types/Calendar/ICalendar.ts +442 -0
- package/Types/Date.ts +39 -0
- package/Types/Email/EmailTemplateType.ts +2 -0
- package/Types/Monitor/SnmpMonitor/SnmpOidListUtil.ts +333 -0
- package/Types/NotificationSetting/NotificationSettingEventType.ts +4 -0
- package/Types/OnCallDutyPolicy/CalendarFeedWindow.ts +140 -0
- package/Types/OnCallDutyPolicy/Layer.ts +190 -35
- package/Types/OnCallDutyPolicy/MaterializedShift.ts +274 -0
- package/Types/OnCallDutyPolicy/OnCallCalendarFeedUtil.ts +1415 -0
- package/Types/OnCallDutyPolicy/ScheduleShiftUtil.ts +159 -4
- package/Types/OnCallDutyPolicy/ShiftSeamUtil.ts +106 -0
- package/Types/Permission.ts +96 -0
- package/Types/Rum/SessionReplay.ts +21 -0
- package/Types/Telemetry/SourceMap.ts +8 -0
- package/UI/Components/Charts/ChartLibrary/Annotations/AnnotationHoverCard.tsx +176 -0
- package/UI/Components/Charts/ChartLibrary/Annotations/AnnotationLayout.ts +745 -0
- package/UI/Components/Charts/ChartLibrary/Annotations/ChartAnnotationLayer.tsx +576 -0
- package/UI/Components/Charts/ChartLibrary/Annotations/UseChartAnnotations.tsx +204 -0
- package/UI/Components/Charts/ChartLibrary/AreaChart/AreaChart.tsx +491 -544
- package/UI/Components/Charts/ChartLibrary/BarChart/BarChart.tsx +324 -372
- package/UI/Components/Charts/ChartLibrary/LineChart/LineChart.tsx +487 -540
- package/UI/Components/Charts/ChartLibrary/Types/FormattedReferenceRegion.ts +7 -3
- package/UI/Components/Charts/ChartLibrary/Types/FormattedTimeReferenceLine.ts +14 -3
- package/UI/Components/Charts/Types/ChartEventKind.ts +13 -0
- package/UI/Components/Charts/Types/ReferenceRegionProps.ts +6 -0
- package/UI/Components/Charts/Types/TimeReferenceLineProps.ts +20 -3
- package/UI/Components/Charts/Utils/TimeAnnotation.ts +69 -35
- package/UI/Components/Charts/Utils/XAxis.ts +125 -18
- package/UI/Components/EditionLabel/EditionLabel.tsx +280 -26
- package/UI/Components/ErrorMessage/ErrorMessage.tsx +21 -10
- package/UI/Components/Feed/FeedItem.tsx +4 -5
- package/UI/Components/Header/HeaderIconDropdownButton.tsx +1 -2
- package/UI/Components/Header/UserProfile/UserProfile.tsx +1 -2
- package/UI/Components/Image/Image.tsx +20 -3
- package/UI/Components/Markdown.tsx/MarkdownConverters.ts +0 -0
- package/UI/Components/MemberRoleAssignment/MemberRoleAssignment.tsx +1 -2
- package/UI/Components/ModelTable/BaseModelTable.tsx +150 -24
- package/UI/Components/Table/TableHeader.tsx +64 -48
- package/UI/Components/Table/TableRow.tsx +13 -3
- package/UI/Styles/Theme.css +38 -0
- package/Utils/EnterpriseLicense/EnterpriseLicenseSeats.ts +271 -0
- package/Utils/NetworkDiscovery/AutoImportRuleMatcher.ts +6 -0
- package/Utils/NetworkDiscovery/DiscoveredDeviceBuilder.ts +141 -10
- package/Utils/NetworkDiscovery/DiscoveredHostUtil.ts +55 -3
- package/Utils/NetworkDiscovery/ReverseDnsNameUtil.ts +151 -0
- package/Utils/Rules/RuleEngineLimits.ts +32 -0
- package/build/dist/Models/AnalyticsModels/SecurityEvent.js +48 -16
- package/build/dist/Models/AnalyticsModels/SecurityEvent.js.map +1 -1
- package/build/dist/Models/AnalyticsModels/ThreatIntelIndicator.js +10 -5
- package/build/dist/Models/AnalyticsModels/ThreatIntelIndicator.js.map +1 -1
- package/build/dist/Models/DatabaseModels/AlertSeverity.js +46 -1
- package/build/dist/Models/DatabaseModels/AlertSeverity.js.map +1 -1
- package/build/dist/Models/DatabaseModels/DetectionRule.js +16 -5
- package/build/dist/Models/DatabaseModels/DetectionRule.js.map +1 -1
- package/build/dist/Models/DatabaseModels/GoogleSecOpsConnection.js +14 -5
- package/build/dist/Models/DatabaseModels/GoogleSecOpsConnection.js.map +1 -1
- package/build/dist/Models/DatabaseModels/IncidentSeverity.js +46 -1
- package/build/dist/Models/DatabaseModels/IncidentSeverity.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Index.js +13 -0
- package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
- package/build/dist/Models/DatabaseModels/NetworkDevice.js +115 -3
- package/build/dist/Models/DatabaseModels/NetworkDevice.js.map +1 -1
- package/build/dist/Models/DatabaseModels/NetworkDeviceAutoImportRule.js +88 -0
- package/build/dist/Models/DatabaseModels/NetworkDeviceAutoImportRule.js.map +1 -1
- package/build/dist/Models/DatabaseModels/NetworkDeviceDiscoveryScan.js.map +1 -1
- package/build/dist/Models/DatabaseModels/NetworkDeviceOidTemplate.js +519 -0
- package/build/dist/Models/DatabaseModels/NetworkDeviceOidTemplate.js.map +1 -0
- package/build/dist/Models/DatabaseModels/OnCallDutyPolicySchedule.js +44 -0
- package/build/dist/Models/DatabaseModels/OnCallDutyPolicySchedule.js.map +1 -1
- package/build/dist/Models/DatabaseModels/OnCallDutyPolicyScheduleCalendarFeed.js +699 -0
- package/build/dist/Models/DatabaseModels/OnCallDutyPolicyScheduleCalendarFeed.js.map +1 -0
- package/build/dist/Models/DatabaseModels/ProjectOnCallCalendarFeed.js +620 -0
- package/build/dist/Models/DatabaseModels/ProjectOnCallCalendarFeed.js.map +1 -0
- package/build/dist/Models/DatabaseModels/ThreatIntelFeed.js +16 -5
- package/build/dist/Models/DatabaseModels/ThreatIntelFeed.js.map +1 -1
- package/build/dist/Models/DatabaseModels/UserOnCallCalendarFeed.js +585 -0
- package/build/dist/Models/DatabaseModels/UserOnCallCalendarFeed.js.map +1 -0
- package/build/dist/Models/DatabaseModels/UserOnCallShiftReminder.js +247 -0
- package/build/dist/Models/DatabaseModels/UserOnCallShiftReminder.js.map +1 -0
- package/build/dist/Models/DatabaseModels/UserOnCallShiftReminderLog.js +355 -0
- package/build/dist/Models/DatabaseModels/UserOnCallShiftReminderLog.js.map +1 -0
- package/build/dist/Server/API/GlobalConfigAPI.js +293 -176
- package/build/dist/Server/API/GlobalConfigAPI.js.map +1 -1
- package/build/dist/Server/API/OnCallCalendarAPI.js +1371 -0
- package/build/dist/Server/API/OnCallCalendarAPI.js.map +1 -0
- package/build/dist/Server/API/TelemetryAPI.js +31 -3
- package/build/dist/Server/API/TelemetryAPI.js.map +1 -1
- package/build/dist/Server/EnvironmentConfig.js +185 -0
- package/build/dist/Server/EnvironmentConfig.js.map +1 -1
- package/build/dist/Server/Infrastructure/OnCallCalendarFeedCache.js +663 -0
- package/build/dist/Server/Infrastructure/OnCallCalendarFeedCache.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1790400000000-AddOnCallCalendarFeeds.js +103 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1790400000000-AddOnCallCalendarFeeds.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1790500000000-AddNetworkDeviceOidTemplate.js +26 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1790500000000-AddNetworkDeviceOidTemplate.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1790600000000-AddAutoImportRuleOidTemplate.js +14 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1790600000000-AddAutoImportRuleOidTemplate.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +6 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
- package/build/dist/Server/Middleware/MultipartFormData.js +93 -28
- package/build/dist/Server/Middleware/MultipartFormData.js.map +1 -1
- package/build/dist/Server/Middleware/OnCallCalendarFeedRateLimit.js +342 -0
- package/build/dist/Server/Middleware/OnCallCalendarFeedRateLimit.js.map +1 -0
- package/build/dist/Server/Services/AlertEpisodeLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/AlertEpisodeLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/AlertEpisodeOnCallRuleEngineService.js +8 -1
- package/build/dist/Server/Services/AlertEpisodeOnCallRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/AlertEpisodeOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/AlertEpisodeOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/AlertEpisodePrivacyRuleEngineService.js +8 -1
- package/build/dist/Server/Services/AlertEpisodePrivacyRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/AlertGroupingEngineService.js +8 -1
- package/build/dist/Server/Services/AlertGroupingEngineService.js.map +1 -1
- package/build/dist/Server/Services/AlertLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/AlertLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/AlertOnCallRuleEngineService.js +8 -1
- package/build/dist/Server/Services/AlertOnCallRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/AlertOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/AlertOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/AlertPrivacyRuleEngineService.js +8 -1
- package/build/dist/Server/Services/AlertPrivacyRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/AlertReminderRuleService.js +8 -1
- package/build/dist/Server/Services/AlertReminderRuleService.js.map +1 -1
- package/build/dist/Server/Services/AutoRemediationRuleEngineService.js +8 -1
- package/build/dist/Server/Services/AutoRemediationRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/CephClusterLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/CephClusterLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/CephClusterOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/CephClusterOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/CloudResourceLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/CloudResourceLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/CloudResourceOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/CloudResourceOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/DashboardLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/DashboardLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/DashboardOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/DashboardOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/DockerHostLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/DockerHostLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/DockerHostOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/DockerHostOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/DockerSwarmClusterLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/DockerSwarmClusterLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/DockerSwarmClusterOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/DockerSwarmClusterOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/HostLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/HostLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/HostOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/HostOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/IncidentEpisodeLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/IncidentEpisodeLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/IncidentEpisodeOnCallRuleEngineService.js +8 -1
- package/build/dist/Server/Services/IncidentEpisodeOnCallRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/IncidentEpisodeOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/IncidentEpisodeOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/IncidentEpisodePrivacyRuleEngineService.js +8 -1
- package/build/dist/Server/Services/IncidentEpisodePrivacyRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/IncidentGroupingEngineService.js +8 -1
- package/build/dist/Server/Services/IncidentGroupingEngineService.js.map +1 -1
- package/build/dist/Server/Services/IncidentLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/IncidentLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/IncidentOnCallRuleEngineService.js +8 -1
- package/build/dist/Server/Services/IncidentOnCallRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/IncidentOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/IncidentOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/IncidentPrivacyRuleEngineService.js +8 -1
- package/build/dist/Server/Services/IncidentPrivacyRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/IncidentReminderRuleService.js +8 -1
- package/build/dist/Server/Services/IncidentReminderRuleService.js.map +1 -1
- package/build/dist/Server/Services/IncidentSlaRuleService.js +8 -1
- package/build/dist/Server/Services/IncidentSlaRuleService.js.map +1 -1
- package/build/dist/Server/Services/IncomingCallPolicyLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/IncomingCallPolicyLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/IncomingCallPolicyOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/IncomingCallPolicyOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/Index.js +14 -0
- package/build/dist/Server/Services/Index.js.map +1 -1
- package/build/dist/Server/Services/IoTFleetLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/IoTFleetLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/IoTFleetOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/IoTFleetOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/KubernetesClusterLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/KubernetesClusterLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/KubernetesClusterOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/KubernetesClusterOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/KubernetesResourceService.js +5 -1
- package/build/dist/Server/Services/KubernetesResourceService.js.map +1 -1
- package/build/dist/Server/Services/MonitorLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/MonitorLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/MonitorOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/MonitorOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/NetworkDeviceAutoImportRuleEngineService.js +30 -21
- package/build/dist/Server/Services/NetworkDeviceAutoImportRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/NetworkDeviceAutoImportRuleService.js +64 -0
- package/build/dist/Server/Services/NetworkDeviceAutoImportRuleService.js.map +1 -1
- package/build/dist/Server/Services/NetworkDeviceLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/NetworkDeviceLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/NetworkDeviceOidTemplateService.js +180 -0
- package/build/dist/Server/Services/NetworkDeviceOidTemplateService.js.map +1 -0
- package/build/dist/Server/Services/NetworkDeviceOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/NetworkDeviceOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/NetworkDeviceService.js +154 -1
- package/build/dist/Server/Services/NetworkDeviceService.js.map +1 -1
- package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleScheduleService.js +20 -0
- package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleScheduleService.js.map +1 -1
- package/build/dist/Server/Services/OnCallDutyPolicyLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/OnCallDutyPolicyLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/OnCallDutyPolicyOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/OnCallDutyPolicyOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/OnCallDutyPolicyScheduleCalendarFeedService.js +219 -0
- package/build/dist/Server/Services/OnCallDutyPolicyScheduleCalendarFeedService.js.map +1 -0
- package/build/dist/Server/Services/OnCallDutyPolicyScheduleLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/OnCallDutyPolicyScheduleLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/OnCallDutyPolicyScheduleLayerService.js +47 -3
- package/build/dist/Server/Services/OnCallDutyPolicyScheduleLayerService.js.map +1 -1
- package/build/dist/Server/Services/OnCallDutyPolicyScheduleLayerUserService.js +112 -3
- package/build/dist/Server/Services/OnCallDutyPolicyScheduleLayerUserService.js.map +1 -1
- package/build/dist/Server/Services/OnCallDutyPolicyScheduleOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/OnCallDutyPolicyScheduleOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/OnCallDutyPolicyScheduleService.js +955 -9
- package/build/dist/Server/Services/OnCallDutyPolicyScheduleService.js.map +1 -1
- package/build/dist/Server/Services/OnCallDutyPolicyUserOverrideService.js +93 -6
- package/build/dist/Server/Services/OnCallDutyPolicyUserOverrideService.js.map +1 -1
- package/build/dist/Server/Services/PodmanHostLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/PodmanHostLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/PodmanHostOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/PodmanHostOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/ProjectOnCallCalendarFeedService.js +157 -0
- package/build/dist/Server/Services/ProjectOnCallCalendarFeedService.js.map +1 -0
- package/build/dist/Server/Services/ProxmoxClusterLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/ProxmoxClusterLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/ProxmoxClusterOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/ProxmoxClusterOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/RumApplicationLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/RumApplicationLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/RumApplicationOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/RumApplicationOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/RunbookLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/RunbookLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/RunbookOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/RunbookOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/RunbookRuleEngineService.js +8 -1
- package/build/dist/Server/Services/RunbookRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/ScheduledMaintenanceLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/ScheduledMaintenanceLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/ScheduledMaintenanceOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/ScheduledMaintenanceOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/ScheduledMaintenanceReminderRuleService.js +8 -1
- package/build/dist/Server/Services/ScheduledMaintenanceReminderRuleService.js.map +1 -1
- package/build/dist/Server/Services/ServerlessFunctionLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/ServerlessFunctionLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/ServerlessFunctionOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/ServerlessFunctionOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/ServiceLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/ServiceLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/ServiceOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/ServiceOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/StatusPageLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/StatusPageLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/StatusPageMonitorRuleEngineService.js +6 -0
- package/build/dist/Server/Services/StatusPageMonitorRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/StatusPageOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/StatusPageOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/TeamMemberService.js +396 -1
- package/build/dist/Server/Services/TeamMemberService.js.map +1 -1
- package/build/dist/Server/Services/TeamService.js +43 -0
- package/build/dist/Server/Services/TeamService.js.map +1 -1
- package/build/dist/Server/Services/TelemetrySourceMapService.js +213 -19
- package/build/dist/Server/Services/TelemetrySourceMapService.js.map +1 -1
- package/build/dist/Server/Services/UserNotificationSettingService.js +26 -1
- package/build/dist/Server/Services/UserNotificationSettingService.js.map +1 -1
- package/build/dist/Server/Services/UserOnCallCalendarFeedService.js +140 -0
- package/build/dist/Server/Services/UserOnCallCalendarFeedService.js.map +1 -0
- package/build/dist/Server/Services/UserOnCallShiftReminderLogService.js +116 -0
- package/build/dist/Server/Services/UserOnCallShiftReminderLogService.js.map +1 -0
- package/build/dist/Server/Services/UserOnCallShiftReminderService.js +92 -0
- package/build/dist/Server/Services/UserOnCallShiftReminderService.js.map +1 -0
- package/build/dist/Server/Services/UserService.js +25 -0
- package/build/dist/Server/Services/UserService.js.map +1 -1
- package/build/dist/Server/Services/WorkflowLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/WorkflowLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/WorkflowOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/WorkflowOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Utils/EnterpriseLicense/EnterpriseLicenseSeatUtil.js +145 -0
- package/build/dist/Server/Utils/EnterpriseLicense/EnterpriseLicenseSeatUtil.js.map +1 -0
- package/build/dist/Server/Utils/Monitor/CapturedMetricAttributeUtil.js +201 -0
- package/build/dist/Server/Utils/Monitor/CapturedMetricAttributeUtil.js.map +1 -0
- package/build/dist/Server/Utils/Monitor/Criteria/SnmpMonitorCriteria.js +19 -2
- package/build/dist/Server/Utils/Monitor/Criteria/SnmpMonitorCriteria.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorMetricUtil.js +42 -23
- package/build/dist/Server/Utils/Monitor/MonitorMetricUtil.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorTemplateUtil.js +29 -0
- package/build/dist/Server/Utils/Monitor/MonitorTemplateUtil.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/NetworkDeviceMetricUtil.js +11 -2
- package/build/dist/Server/Utils/Monitor/NetworkDeviceMetricUtil.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/NetworkDeviceWalkUtil.js +16 -1
- package/build/dist/Server/Utils/Monitor/NetworkDeviceWalkUtil.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/NetworkInventoryUtil.js +10 -0
- package/build/dist/Server/Utils/Monitor/NetworkInventoryUtil.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/SeriesResourceLabels.js +33 -0
- package/build/dist/Server/Utils/Monitor/SeriesResourceLabels.js.map +1 -1
- package/build/dist/Server/Utils/OnCall/CalendarFeedToken.js +161 -0
- package/build/dist/Server/Utils/OnCall/CalendarFeedToken.js.map +1 -0
- package/build/dist/Server/Utils/OnCall/OnCallCalendarFeedRenderer.js +983 -0
- package/build/dist/Server/Utils/OnCall/OnCallCalendarFeedRenderer.js.map +1 -0
- package/build/dist/Server/Utils/OnCall/OnCallCalendarFeedUrls.js +155 -0
- package/build/dist/Server/Utils/OnCall/OnCallCalendarFeedUrls.js.map +1 -0
- package/build/dist/Server/Utils/OnCall/OnCallShiftChangeListeners.js +145 -0
- package/build/dist/Server/Utils/OnCall/OnCallShiftChangeListeners.js.map +1 -0
- package/build/dist/Server/Utils/OnCall/OnCallShiftMaterializer.js +752 -0
- package/build/dist/Server/Utils/OnCall/OnCallShiftMaterializer.js.map +1 -0
- package/build/dist/Server/Utils/OnCall/OnCallShiftReminderListener.js +92 -0
- package/build/dist/Server/Utils/OnCall/OnCallShiftReminderListener.js.map +1 -0
- package/build/dist/Server/Utils/OnCall/OnCallShiftReminderRunner.js +1786 -0
- package/build/dist/Server/Utils/OnCall/OnCallShiftReminderRunner.js.map +1 -0
- package/build/dist/Server/Utils/Response.js +97 -0
- package/build/dist/Server/Utils/Response.js.map +1 -1
- package/build/dist/Server/Utils/Rules/RuleEngineRuleRead.js +37 -0
- package/build/dist/Server/Utils/Rules/RuleEngineRuleRead.js.map +1 -0
- package/build/dist/Server/Utils/StartServer.js +9 -1
- package/build/dist/Server/Utils/StartServer.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/AppMetrics.js +41 -0
- package/build/dist/Server/Utils/Telemetry/AppMetrics.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/ExceptionSanitizer.js +12 -1
- package/build/dist/Server/Utils/Telemetry/ExceptionSanitizer.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/LogExceptionExtractor.js +14 -2
- package/build/dist/Server/Utils/Telemetry/LogExceptionExtractor.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/SourceMapResolver.js +15 -5
- package/build/dist/Server/Utils/Telemetry/SourceMapResolver.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/StackTraceParser.js +307 -0
- package/build/dist/Server/Utils/Telemetry/StackTraceParser.js.map +1 -1
- package/build/dist/Types/Calendar/ICalendar.js +290 -0
- package/build/dist/Types/Calendar/ICalendar.js.map +1 -0
- package/build/dist/Types/Date.js +27 -0
- package/build/dist/Types/Date.js.map +1 -1
- package/build/dist/Types/Email/EmailTemplateType.js +2 -0
- package/build/dist/Types/Email/EmailTemplateType.js.map +1 -1
- package/build/dist/Types/Monitor/SnmpMonitor/SnmpOidListUtil.js +253 -0
- package/build/dist/Types/Monitor/SnmpMonitor/SnmpOidListUtil.js.map +1 -0
- package/build/dist/Types/NotificationSetting/NotificationSettingEventType.js +3 -0
- package/build/dist/Types/NotificationSetting/NotificationSettingEventType.js.map +1 -1
- package/build/dist/Types/OnCallDutyPolicy/CalendarFeedWindow.js +97 -0
- package/build/dist/Types/OnCallDutyPolicy/CalendarFeedWindow.js.map +1 -0
- package/build/dist/Types/OnCallDutyPolicy/Layer.js +113 -19
- package/build/dist/Types/OnCallDutyPolicy/Layer.js.map +1 -1
- package/build/dist/Types/OnCallDutyPolicy/MaterializedShift.js +134 -0
- package/build/dist/Types/OnCallDutyPolicy/MaterializedShift.js.map +1 -0
- package/build/dist/Types/OnCallDutyPolicy/OnCallCalendarFeedUtil.js +800 -0
- package/build/dist/Types/OnCallDutyPolicy/OnCallCalendarFeedUtil.js.map +1 -0
- package/build/dist/Types/OnCallDutyPolicy/ScheduleShiftUtil.js +97 -3
- package/build/dist/Types/OnCallDutyPolicy/ScheduleShiftUtil.js.map +1 -1
- package/build/dist/Types/OnCallDutyPolicy/ShiftSeamUtil.js +77 -0
- package/build/dist/Types/OnCallDutyPolicy/ShiftSeamUtil.js.map +1 -0
- package/build/dist/Types/Permission.js +86 -0
- package/build/dist/Types/Permission.js.map +1 -1
- package/build/dist/Types/Rum/SessionReplay.js +19 -0
- package/build/dist/Types/Rum/SessionReplay.js.map +1 -1
- package/build/dist/UI/Components/Charts/ChartLibrary/Annotations/AnnotationHoverCard.js +83 -0
- package/build/dist/UI/Components/Charts/ChartLibrary/Annotations/AnnotationHoverCard.js.map +1 -0
- package/build/dist/UI/Components/Charts/ChartLibrary/Annotations/AnnotationLayout.js +531 -0
- package/build/dist/UI/Components/Charts/ChartLibrary/Annotations/AnnotationLayout.js.map +1 -0
- package/build/dist/UI/Components/Charts/ChartLibrary/Annotations/ChartAnnotationLayer.js +264 -0
- package/build/dist/UI/Components/Charts/ChartLibrary/Annotations/ChartAnnotationLayer.js.map +1 -0
- package/build/dist/UI/Components/Charts/ChartLibrary/Annotations/UseChartAnnotations.js +122 -0
- package/build/dist/UI/Components/Charts/ChartLibrary/Annotations/UseChartAnnotations.js.map +1 -0
- package/build/dist/UI/Components/Charts/ChartLibrary/AreaChart/AreaChart.js +213 -233
- package/build/dist/UI/Components/Charts/ChartLibrary/AreaChart/AreaChart.js.map +1 -1
- package/build/dist/UI/Components/Charts/ChartLibrary/BarChart/BarChart.js +139 -152
- package/build/dist/UI/Components/Charts/ChartLibrary/BarChart/BarChart.js.map +1 -1
- package/build/dist/UI/Components/Charts/ChartLibrary/LineChart/LineChart.js +212 -232
- package/build/dist/UI/Components/Charts/ChartLibrary/LineChart/LineChart.js.map +1 -1
- package/build/dist/UI/Components/Charts/Types/ChartEventKind.js +14 -0
- package/build/dist/UI/Components/Charts/Types/ChartEventKind.js.map +1 -0
- package/build/dist/UI/Components/Charts/Utils/TimeAnnotation.js +57 -28
- package/build/dist/UI/Components/Charts/Utils/TimeAnnotation.js.map +1 -1
- package/build/dist/UI/Components/Charts/Utils/XAxis.js +103 -17
- package/build/dist/UI/Components/Charts/Utils/XAxis.js.map +1 -1
- package/build/dist/UI/Components/EditionLabel/EditionLabel.js +198 -23
- package/build/dist/UI/Components/EditionLabel/EditionLabel.js.map +1 -1
- package/build/dist/UI/Components/ErrorMessage/ErrorMessage.js +15 -5
- package/build/dist/UI/Components/ErrorMessage/ErrorMessage.js.map +1 -1
- package/build/dist/UI/Components/Feed/FeedItem.js +4 -5
- package/build/dist/UI/Components/Feed/FeedItem.js.map +1 -1
- package/build/dist/UI/Components/Header/HeaderIconDropdownButton.js +1 -2
- package/build/dist/UI/Components/Header/HeaderIconDropdownButton.js.map +1 -1
- package/build/dist/UI/Components/Header/UserProfile/UserProfile.js.map +1 -1
- package/build/dist/UI/Components/Image/Image.js +6 -1
- package/build/dist/UI/Components/Image/Image.js.map +1 -1
- package/build/dist/UI/Components/Markdown.tsx/MarkdownConverters.js +0 -0
- package/build/dist/UI/Components/Markdown.tsx/MarkdownConverters.js.map +1 -1
- package/build/dist/UI/Components/MemberRoleAssignment/MemberRoleAssignment.js +1 -2
- package/build/dist/UI/Components/MemberRoleAssignment/MemberRoleAssignment.js.map +1 -1
- package/build/dist/UI/Components/ModelTable/BaseModelTable.js +104 -23
- package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
- package/build/dist/UI/Components/Table/TableHeader.js +20 -22
- package/build/dist/UI/Components/Table/TableHeader.js.map +1 -1
- package/build/dist/UI/Components/Table/TableRow.js +13 -4
- package/build/dist/UI/Components/Table/TableRow.js.map +1 -1
- package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseSeats.js +153 -0
- package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseSeats.js.map +1 -0
- package/build/dist/Utils/NetworkDiscovery/AutoImportRuleMatcher.js.map +1 -1
- package/build/dist/Utils/NetworkDiscovery/DiscoveredDeviceBuilder.js +127 -7
- package/build/dist/Utils/NetworkDiscovery/DiscoveredDeviceBuilder.js.map +1 -1
- package/build/dist/Utils/NetworkDiscovery/DiscoveredHostUtil.js +50 -3
- package/build/dist/Utils/NetworkDiscovery/DiscoveredHostUtil.js.map +1 -1
- package/build/dist/Utils/NetworkDiscovery/ReverseDnsNameUtil.js +132 -0
- package/build/dist/Utils/NetworkDiscovery/ReverseDnsNameUtil.js.map +1 -0
- package/build/dist/Utils/Rules/RuleEngineLimits.js +31 -0
- package/build/dist/Utils/Rules/RuleEngineLimits.js.map +1 -0
- package/jest.config.json +1 -0
- package/package.json +2 -2
|
@@ -0,0 +1,983 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
8
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
9
|
+
};
|
|
10
|
+
import DatabaseConfig from "../../DatabaseConfig";
|
|
11
|
+
import { IsBillingEnabled, getAllEnvVars } from "../../EnvironmentConfig";
|
|
12
|
+
import OnCallCalendarFeedCache from "../../Infrastructure/OnCallCalendarFeedCache";
|
|
13
|
+
import OnCallDutyPolicyScheduleService from "../../Services/OnCallDutyPolicyScheduleService";
|
|
14
|
+
import ProjectService from "../../Services/ProjectService";
|
|
15
|
+
import UserService from "../../Services/UserService";
|
|
16
|
+
import QueryHelper from "../../Types/Database/QueryHelper";
|
|
17
|
+
import logger from "../Logger";
|
|
18
|
+
import Response from "../Response";
|
|
19
|
+
import AppMetrics from "../Telemetry/AppMetrics";
|
|
20
|
+
import CaptureSpan from "../Telemetry/CaptureSpan";
|
|
21
|
+
import OnCallCalendarFeedUrls from "./OnCallCalendarFeedUrls";
|
|
22
|
+
import OnCallShiftMaterializer from "./OnCallShiftMaterializer";
|
|
23
|
+
import SubscriptionPlan, { PlanType, } from "../../../Types/Billing/SubscriptionPlan";
|
|
24
|
+
import OneUptimeDate from "../../../Types/Date";
|
|
25
|
+
import { LIMIT_PER_PROJECT } from "../../../Types/Database/LimitMax";
|
|
26
|
+
import ObjectID from "../../../Types/ObjectID";
|
|
27
|
+
import SortOrder from "../../../Types/BaseDatabase/SortOrder";
|
|
28
|
+
import CalendarFeedWindow, { BODY_CACHE_TTL_SECONDS, FEED_SIMULATION_ITERATION_CAP, MAX_EVENTS, MAX_GAP_EVENTS, SCHEDULE_CACHE_TTL_SECONDS, } from "../../../Types/OnCallDutyPolicy/CalendarFeedWindow";
|
|
29
|
+
import MaterializedShiftUtil from "../../../Types/OnCallDutyPolicy/MaterializedShift";
|
|
30
|
+
import OnCallCalendarFeedUtil, { OnCallCalendarFeedKind, } from "../../../Types/OnCallDutyPolicy/OnCallCalendarFeedUtil";
|
|
31
|
+
import { createHash } from "crypto";
|
|
32
|
+
/*
|
|
33
|
+
* Turns one feed row plus its request into a calendar body.
|
|
34
|
+
*
|
|
35
|
+
* Everything between "the token resolved to this row" and "send these bytes"
|
|
36
|
+
* lives here so the three public routes (personal, schedule, project) and
|
|
37
|
+
* the session-authenticated /my-shifts route share one pipeline:
|
|
38
|
+
*
|
|
39
|
+
* authorisation (re-derived on EVERY fetch; a valid token is not
|
|
40
|
+
* authorisation) -> body cache -> render slot -> schedule-level cache ->
|
|
41
|
+
* materialize -> shrink to MAX_EVENTS -> coverage gaps -> serialize ->
|
|
42
|
+
* body + last-good cache -> metrics.
|
|
43
|
+
*
|
|
44
|
+
* Three outcomes come out of it, matching the one response rule the routes
|
|
45
|
+
* apply: a rendered body (200), an empty calendar that says why (200, so
|
|
46
|
+
* subscribed clients clear their copy instead of dropping the calendar), or
|
|
47
|
+
* "unavailable" (503 + Retry-After) when nothing at all can be served.
|
|
48
|
+
*
|
|
49
|
+
* Stale-while-error: when a render throws, hits the per-process render cap
|
|
50
|
+
* or trips a schedule's iteration cap, the most recent body that rendered
|
|
51
|
+
* successfully for the same key is served instead, flagged `stale` so the
|
|
52
|
+
* route adds `Warning: 110` and the bookkeeping records lastRenderTruncated.
|
|
53
|
+
* Only when there is nothing to fall back to does the outcome turn into a
|
|
54
|
+
* 503.
|
|
55
|
+
*
|
|
56
|
+
* Nothing here ever sees the plaintext token. The body-cache key carries the
|
|
57
|
+
* token HASH (so a rotation is a new key) and the log lines carry the feed
|
|
58
|
+
* kind and row id.
|
|
59
|
+
*/
|
|
60
|
+
export var FeedRenderStatus;
|
|
61
|
+
(function (FeedRenderStatus) {
|
|
62
|
+
FeedRenderStatus["Rendered"] = "rendered";
|
|
63
|
+
FeedRenderStatus["Empty"] = "empty";
|
|
64
|
+
FeedRenderStatus["Unavailable"] = "unavailable";
|
|
65
|
+
})(FeedRenderStatus || (FeedRenderStatus = {}));
|
|
66
|
+
export const RENDER_CAP_RETRY_AFTER_SECONDS = 60;
|
|
67
|
+
/*
|
|
68
|
+
* The X-WR-CALDESC sentences for every "200 but empty" case. Exported so the
|
|
69
|
+
* routes, the tests and (through the docs) the users see the same words.
|
|
70
|
+
*/
|
|
71
|
+
export const FEED_DISABLED_REASON = "This calendar feed is turned off in OneUptime. Turn it back on from the Calendar Feed settings to see shifts here again.";
|
|
72
|
+
export const TOKEN_ROTATED_REASON = "This calendar link was regenerated in OneUptime. Subscribe to the new link from the Calendar Feed settings; this one will stop working soon.";
|
|
73
|
+
export const PLAN_REASON = "Calendar feeds need the Growth plan or higher. Upgrade the project's plan in OneUptime to see shifts here.";
|
|
74
|
+
export const USER_MISSING_REASON = "The user this calendar link belongs to no longer exists.";
|
|
75
|
+
export const NO_SCHEDULES_REASON = "You are not on any on-call schedule in this project right now. Shifts appear here once you are added to a schedule.";
|
|
76
|
+
export const FILTERED_SCHEDULE_REASON = "You are not on the on-call schedule this calendar link is filtered to.";
|
|
77
|
+
export const SCHEDULE_MISSING_REASON = "The on-call schedule this calendar link belongs to no longer exists.";
|
|
78
|
+
export const PROJECT_MISSING_REASON = "The project this calendar link belongs to no longer exists.";
|
|
79
|
+
export const NO_PROJECT_SCHEDULES_REASON = "This project has no on-call schedules yet. Shifts appear here once a schedule is created.";
|
|
80
|
+
export default class OnCallCalendarFeedRenderer {
|
|
81
|
+
// -- Outcomes ----------------------------------------------------------
|
|
82
|
+
/*
|
|
83
|
+
* The empty VCALENDAR outcome for one of the "200 but nothing to show"
|
|
84
|
+
* cases. Cheap enough not to cache: it is a header and a sentence.
|
|
85
|
+
*/
|
|
86
|
+
static buildEmptyOutcome(options) {
|
|
87
|
+
const now = options.now || OneUptimeDate.getCurrentDate();
|
|
88
|
+
const body = OnCallCalendarFeedUtil.renderEmpty({
|
|
89
|
+
kind: options.kind,
|
|
90
|
+
reason: options.reason,
|
|
91
|
+
scheduleName: options.scheduleName,
|
|
92
|
+
projectName: options.projectName,
|
|
93
|
+
filterScheduleName: options.filterScheduleName,
|
|
94
|
+
timezone: options.timezone,
|
|
95
|
+
});
|
|
96
|
+
return {
|
|
97
|
+
status: FeedRenderStatus.Empty,
|
|
98
|
+
kind: options.kind,
|
|
99
|
+
body,
|
|
100
|
+
etag: Response.getCalendarETag(body),
|
|
101
|
+
lastModified: now,
|
|
102
|
+
stale: false,
|
|
103
|
+
truncated: false,
|
|
104
|
+
eventCount: 0,
|
|
105
|
+
cacheHit: false,
|
|
106
|
+
reason: options.reason,
|
|
107
|
+
retryAfterSeconds: null,
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
static buildUnavailableOutcome(kind, retryAfterSeconds) {
|
|
111
|
+
return {
|
|
112
|
+
status: FeedRenderStatus.Unavailable,
|
|
113
|
+
kind,
|
|
114
|
+
body: "",
|
|
115
|
+
etag: "",
|
|
116
|
+
lastModified: OneUptimeDate.getCurrentDate(),
|
|
117
|
+
stale: false,
|
|
118
|
+
truncated: false,
|
|
119
|
+
eventCount: 0,
|
|
120
|
+
cacheHit: false,
|
|
121
|
+
reason: null,
|
|
122
|
+
retryAfterSeconds,
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
static outcomeFromCachedBody(data) {
|
|
126
|
+
return {
|
|
127
|
+
status: FeedRenderStatus.Rendered,
|
|
128
|
+
kind: data.kind,
|
|
129
|
+
body: data.cached.body,
|
|
130
|
+
etag: data.cached.etag,
|
|
131
|
+
lastModified: data.cached.lastModified,
|
|
132
|
+
stale: data.stale,
|
|
133
|
+
truncated: data.truncated,
|
|
134
|
+
eventCount: OnCallCalendarFeedRenderer.countEvents(data.cached.body),
|
|
135
|
+
cacheHit: data.cacheHit,
|
|
136
|
+
reason: null,
|
|
137
|
+
retryAfterSeconds: null,
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
// -- Plan --------------------------------------------------------------
|
|
141
|
+
/*
|
|
142
|
+
* Decision 3: below-plan projects render an EMPTY calendar, never a 404.
|
|
143
|
+
* The check is imperative because the public routes read as root, so the
|
|
144
|
+
* models' @TableBillingAccessControl never runs for them. A project whose
|
|
145
|
+
* plan cannot be read (deleted mid-request, or no plan yet) is treated as
|
|
146
|
+
* below plan: failing closed here costs one empty calendar, failing open
|
|
147
|
+
* would hand out rosters for free.
|
|
148
|
+
*/
|
|
149
|
+
static async isProjectOnPlan(projectId, options) {
|
|
150
|
+
const billingEnabled = (options === null || options === void 0 ? void 0 : options.billingEnabled) === undefined
|
|
151
|
+
? IsBillingEnabled
|
|
152
|
+
: options.billingEnabled;
|
|
153
|
+
if (!billingEnabled) {
|
|
154
|
+
return true;
|
|
155
|
+
}
|
|
156
|
+
try {
|
|
157
|
+
const current = await ProjectService.getCurrentPlan(projectId);
|
|
158
|
+
if (!current.plan) {
|
|
159
|
+
return false;
|
|
160
|
+
}
|
|
161
|
+
return SubscriptionPlan.isFeatureAccessibleOnCurrentPlan(PlanType.Growth, current.plan, getAllEnvVars());
|
|
162
|
+
}
|
|
163
|
+
catch (err) {
|
|
164
|
+
logger.warn(`OnCallCalendarFeedRenderer: could not read the plan of project ${projectId.toString()}; treating it as below plan.`);
|
|
165
|
+
logger.warn(err);
|
|
166
|
+
return false;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
// -- Render ------------------------------------------------------------
|
|
170
|
+
static async render(request) {
|
|
171
|
+
const now = request.now || OneUptimeDate.getCurrentDate();
|
|
172
|
+
const pastDays = CalendarFeedWindow.clampPastDays(request.pastDays);
|
|
173
|
+
const futureDays = CalendarFeedWindow.clampFutureDays(request.futureDays);
|
|
174
|
+
const window = CalendarFeedWindow.computeFeedWindow({
|
|
175
|
+
now,
|
|
176
|
+
pastDays,
|
|
177
|
+
futureDays,
|
|
178
|
+
});
|
|
179
|
+
const context = await OnCallCalendarFeedRenderer.resolveContext(request, window);
|
|
180
|
+
if (context.empty) {
|
|
181
|
+
return OnCallCalendarFeedRenderer.buildEmptyOutcome({
|
|
182
|
+
kind: request.kind,
|
|
183
|
+
reason: context.reason,
|
|
184
|
+
scheduleName: context.scheduleName,
|
|
185
|
+
projectName: context.projectName,
|
|
186
|
+
filterScheduleName: context.filterScheduleName,
|
|
187
|
+
timezone: context.timezone,
|
|
188
|
+
now,
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
const scheduleIds = context.schedules.map((schedule) => {
|
|
192
|
+
return schedule.id.toString();
|
|
193
|
+
});
|
|
194
|
+
const bodyKey = OnCallCalendarFeedRenderer.buildBodyCacheKey({
|
|
195
|
+
request,
|
|
196
|
+
pastDays,
|
|
197
|
+
futureDays,
|
|
198
|
+
schedules: context.schedules,
|
|
199
|
+
now,
|
|
200
|
+
});
|
|
201
|
+
const lastGoodKey = OnCallCalendarFeedRenderer.buildLastGoodCacheKey({
|
|
202
|
+
request,
|
|
203
|
+
pastDays,
|
|
204
|
+
futureDays,
|
|
205
|
+
schedules: context.schedules,
|
|
206
|
+
});
|
|
207
|
+
const scope = {
|
|
208
|
+
projectId: request.projectId.toString(),
|
|
209
|
+
userId: request.kind === OnCallCalendarFeedKind.Personal
|
|
210
|
+
? request.userId.toString()
|
|
211
|
+
: undefined,
|
|
212
|
+
scheduleIds,
|
|
213
|
+
};
|
|
214
|
+
const cachedBody = await OnCallCalendarFeedCache.getBody({ key: bodyKey, scope });
|
|
215
|
+
if (cachedBody) {
|
|
216
|
+
return OnCallCalendarFeedRenderer.outcomeFromCachedBody({
|
|
217
|
+
kind: request.kind,
|
|
218
|
+
cached: cachedBody,
|
|
219
|
+
stale: false,
|
|
220
|
+
cacheHit: true,
|
|
221
|
+
truncated: false,
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
if (!OnCallCalendarFeedCache.tryAcquireRenderSlot()) {
|
|
225
|
+
return await OnCallCalendarFeedRenderer.fallBackToLastGood({
|
|
226
|
+
kind: request.kind,
|
|
227
|
+
lastGoodKey,
|
|
228
|
+
why: "render cap reached",
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
const startedAt = Date.now();
|
|
232
|
+
try {
|
|
233
|
+
const segments = await OnCallCalendarFeedRenderer.loadScheduleSegmentsBatch({
|
|
234
|
+
schedules: context.schedules,
|
|
235
|
+
windowStart: window.feedStart,
|
|
236
|
+
windowEnd: window.feedEnd,
|
|
237
|
+
now,
|
|
238
|
+
});
|
|
239
|
+
const iterationTruncated = segments.filter((segment) => {
|
|
240
|
+
return segment.truncated;
|
|
241
|
+
});
|
|
242
|
+
/*
|
|
243
|
+
* A capped expansion is missing shifts. A complete body from an
|
|
244
|
+
* earlier render is better than a partial one now; only when there is
|
|
245
|
+
* none does the partial render go out, with a note saying so.
|
|
246
|
+
*/
|
|
247
|
+
if (iterationTruncated.length > 0) {
|
|
248
|
+
const lastGood = await OnCallCalendarFeedCache.getLastGood(lastGoodKey);
|
|
249
|
+
if (lastGood) {
|
|
250
|
+
logger.warn(`OnCallCalendarFeedRenderer: ${request.kind} feed ${request.feedId.toString()} hit the iteration cap; serving the last good body.`);
|
|
251
|
+
return OnCallCalendarFeedRenderer.outcomeFromCachedBody({
|
|
252
|
+
kind: request.kind,
|
|
253
|
+
cached: lastGood,
|
|
254
|
+
stale: true,
|
|
255
|
+
cacheHit: false,
|
|
256
|
+
truncated: true,
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
/*
|
|
261
|
+
* The schedules' full resolution, before the personal feed narrows it to
|
|
262
|
+
* the subscriber. A policy-scoped override materializes as a variant
|
|
263
|
+
* shift belonging to the SUBSTITUTE, so filtering it away would leave
|
|
264
|
+
* the rostered user's own event claiming to page them through a policy
|
|
265
|
+
* that pages somebody else. The unfiltered list is handed to the mapper
|
|
266
|
+
* as context (it never becomes VEVENTs) so that event can say so.
|
|
267
|
+
*/
|
|
268
|
+
const allScheduleShifts = OnCallCalendarFeedRenderer.collectShifts(segments, now);
|
|
269
|
+
let shifts = allScheduleShifts;
|
|
270
|
+
if (request.kind === OnCallCalendarFeedKind.Personal) {
|
|
271
|
+
shifts = OnCallShiftMaterializer.filterShiftsForUser(shifts, request.userId);
|
|
272
|
+
}
|
|
273
|
+
const shrink = OnCallCalendarFeedUtil.shrinkWindowToFit({
|
|
274
|
+
shifts,
|
|
275
|
+
feedStart: window.feedStart,
|
|
276
|
+
feedEnd: window.feedEnd,
|
|
277
|
+
});
|
|
278
|
+
const notes = [];
|
|
279
|
+
if (shrink.truncated) {
|
|
280
|
+
notes.push(`Shortened to ${Math.max(0, futureDays - shrink.daysDropped)} days ahead because the feed would exceed ${MAX_EVENTS} events.`);
|
|
281
|
+
}
|
|
282
|
+
if (iterationTruncated.length > 0) {
|
|
283
|
+
const names = iterationTruncated
|
|
284
|
+
.map((segment) => {
|
|
285
|
+
return segment.scheduleName;
|
|
286
|
+
})
|
|
287
|
+
.join(", ");
|
|
288
|
+
notes.push(`Some shifts may be missing: the schedule ${names} is too complex to expand fully. Simplify its layers or shorten the feed window.`);
|
|
289
|
+
}
|
|
290
|
+
let gapEvents = [];
|
|
291
|
+
let gapsTruncated = false;
|
|
292
|
+
const dashboardUrl = (await DatabaseConfig.getDashboardUrl()).toString();
|
|
293
|
+
if (request.kind !== OnCallCalendarFeedKind.Personal &&
|
|
294
|
+
request.includeCoverageGaps) {
|
|
295
|
+
const gaps = OnCallCalendarFeedRenderer.buildGapEvents({
|
|
296
|
+
segments,
|
|
297
|
+
feedStart: window.feedStart,
|
|
298
|
+
feedEnd: shrink.feedEnd,
|
|
299
|
+
minimumGapMinutes: request.minimumGapMinutes,
|
|
300
|
+
dashboardUrl,
|
|
301
|
+
});
|
|
302
|
+
gapEvents = gaps.events;
|
|
303
|
+
gapsTruncated = gaps.truncated;
|
|
304
|
+
if (gapsTruncated) {
|
|
305
|
+
notes.push(`Only the first ${MAX_GAP_EVENTS} coverage gaps are shown.`);
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
const rendered = OnCallCalendarFeedUtil.render({
|
|
309
|
+
kind: request.kind,
|
|
310
|
+
shifts: shrink.shifts,
|
|
311
|
+
contextShifts: allScheduleShifts,
|
|
312
|
+
dashboardUrl,
|
|
313
|
+
viewerTimezone: context.viewerTimezone,
|
|
314
|
+
calendarTimezone: context.calendarTimezone,
|
|
315
|
+
scheduleName: context.scheduleName,
|
|
316
|
+
projectName: context.projectName,
|
|
317
|
+
filterScheduleName: context.filterScheduleName,
|
|
318
|
+
notes,
|
|
319
|
+
gapEvents,
|
|
320
|
+
});
|
|
321
|
+
const value = {
|
|
322
|
+
body: rendered.body,
|
|
323
|
+
etag: Response.getCalendarETag(rendered.body),
|
|
324
|
+
lastModified: rendered.lastModifiedAt || now,
|
|
325
|
+
};
|
|
326
|
+
await OnCallCalendarFeedCache.setBody({
|
|
327
|
+
key: bodyKey,
|
|
328
|
+
scope,
|
|
329
|
+
value,
|
|
330
|
+
ttlSeconds: BODY_CACHE_TTL_SECONDS,
|
|
331
|
+
});
|
|
332
|
+
/*
|
|
333
|
+
* A partial render must never become the "last good" body: the next
|
|
334
|
+
* complete render would then be shadowed by it on the next failure.
|
|
335
|
+
*/
|
|
336
|
+
if (iterationTruncated.length === 0) {
|
|
337
|
+
await OnCallCalendarFeedCache.setLastGood(lastGoodKey, value);
|
|
338
|
+
}
|
|
339
|
+
OnCallCalendarFeedRenderer.recordMetrics({
|
|
340
|
+
kind: request.kind,
|
|
341
|
+
durationMs: Date.now() - startedAt,
|
|
342
|
+
eventCount: rendered.eventCount,
|
|
343
|
+
});
|
|
344
|
+
return {
|
|
345
|
+
status: FeedRenderStatus.Rendered,
|
|
346
|
+
kind: request.kind,
|
|
347
|
+
body: value.body,
|
|
348
|
+
etag: value.etag,
|
|
349
|
+
lastModified: value.lastModified,
|
|
350
|
+
stale: false,
|
|
351
|
+
truncated: shrink.truncated || iterationTruncated.length > 0 || gapsTruncated,
|
|
352
|
+
eventCount: rendered.eventCount,
|
|
353
|
+
cacheHit: false,
|
|
354
|
+
reason: null,
|
|
355
|
+
retryAfterSeconds: null,
|
|
356
|
+
};
|
|
357
|
+
}
|
|
358
|
+
catch (err) {
|
|
359
|
+
logger.error(`OnCallCalendarFeedRenderer: rendering the ${request.kind} feed ${request.feedId.toString()} failed.`);
|
|
360
|
+
logger.error(err);
|
|
361
|
+
return await OnCallCalendarFeedRenderer.fallBackToLastGood({
|
|
362
|
+
kind: request.kind,
|
|
363
|
+
lastGoodKey,
|
|
364
|
+
why: "render failed",
|
|
365
|
+
});
|
|
366
|
+
}
|
|
367
|
+
finally {
|
|
368
|
+
OnCallCalendarFeedCache.releaseRenderSlot();
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
// -- /my-shifts --------------------------------------------------------
|
|
372
|
+
/*
|
|
373
|
+
* The caller's own shifts between two instants, through the same
|
|
374
|
+
* schedule-level cache the feeds use. The window handed to the cache is
|
|
375
|
+
* widened to whole UTC days so a mobile client asking for "now to +30 d"
|
|
376
|
+
* every few minutes keys the same entries as the feeds do, and the result
|
|
377
|
+
* is then cut back to what was asked for.
|
|
378
|
+
*/
|
|
379
|
+
static async materializeUserShifts(data) {
|
|
380
|
+
const now = data.now || OneUptimeDate.getCurrentDate();
|
|
381
|
+
const windowStart = new Date(CalendarFeedWindow.startOfUtcDay(data.from));
|
|
382
|
+
const endDayStart = CalendarFeedWindow.startOfUtcDay(data.to);
|
|
383
|
+
const windowEnd = new Date(data.to.getTime() > endDayStart
|
|
384
|
+
? endDayStart + 24 * 60 * 60 * 1000
|
|
385
|
+
: endDayStart);
|
|
386
|
+
const candidateIds = await OnCallShiftMaterializer.getCandidateScheduleIdsForUser({
|
|
387
|
+
userId: data.userId,
|
|
388
|
+
projectIds: data.projectIds,
|
|
389
|
+
windowStart,
|
|
390
|
+
windowEnd,
|
|
391
|
+
includeCoveringShifts: true,
|
|
392
|
+
});
|
|
393
|
+
if (candidateIds.length === 0) {
|
|
394
|
+
return { shifts: [], truncated: false, generatedAt: now };
|
|
395
|
+
}
|
|
396
|
+
const schedules = await OnCallCalendarFeedRenderer.loadSchedules(candidateIds);
|
|
397
|
+
const segments = await OnCallCalendarFeedRenderer.loadScheduleSegmentsBatch({
|
|
398
|
+
schedules,
|
|
399
|
+
windowStart,
|
|
400
|
+
windowEnd,
|
|
401
|
+
now,
|
|
402
|
+
});
|
|
403
|
+
const own = OnCallShiftMaterializer.filterShiftsForUser(OnCallCalendarFeedRenderer.collectShifts(segments, now), data.userId);
|
|
404
|
+
const inRange = own.filter((shift) => {
|
|
405
|
+
return shift.start < data.to && shift.end > data.from;
|
|
406
|
+
});
|
|
407
|
+
return {
|
|
408
|
+
shifts: MaterializedShiftUtil.sortByStart(inRange),
|
|
409
|
+
truncated: segments.some((segment) => {
|
|
410
|
+
return segment.truncated;
|
|
411
|
+
}),
|
|
412
|
+
generatedAt: now,
|
|
413
|
+
};
|
|
414
|
+
}
|
|
415
|
+
// -- Schedule-level cache ---------------------------------------------
|
|
416
|
+
/*
|
|
417
|
+
* One schedule's materialization over one window, from the shared cache or
|
|
418
|
+
* freshly rendered into it. The key is the schedule's shiftConfigVersion
|
|
419
|
+
* plus the exact window, so every feed and /my-shifts call that lands on
|
|
420
|
+
* the same day-aligned window shares one LayerUtil expansion.
|
|
421
|
+
*
|
|
422
|
+
* The coverage envelope is computed in the same callback: it is the same
|
|
423
|
+
* cost class as the expansion and the gap-event path would otherwise
|
|
424
|
+
* expand every layer a second time.
|
|
425
|
+
*/
|
|
426
|
+
static async loadScheduleSegments(data) {
|
|
427
|
+
const loaded = await OnCallCalendarFeedRenderer.loadScheduleSegmentsBatch({
|
|
428
|
+
schedules: [data.schedule],
|
|
429
|
+
windowStart: data.windowStart,
|
|
430
|
+
windowEnd: data.windowEnd,
|
|
431
|
+
now: data.now,
|
|
432
|
+
});
|
|
433
|
+
const segments = loaded[0];
|
|
434
|
+
if (!segments) {
|
|
435
|
+
throw new Error(`OnCallCalendarFeedRenderer: no segments were produced for schedule ${data.schedule.id.toString()}.`);
|
|
436
|
+
}
|
|
437
|
+
return segments;
|
|
438
|
+
}
|
|
439
|
+
/*
|
|
440
|
+
* Every schedule of one feed, over one window, in ONE pass: the cache
|
|
441
|
+
* separates hits from misses and the misses are materialized together.
|
|
442
|
+
* Reading them one by one made each schedule its own resolver call --
|
|
443
|
+
* seven queries per schedule and the same user and project rows read again
|
|
444
|
+
* for every one of them -- fanned out concurrently, which for a project
|
|
445
|
+
* feed over fifty schedules was hundreds of statements in flight against a
|
|
446
|
+
* fifty-connection pool. The order of `schedules` is preserved.
|
|
447
|
+
*/
|
|
448
|
+
static async loadScheduleSegmentsBatch(data) {
|
|
449
|
+
if (data.schedules.length === 0) {
|
|
450
|
+
return [];
|
|
451
|
+
}
|
|
452
|
+
const byId = new Map();
|
|
453
|
+
for (const schedule of data.schedules) {
|
|
454
|
+
byId.set(schedule.id.toString(), schedule);
|
|
455
|
+
}
|
|
456
|
+
const entries = data.schedules.map((schedule) => {
|
|
457
|
+
return {
|
|
458
|
+
scheduleId: schedule.id.toString(),
|
|
459
|
+
key: `${schedule.shiftConfigVersion}:${data.windowStart.toISOString()}:${data.windowEnd.toISOString()}`,
|
|
460
|
+
};
|
|
461
|
+
});
|
|
462
|
+
const rendered = await OnCallCalendarFeedCache.getOrRenderScheduleSegmentsBatch({
|
|
463
|
+
entries,
|
|
464
|
+
ttlSeconds: SCHEDULE_CACHE_TTL_SECONDS,
|
|
465
|
+
renderMissing: async (missing) => {
|
|
466
|
+
const schedules = [];
|
|
467
|
+
for (const entry of missing) {
|
|
468
|
+
const schedule = byId.get(entry.scheduleId);
|
|
469
|
+
if (schedule) {
|
|
470
|
+
schedules.push(schedule);
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
return await OnCallCalendarFeedRenderer.renderScheduleSegments({
|
|
474
|
+
schedules,
|
|
475
|
+
windowStart: data.windowStart,
|
|
476
|
+
windowEnd: data.windowEnd,
|
|
477
|
+
now: data.now,
|
|
478
|
+
});
|
|
479
|
+
},
|
|
480
|
+
});
|
|
481
|
+
const ordered = [];
|
|
482
|
+
for (const schedule of data.schedules) {
|
|
483
|
+
const segments = rendered.get(schedule.id.toString());
|
|
484
|
+
if (segments) {
|
|
485
|
+
ordered.push(segments);
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
return ordered;
|
|
489
|
+
}
|
|
490
|
+
/*
|
|
491
|
+
* ONE resolver call for every schedule that missed the cache, split back
|
|
492
|
+
* into one cache entry per schedule.
|
|
493
|
+
*/
|
|
494
|
+
static async renderScheduleSegments(data) {
|
|
495
|
+
var _a, _b, _c, _d;
|
|
496
|
+
const out = new Map();
|
|
497
|
+
if (data.schedules.length === 0) {
|
|
498
|
+
return out;
|
|
499
|
+
}
|
|
500
|
+
const result = await OnCallShiftMaterializer.materializeForSchedules({
|
|
501
|
+
scheduleIds: data.schedules.map((schedule) => {
|
|
502
|
+
return schedule.id;
|
|
503
|
+
}),
|
|
504
|
+
windowStart: data.windowStart,
|
|
505
|
+
windowEnd: data.windowEnd,
|
|
506
|
+
now: data.now,
|
|
507
|
+
maxSimulationIterations: FEED_SIMULATION_ITERATION_CAP,
|
|
508
|
+
});
|
|
509
|
+
const shiftsBySchedule = new Map();
|
|
510
|
+
for (const shift of result.shifts) {
|
|
511
|
+
const list = shiftsBySchedule.get(shift.scheduleId) || [];
|
|
512
|
+
list.push(shift);
|
|
513
|
+
shiftsBySchedule.set(shift.scheduleId, list);
|
|
514
|
+
}
|
|
515
|
+
for (const schedule of data.schedules) {
|
|
516
|
+
const scheduleId = schedule.id.toString();
|
|
517
|
+
const info = result.schedules.find((candidate) => {
|
|
518
|
+
return candidate.scheduleId === scheduleId;
|
|
519
|
+
});
|
|
520
|
+
let envelope = { segments: [], truncated: false };
|
|
521
|
+
if (info) {
|
|
522
|
+
envelope = OnCallCalendarFeedUtil.computeCoverageEnvelope({
|
|
523
|
+
layers: info.layerProps,
|
|
524
|
+
windowStart: data.windowStart,
|
|
525
|
+
windowEnd: data.windowEnd,
|
|
526
|
+
maxSimulationIterations: FEED_SIMULATION_ITERATION_CAP,
|
|
527
|
+
});
|
|
528
|
+
}
|
|
529
|
+
out.set(scheduleId, {
|
|
530
|
+
scheduleId,
|
|
531
|
+
scheduleName: (info === null || info === void 0 ? void 0 : info.scheduleName) || schedule.name,
|
|
532
|
+
scheduleTimezone: (_b = (_a = info === null || info === void 0 ? void 0 : info.scheduleTimezone) !== null && _a !== void 0 ? _a : schedule.timezone) !== null && _b !== void 0 ? _b : null,
|
|
533
|
+
projectId: (info === null || info === void 0 ? void 0 : info.projectId) || schedule.projectId.toString(),
|
|
534
|
+
projectName: (_c = info === null || info === void 0 ? void 0 : info.projectName) !== null && _c !== void 0 ? _c : null,
|
|
535
|
+
shiftConfigVersion: (_d = info === null || info === void 0 ? void 0 : info.shiftConfigVersion) !== null && _d !== void 0 ? _d : schedule.shiftConfigVersion,
|
|
536
|
+
lastModifiedAt: ((info === null || info === void 0 ? void 0 : info.lastModifiedAt) || data.now).toISOString(),
|
|
537
|
+
truncated: info ? info.truncated : result.truncated,
|
|
538
|
+
shifts: MaterializedShiftUtil.toJSONArray(shiftsBySchedule.get(scheduleId) || []),
|
|
539
|
+
envelope: envelope.segments.map((segment) => {
|
|
540
|
+
return {
|
|
541
|
+
start: segment.start.toISOString(),
|
|
542
|
+
end: segment.end.toISOString(),
|
|
543
|
+
};
|
|
544
|
+
}),
|
|
545
|
+
envelopeTruncated: envelope.truncated,
|
|
546
|
+
});
|
|
547
|
+
}
|
|
548
|
+
return out;
|
|
549
|
+
}
|
|
550
|
+
// -- Cache key ---------------------------------------------------------
|
|
551
|
+
/*
|
|
552
|
+
* `${kind}:${tokenHash}:${filters}:${window}` -- everything that identifies
|
|
553
|
+
* the FEED, with nothing in it that changes when the roster does. Shared by
|
|
554
|
+
* the body key and the last-good key.
|
|
555
|
+
*/
|
|
556
|
+
static buildFeedIdentityKey(data) {
|
|
557
|
+
var _a;
|
|
558
|
+
const request = data.request;
|
|
559
|
+
let filters;
|
|
560
|
+
if (request.kind === OnCallCalendarFeedKind.Personal) {
|
|
561
|
+
filters = `s=${((_a = request.scheduleFilterId) === null || _a === void 0 ? void 0 : _a.toString()) || ""};c=${request.includeCoveringShifts ? 1 : 0}`;
|
|
562
|
+
}
|
|
563
|
+
else {
|
|
564
|
+
filters = `g=${request.includeCoverageGaps ? 1 : 0};m=${request.minimumGapMinutes}`;
|
|
565
|
+
}
|
|
566
|
+
return [
|
|
567
|
+
request.kind,
|
|
568
|
+
request.tokenHash,
|
|
569
|
+
filters,
|
|
570
|
+
`w=${data.pastDays}/${data.futureDays}`,
|
|
571
|
+
].join(":");
|
|
572
|
+
}
|
|
573
|
+
static digestOf(value) {
|
|
574
|
+
return createHash("sha256")
|
|
575
|
+
.update(value, "utf8")
|
|
576
|
+
.digest("hex")
|
|
577
|
+
.slice(0, 24);
|
|
578
|
+
}
|
|
579
|
+
/*
|
|
580
|
+
* `${identity}:${digest(scheduleIds+versions)}:${day}`.
|
|
581
|
+
* The candidate set and every shiftConfigVersion are read from Postgres on
|
|
582
|
+
* each request, so any configuration edit changes the key immediately --
|
|
583
|
+
* no counters to lose. The day bucket rolls the window at UTC midnight.
|
|
584
|
+
*/
|
|
585
|
+
static buildBodyCacheKey(data) {
|
|
586
|
+
const versions = data.schedules
|
|
587
|
+
.map((schedule) => {
|
|
588
|
+
return `${schedule.id.toString()}@${schedule.shiftConfigVersion}`;
|
|
589
|
+
})
|
|
590
|
+
.sort()
|
|
591
|
+
.join(",");
|
|
592
|
+
return [
|
|
593
|
+
OnCallCalendarFeedRenderer.buildFeedIdentityKey(data),
|
|
594
|
+
OnCallCalendarFeedRenderer.digestOf(versions),
|
|
595
|
+
CalendarFeedWindow.getUtcDayBucket(data.now),
|
|
596
|
+
].join(":");
|
|
597
|
+
}
|
|
598
|
+
/*
|
|
599
|
+
* The key of the stale-while-error tier: `${identity}:${digest(scheduleIds)}`
|
|
600
|
+
* -- deliberately NOT the body key.
|
|
601
|
+
*
|
|
602
|
+
* The body key carries every schedule's shiftConfigVersion and the UTC day
|
|
603
|
+
* bucket, both of which change constantly: every layer/override/attachment
|
|
604
|
+
* edit bumps a version, and every feed's day bucket rolls at midnight UTC.
|
|
605
|
+
* Keying the last-good body on those meant the fallback existed only until
|
|
606
|
+
* the next edit or the next midnight -- and those are exactly the moments
|
|
607
|
+
* it is needed, because they are also when every subscriber's body cache
|
|
608
|
+
* misses at once and the four render slots are scarcest. The result was a
|
|
609
|
+
* 503 (which some clients answer by dropping the subscription) with a
|
|
610
|
+
* perfectly good body sitting one key away.
|
|
611
|
+
*
|
|
612
|
+
* The SORTED SCHEDULE-ID SET stays in the key. That is the authorisation
|
|
613
|
+
* property: a body rendered when the user was on schedules {A, B} can never
|
|
614
|
+
* be served after they are removed from B, because the key is different.
|
|
615
|
+
* The token hash is in it too, so a rotated token never reaches an old body.
|
|
616
|
+
* What is dropped is only "the roster changed" and "the day rolled", which
|
|
617
|
+
* is precisely what "stale" means.
|
|
618
|
+
*/
|
|
619
|
+
static buildLastGoodCacheKey(data) {
|
|
620
|
+
const ids = data.schedules
|
|
621
|
+
.map((schedule) => {
|
|
622
|
+
return schedule.id.toString();
|
|
623
|
+
})
|
|
624
|
+
.sort()
|
|
625
|
+
.join(",");
|
|
626
|
+
return [
|
|
627
|
+
OnCallCalendarFeedRenderer.buildFeedIdentityKey(data),
|
|
628
|
+
OnCallCalendarFeedRenderer.digestOf(ids),
|
|
629
|
+
].join(":");
|
|
630
|
+
}
|
|
631
|
+
// -- Context (authorization, re-derived per fetch) ----------------------
|
|
632
|
+
static async resolveContext(request, window) {
|
|
633
|
+
switch (request.kind) {
|
|
634
|
+
case OnCallCalendarFeedKind.Personal:
|
|
635
|
+
return await OnCallCalendarFeedRenderer.resolvePersonalContext(request, window);
|
|
636
|
+
case OnCallCalendarFeedKind.Schedule:
|
|
637
|
+
return await OnCallCalendarFeedRenderer.resolveScheduleContext(request);
|
|
638
|
+
case OnCallCalendarFeedKind.Project:
|
|
639
|
+
return await OnCallCalendarFeedRenderer.resolveProjectContext(request);
|
|
640
|
+
default:
|
|
641
|
+
return { empty: true, reason: USER_MISSING_REASON };
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
static async resolvePersonalContext(request, window) {
|
|
645
|
+
const user = await UserService.findOneById({
|
|
646
|
+
id: request.userId,
|
|
647
|
+
select: {
|
|
648
|
+
_id: true,
|
|
649
|
+
timezone: true,
|
|
650
|
+
},
|
|
651
|
+
props: {
|
|
652
|
+
isRoot: true,
|
|
653
|
+
ignoreHooks: true,
|
|
654
|
+
},
|
|
655
|
+
});
|
|
656
|
+
if (!user) {
|
|
657
|
+
return { empty: true, reason: USER_MISSING_REASON };
|
|
658
|
+
}
|
|
659
|
+
const viewerTimezone = user.timezone
|
|
660
|
+
? user.timezone.toString()
|
|
661
|
+
: undefined;
|
|
662
|
+
if (!(await OnCallCalendarFeedRenderer.isProjectOnPlan(request.projectId))) {
|
|
663
|
+
return { empty: true, reason: PLAN_REASON, timezone: viewerTimezone };
|
|
664
|
+
}
|
|
665
|
+
const candidateIds = await OnCallShiftMaterializer.getCandidateScheduleIdsForUser({
|
|
666
|
+
userId: request.userId,
|
|
667
|
+
projectIds: [request.projectId],
|
|
668
|
+
scheduleId: request.scheduleFilterId,
|
|
669
|
+
windowStart: window.feedStart,
|
|
670
|
+
windowEnd: window.feedEnd,
|
|
671
|
+
includeCoveringShifts: request.includeCoveringShifts,
|
|
672
|
+
});
|
|
673
|
+
let filterScheduleName = undefined;
|
|
674
|
+
if (request.scheduleFilterId) {
|
|
675
|
+
const filtered = await OnCallCalendarFeedRenderer.loadSchedules([
|
|
676
|
+
request.scheduleFilterId,
|
|
677
|
+
]);
|
|
678
|
+
const candidate = filtered[0];
|
|
679
|
+
/*
|
|
680
|
+
* loadSchedules is a root read by id, and the id came from the query
|
|
681
|
+
* string. The name goes into X-WR-CALNAME/X-WR-CALDESC of a 200 body,
|
|
682
|
+
* so naming a schedule that belongs to another project would turn any
|
|
683
|
+
* personal feed link into an id-to-name oracle across tenants. Only a
|
|
684
|
+
* schedule in the token's own project is ever named.
|
|
685
|
+
*/
|
|
686
|
+
if (candidate &&
|
|
687
|
+
candidate.projectId.toString() === request.projectId.toString()) {
|
|
688
|
+
filterScheduleName = candidate.name;
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
if (candidateIds.length === 0) {
|
|
692
|
+
return {
|
|
693
|
+
empty: true,
|
|
694
|
+
reason: request.scheduleFilterId
|
|
695
|
+
? FILTERED_SCHEDULE_REASON
|
|
696
|
+
: NO_SCHEDULES_REASON,
|
|
697
|
+
filterScheduleName,
|
|
698
|
+
timezone: viewerTimezone,
|
|
699
|
+
};
|
|
700
|
+
}
|
|
701
|
+
const schedules = (await OnCallCalendarFeedRenderer.loadSchedules(candidateIds)).filter((schedule) => {
|
|
702
|
+
/*
|
|
703
|
+
* Belt and braces: the candidate query was scoped to the project, but
|
|
704
|
+
* a schedule row from another project must never render under this
|
|
705
|
+
* project's token.
|
|
706
|
+
*/
|
|
707
|
+
return schedule.projectId.toString() === request.projectId.toString();
|
|
708
|
+
});
|
|
709
|
+
if (schedules.length === 0) {
|
|
710
|
+
return {
|
|
711
|
+
empty: true,
|
|
712
|
+
reason: request.scheduleFilterId
|
|
713
|
+
? FILTERED_SCHEDULE_REASON
|
|
714
|
+
: NO_SCHEDULES_REASON,
|
|
715
|
+
filterScheduleName,
|
|
716
|
+
timezone: viewerTimezone,
|
|
717
|
+
};
|
|
718
|
+
}
|
|
719
|
+
return {
|
|
720
|
+
empty: false,
|
|
721
|
+
schedules,
|
|
722
|
+
viewerTimezone,
|
|
723
|
+
calendarTimezone: viewerTimezone,
|
|
724
|
+
filterScheduleName,
|
|
725
|
+
};
|
|
726
|
+
}
|
|
727
|
+
static async resolveScheduleContext(request) {
|
|
728
|
+
const schedules = await OnCallCalendarFeedRenderer.loadSchedules([request.scheduleId]);
|
|
729
|
+
const schedule = schedules[0];
|
|
730
|
+
if (!schedule ||
|
|
731
|
+
schedule.projectId.toString() !== request.projectId.toString()) {
|
|
732
|
+
return { empty: true, reason: SCHEDULE_MISSING_REASON };
|
|
733
|
+
}
|
|
734
|
+
if (!(await OnCallCalendarFeedRenderer.isProjectOnPlan(request.projectId))) {
|
|
735
|
+
return {
|
|
736
|
+
empty: true,
|
|
737
|
+
reason: PLAN_REASON,
|
|
738
|
+
scheduleName: schedule.name,
|
|
739
|
+
timezone: schedule.timezone,
|
|
740
|
+
};
|
|
741
|
+
}
|
|
742
|
+
return {
|
|
743
|
+
empty: false,
|
|
744
|
+
schedules: [schedule],
|
|
745
|
+
scheduleName: schedule.name,
|
|
746
|
+
calendarTimezone: schedule.timezone,
|
|
747
|
+
};
|
|
748
|
+
}
|
|
749
|
+
static async resolveProjectContext(request) {
|
|
750
|
+
const project = await ProjectService.findOneById({
|
|
751
|
+
id: request.projectId,
|
|
752
|
+
select: {
|
|
753
|
+
_id: true,
|
|
754
|
+
name: true,
|
|
755
|
+
},
|
|
756
|
+
props: {
|
|
757
|
+
isRoot: true,
|
|
758
|
+
ignoreHooks: true,
|
|
759
|
+
},
|
|
760
|
+
});
|
|
761
|
+
if (!project) {
|
|
762
|
+
return { empty: true, reason: PROJECT_MISSING_REASON };
|
|
763
|
+
}
|
|
764
|
+
const projectName = project.name || undefined;
|
|
765
|
+
if (!(await OnCallCalendarFeedRenderer.isProjectOnPlan(request.projectId))) {
|
|
766
|
+
return { empty: true, reason: PLAN_REASON, projectName };
|
|
767
|
+
}
|
|
768
|
+
const rows = await OnCallDutyPolicyScheduleService.findBy({
|
|
769
|
+
query: {
|
|
770
|
+
projectId: request.projectId,
|
|
771
|
+
},
|
|
772
|
+
select: OnCallCalendarFeedRenderer.scheduleSelect(),
|
|
773
|
+
limit: LIMIT_PER_PROJECT,
|
|
774
|
+
skip: 0,
|
|
775
|
+
sort: {
|
|
776
|
+
name: SortOrder.Ascending,
|
|
777
|
+
},
|
|
778
|
+
props: {
|
|
779
|
+
isRoot: true,
|
|
780
|
+
ignoreHooks: true,
|
|
781
|
+
},
|
|
782
|
+
});
|
|
783
|
+
const schedules = OnCallCalendarFeedRenderer.toScheduleInfos(rows);
|
|
784
|
+
if (schedules.length === 0) {
|
|
785
|
+
return { empty: true, reason: NO_PROJECT_SCHEDULES_REASON, projectName };
|
|
786
|
+
}
|
|
787
|
+
return {
|
|
788
|
+
empty: false,
|
|
789
|
+
schedules,
|
|
790
|
+
projectName,
|
|
791
|
+
};
|
|
792
|
+
}
|
|
793
|
+
// -- Helpers -----------------------------------------------------------
|
|
794
|
+
static scheduleSelect() {
|
|
795
|
+
return {
|
|
796
|
+
_id: true,
|
|
797
|
+
name: true,
|
|
798
|
+
timezone: true,
|
|
799
|
+
projectId: true,
|
|
800
|
+
shiftConfigVersion: true,
|
|
801
|
+
};
|
|
802
|
+
}
|
|
803
|
+
/*
|
|
804
|
+
* Root read of the schedule facts the render needs (name, zone, project,
|
|
805
|
+
* shiftConfigVersion). Input order is preserved; unknown ids are dropped.
|
|
806
|
+
*/
|
|
807
|
+
static async loadSchedules(ids) {
|
|
808
|
+
if (ids.length === 0) {
|
|
809
|
+
return [];
|
|
810
|
+
}
|
|
811
|
+
const rows = await OnCallDutyPolicyScheduleService.findBy({
|
|
812
|
+
query: {
|
|
813
|
+
_id: QueryHelper.any(ids),
|
|
814
|
+
},
|
|
815
|
+
select: OnCallCalendarFeedRenderer.scheduleSelect(),
|
|
816
|
+
limit: LIMIT_PER_PROJECT,
|
|
817
|
+
skip: 0,
|
|
818
|
+
props: {
|
|
819
|
+
isRoot: true,
|
|
820
|
+
ignoreHooks: true,
|
|
821
|
+
},
|
|
822
|
+
});
|
|
823
|
+
const byId = new Map();
|
|
824
|
+
for (const info of OnCallCalendarFeedRenderer.toScheduleInfos(rows)) {
|
|
825
|
+
byId.set(info.id.toString(), info);
|
|
826
|
+
}
|
|
827
|
+
const ordered = [];
|
|
828
|
+
for (const id of ids) {
|
|
829
|
+
const info = byId.get(id.toString());
|
|
830
|
+
if (info && !ordered.includes(info)) {
|
|
831
|
+
ordered.push(info);
|
|
832
|
+
}
|
|
833
|
+
}
|
|
834
|
+
return ordered;
|
|
835
|
+
}
|
|
836
|
+
static toScheduleInfos(rows) {
|
|
837
|
+
const infos = [];
|
|
838
|
+
for (const row of rows) {
|
|
839
|
+
if (!row.id || !row.projectId) {
|
|
840
|
+
continue;
|
|
841
|
+
}
|
|
842
|
+
const timezone = row.timezone
|
|
843
|
+
? row.timezone.toString()
|
|
844
|
+
: undefined;
|
|
845
|
+
const info = {
|
|
846
|
+
id: row.id,
|
|
847
|
+
name: row.name || "",
|
|
848
|
+
projectId: row.projectId,
|
|
849
|
+
shiftConfigVersion: typeof row.shiftConfigVersion === "number" &&
|
|
850
|
+
Number.isFinite(row.shiftConfigVersion)
|
|
851
|
+
? row.shiftConfigVersion
|
|
852
|
+
: Number(row.shiftConfigVersion) || 0,
|
|
853
|
+
};
|
|
854
|
+
if (timezone) {
|
|
855
|
+
info.timezone = timezone;
|
|
856
|
+
}
|
|
857
|
+
infos.push(info);
|
|
858
|
+
}
|
|
859
|
+
return infos;
|
|
860
|
+
}
|
|
861
|
+
/*
|
|
862
|
+
* Every cached shift of every schedule as MaterializedShift objects, with
|
|
863
|
+
* isPast re-evaluated against THIS request's clock (a schedule entry can be
|
|
864
|
+
* up to an hour old).
|
|
865
|
+
*/
|
|
866
|
+
static collectShifts(segments, now) {
|
|
867
|
+
const shifts = [];
|
|
868
|
+
for (const segment of segments) {
|
|
869
|
+
for (const shift of MaterializedShiftUtil.fromJSONArray(segment.shifts)) {
|
|
870
|
+
shift.isPast = shift.start.getTime() < now.getTime();
|
|
871
|
+
shifts.push(shift);
|
|
872
|
+
}
|
|
873
|
+
}
|
|
874
|
+
return MaterializedShiftUtil.sortByStart(shifts);
|
|
875
|
+
}
|
|
876
|
+
static buildGapEvents(data) {
|
|
877
|
+
const collected = [];
|
|
878
|
+
let truncated = false;
|
|
879
|
+
const minimumGapSeconds = Math.max(0, Math.floor(data.minimumGapMinutes)) * 60;
|
|
880
|
+
for (const segment of data.segments) {
|
|
881
|
+
const shifts = segment.shifts.map((shift) => {
|
|
882
|
+
return {
|
|
883
|
+
start: new Date(shift.start),
|
|
884
|
+
end: new Date(shift.end),
|
|
885
|
+
};
|
|
886
|
+
});
|
|
887
|
+
const envelope = segment.envelope.map((window) => {
|
|
888
|
+
return { start: new Date(window.start), end: new Date(window.end) };
|
|
889
|
+
});
|
|
890
|
+
const result = OnCallCalendarFeedUtil.buildCoverageGapEvents({
|
|
891
|
+
scheduleId: segment.scheduleId,
|
|
892
|
+
scheduleName: segment.scheduleName,
|
|
893
|
+
projectId: segment.projectId,
|
|
894
|
+
shifts,
|
|
895
|
+
feedStart: data.feedStart,
|
|
896
|
+
feedEnd: data.feedEnd,
|
|
897
|
+
envelope,
|
|
898
|
+
minimumGapSeconds,
|
|
899
|
+
lastModifiedAt: new Date(segment.lastModifiedAt),
|
|
900
|
+
shiftConfigVersion: segment.shiftConfigVersion,
|
|
901
|
+
dashboardUrl: data.dashboardUrl,
|
|
902
|
+
maxGapEvents: MAX_GAP_EVENTS,
|
|
903
|
+
});
|
|
904
|
+
truncated = truncated || result.truncated;
|
|
905
|
+
collected.push(...result.events);
|
|
906
|
+
}
|
|
907
|
+
collected.sort((a, b) => {
|
|
908
|
+
return a.start.getTime() - b.start.getTime();
|
|
909
|
+
});
|
|
910
|
+
if (collected.length > MAX_GAP_EVENTS) {
|
|
911
|
+
return { events: collected.slice(0, MAX_GAP_EVENTS), truncated: true };
|
|
912
|
+
}
|
|
913
|
+
return { events: collected, truncated };
|
|
914
|
+
}
|
|
915
|
+
static async fallBackToLastGood(data) {
|
|
916
|
+
const lastGood = await OnCallCalendarFeedCache.getLastGood(data.lastGoodKey);
|
|
917
|
+
if (lastGood) {
|
|
918
|
+
logger.warn(`OnCallCalendarFeedRenderer: ${data.why}; serving the last good ${data.kind} feed body.`);
|
|
919
|
+
return OnCallCalendarFeedRenderer.outcomeFromCachedBody({
|
|
920
|
+
kind: data.kind,
|
|
921
|
+
cached: lastGood,
|
|
922
|
+
stale: true,
|
|
923
|
+
cacheHit: false,
|
|
924
|
+
truncated: true,
|
|
925
|
+
});
|
|
926
|
+
}
|
|
927
|
+
logger.warn(`OnCallCalendarFeedRenderer: ${data.why} and nothing is cached for this ${data.kind} feed; answering unavailable.`);
|
|
928
|
+
return OnCallCalendarFeedRenderer.buildUnavailableOutcome(data.kind, RENDER_CAP_RETRY_AFTER_SECONDS);
|
|
929
|
+
}
|
|
930
|
+
static recordMetrics(data) {
|
|
931
|
+
try {
|
|
932
|
+
const attributes = {
|
|
933
|
+
[AppMetrics.ON_CALL_CALENDAR_FEED_KIND_ATTRIBUTE]: OnCallCalendarFeedUrls.getKindSegment(data.kind),
|
|
934
|
+
};
|
|
935
|
+
AppMetrics.getOnCallCalendarRenderDuration().record(data.durationMs, attributes);
|
|
936
|
+
AppMetrics.getOnCallCalendarRenderEvents().record(data.eventCount, attributes);
|
|
937
|
+
}
|
|
938
|
+
catch (err) {
|
|
939
|
+
logger.debug(`OnCallCalendarFeedRenderer: metrics unavailable (${String(err)})`);
|
|
940
|
+
}
|
|
941
|
+
}
|
|
942
|
+
/* VEVENT count of a serialized body, for outcomes rebuilt from a cache. */
|
|
943
|
+
static countEvents(body) {
|
|
944
|
+
return (body.match(/BEGIN:VEVENT/g) || []).length;
|
|
945
|
+
}
|
|
946
|
+
}
|
|
947
|
+
__decorate([
|
|
948
|
+
CaptureSpan(),
|
|
949
|
+
__metadata("design:type", Function),
|
|
950
|
+
__metadata("design:paramtypes", [ObjectID, Object]),
|
|
951
|
+
__metadata("design:returntype", Promise)
|
|
952
|
+
], OnCallCalendarFeedRenderer, "isProjectOnPlan", null);
|
|
953
|
+
__decorate([
|
|
954
|
+
CaptureSpan(),
|
|
955
|
+
__metadata("design:type", Function),
|
|
956
|
+
__metadata("design:paramtypes", [Object]),
|
|
957
|
+
__metadata("design:returntype", Promise)
|
|
958
|
+
], OnCallCalendarFeedRenderer, "render", null);
|
|
959
|
+
__decorate([
|
|
960
|
+
CaptureSpan(),
|
|
961
|
+
__metadata("design:type", Function),
|
|
962
|
+
__metadata("design:paramtypes", [Object]),
|
|
963
|
+
__metadata("design:returntype", Promise)
|
|
964
|
+
], OnCallCalendarFeedRenderer, "materializeUserShifts", null);
|
|
965
|
+
__decorate([
|
|
966
|
+
CaptureSpan(),
|
|
967
|
+
__metadata("design:type", Function),
|
|
968
|
+
__metadata("design:paramtypes", [Object]),
|
|
969
|
+
__metadata("design:returntype", Promise)
|
|
970
|
+
], OnCallCalendarFeedRenderer, "loadScheduleSegments", null);
|
|
971
|
+
__decorate([
|
|
972
|
+
CaptureSpan(),
|
|
973
|
+
__metadata("design:type", Function),
|
|
974
|
+
__metadata("design:paramtypes", [Object]),
|
|
975
|
+
__metadata("design:returntype", Promise)
|
|
976
|
+
], OnCallCalendarFeedRenderer, "loadScheduleSegmentsBatch", null);
|
|
977
|
+
__decorate([
|
|
978
|
+
CaptureSpan(),
|
|
979
|
+
__metadata("design:type", Function),
|
|
980
|
+
__metadata("design:paramtypes", [Array]),
|
|
981
|
+
__metadata("design:returntype", Promise)
|
|
982
|
+
], OnCallCalendarFeedRenderer, "loadSchedules", null);
|
|
983
|
+
//# sourceMappingURL=OnCallCalendarFeedRenderer.js.map
|