@oneuptime/common 11.7.2 → 11.7.4
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/KubernetesCostAllocation.ts +103 -0
- package/Models/DatabaseModels/AlertEpisodeStateTimeline.ts +1 -0
- package/Models/DatabaseModels/AlertStateTimeline.ts +1 -0
- package/Models/DatabaseModels/IncidentEpisodeStateTimeline.ts +1 -0
- package/Models/DatabaseModels/IncidentStateTimeline.ts +1 -0
- package/Models/DatabaseModels/Index.ts +5 -0
- package/Models/DatabaseModels/LogDropFilter.ts +89 -0
- package/Models/DatabaseModels/NetworkDeviceDiscoveryScan.ts +13 -3
- package/Models/DatabaseModels/RecommendationDismissal.ts +463 -0
- package/Models/DatabaseModels/ScheduledMaintenanceStateTimeline.ts +1 -0
- package/Models/DatabaseModels/StatusPageGroup.ts +95 -0
- package/Models/DatabaseModels/TableView.ts +40 -0
- package/Models/DatabaseModels/TraceDropFilter.ts +89 -0
- package/Models/DatabaseModels/WorkflowVariable.ts +5 -1
- package/Server/API/AlertAPI.ts +32 -17
- package/Server/API/BaseAPI.ts +31 -2
- package/Server/API/BaseAnalyticsAPI.ts +36 -2
- package/Server/API/CommonAPI.ts +57 -0
- package/Server/API/IncidentAPI.ts +60 -33
- package/Server/API/IncidentEpisodeAPI.ts +31 -16
- package/Server/API/MonitorAPI.ts +30 -0
- package/Server/API/MonitorTemplateAPI.ts +8 -0
- package/Server/API/ProbeAPI.ts +196 -15
- package/Server/API/ProjectAPI.ts +79 -1
- package/Server/API/ScheduledMaintenanceAPI.ts +33 -18
- package/Server/API/StatusPageAPI.ts +74 -37
- package/Server/API/WorkspaceNotificationRuleAPI.ts +34 -4
- package/Server/Infrastructure/Postgres/SchemaMigrations/1785241000000-AddColumnsToTableView.ts +13 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1785320000000-RepairCrossProjectIncidentReferences.ts +527 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1785329453269-AddParentGroupToStatusPageGroup.ts +31 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1785397674289-AddRecommendationDismissalTable.ts +55 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1785405581596-AddDroppedCountersToDropFilters.ts +53 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +10 -0
- package/Server/Services/AlertEpisodeService.ts +47 -0
- package/Server/Services/AlertService.ts +125 -0
- package/Server/Services/BillingService.ts +98 -0
- package/Server/Services/DatabaseService.ts +184 -20
- package/Server/Services/IncidentEpisodeService.ts +47 -0
- package/Server/Services/IncidentService.ts +123 -0
- package/Server/Services/IncidentTemplateService.ts +123 -1
- package/Server/Services/Index.ts +2 -0
- package/Server/Services/LogDropFilterService.ts +133 -0
- package/Server/Services/MonitorProbeService.ts +94 -4
- package/Server/Services/MonitorService.ts +48 -43
- package/Server/Services/NetworkDeviceDiscoveryScanService.ts +70 -0
- package/Server/Services/ProbeService.ts +66 -0
- package/Server/Services/ProjectService.ts +131 -7
- package/Server/Services/RecommendationDismissalService.ts +52 -0
- package/Server/Services/RunbookAgentJobService.ts +68 -7
- package/Server/Services/ScheduledMaintenanceService.ts +103 -0
- package/Server/Services/ScheduledMaintenanceTemplateService.ts +90 -0
- package/Server/Services/StatusPageGroupService.ts +186 -0
- package/Server/Services/TraceDropFilterService.ts +133 -0
- package/Server/Types/Workflow/Components/API/Delete.ts +12 -0
- package/Server/Types/Workflow/Components/API/Get.ts +12 -0
- package/Server/Types/Workflow/Components/API/Patch.ts +12 -0
- package/Server/Types/Workflow/Components/API/Post.ts +12 -0
- package/Server/Types/Workflow/Components/API/Put.ts +13 -0
- package/Server/Utils/Database/ProjectScopedReferenceValidator.ts +212 -0
- package/Server/Utils/DropFilterValidation.ts +127 -0
- package/Server/Utils/Errors.ts +5 -0
- package/Server/Utils/Monitor/MonitorAlert.ts +28 -1
- package/Server/Utils/Monitor/MonitorIncident.ts +31 -2
- package/Server/Utils/Telemetry/AppMetrics.ts +31 -0
- package/Tests/Models/AnalyticsModels/KubernetesCostAllocation.test.ts +16 -0
- package/Tests/Models/DatabaseModels/MonitorProbeColumnAccessControl.test.ts +196 -0
- package/Tests/Models/RecommendationDismissalModel.test.ts +269 -0
- package/Tests/Server/API/BaseAPIUpdatePayloadValidation.test.ts +320 -0
- package/Tests/Server/API/BaseAnalyticsAPIUpdatePayloadValidation.test.ts +293 -0
- package/Tests/Server/API/CommonAPIAuthGuard.test.ts +164 -0
- package/Tests/Server/API/ProbeAPI.test.ts +422 -53
- package/Tests/Server/API/ProjectAPI.test.ts +180 -0
- package/Tests/Server/API/ProjectAPIExtendTrialBillingDisabled.test.ts +138 -0
- package/Tests/Server/API/ProjectScopedCustomRouteAuth.test.ts +458 -0
- package/Tests/Server/Infrastructure/ContainerBootConfiguration.test.ts +359 -0
- package/Tests/Server/Infrastructure/ProcessSignalDelivery.test.ts +427 -0
- package/Tests/Server/Services/BillingServiceExtendTrial.test.ts +439 -0
- package/Tests/Server/Services/CrossProjectReferenceWriteGuard.test.ts +810 -0
- package/Tests/Server/Services/DatabaseServiceAtomicAddToColumns.test.ts +269 -0
- package/Tests/Server/Services/DatabaseServiceEmptyUpdate.test.ts +277 -0
- package/Tests/Server/Services/DatabaseServiceSortColumnSelect.test.ts +201 -0
- package/Tests/Server/Services/DiscoveryScanClaimHookFreeSafety.test.ts +81 -23
- package/Tests/Server/Services/DropFilterSaveValidation.test.ts +398 -0
- package/Tests/Server/Services/MonitorProbeDeleteHooks.test.ts +280 -0
- package/Tests/Server/Services/MonitorProbeServiceProbeTenancy.test.ts +304 -0
- package/Tests/Server/Services/NetworkDeviceDiscoveryScanService.test.ts +262 -0
- package/Tests/Server/Services/ProjectServiceExtendTrial.test.ts +614 -0
- package/Tests/Server/Services/RecommendationDismissalService.test.ts +306 -0
- package/Tests/Server/Services/RepairCrossProjectIncidentReferencesMigration.test.ts +528 -0
- package/Tests/Server/Services/StatusPageGroupNesting.test.ts +395 -0
- package/Tests/Server/TestingUtils/Services/BillingServiceHelper.ts +26 -21
- package/Tests/Server/Types/Database/Permissions/WorkflowVariableColumnPermission.test.ts +227 -0
- package/Tests/Server/Types/Workflow/Components/ApiComponentErrorPort.test.ts +285 -0
- package/Tests/Server/Utils/Database/ProjectScopedReferenceValidator.test.ts +463 -0
- package/Tests/Server/Utils/DropFilterValidation.test.ts +269 -0
- package/Tests/Server/Utils/Telemetry/SpanUtil.test.ts +94 -0
- package/Tests/Types/DateUserTimezone.test.ts +52 -0
- package/Tests/Types/JSONFunctions.test.ts +103 -1
- package/Tests/Types/Monitor/KubernetesAlertTemplates.test.ts +177 -9
- package/Tests/Types/Monitor/MonitorStepDnsMonitor.test.ts +105 -0
- package/Tests/Types/Monitor/MonitorStepDnssecMonitor.test.ts +131 -0
- package/Tests/Types/Monitor/MonitorStepDomainMonitor.test.ts +60 -0
- package/Tests/Types/Monitor/MonitorStepExternalStatusPageMonitor.test.ts +82 -0
- package/Tests/Types/Monitor/MonitorStepInfrastructureMonitors.test.ts +268 -0
- package/Tests/Types/Monitor/MonitorStepMetricMonitor.test.ts +386 -0
- package/Tests/Types/Monitor/MonitorStepProfileMonitor.test.ts +185 -0
- package/Tests/Types/Monitor/MonitorStepSnmpMonitor.test.ts +156 -0
- package/Tests/Types/Monitor/Recommendation/MonitorRecommendationCatalog.test.ts +371 -0
- package/Tests/Types/Monitor/Recommendation/MonitorRecommendationCoverage.test.ts +901 -0
- package/Tests/Types/Monitor/Recommendation/MonitorRecommendationNotificationMode.test.ts +607 -0
- package/Tests/Types/Monitor/Recommendation/MonitorRecommendationSeverityMapper.test.ts +754 -0
- package/Tests/Types/Monitor/Recommendation/MonitorRecommendationUtil.test.ts +960 -0
- package/Tests/Types/RollingTime/RollingTimeUtil.test.ts +186 -0
- package/Tests/Types/Runbook/RunbookStepTimeout.test.ts +410 -0
- package/Tests/Types/Telemetry/DropFilterSampling.test.ts +241 -0
- package/Tests/Types/Workspace/NotificationRuleConditionUtil.test.ts +353 -0
- package/Tests/Types/Workspace/NotificationRuleUtil.test.ts +566 -0
- package/Tests/UI/Components/CodeEditor.test.tsx +174 -0
- package/Tests/UI/Components/ErrorBoundary.test.tsx +555 -24
- package/Tests/UI/Components/InfoCard.test.tsx +358 -0
- package/Tests/UI/Components/LogTimeRangePicker.test.tsx +138 -0
- package/Tests/UI/Components/Modal.test.tsx +43 -5
- package/Tests/UI/Components/ModelTable/BaseModelTableColumnCustomization.test.tsx +679 -0
- package/Tests/UI/Components/ModelTable/BaseModelTableSearchLabels.test.tsx +397 -0
- package/Tests/UI/Components/ModelTable/ColumnCustomizationModal.test.tsx +999 -0
- package/Tests/UI/Components/ModelTable/ColumnPreference.test.ts +1678 -0
- package/Tests/UI/Components/ModelTable/CustomFieldColumns.test.tsx +1094 -0
- package/Tests/UI/Components/Runbook/StepTimeoutInput.test.tsx +386 -0
- package/Tests/UI/Components/StatusPage/ResourceGroupSection.test.tsx +671 -0
- package/Tests/UI/Components/TelemetryTimeRangePicker.test.tsx +404 -0
- package/Tests/UI/Utils/DropdownAlignment.test.ts +306 -0
- package/Tests/UI/Utils/TableFilterUrlState.test.ts +292 -0
- package/Tests/Utils/Monitor/MonitorSummaryProbeUtil.test.ts +263 -0
- package/Tests/Utils/NetworkDiscovery/ScanTargetUtil.test.ts +583 -0
- package/Tests/Utils/StatusPage/GroupNestingLayout.test.ts +1072 -0
- package/Tests/Utils/StatusPage/GroupTree.test.ts +583 -0
- package/Tests/Utils/StatusPage/ResourceUptime.test.ts +411 -0
- package/Tests/Utils/UserPreferences.test.ts +563 -0
- package/Types/Date.ts +15 -6
- package/Types/JSONFunctions.ts +7 -2
- package/Types/Kubernetes/KubernetesCostIngest.ts +37 -1
- package/Types/Monitor/KubernetesAlertTemplates.ts +205 -0
- package/Types/Monitor/MonitorStep.ts +10 -1
- package/Types/Monitor/MonitorStepMetricMonitor.ts +46 -1
- package/Types/Monitor/Recommendation/MonitorRecommendationCatalog.ts +413 -0
- package/Types/Monitor/Recommendation/MonitorRecommendationSeverityMapper.ts +168 -0
- package/Types/Monitor/Recommendation/MonitorRecommendationTypes.ts +175 -0
- package/Types/Monitor/Recommendation/MonitorRecommendationUtil.ts +743 -0
- package/Types/Permission.ts +45 -0
- package/Types/Recommendation/RecommendationType.ts +20 -0
- package/Types/Runbook/RunbookExecutionDeadline.ts +129 -0
- package/Types/Runbook/RunbookStepTimeout.ts +202 -0
- package/Types/Telemetry/DropFilterSampling.ts +92 -0
- package/UI/Components/AI/GenerateFromAIModal.tsx +0 -2
- package/UI/Components/Accordion/Accordion.tsx +10 -2
- package/UI/Components/BulkUpdate/BulkLabelActions.tsx +0 -1
- package/UI/Components/CodeEditor/CodeEditor.tsx +34 -20
- package/UI/Components/Date/RangeStartAndEndDateView.tsx +0 -1
- package/UI/Components/EditionLabel/EditionLabel.tsx +1 -27
- package/UI/Components/Error/PageError.tsx +0 -4
- package/UI/Components/ErrorBoundary.tsx +252 -15
- package/UI/Components/InfoCard/InfoCard.tsx +58 -1
- package/UI/Components/LogsViewer/components/LogTimeRangePicker.tsx +34 -1
- package/UI/Components/MasterPage/MasterPage.tsx +65 -0
- package/UI/Components/Modal/Modal.tsx +16 -60
- package/UI/Components/ModelFormModal/ModelFormModal.tsx +0 -8
- package/UI/Components/ModelTable/BaseModelTable.tsx +503 -71
- package/UI/Components/ModelTable/Column.ts +17 -0
- package/UI/Components/ModelTable/ColumnCustomizationModal.tsx +523 -0
- package/UI/Components/ModelTable/ColumnPreference.ts +482 -0
- package/UI/Components/ModelTable/CustomFieldColumns.tsx +326 -0
- package/UI/Components/ModelTable/TableView.tsx +24 -2
- package/UI/Components/ModelTable/useCustomFieldColumns.ts +150 -0
- package/UI/Components/Runbook/StepTimeoutInput.tsx +173 -0
- package/UI/Components/SideMenu/SideMenu.tsx +24 -4
- package/UI/Components/StatusPage/ResourceGroupSection.tsx +231 -0
- package/UI/Components/Table/Table.tsx +14 -1
- package/UI/Components/Table/TableRow.tsx +180 -175
- package/UI/Components/Table/Types/Column.ts +2 -0
- package/UI/Components/TelemetryViewer/components/TelemetryTimeRangePicker.tsx +34 -1
- package/UI/Utils/DropdownAlignment.ts +162 -0
- package/UI/Utils/TableFilterUrlState.ts +59 -20
- package/Utils/API.ts +106 -2
- package/Utils/Monitor/MonitorSummaryProbeUtil.ts +130 -0
- package/Utils/NetworkDiscovery/ScanTargetUtil.ts +434 -0
- package/Utils/StatusPage/GroupNestingLayout.ts +343 -0
- package/Utils/StatusPage/GroupTree.ts +307 -0
- package/Utils/StatusPage/ResourceUptime.ts +90 -17
- package/Utils/UserPreferences.ts +53 -0
- package/build/dist/Models/AnalyticsModels/KubernetesCostAllocation.js +86 -0
- package/build/dist/Models/AnalyticsModels/KubernetesCostAllocation.js.map +1 -1
- package/build/dist/Models/DatabaseModels/AlertEpisodeStateTimeline.js +1 -0
- package/build/dist/Models/DatabaseModels/AlertEpisodeStateTimeline.js.map +1 -1
- package/build/dist/Models/DatabaseModels/AlertStateTimeline.js +1 -0
- package/build/dist/Models/DatabaseModels/AlertStateTimeline.js.map +1 -1
- package/build/dist/Models/DatabaseModels/IncidentEpisodeStateTimeline.js +1 -0
- package/build/dist/Models/DatabaseModels/IncidentEpisodeStateTimeline.js.map +1 -1
- package/build/dist/Models/DatabaseModels/IncidentStateTimeline.js +1 -0
- package/build/dist/Models/DatabaseModels/IncidentStateTimeline.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Index.js +2 -0
- package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
- package/build/dist/Models/DatabaseModels/LogDropFilter.js +91 -0
- package/build/dist/Models/DatabaseModels/LogDropFilter.js.map +1 -1
- package/build/dist/Models/DatabaseModels/NetworkDeviceDiscoveryScan.js +14 -4
- package/build/dist/Models/DatabaseModels/NetworkDeviceDiscoveryScan.js.map +1 -1
- package/build/dist/Models/DatabaseModels/RecommendationDismissal.js +484 -0
- package/build/dist/Models/DatabaseModels/RecommendationDismissal.js.map +1 -0
- package/build/dist/Models/DatabaseModels/ScheduledMaintenanceStateTimeline.js +1 -0
- package/build/dist/Models/DatabaseModels/ScheduledMaintenanceStateTimeline.js.map +1 -1
- package/build/dist/Models/DatabaseModels/StatusPageGroup.js +94 -0
- package/build/dist/Models/DatabaseModels/StatusPageGroup.js.map +1 -1
- package/build/dist/Models/DatabaseModels/TableView.js +40 -0
- package/build/dist/Models/DatabaseModels/TableView.js.map +1 -1
- package/build/dist/Models/DatabaseModels/TraceDropFilter.js +91 -0
- package/build/dist/Models/DatabaseModels/TraceDropFilter.js.map +1 -1
- package/build/dist/Models/DatabaseModels/WorkflowVariable.js +5 -1
- package/build/dist/Models/DatabaseModels/WorkflowVariable.js.map +1 -1
- package/build/dist/Server/API/AlertAPI.js +22 -13
- package/build/dist/Server/API/AlertAPI.js.map +1 -1
- package/build/dist/Server/API/BaseAPI.js +22 -1
- package/build/dist/Server/API/BaseAPI.js.map +1 -1
- package/build/dist/Server/API/BaseAnalyticsAPI.js +24 -1
- package/build/dist/Server/API/BaseAnalyticsAPI.js.map +1 -1
- package/build/dist/Server/API/CommonAPI.js +42 -0
- package/build/dist/Server/API/CommonAPI.js.map +1 -1
- package/build/dist/Server/API/IncidentAPI.js +43 -26
- package/build/dist/Server/API/IncidentAPI.js.map +1 -1
- package/build/dist/Server/API/IncidentEpisodeAPI.js +21 -12
- package/build/dist/Server/API/IncidentEpisodeAPI.js.map +1 -1
- package/build/dist/Server/API/MonitorAPI.js +23 -0
- package/build/dist/Server/API/MonitorAPI.js.map +1 -1
- package/build/dist/Server/API/MonitorTemplateAPI.js +4 -0
- package/build/dist/Server/API/MonitorTemplateAPI.js.map +1 -1
- package/build/dist/Server/API/ProbeAPI.js +131 -15
- package/build/dist/Server/API/ProbeAPI.js.map +1 -1
- package/build/dist/Server/API/ProjectAPI.js +62 -3
- package/build/dist/Server/API/ProjectAPI.js.map +1 -1
- package/build/dist/Server/API/ScheduledMaintenanceAPI.js +23 -14
- package/build/dist/Server/API/ScheduledMaintenanceAPI.js.map +1 -1
- package/build/dist/Server/API/StatusPageAPI.js +61 -33
- package/build/dist/Server/API/StatusPageAPI.js.map +1 -1
- package/build/dist/Server/API/WorkspaceNotificationRuleAPI.js +26 -2
- package/build/dist/Server/API/WorkspaceNotificationRuleAPI.js.map +1 -1
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785241000000-AddColumnsToTableView.js +12 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785241000000-AddColumnsToTableView.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785320000000-RepairCrossProjectIncidentReferences.js +397 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785320000000-RepairCrossProjectIncidentReferences.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785329453269-AddParentGroupToStatusPageGroup.js +16 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785329453269-AddParentGroupToStatusPageGroup.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785397674289-AddRecommendationDismissalTable.js +30 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785397674289-AddRecommendationDismissalTable.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785405581596-AddDroppedCountersToDropFilters.js +34 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785405581596-AddDroppedCountersToDropFilters.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +10 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
- package/build/dist/Server/Services/AlertEpisodeService.js +39 -0
- package/build/dist/Server/Services/AlertEpisodeService.js.map +1 -1
- package/build/dist/Server/Services/AlertService.js +95 -0
- package/build/dist/Server/Services/AlertService.js.map +1 -1
- package/build/dist/Server/Services/BillingService.js +71 -0
- package/build/dist/Server/Services/BillingService.js.map +1 -1
- package/build/dist/Server/Services/DatabaseService.js +140 -17
- package/build/dist/Server/Services/DatabaseService.js.map +1 -1
- package/build/dist/Server/Services/IncidentEpisodeService.js +39 -0
- package/build/dist/Server/Services/IncidentEpisodeService.js.map +1 -1
- package/build/dist/Server/Services/IncidentService.js +100 -0
- package/build/dist/Server/Services/IncidentService.js.map +1 -1
- package/build/dist/Server/Services/IncidentTemplateService.js +97 -0
- package/build/dist/Server/Services/IncidentTemplateService.js.map +1 -1
- package/build/dist/Server/Services/Index.js +2 -0
- package/build/dist/Server/Services/Index.js.map +1 -1
- package/build/dist/Server/Services/LogDropFilterService.js +93 -0
- package/build/dist/Server/Services/LogDropFilterService.js.map +1 -1
- package/build/dist/Server/Services/MonitorProbeService.js +73 -5
- package/build/dist/Server/Services/MonitorProbeService.js.map +1 -1
- package/build/dist/Server/Services/MonitorService.js +34 -39
- package/build/dist/Server/Services/MonitorService.js.map +1 -1
- package/build/dist/Server/Services/NetworkDeviceDiscoveryScanService.js +71 -0
- package/build/dist/Server/Services/NetworkDeviceDiscoveryScanService.js.map +1 -1
- package/build/dist/Server/Services/ProbeService.js +64 -0
- package/build/dist/Server/Services/ProbeService.js.map +1 -1
- package/build/dist/Server/Services/ProjectService.js +103 -7
- package/build/dist/Server/Services/ProjectService.js.map +1 -1
- package/build/dist/Server/Services/RecommendationDismissalService.js +50 -0
- package/build/dist/Server/Services/RecommendationDismissalService.js.map +1 -0
- package/build/dist/Server/Services/RunbookAgentJobService.js +63 -5
- package/build/dist/Server/Services/RunbookAgentJobService.js.map +1 -1
- package/build/dist/Server/Services/ScheduledMaintenanceService.js +83 -0
- package/build/dist/Server/Services/ScheduledMaintenanceService.js.map +1 -1
- package/build/dist/Server/Services/ScheduledMaintenanceTemplateService.js +65 -0
- package/build/dist/Server/Services/ScheduledMaintenanceTemplateService.js.map +1 -1
- package/build/dist/Server/Services/StatusPageGroupService.js +136 -0
- package/build/dist/Server/Services/StatusPageGroupService.js.map +1 -1
- package/build/dist/Server/Services/TraceDropFilterService.js +93 -0
- package/build/dist/Server/Services/TraceDropFilterService.js.map +1 -1
- package/build/dist/Server/Types/Workflow/Components/API/Delete.js +11 -0
- package/build/dist/Server/Types/Workflow/Components/API/Delete.js.map +1 -1
- package/build/dist/Server/Types/Workflow/Components/API/Get.js +11 -0
- package/build/dist/Server/Types/Workflow/Components/API/Get.js.map +1 -1
- package/build/dist/Server/Types/Workflow/Components/API/Patch.js +11 -0
- package/build/dist/Server/Types/Workflow/Components/API/Patch.js.map +1 -1
- package/build/dist/Server/Types/Workflow/Components/API/Post.js +11 -0
- package/build/dist/Server/Types/Workflow/Components/API/Post.js.map +1 -1
- package/build/dist/Server/Types/Workflow/Components/API/Put.js +12 -0
- package/build/dist/Server/Types/Workflow/Components/API/Put.js.map +1 -1
- package/build/dist/Server/Utils/Database/ProjectScopedReferenceValidator.js +132 -0
- package/build/dist/Server/Utils/Database/ProjectScopedReferenceValidator.js.map +1 -0
- package/build/dist/Server/Utils/DropFilterValidation.js +80 -0
- package/build/dist/Server/Utils/DropFilterValidation.js.map +1 -0
- package/build/dist/Server/Utils/Errors.js +3 -0
- package/build/dist/Server/Utils/Errors.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorAlert.js +30 -12
- package/build/dist/Server/Utils/Monitor/MonitorAlert.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorIncident.js +38 -18
- package/build/dist/Server/Utils/Monitor/MonitorIncident.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/AppMetrics.js +26 -0
- package/build/dist/Server/Utils/Telemetry/AppMetrics.js.map +1 -1
- package/build/dist/Types/Date.js +14 -4
- package/build/dist/Types/Date.js.map +1 -1
- package/build/dist/Types/JSONFunctions.js +8 -3
- package/build/dist/Types/JSONFunctions.js.map +1 -1
- package/build/dist/Types/Kubernetes/KubernetesCostIngest.js.map +1 -1
- package/build/dist/Types/Monitor/KubernetesAlertTemplates.js +192 -0
- package/build/dist/Types/Monitor/KubernetesAlertTemplates.js.map +1 -1
- package/build/dist/Types/Monitor/MonitorStep.js +6 -1
- package/build/dist/Types/Monitor/MonitorStep.js.map +1 -1
- package/build/dist/Types/Monitor/MonitorStepMetricMonitor.js +32 -1
- package/build/dist/Types/Monitor/MonitorStepMetricMonitor.js.map +1 -1
- package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationCatalog.js +294 -0
- package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationCatalog.js.map +1 -0
- package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationSeverityMapper.js +110 -0
- package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationSeverityMapper.js.map +1 -0
- package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationTypes.js +58 -0
- package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationTypes.js.map +1 -0
- package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationUtil.js +451 -0
- package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationUtil.js.map +1 -0
- package/build/dist/Types/Permission.js +40 -0
- package/build/dist/Types/Permission.js.map +1 -1
- package/build/dist/Types/Recommendation/RecommendationType.js +21 -0
- package/build/dist/Types/Recommendation/RecommendationType.js.map +1 -0
- package/build/dist/Types/Runbook/RunbookExecutionDeadline.js +93 -0
- package/build/dist/Types/Runbook/RunbookExecutionDeadline.js.map +1 -0
- package/build/dist/Types/Runbook/RunbookStepTimeout.js +142 -0
- package/build/dist/Types/Runbook/RunbookStepTimeout.js.map +1 -0
- package/build/dist/Types/Telemetry/DropFilterSampling.js +75 -0
- package/build/dist/Types/Telemetry/DropFilterSampling.js.map +1 -0
- package/build/dist/UI/Components/AI/GenerateFromAIModal.js +1 -2
- package/build/dist/UI/Components/AI/GenerateFromAIModal.js.map +1 -1
- package/build/dist/UI/Components/Accordion/Accordion.js +9 -2
- package/build/dist/UI/Components/Accordion/Accordion.js.map +1 -1
- package/build/dist/UI/Components/BulkUpdate/BulkLabelActions.js +1 -1
- package/build/dist/UI/Components/BulkUpdate/BulkLabelActions.js.map +1 -1
- package/build/dist/UI/Components/CodeEditor/CodeEditor.js +27 -14
- package/build/dist/UI/Components/CodeEditor/CodeEditor.js.map +1 -1
- package/build/dist/UI/Components/Date/RangeStartAndEndDateView.js +1 -1
- package/build/dist/UI/Components/Date/RangeStartAndEndDateView.js.map +1 -1
- package/build/dist/UI/Components/EditionLabel/EditionLabel.js +2 -20
- package/build/dist/UI/Components/EditionLabel/EditionLabel.js.map +1 -1
- package/build/dist/UI/Components/Error/PageError.js +1 -3
- package/build/dist/UI/Components/Error/PageError.js.map +1 -1
- package/build/dist/UI/Components/ErrorBoundary.js +145 -11
- package/build/dist/UI/Components/ErrorBoundary.js.map +1 -1
- package/build/dist/UI/Components/InfoCard/InfoCard.js +28 -1
- package/build/dist/UI/Components/InfoCard/InfoCard.js.map +1 -1
- package/build/dist/UI/Components/LogsViewer/components/LogTimeRangePicker.js +13 -2
- package/build/dist/UI/Components/LogsViewer/components/LogTimeRangePicker.js.map +1 -1
- package/build/dist/UI/Components/MasterPage/MasterPage.js +50 -1
- package/build/dist/UI/Components/MasterPage/MasterPage.js.map +1 -1
- package/build/dist/UI/Components/Modal/Modal.js +4 -32
- package/build/dist/UI/Components/Modal/Modal.js.map +1 -1
- package/build/dist/UI/Components/ModelFormModal/ModelFormModal.js.map +1 -1
- package/build/dist/UI/Components/ModelTable/BaseModelTable.js +308 -40
- package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
- package/build/dist/UI/Components/ModelTable/ColumnCustomizationModal.js +230 -0
- package/build/dist/UI/Components/ModelTable/ColumnCustomizationModal.js.map +1 -0
- package/build/dist/UI/Components/ModelTable/ColumnPreference.js +258 -0
- package/build/dist/UI/Components/ModelTable/ColumnPreference.js.map +1 -0
- package/build/dist/UI/Components/ModelTable/CustomFieldColumns.js +168 -0
- package/build/dist/UI/Components/ModelTable/CustomFieldColumns.js.map +1 -0
- package/build/dist/UI/Components/ModelTable/TableView.js +13 -2
- package/build/dist/UI/Components/ModelTable/TableView.js.map +1 -1
- package/build/dist/UI/Components/ModelTable/useCustomFieldColumns.js +84 -0
- package/build/dist/UI/Components/ModelTable/useCustomFieldColumns.js.map +1 -0
- package/build/dist/UI/Components/Runbook/StepTimeoutInput.js +101 -0
- package/build/dist/UI/Components/Runbook/StepTimeoutInput.js.map +1 -0
- package/build/dist/UI/Components/SideMenu/SideMenu.js +15 -5
- package/build/dist/UI/Components/SideMenu/SideMenu.js.map +1 -1
- package/build/dist/UI/Components/StatusPage/ResourceGroupSection.js +73 -0
- package/build/dist/UI/Components/StatusPage/ResourceGroupSection.js.map +1 -0
- package/build/dist/UI/Components/Table/Table.js +15 -2
- package/build/dist/UI/Components/Table/Table.js.map +1 -1
- package/build/dist/UI/Components/Table/TableRow.js +11 -6
- package/build/dist/UI/Components/Table/TableRow.js.map +1 -1
- package/build/dist/UI/Components/TelemetryViewer/components/TelemetryTimeRangePicker.js +13 -2
- package/build/dist/UI/Components/TelemetryViewer/components/TelemetryTimeRangePicker.js.map +1 -1
- package/build/dist/UI/Utils/DropdownAlignment.js +98 -0
- package/build/dist/UI/Utils/DropdownAlignment.js.map +1 -0
- package/build/dist/UI/Utils/TableFilterUrlState.js +48 -15
- package/build/dist/UI/Utils/TableFilterUrlState.js.map +1 -1
- package/build/dist/Utils/API.js +39 -2
- package/build/dist/Utils/API.js.map +1 -1
- package/build/dist/Utils/Monitor/MonitorSummaryProbeUtil.js +97 -0
- package/build/dist/Utils/Monitor/MonitorSummaryProbeUtil.js.map +1 -0
- package/build/dist/Utils/NetworkDiscovery/ScanTargetUtil.js +330 -0
- package/build/dist/Utils/NetworkDiscovery/ScanTargetUtil.js.map +1 -0
- package/build/dist/Utils/StatusPage/GroupNestingLayout.js +280 -0
- package/build/dist/Utils/StatusPage/GroupNestingLayout.js.map +1 -0
- package/build/dist/Utils/StatusPage/GroupTree.js +214 -0
- package/build/dist/Utils/StatusPage/GroupTree.js.map +1 -0
- package/build/dist/Utils/StatusPage/ResourceUptime.js +60 -16
- package/build/dist/Utils/StatusPage/ResourceUptime.js.map +1 -1
- package/build/dist/Utils/UserPreferences.js +33 -0
- package/build/dist/Utils/UserPreferences.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,614 @@
|
|
|
1
|
+
import ProjectService from "../../../Server/Services/ProjectService";
|
|
2
|
+
import BillingService from "../../../Server/Services/BillingService";
|
|
3
|
+
import Project from "../../../Models/DatabaseModels/Project";
|
|
4
|
+
import SubscriptionPlan from "../../../Types/Billing/SubscriptionPlan";
|
|
5
|
+
import SubscriptionStatus from "../../../Types/Billing/SubscriptionStatus";
|
|
6
|
+
import OneUptimeDate from "../../../Types/Date";
|
|
7
|
+
import ObjectID from "../../../Types/ObjectID";
|
|
8
|
+
import { describe, expect, it, afterEach } from "@jest/globals";
|
|
9
|
+
|
|
10
|
+
/*
|
|
11
|
+
* ProjectService.extendTrial is the orchestration layer: the payment provider
|
|
12
|
+
* is the source of truth for what the customer is charged, so these tests pin
|
|
13
|
+
* the ordering (Stripe first, project row second) and the fact that a failed
|
|
14
|
+
* push leaves the stored trial date alone. Everything below the service
|
|
15
|
+
* boundary is spied - no database, no Stripe.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
jest.mock("../../../Server/EnvironmentConfig", () => {
|
|
19
|
+
return {
|
|
20
|
+
...jest.requireActual("../../../Server/EnvironmentConfig"),
|
|
21
|
+
IsBillingEnabled: true,
|
|
22
|
+
|
|
23
|
+
/*
|
|
24
|
+
* config.env carries a real incoming webhook URL, and reactiveSubscription
|
|
25
|
+
* announces every plan change on it. Blanked so the suite cannot post to
|
|
26
|
+
* Slack.
|
|
27
|
+
*/
|
|
28
|
+
NotificationSlackWebhookOnSubscriptionUpdate: "",
|
|
29
|
+
};
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
const PROJECT_ID: ObjectID = new ObjectID(
|
|
33
|
+
"11111111-1111-4111-8111-111111111111",
|
|
34
|
+
);
|
|
35
|
+
const SUBSCRIPTION_ID: string = "sub_main_123";
|
|
36
|
+
const METERED_SUBSCRIPTION_ID: string = "sub_metered_456";
|
|
37
|
+
|
|
38
|
+
function fakeProject(overrides?: Record<string, unknown>): Project {
|
|
39
|
+
return {
|
|
40
|
+
id: PROJECT_ID,
|
|
41
|
+
_id: PROJECT_ID.toString(),
|
|
42
|
+
trialEndsAt: OneUptimeDate.getSomeDaysAfter(2),
|
|
43
|
+
paymentProviderSubscriptionId: SUBSCRIPTION_ID,
|
|
44
|
+
paymentProviderMeteredSubscriptionId: METERED_SUBSCRIPTION_ID,
|
|
45
|
+
...overrides,
|
|
46
|
+
} as unknown as Project;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
describe("ProjectService.extendTrial", () => {
|
|
50
|
+
const newTrialEndDate: Date = OneUptimeDate.getSomeDaysAfter(30);
|
|
51
|
+
|
|
52
|
+
afterEach(() => {
|
|
53
|
+
jest.restoreAllMocks();
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
interface ExtendTrialSpies {
|
|
57
|
+
findOneById: jest.SpyInstance;
|
|
58
|
+
extendTrial: jest.SpyInstance;
|
|
59
|
+
getSubscriptionStatus: jest.SpyInstance;
|
|
60
|
+
updateOneById: jest.SpyInstance;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function setup(data?: {
|
|
64
|
+
project?: Project | null;
|
|
65
|
+
extendTrialError?: Error;
|
|
66
|
+
}): ExtendTrialSpies {
|
|
67
|
+
const findOneById: jest.SpyInstance = jest
|
|
68
|
+
.spyOn(ProjectService, "findOneById")
|
|
69
|
+
.mockResolvedValue(
|
|
70
|
+
data && data.project !== undefined ? data.project : fakeProject(),
|
|
71
|
+
);
|
|
72
|
+
|
|
73
|
+
const extendTrial: jest.SpyInstance = jest.spyOn(
|
|
74
|
+
BillingService,
|
|
75
|
+
"extendTrial",
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
if (data?.extendTrialError) {
|
|
79
|
+
extendTrial.mockRejectedValue(data.extendTrialError as never);
|
|
80
|
+
} else {
|
|
81
|
+
extendTrial.mockResolvedValue(undefined as never);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const getSubscriptionStatus: jest.SpyInstance = jest
|
|
85
|
+
.spyOn(BillingService, "getSubscriptionStatus")
|
|
86
|
+
.mockResolvedValue(SubscriptionStatus.Trialing as never);
|
|
87
|
+
|
|
88
|
+
const updateOneById: jest.SpyInstance = jest
|
|
89
|
+
.spyOn(ProjectService, "updateOneById")
|
|
90
|
+
.mockResolvedValue(undefined as never);
|
|
91
|
+
|
|
92
|
+
return { findOneById, extendTrial, getSubscriptionStatus, updateOneById };
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
describe("guards", () => {
|
|
96
|
+
it("should throw Project not found when the project does not exist", async () => {
|
|
97
|
+
const spies: ExtendTrialSpies = setup({ project: null });
|
|
98
|
+
|
|
99
|
+
await expect(
|
|
100
|
+
ProjectService.extendTrial({
|
|
101
|
+
projectId: PROJECT_ID,
|
|
102
|
+
trialEndsAt: newTrialEndDate,
|
|
103
|
+
}),
|
|
104
|
+
).rejects.toThrow("Project not found");
|
|
105
|
+
|
|
106
|
+
expect(spies.extendTrial).not.toHaveBeenCalled();
|
|
107
|
+
expect(spies.updateOneById).not.toHaveBeenCalled();
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
it("should throw when the project has no payment provider subscription", async () => {
|
|
111
|
+
const spies: ExtendTrialSpies = setup({
|
|
112
|
+
project: fakeProject({ paymentProviderSubscriptionId: undefined }),
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
await expect(
|
|
116
|
+
ProjectService.extendTrial({
|
|
117
|
+
projectId: PROJECT_ID,
|
|
118
|
+
trialEndsAt: newTrialEndDate,
|
|
119
|
+
}),
|
|
120
|
+
).rejects.toThrow("Payment Provider subscription not found");
|
|
121
|
+
|
|
122
|
+
expect(spies.extendTrial).not.toHaveBeenCalled();
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
it("should throw when the project has no metered subscription", async () => {
|
|
126
|
+
/*
|
|
127
|
+
* Every billed project gets both subscriptions at creation. A row with
|
|
128
|
+
* only one is broken, and extending half of it would bill usage during
|
|
129
|
+
* the trial - so fail loudly rather than partially apply.
|
|
130
|
+
*/
|
|
131
|
+
const spies: ExtendTrialSpies = setup({
|
|
132
|
+
project: fakeProject({
|
|
133
|
+
paymentProviderMeteredSubscriptionId: undefined,
|
|
134
|
+
}),
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
await expect(
|
|
138
|
+
ProjectService.extendTrial({
|
|
139
|
+
projectId: PROJECT_ID,
|
|
140
|
+
trialEndsAt: newTrialEndDate,
|
|
141
|
+
}),
|
|
142
|
+
).rejects.toThrow("Payment Provider metered subscription not found");
|
|
143
|
+
|
|
144
|
+
expect(spies.extendTrial).not.toHaveBeenCalled();
|
|
145
|
+
expect(spies.updateOneById).not.toHaveBeenCalled();
|
|
146
|
+
});
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
describe("reading the project", () => {
|
|
150
|
+
it("should select the trial date and both subscription ids as root", async () => {
|
|
151
|
+
const spies: ExtendTrialSpies = setup();
|
|
152
|
+
|
|
153
|
+
await ProjectService.extendTrial({
|
|
154
|
+
projectId: PROJECT_ID,
|
|
155
|
+
trialEndsAt: newTrialEndDate,
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
expect(spies.findOneById).toHaveBeenCalledWith({
|
|
159
|
+
id: PROJECT_ID,
|
|
160
|
+
select: {
|
|
161
|
+
_id: true,
|
|
162
|
+
trialEndsAt: true,
|
|
163
|
+
paymentProviderSubscriptionId: true,
|
|
164
|
+
paymentProviderMeteredSubscriptionId: true,
|
|
165
|
+
},
|
|
166
|
+
props: {
|
|
167
|
+
isRoot: true,
|
|
168
|
+
},
|
|
169
|
+
});
|
|
170
|
+
});
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
describe("pushing to the payment provider", () => {
|
|
174
|
+
it("should send both subscription ids and the new date", async () => {
|
|
175
|
+
const spies: ExtendTrialSpies = setup();
|
|
176
|
+
|
|
177
|
+
await ProjectService.extendTrial({
|
|
178
|
+
projectId: PROJECT_ID,
|
|
179
|
+
trialEndsAt: newTrialEndDate,
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
expect(spies.extendTrial).toHaveBeenCalledWith({
|
|
183
|
+
subscriptionId: SUBSCRIPTION_ID,
|
|
184
|
+
meteredSubscriptionId: METERED_SUBSCRIPTION_ID,
|
|
185
|
+
trialEndsAt: newTrialEndDate,
|
|
186
|
+
});
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
it("should not require the customer to have a payment method", async () => {
|
|
190
|
+
/*
|
|
191
|
+
* A trial extension is most useful for a customer who has not entered a
|
|
192
|
+
* card yet, so it deliberately does not gate on one the way changePlan
|
|
193
|
+
* does.
|
|
194
|
+
*/
|
|
195
|
+
setup();
|
|
196
|
+
|
|
197
|
+
const hasPaymentMethods: jest.SpyInstance = jest.spyOn(
|
|
198
|
+
BillingService,
|
|
199
|
+
"hasPaymentMethods",
|
|
200
|
+
);
|
|
201
|
+
|
|
202
|
+
await ProjectService.extendTrial({
|
|
203
|
+
projectId: PROJECT_ID,
|
|
204
|
+
trialEndsAt: newTrialEndDate,
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
expect(hasPaymentMethods).not.toHaveBeenCalled();
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
it("should call the payment provider before writing the project row", async () => {
|
|
211
|
+
const callOrder: Array<string> = [];
|
|
212
|
+
|
|
213
|
+
jest
|
|
214
|
+
.spyOn(ProjectService, "findOneById")
|
|
215
|
+
.mockResolvedValue(fakeProject());
|
|
216
|
+
jest
|
|
217
|
+
.spyOn(BillingService, "getSubscriptionStatus")
|
|
218
|
+
.mockResolvedValue(SubscriptionStatus.Trialing as never);
|
|
219
|
+
|
|
220
|
+
jest.spyOn(BillingService, "extendTrial").mockImplementation((():
|
|
221
|
+
| Promise<void>
|
|
222
|
+
| undefined => {
|
|
223
|
+
callOrder.push("stripe");
|
|
224
|
+
return Promise.resolve();
|
|
225
|
+
}) as never);
|
|
226
|
+
|
|
227
|
+
jest.spyOn(ProjectService, "updateOneById").mockImplementation((():
|
|
228
|
+
| Promise<void>
|
|
229
|
+
| undefined => {
|
|
230
|
+
callOrder.push("database");
|
|
231
|
+
return Promise.resolve();
|
|
232
|
+
}) as never);
|
|
233
|
+
|
|
234
|
+
await ProjectService.extendTrial({
|
|
235
|
+
projectId: PROJECT_ID,
|
|
236
|
+
trialEndsAt: newTrialEndDate,
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
expect(callOrder).toEqual(["stripe", "database"]);
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
it("should not write to the project row when the payment provider rejects", async () => {
|
|
243
|
+
/*
|
|
244
|
+
* If Stripe refuses, the stored trial date has to stay put - otherwise
|
|
245
|
+
* the customer sees a trial in the dashboard that they are actually
|
|
246
|
+
* being billed for.
|
|
247
|
+
*/
|
|
248
|
+
const spies: ExtendTrialSpies = setup({
|
|
249
|
+
extendTrialError: new Error("Stripe API error"),
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
await expect(
|
|
253
|
+
ProjectService.extendTrial({
|
|
254
|
+
projectId: PROJECT_ID,
|
|
255
|
+
trialEndsAt: newTrialEndDate,
|
|
256
|
+
}),
|
|
257
|
+
).rejects.toThrow("Stripe API error");
|
|
258
|
+
|
|
259
|
+
expect(spies.updateOneById).not.toHaveBeenCalled();
|
|
260
|
+
});
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
describe("persisting the result", () => {
|
|
264
|
+
it("should persist the trial date with isRoot and ignoreHooks", async () => {
|
|
265
|
+
/*
|
|
266
|
+
* Project.trialEndsAt has an empty update ACL, so nothing but a root
|
|
267
|
+
* write can set it. ignoreHooks matches how changePlan persists.
|
|
268
|
+
*/
|
|
269
|
+
const spies: ExtendTrialSpies = setup();
|
|
270
|
+
|
|
271
|
+
await ProjectService.extendTrial({
|
|
272
|
+
projectId: PROJECT_ID,
|
|
273
|
+
trialEndsAt: newTrialEndDate,
|
|
274
|
+
});
|
|
275
|
+
|
|
276
|
+
expect(spies.updateOneById).toHaveBeenCalledWith({
|
|
277
|
+
id: PROJECT_ID,
|
|
278
|
+
data: {
|
|
279
|
+
trialEndsAt: newTrialEndDate,
|
|
280
|
+
paymentProviderSubscriptionStatus: SubscriptionStatus.Trialing,
|
|
281
|
+
paymentProviderMeteredSubscriptionStatus: SubscriptionStatus.Trialing,
|
|
282
|
+
},
|
|
283
|
+
props: {
|
|
284
|
+
isRoot: true,
|
|
285
|
+
ignoreHooks: true,
|
|
286
|
+
},
|
|
287
|
+
});
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
it("should read both subscription statuses back from the payment provider", async () => {
|
|
291
|
+
const spies: ExtendTrialSpies = setup();
|
|
292
|
+
|
|
293
|
+
await ProjectService.extendTrial({
|
|
294
|
+
projectId: PROJECT_ID,
|
|
295
|
+
trialEndsAt: newTrialEndDate,
|
|
296
|
+
});
|
|
297
|
+
|
|
298
|
+
expect(spies.getSubscriptionStatus).toHaveBeenCalledWith(SUBSCRIPTION_ID);
|
|
299
|
+
expect(spies.getSubscriptionStatus).toHaveBeenCalledWith(
|
|
300
|
+
METERED_SUBSCRIPTION_ID,
|
|
301
|
+
);
|
|
302
|
+
});
|
|
303
|
+
|
|
304
|
+
it("should persist whatever statuses the payment provider reports", async () => {
|
|
305
|
+
/*
|
|
306
|
+
* The statuses are read back rather than assumed to be Trialing: the
|
|
307
|
+
* project row drives the customer's trial banner and the paywall, so it
|
|
308
|
+
* has to match Stripe even when Stripe disagrees with what we expected.
|
|
309
|
+
*/
|
|
310
|
+
const spies: ExtendTrialSpies = setup();
|
|
311
|
+
|
|
312
|
+
spies.getSubscriptionStatus
|
|
313
|
+
.mockResolvedValueOnce(SubscriptionStatus.Trialing as never)
|
|
314
|
+
.mockResolvedValueOnce(SubscriptionStatus.Active as never);
|
|
315
|
+
|
|
316
|
+
await ProjectService.extendTrial({
|
|
317
|
+
projectId: PROJECT_ID,
|
|
318
|
+
trialEndsAt: newTrialEndDate,
|
|
319
|
+
});
|
|
320
|
+
|
|
321
|
+
expect(spies.updateOneById).toHaveBeenCalledWith(
|
|
322
|
+
expect.objectContaining({
|
|
323
|
+
data: {
|
|
324
|
+
trialEndsAt: newTrialEndDate,
|
|
325
|
+
paymentProviderSubscriptionStatus: SubscriptionStatus.Trialing,
|
|
326
|
+
paymentProviderMeteredSubscriptionStatus: SubscriptionStatus.Active,
|
|
327
|
+
},
|
|
328
|
+
}),
|
|
329
|
+
);
|
|
330
|
+
});
|
|
331
|
+
});
|
|
332
|
+
});
|
|
333
|
+
|
|
334
|
+
const CUSTOMER_ID: string = "cus_789";
|
|
335
|
+
const PLAN_ID: string = "monthly_growth_plan_id";
|
|
336
|
+
const REACTIVATED_SUBSCRIPTION_ID: string = "sub_main_new_789";
|
|
337
|
+
const REACTIVATED_METERED_SUBSCRIPTION_ID: string = "sub_metered_new_012";
|
|
338
|
+
|
|
339
|
+
function fakeReactivationProject(overrides?: Record<string, unknown>): Project {
|
|
340
|
+
return {
|
|
341
|
+
id: PROJECT_ID,
|
|
342
|
+
_id: PROJECT_ID.toString(),
|
|
343
|
+
trialEndsAt: OneUptimeDate.getSomeDaysAfter(20),
|
|
344
|
+
paymentProviderCustomerId: CUSTOMER_ID,
|
|
345
|
+
paymentProviderSubscriptionId: SUBSCRIPTION_ID,
|
|
346
|
+
paymentProviderMeteredSubscriptionId: METERED_SUBSCRIPTION_ID,
|
|
347
|
+
paymentProviderSubscriptionSeats: 4,
|
|
348
|
+
paymentProviderPlanId: PLAN_ID,
|
|
349
|
+
...overrides,
|
|
350
|
+
} as unknown as Project;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
/*
|
|
354
|
+
* reactiveSubscription puts a project back on its plan after payment recovers.
|
|
355
|
+
* It goes through BillingService.changePlan, which cancels both subscriptions
|
|
356
|
+
* and creates replacements - so a trial the project still has to run exists
|
|
357
|
+
* only if it is handed to those replacements and then written back.
|
|
358
|
+
*
|
|
359
|
+
* These tests pin that, because dropping it bills a customer whose trial a
|
|
360
|
+
* master admin extended as a goodwill gesture on the spot.
|
|
361
|
+
*/
|
|
362
|
+
describe("ProjectService.reactiveSubscription", () => {
|
|
363
|
+
afterEach(() => {
|
|
364
|
+
jest.restoreAllMocks();
|
|
365
|
+
});
|
|
366
|
+
|
|
367
|
+
interface ReactivationSpies {
|
|
368
|
+
findOneById: jest.SpyInstance;
|
|
369
|
+
changePlan: jest.SpyInstance;
|
|
370
|
+
getSubscriptionStatus: jest.SpyInstance;
|
|
371
|
+
updateOneById: jest.SpyInstance;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
function setupReactivation(data?: {
|
|
375
|
+
project?: Project;
|
|
376
|
+
|
|
377
|
+
/*
|
|
378
|
+
* The trial the payment provider reports on the subscriptions it created.
|
|
379
|
+
* Omitted means it reported none.
|
|
380
|
+
*/
|
|
381
|
+
billingTrialEndsAt?: Date | undefined;
|
|
382
|
+
}): ReactivationSpies {
|
|
383
|
+
const findOneById: jest.SpyInstance = jest
|
|
384
|
+
.spyOn(ProjectService, "findOneById")
|
|
385
|
+
.mockResolvedValue(data?.project || fakeReactivationProject());
|
|
386
|
+
|
|
387
|
+
jest
|
|
388
|
+
.spyOn(SubscriptionPlan, "getSubscriptionPlanById")
|
|
389
|
+
.mockReturnValue(
|
|
390
|
+
new SubscriptionPlan(
|
|
391
|
+
PLAN_ID,
|
|
392
|
+
"yearly_growth_plan_id",
|
|
393
|
+
"Growth",
|
|
394
|
+
25,
|
|
395
|
+
250,
|
|
396
|
+
2,
|
|
397
|
+
14,
|
|
398
|
+
),
|
|
399
|
+
);
|
|
400
|
+
|
|
401
|
+
const changePlan: jest.SpyInstance = jest
|
|
402
|
+
.spyOn(BillingService, "changePlan")
|
|
403
|
+
.mockResolvedValue({
|
|
404
|
+
subscriptionId: REACTIVATED_SUBSCRIPTION_ID,
|
|
405
|
+
meteredSubscriptionId: REACTIVATED_METERED_SUBSCRIPTION_ID,
|
|
406
|
+
trialEndsAt: data?.billingTrialEndsAt,
|
|
407
|
+
} as never);
|
|
408
|
+
|
|
409
|
+
const getSubscriptionStatus: jest.SpyInstance = jest
|
|
410
|
+
.spyOn(BillingService, "getSubscriptionStatus")
|
|
411
|
+
.mockResolvedValue(SubscriptionStatus.Active as never);
|
|
412
|
+
|
|
413
|
+
const updateOneById: jest.SpyInstance = jest
|
|
414
|
+
.spyOn(ProjectService, "updateOneById")
|
|
415
|
+
.mockResolvedValue(undefined as never);
|
|
416
|
+
|
|
417
|
+
return { findOneById, changePlan, getSubscriptionStatus, updateOneById };
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
function getUpdatedData(spies: ReactivationSpies): Record<string, unknown> {
|
|
421
|
+
return (
|
|
422
|
+
spies.updateOneById.mock.calls[0]![0] as {
|
|
423
|
+
data: Record<string, unknown>;
|
|
424
|
+
}
|
|
425
|
+
).data;
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
describe("reading the project", () => {
|
|
429
|
+
it("should select the trial date", async () => {
|
|
430
|
+
/*
|
|
431
|
+
* Without this column in the select the trial date reads back undefined
|
|
432
|
+
* and every extension is silently dropped - which is the bug this
|
|
433
|
+
* suite exists for.
|
|
434
|
+
*/
|
|
435
|
+
const spies: ReactivationSpies = setupReactivation();
|
|
436
|
+
|
|
437
|
+
await ProjectService.reactiveSubscription(PROJECT_ID);
|
|
438
|
+
|
|
439
|
+
expect(spies.findOneById).toHaveBeenCalledWith(
|
|
440
|
+
expect.objectContaining({
|
|
441
|
+
select: expect.objectContaining({
|
|
442
|
+
trialEndsAt: true,
|
|
443
|
+
}),
|
|
444
|
+
}),
|
|
445
|
+
);
|
|
446
|
+
});
|
|
447
|
+
});
|
|
448
|
+
|
|
449
|
+
describe("carrying the trial onto the new subscriptions", () => {
|
|
450
|
+
it("should send a trial that is still running as endTrialAt", async () => {
|
|
451
|
+
const trialEndsAt: Date = OneUptimeDate.getSomeDaysAfter(30);
|
|
452
|
+
|
|
453
|
+
const spies: ReactivationSpies = setupReactivation({
|
|
454
|
+
project: fakeReactivationProject({ trialEndsAt: trialEndsAt }),
|
|
455
|
+
});
|
|
456
|
+
|
|
457
|
+
await ProjectService.reactiveSubscription(PROJECT_ID);
|
|
458
|
+
|
|
459
|
+
expect(spies.changePlan).toHaveBeenCalledWith(
|
|
460
|
+
expect.objectContaining({
|
|
461
|
+
endTrialAt: trialEndsAt,
|
|
462
|
+
}),
|
|
463
|
+
);
|
|
464
|
+
});
|
|
465
|
+
|
|
466
|
+
it("should not send a trial that has already lapsed", async () => {
|
|
467
|
+
/*
|
|
468
|
+
* Reactivation is not the place to hand out free service: a project
|
|
469
|
+
* whose trial ran out months ago goes back onto its plan billing.
|
|
470
|
+
*/
|
|
471
|
+
const spies: ReactivationSpies = setupReactivation({
|
|
472
|
+
project: fakeReactivationProject({
|
|
473
|
+
trialEndsAt: OneUptimeDate.getSomeDaysAgo(30),
|
|
474
|
+
}),
|
|
475
|
+
});
|
|
476
|
+
|
|
477
|
+
await ProjectService.reactiveSubscription(PROJECT_ID);
|
|
478
|
+
|
|
479
|
+
expect(spies.changePlan).toHaveBeenCalledWith(
|
|
480
|
+
expect.objectContaining({
|
|
481
|
+
endTrialAt: undefined,
|
|
482
|
+
}),
|
|
483
|
+
);
|
|
484
|
+
});
|
|
485
|
+
|
|
486
|
+
it("should not send a trial when the project has none", async () => {
|
|
487
|
+
const spies: ReactivationSpies = setupReactivation({
|
|
488
|
+
project: fakeReactivationProject({ trialEndsAt: null }),
|
|
489
|
+
});
|
|
490
|
+
|
|
491
|
+
await ProjectService.reactiveSubscription(PROJECT_ID);
|
|
492
|
+
|
|
493
|
+
expect(spies.changePlan).toHaveBeenCalledWith(
|
|
494
|
+
expect.objectContaining({
|
|
495
|
+
endTrialAt: undefined,
|
|
496
|
+
}),
|
|
497
|
+
);
|
|
498
|
+
});
|
|
499
|
+
});
|
|
500
|
+
|
|
501
|
+
describe("persisting the result", () => {
|
|
502
|
+
it("should persist the trial date the payment provider reports", async () => {
|
|
503
|
+
/*
|
|
504
|
+
* The payment provider is what actually charges the customer, so the
|
|
505
|
+
* date it puts on the new subscriptions wins over the one requested.
|
|
506
|
+
*/
|
|
507
|
+
const billingTrialEndsAt: Date = OneUptimeDate.getSomeDaysAfter(45);
|
|
508
|
+
|
|
509
|
+
const spies: ReactivationSpies = setupReactivation({
|
|
510
|
+
project: fakeReactivationProject({
|
|
511
|
+
trialEndsAt: OneUptimeDate.getSomeDaysAfter(20),
|
|
512
|
+
}),
|
|
513
|
+
billingTrialEndsAt: billingTrialEndsAt,
|
|
514
|
+
});
|
|
515
|
+
|
|
516
|
+
await ProjectService.reactiveSubscription(PROJECT_ID);
|
|
517
|
+
|
|
518
|
+
expect(getUpdatedData(spies)["trialEndsAt"]).toEqual(billingTrialEndsAt);
|
|
519
|
+
});
|
|
520
|
+
|
|
521
|
+
it("should fall back to the trial it sent when the provider reports none", async () => {
|
|
522
|
+
const trialEndsAt: Date = OneUptimeDate.getSomeDaysAfter(30);
|
|
523
|
+
|
|
524
|
+
const spies: ReactivationSpies = setupReactivation({
|
|
525
|
+
project: fakeReactivationProject({ trialEndsAt: trialEndsAt }),
|
|
526
|
+
});
|
|
527
|
+
|
|
528
|
+
await ProjectService.reactiveSubscription(PROJECT_ID);
|
|
529
|
+
|
|
530
|
+
expect(getUpdatedData(spies)["trialEndsAt"]).toEqual(trialEndsAt);
|
|
531
|
+
});
|
|
532
|
+
|
|
533
|
+
it("should leave the stored trial date alone when there is no trial", async () => {
|
|
534
|
+
/*
|
|
535
|
+
* A project that stopped trialing long ago keeps the date it ended on
|
|
536
|
+
* rather than being stamped with a fresh one by an unrelated
|
|
537
|
+
* reactivation.
|
|
538
|
+
*/
|
|
539
|
+
const spies: ReactivationSpies = setupReactivation({
|
|
540
|
+
project: fakeReactivationProject({
|
|
541
|
+
trialEndsAt: OneUptimeDate.getSomeDaysAgo(30),
|
|
542
|
+
}),
|
|
543
|
+
});
|
|
544
|
+
|
|
545
|
+
await ProjectService.reactiveSubscription(PROJECT_ID);
|
|
546
|
+
|
|
547
|
+
expect(Object.keys(getUpdatedData(spies))).not.toContain("trialEndsAt");
|
|
548
|
+
});
|
|
549
|
+
|
|
550
|
+
it("should still persist the new subscription ids and statuses", async () => {
|
|
551
|
+
const spies: ReactivationSpies = setupReactivation();
|
|
552
|
+
|
|
553
|
+
spies.getSubscriptionStatus
|
|
554
|
+
.mockResolvedValueOnce(SubscriptionStatus.Trialing as never)
|
|
555
|
+
.mockResolvedValueOnce(SubscriptionStatus.Active as never);
|
|
556
|
+
|
|
557
|
+
await ProjectService.reactiveSubscription(PROJECT_ID);
|
|
558
|
+
|
|
559
|
+
expect(getUpdatedData(spies)).toEqual(
|
|
560
|
+
expect.objectContaining({
|
|
561
|
+
paymentProviderSubscriptionId: REACTIVATED_SUBSCRIPTION_ID,
|
|
562
|
+
paymentProviderMeteredSubscriptionId:
|
|
563
|
+
REACTIVATED_METERED_SUBSCRIPTION_ID,
|
|
564
|
+
paymentProviderSubscriptionStatus: SubscriptionStatus.Trialing,
|
|
565
|
+
paymentProviderMeteredSubscriptionStatus: SubscriptionStatus.Active,
|
|
566
|
+
}),
|
|
567
|
+
);
|
|
568
|
+
});
|
|
569
|
+
|
|
570
|
+
it("should write the project row as root", async () => {
|
|
571
|
+
// Project.trialEndsAt has an empty update ACL - only a root write sets it.
|
|
572
|
+
const spies: ReactivationSpies = setupReactivation();
|
|
573
|
+
|
|
574
|
+
await ProjectService.reactiveSubscription(PROJECT_ID);
|
|
575
|
+
|
|
576
|
+
expect(spies.updateOneById).toHaveBeenCalledWith(
|
|
577
|
+
expect.objectContaining({
|
|
578
|
+
id: PROJECT_ID,
|
|
579
|
+
props: {
|
|
580
|
+
isRoot: true,
|
|
581
|
+
},
|
|
582
|
+
}),
|
|
583
|
+
);
|
|
584
|
+
});
|
|
585
|
+
});
|
|
586
|
+
|
|
587
|
+
describe("the goodwill extension it exists to protect", () => {
|
|
588
|
+
it("should keep an extended trial across a reactivation", async () => {
|
|
589
|
+
/*
|
|
590
|
+
* The end-to-end shape of the bug: support extends a customer's trial,
|
|
591
|
+
* their subscription is later reactivated, and the extension has to
|
|
592
|
+
* still be there afterwards - on the new subscriptions and on the row.
|
|
593
|
+
*/
|
|
594
|
+
const extendedTrialEndsAt: Date = OneUptimeDate.getSomeDaysAfter(60);
|
|
595
|
+
|
|
596
|
+
const spies: ReactivationSpies = setupReactivation({
|
|
597
|
+
project: fakeReactivationProject({
|
|
598
|
+
trialEndsAt: extendedTrialEndsAt,
|
|
599
|
+
}),
|
|
600
|
+
billingTrialEndsAt: extendedTrialEndsAt,
|
|
601
|
+
});
|
|
602
|
+
|
|
603
|
+
await ProjectService.reactiveSubscription(PROJECT_ID);
|
|
604
|
+
|
|
605
|
+
expect(spies.changePlan).toHaveBeenCalledWith(
|
|
606
|
+
expect.objectContaining({
|
|
607
|
+
endTrialAt: extendedTrialEndsAt,
|
|
608
|
+
}),
|
|
609
|
+
);
|
|
610
|
+
|
|
611
|
+
expect(getUpdatedData(spies)["trialEndsAt"]).toEqual(extendedTrialEndsAt);
|
|
612
|
+
});
|
|
613
|
+
});
|
|
614
|
+
});
|