@oneuptime/common 11.7.4 → 12.0.1
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/ExceptionInstance.ts +67 -0
- package/Models/AnalyticsModels/Index.ts +10 -0
- package/Models/AnalyticsModels/Log.ts +60 -0
- package/Models/AnalyticsModels/RumSession.ts +1401 -0
- package/Models/AnalyticsModels/RumSessionChunk.ts +798 -0
- package/Models/AnalyticsModels/Span.ts +60 -0
- package/Models/DatabaseModels/AIAgentTaskPullRequest.ts +52 -0
- package/Models/DatabaseModels/AIRun.ts +31 -0
- package/Models/DatabaseModels/Alert.ts +29 -0
- package/Models/DatabaseModels/AlertCustomField.ts +1 -1
- package/Models/DatabaseModels/AlertFeed.ts +1 -0
- package/Models/DatabaseModels/AutoRemediationRule.ts +989 -0
- package/Models/DatabaseModels/AutoRemediationSuggestion.ts +874 -0
- package/Models/DatabaseModels/CodeRepository.ts +129 -0
- package/Models/DatabaseModels/GlobalConfig.ts +312 -0
- package/Models/DatabaseModels/Incident.ts +29 -0
- package/Models/DatabaseModels/IncidentCustomField.ts +1 -1
- package/Models/DatabaseModels/IncidentFeed.ts +1 -0
- package/Models/DatabaseModels/Index.ts +21 -8
- package/Models/DatabaseModels/InstanceHealthLog.ts +8 -0
- package/Models/DatabaseModels/MonitorCustomField.ts +1 -1
- package/Models/DatabaseModels/MonitorStatus.ts +1 -1
- package/Models/DatabaseModels/NetworkDeviceLabelRule.ts +2 -2
- package/Models/DatabaseModels/NetworkDeviceOwnerRule.ts +2 -2
- package/Models/DatabaseModels/NetworkSiteAssignmentRule.ts +1 -1
- package/Models/DatabaseModels/OnCallDutyPolicyCustomField.ts +1 -1
- package/Models/DatabaseModels/OnCallDutyPolicyScheduleLayer.ts +12 -2
- package/Models/DatabaseModels/Project.ts +231 -0
- package/Models/DatabaseModels/RumApplication.ts +906 -0
- package/Models/DatabaseModels/RumSessionErasureRequest.ts +561 -0
- package/Models/DatabaseModels/RumSessionPin.ts +457 -0
- package/Models/DatabaseModels/RumSessionReplayView.ts +406 -0
- package/Models/DatabaseModels/RunbookCredential.ts +673 -0
- package/Models/DatabaseModels/RunbookSecret.ts +7 -7
- package/Models/DatabaseModels/{RunbookAgent.ts → Runner.ts} +206 -46
- package/Models/DatabaseModels/{RunbookAgentJob.ts → RunnerJob.ts} +151 -18
- package/Models/DatabaseModels/{RunbookAgentOwnerTeam.ts → RunnerOwnerTeam.ts} +41 -43
- package/Models/DatabaseModels/{RunbookAgentOwnerUser.ts → RunnerOwnerUser.ts} +41 -43
- package/Models/DatabaseModels/ScheduledMaintenanceCustomField.ts +1 -1
- package/Models/DatabaseModels/StatusPageCustomField.ts +1 -1
- package/Models/DatabaseModels/TeamCustomField.ts +1 -1
- package/Models/DatabaseModels/TeamMemberCustomField.ts +1 -1
- package/Server/API/AIAgentDataAPI.ts +179 -48
- package/Server/API/AIAgentTaskAPI.ts +36 -37
- package/Server/API/AIAgentTaskLogAPI.ts +19 -33
- package/Server/API/AutoRemediationAPI.ts +557 -0
- package/Server/API/BaseAnalyticsAPI.ts +4 -1
- package/Server/API/CommonAPI.ts +35 -0
- package/Server/API/DashboardAPI.ts +340 -15
- package/Server/API/TelemetryAPI.ts +1622 -3
- package/Server/API/UserIncomingCallNumberAPI.ts +31 -0
- package/Server/DatabaseConfig.ts +26 -1
- package/Server/EnvironmentConfig.ts +13 -0
- package/Server/Infrastructure/Postgres/LocalMigrationGenerationDataSource.ts +12 -2
- package/Server/Infrastructure/Postgres/SchemaMigrations/1785417351021-AddSessionReplay.ts +293 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1785491583874-EnableSessionReplayByDefault.ts +67 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1785496223183-AddMonitorSummaryToIncidentAndAlert.ts +33 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1785516996695-AddSessionReplayReliabilityColumns.ts +40 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1785533806494-AddSessionReplayCorrelationColumns.ts +54 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1785749674203-AddRedisAndPostgresHealthNotificationColumns.ts +104 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1785763818197-AddAutoRemediation.ts +349 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1785768089408-AddRemediationVerification.ts +67 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1785776960660-AddRunnerCapabilities.ts +23 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1785790000000-AddIncidentInvestigationGating.ts +42 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1785800000000-AddRunbookCredential.ts +84 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1785810000000-RenameRunbookAgentToRunner.ts +152 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1785860000000-SessionReplayDefaultToSensitiveInputMasking.ts +81 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1785870000000-AddAiCommandRemediation.ts +151 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1785880000000-AlignRunnerSchemaWithEntities.ts +597 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1785890000000-AddFixVerificationAndAutomaticCodeFixes.ts +71 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +32 -0
- package/Server/Services/AIRunService.ts +10 -0
- package/Server/Services/AIService.ts +30 -0
- package/Server/Services/AlertService.ts +41 -4
- package/Server/Services/AlertSeverityService.ts +25 -11
- package/Server/Services/AlertStateService.ts +25 -11
- package/Server/Services/AutoRemediationRuleEngineService.ts +1101 -0
- package/Server/Services/{RunbookAgentOwnerTeamService.ts → AutoRemediationRuleService.ts} +1 -1
- package/Server/Services/AutoRemediationSuggestionService.ts +183 -0
- package/Server/Services/BillingService.ts +50 -1
- package/Server/Services/DatabaseService.ts +92 -4
- package/Server/Services/IncidentService.ts +56 -4
- package/Server/Services/IncidentSeverityService.ts +25 -11
- package/Server/Services/IncidentStateService.ts +25 -11
- package/Server/Services/Index.ts +19 -0
- package/Server/Services/LlmProviderService.ts +69 -9
- package/Server/Services/MonitorService.ts +24 -0
- package/Server/Services/MonitorStatusService.ts +25 -11
- package/Server/Services/NetworkDeviceLabelRuleEngineService.ts +18 -19
- package/Server/Services/NetworkDeviceLabelRuleService.ts +39 -0
- package/Server/Services/NetworkDeviceOwnerRuleEngineService.ts +18 -19
- package/Server/Services/NetworkDeviceOwnerRuleService.ts +37 -0
- package/Server/Services/NetworkDeviceService.ts +172 -21
- package/Server/Services/NetworkSiteAssignmentRuleService.ts +92 -12
- package/Server/Services/NetworkSiteService.ts +27 -10
- package/Server/Services/ProjectService.ts +47 -0
- package/Server/Services/RumApplicationService.ts +240 -1
- package/Server/Services/RumSessionChunkService.ts +11 -0
- package/Server/Services/RumSessionErasureRequestService.ts +197 -0
- package/Server/Services/RumSessionPinService.ts +213 -0
- package/Server/Services/RumSessionReplayViewService.ts +201 -0
- package/Server/Services/RumSessionService.ts +123 -0
- package/Server/Services/RunbookCredentialService.ts +76 -0
- package/Server/Services/{RunbookAgentJobService.ts → RunnerJobService.ts} +202 -51
- package/Server/Services/{RunbookAgentOwnerUserService.ts → RunnerOwnerTeamService.ts} +1 -1
- package/Server/Services/RunnerOwnerUserService.ts +10 -0
- package/Server/Services/RunnerService.ts +166 -0
- package/Server/Services/ScheduledMaintenanceStateService.ts +25 -11
- package/Server/Services/ScheduledMaintenanceStateTimelineService.ts +15 -1
- package/Server/Services/ServiceService.ts +8 -2
- package/Server/Services/StatusPageService.ts +240 -36
- package/Server/Services/StatusPageSubscriberNotificationTemplateService.ts +20 -1
- package/Server/Services/TelemetryExceptionService.ts +3 -16
- package/Server/Services/TelemetryUsageBillingService.ts +33 -2
- package/Server/Services/TraceAggregationService.ts +196 -32
- package/Server/Types/Billing/MeteredPlan/AllMeteredPlans.ts +17 -0
- package/Server/Types/Billing/MeteredPlan/ServerMeteredPlan.ts +10 -0
- package/Server/Utils/AI/Chat/ObservabilityAssistant.ts +63 -7
- package/Server/Utils/AI/CodeFix/CodeFixAgentAuth.ts +128 -0
- package/Server/Utils/AI/CodeFix/CodeFixAgentAvailability.ts +54 -0
- package/Server/Utils/AI/CodeFix/CodeFixReadiness.ts +17 -10
- package/Server/Utils/AI/CodeFix/CodeFixRunQueue.ts +8 -6
- package/Server/Utils/AI/Remediation/RemediationCommandTools.ts +943 -0
- package/Server/Utils/AI/Remediation/RemediationExecutionRunner.ts +866 -0
- package/Server/Utils/AI/Remediation/RemediationPlanRunner.ts +823 -0
- package/Server/Utils/AI/SRE/AIInvestigationEngine.ts +103 -12
- package/Server/Utils/AI/SRE/AlertInvestigationRunner.ts +75 -17
- package/Server/Utils/AI/SRE/ConfidenceSignal.ts +28 -6
- package/Server/Utils/AI/SRE/FixFromIncidentTaskTrigger.ts +202 -12
- package/Server/Utils/AI/SRE/IncidentInvestigationRunner.ts +264 -14
- package/Server/Utils/AI/SRE/Insights/Triage.ts +2 -7
- package/Server/Utils/AI/SRE/InvestigationGrader.ts +5 -24
- package/Server/Utils/AI/SRE/InvestigationQueue.ts +259 -20
- package/Server/Utils/AI/SRE/PostedRootCause.ts +82 -0
- package/Server/Utils/AI/SRE/README.md +3 -2
- package/Server/Utils/AI/SRE/RemediationHandoff.ts +82 -0
- package/Server/Utils/AI/SRE/SubjectCodeFixRun.ts +6 -19
- package/Server/Utils/AI/Toolbox/CodeWriteTools.ts +2 -2
- package/Server/Utils/Alert/AlertPrivacyFilter.ts +58 -0
- package/Server/Utils/AutoRemediation/CommandPlanExecutor.ts +604 -0
- package/Server/Utils/AutoRemediation/RemediationVerifier.ts +619 -0
- package/Server/Utils/CorsOptions.ts +52 -0
- package/Server/Utils/Database/RelationIdUtil.ts +68 -0
- package/Server/Utils/Incident/IncidentPrivacyFilter.ts +60 -0
- package/Server/Utils/InstanceHealth/PostgresHealth.ts +286 -0
- package/Server/Utils/InstanceHealth/RedisHealth.ts +434 -0
- package/Server/Utils/Monitor/Criteria/CompareCriteria.ts +12 -0
- package/Server/Utils/Monitor/MonitorAlert.ts +20 -0
- package/Server/Utils/Monitor/MonitorIncident.ts +20 -0
- package/Server/Utils/Monitor/MonitorResource.ts +19 -0
- package/Server/Utils/Monitor/MonitorSummaryCapture.ts +104 -0
- package/Server/Utils/NetworkDevice/RulePatternValidator.ts +44 -0
- package/Server/Utils/OpenAPI.ts +2 -1
- package/Server/Utils/Runbook/RunbookExecutePermission.ts +94 -0
- package/Server/Utils/SessionReplay/SessionReplayErasureTombstone.ts +128 -0
- package/Server/Utils/SessionReplay/SessionReplayGateCache.ts +586 -0
- package/Server/Utils/SessionReplay/SessionReplayGateCacheStore.ts +188 -0
- package/Server/Utils/SessionReplay/SessionReplayReadService.ts +1449 -0
- package/Server/Utils/SessionReplay/SessionReplayRetention.ts +114 -0
- package/Server/Utils/SessionReplay/SessionReplayTargeting.ts +144 -0
- package/Server/Utils/SessionReplay/SessionReplayUsage.ts +92 -0
- package/Server/Utils/StartServer.ts +47 -3
- package/Server/Utils/Telemetry/TelemetryFanInWriter.ts +44 -10
- package/Tests/App/Dashboard/AddWidgetModal.test.tsx +557 -0
- package/Tests/App/Dashboard/RunnerInstallInstructions.test.tsx +119 -0
- package/Tests/App/Dashboard/RunnerStatus.test.tsx +274 -0
- package/Tests/App/Dashboard/WidgetCatalog.test.ts +479 -0
- package/Tests/App/StatusPage/BulkAddStatusPageMonitors.test.ts +343 -0
- package/Tests/App/StatusPage/BulkAddStatusPageMonitorsModal.test.tsx +320 -0
- package/Tests/Models/AnalyticsModels/RumSessionSchema.test.ts +455 -0
- package/Tests/Models/AnalyticsModels/SessionIdCorrelation.test.ts +158 -0
- package/Tests/Models/DatabaseModels/SessionReplayModels.test.ts +447 -0
- package/Tests/Models/RunnerVersionLabel.test.ts +223 -0
- package/Tests/Server/API/DashboardPublicResourceListAPI.test.ts +1287 -0
- package/Tests/Server/API/LegacyRunbookAgentRoutes.test.ts +117 -0
- package/Tests/Server/API/SessionReplayAPI.test.ts +2093 -0
- package/Tests/Server/API/UserIncomingCallNumberApi.test.ts +429 -0
- package/Tests/Server/API/UserSmsApi.test.ts +68 -2
- package/Tests/Server/DatabaseConfig.test.ts +150 -0
- package/Tests/Server/Infrastructure/ContainerBootConfiguration.test.ts +2 -2
- package/Tests/Server/Infrastructure/ProcessSignalDelivery.test.ts +2 -3
- package/Tests/Server/Services/AIRunCodeFixClaimScoping.test.ts +100 -0
- package/Tests/Server/Services/AIServiceDailyBudget.test.ts +8 -0
- package/Tests/Server/Services/AutoRemediationCommandRuleEngine.test.ts +334 -0
- package/Tests/Server/Services/AutoRemediationRuleEngineService.test.ts +517 -0
- package/Tests/Server/Services/BillingService.test.ts +158 -1
- package/Tests/Server/Services/DatabaseServiceEmptyUpdate.test.ts +24 -2
- package/Tests/Server/Services/DatabaseServiceSanitizeUpdateData.test.ts +17 -10
- package/Tests/Server/Services/DatabaseServiceUpdateColumnsWithoutHooks.test.ts +128 -0
- package/Tests/Server/Services/DatabaseServiceUpdateWriteRouting.test.ts +178 -0
- package/Tests/Server/Services/DatabaseServiceUpdateWriteRoutingMonitor.test.ts +206 -0
- package/Tests/Server/Services/LlmProviderUsableByProject.test.ts +293 -0
- package/Tests/Server/Services/MonitorServiceOperationalStatusSelection.test.ts +145 -0
- package/Tests/Server/Services/NetworkDeviceRuleEngines.test.ts +726 -0
- package/Tests/Server/Services/NetworkDeviceSiteAssignment.test.ts +570 -9
- package/Tests/Server/Services/NetworkSiteAssignmentRuleService.test.ts +94 -1
- package/Tests/Server/Services/NetworkSiteService.test.ts +85 -0
- package/Tests/Server/Services/RumApplicationReplayHealth.test.ts +114 -0
- package/Tests/Server/Services/RunbookCredentialService.test.ts +657 -0
- package/Tests/Server/Services/SessionReplayCreatePath.test.ts +376 -0
- package/Tests/Server/Services/SessionReplayGateCacheInvalidation.test.ts +211 -0
- package/Tests/Server/Services/SessionReplayMetering.test.ts +174 -0
- package/Tests/Server/Services/StatusPageSubscriberReport.test.ts +555 -0
- package/Tests/Server/Services/TelemetryExceptionAIFixReadiness.test.ts +25 -4
- package/Tests/Server/Services/TelemetryExceptionCodeFixRun.test.ts +17 -2
- package/Tests/Server/Services/TraceAggregationService.test.ts +48 -0
- package/Tests/Server/Services/TraceAnalyticsResourceDisplayNames.test.ts +855 -0
- package/Tests/Server/Services/UpdateOneByIdKeepsRowId.test.ts +38 -27
- package/Tests/Server/Utils/AI/AIConfidenceSignal.test.ts +44 -0
- package/Tests/Server/Utils/AI/AIIncidentGating.test.ts +475 -0
- package/Tests/Server/Utils/AI/CodeFix/CodeFixAgentAuth.test.ts +257 -0
- package/Tests/Server/Utils/AI/CodeFix/CodeFixAgentAvailability.test.ts +236 -0
- package/Tests/Server/Utils/AI/CodeFixReadiness.test.ts +44 -6
- package/Tests/Server/Utils/AI/CodeFixRunQueue.test.ts +47 -1
- package/Tests/Server/Utils/AI/CodeWriteTools.test.ts +2 -2
- package/Tests/Server/Utils/AI/FixFromIncidentAutoTrigger.test.ts +294 -0
- package/Tests/Server/Utils/AI/Insights/InsightTriageRunner.test.ts +2 -2
- package/Tests/Server/Utils/AI/Insights/InvestigationQueueInsightSubject.test.ts +47 -3
- package/Tests/Server/Utils/AI/InvestigationQueueRemediationExecution.test.ts +233 -0
- package/Tests/Server/Utils/AI/InvestigationSettlement.test.ts +463 -0
- package/Tests/Server/Utils/AI/PostedRootCause.test.ts +254 -0
- package/Tests/Server/Utils/AI/RemediationAllowlistNormalization.test.ts +248 -0
- package/Tests/Server/Utils/AI/RemediationCommandTools.test.ts +1008 -0
- package/Tests/Server/Utils/AI/RemediationExecutionRunner.test.ts +887 -0
- package/Tests/Server/Utils/AI/RemediationHandoff.test.ts +306 -0
- package/Tests/Server/Utils/AI/RemediationPlanRunner.test.ts +745 -0
- package/Tests/Server/Utils/AI/SubjectCodeFixRunDedupe.test.ts +291 -0
- package/Tests/Server/Utils/AI/ToolArgsExtractors.test.ts +141 -0
- package/Tests/Server/Utils/AI/Toolbox/WidgetBuilder.test.ts +205 -0
- package/Tests/Server/Utils/AutoRemediation/CommandPlanExecutor.test.ts +1050 -0
- package/Tests/Server/Utils/AutoRemediation/CommandPlanVerification.test.ts +350 -0
- package/Tests/Server/Utils/AutoRemediation/RemediationVerifier.test.ts +341 -0
- package/Tests/Server/Utils/CorsOptions.test.ts +119 -0
- package/Tests/Server/Utils/Database/RelationIdUtil.test.ts +120 -0
- package/Tests/Server/Utils/Database/ResolveReferenceId.test.ts +60 -0
- package/Tests/Server/Utils/InstanceHealth/PostgresHealth.test.ts +337 -0
- package/Tests/Server/Utils/InstanceHealth/RedisHealth.test.ts +671 -0
- package/Tests/Server/Utils/Monitor/Criteria/CompareCriteria.test.ts +897 -0
- package/Tests/Server/Utils/Monitor/MonitorSummaryCapture.test.ts +205 -0
- package/Tests/Server/Utils/Monitor/MonitorSummaryPersistence.test.ts +313 -0
- package/Tests/Server/Utils/PushNotificationUtil.test.ts +228 -0
- package/Tests/Server/Utils/SessionReplay/SessionReplayGateCachePolicy.test.ts +177 -0
- package/Tests/Server/Utils/SessionReplay/SessionReplayOriginAllowlist.test.ts +108 -0
- package/Tests/Server/Utils/SessionReplay/SessionReplayRetention.test.ts +229 -0
- package/Tests/Server/Utils/SessionReplay/SessionReplayTargeting.test.ts +246 -0
- package/Tests/Server/Utils/Telemetry/TelemetryFanInWriter.test.ts +110 -0
- package/Tests/Types/AI/AIRunStatus.test.ts +25 -0
- package/Tests/Types/AutoRemediation/AiRemediationCommandPlan.test.ts +1063 -0
- package/Tests/Types/BaseDatabase/AggregationType.test.ts +56 -0
- package/Tests/Types/CustomField/CustomFieldDropdownOption.test.ts +227 -0
- package/Tests/Types/Dashboard/DashboardTemplateInvariants.test.ts +811 -0
- package/Tests/Types/Dashboard/RumDashboardTemplate.test.ts +1238 -0
- package/Tests/Types/Day/DayOfWeek.test.ts +46 -0
- package/Tests/Types/Docker/DockerInventoryExtractor.test.ts +249 -0
- package/Tests/Types/Kubernetes/KubernetesInventoryExtractor.test.ts +231 -0
- package/Tests/Types/Kubernetes/KubernetesRightSizing.test.ts +323 -0
- package/Tests/Types/Metrics/MetricDownsamplingRetentionDays.test.ts +77 -0
- package/Tests/Types/Monitor/Recommendation/MonitorRecommendationCatalog.test.ts +42 -14
- package/Tests/Types/Monitor/Recommendation/MonitorRecommendationCoverage.test.ts +2 -2
- package/Tests/Types/Monitor/Recommendation/MonitorRecommendationNotificationMode.test.ts +3 -2
- package/Tests/Types/Monitor/Recommendation/MonitorRecommendationSeverityMapper.test.ts +1 -1
- package/Tests/Types/Monitor/Recommendation/MonitorRecommendationUtil.test.ts +6 -3
- package/Tests/Types/Monitor/RumAlertTemplates.test.ts +285 -0
- package/Tests/Types/Podman/PodmanInventoryExtractor.test.ts +159 -0
- package/Tests/Types/Runbook/RunbookExecutionDeadline.test.ts +268 -0
- package/Tests/Types/Runbook/RunbookStepType.test.ts +242 -0
- package/Tests/Types/Runner/RunnerLiveStatus.test.ts +320 -0
- package/Tests/Types/Telemetry/TelemetryRetentionConfig.test.ts +225 -0
- package/Tests/Types/Text.test.ts +60 -0
- package/Tests/UI/Components/AiInvestigationSettingsCard.test.tsx +285 -0
- package/Tests/UI/Components/AutocompleteTextInputMenu.test.tsx +555 -0
- package/Tests/UI/Components/BulkLabelActions.test.tsx +1502 -0
- package/Tests/UI/Components/BulkOwnerActions.test.tsx +1255 -0
- package/Tests/UI/Components/CustomFields/DropdownOptionsInput.test.tsx +228 -0
- package/Tests/UI/Components/Detail/DropdownColors.test.tsx +128 -0
- package/Tests/UI/Components/Detail/EntityFields.test.tsx +166 -0
- package/Tests/UI/Components/Dropdown/DropdownValueBadge.test.tsx +60 -0
- package/Tests/UI/Components/FilterModalOperatorMenu.test.tsx +674 -0
- package/Tests/UI/Components/Forms/ColorPicker.test.tsx +48 -0
- package/Tests/UI/Components/Forms/ColorPickerPopup.test.tsx +222 -0
- package/Tests/UI/Components/Forms/IconPickerPopup.test.tsx +270 -0
- package/Tests/UI/Components/ModelTable/CustomFieldColumns.test.tsx +125 -6
- package/Tests/UI/Components/OperatorSelectorFilterTypes.test.tsx +1595 -0
- package/Tests/UI/Components/OperatorSelectorKeyboard.test.tsx +851 -0
- package/Tests/UI/Components/OperatorSelectorMenu.test.tsx +1229 -0
- package/Tests/UI/Components/Pagination.test.tsx +85 -0
- package/Tests/UI/Monitor/MonitorSummarySnapshotRender.test.tsx +248 -0
- package/Tests/UI/Rum/ChunkLoader.test.ts +790 -0
- package/Tests/UI/Rum/ReplayScrubber.test.tsx +236 -0
- package/Tests/UI/Rum/ReplayStage.test.tsx +606 -0
- package/Tests/UI/Utils/Timezone.test.ts +86 -0
- package/Tests/UI/Utils/UseClockTick.test.tsx +276 -0
- package/Tests/Utils/AiRemediation/CommandPolicy.test.ts +1063 -0
- package/Tests/Utils/Dashboard/ClockWidgetFormat.test.ts +1374 -0
- package/Tests/Utils/Dashboard/DashboardClockComponent.test.ts +362 -0
- package/Tests/Utils/Dashboard/DashboardHtmlComponent.test.ts +217 -0
- package/Tests/Utils/Dashboard/HtmlWidgetDocument.test.ts +656 -0
- package/Tests/Utils/Dashboard/ValueWidgetLayout.test.ts +1007 -0
- package/Tests/Utils/Metrics/MetricSeriesScope.test.ts +1197 -0
- package/Tests/Utils/Monitor/MonitorSummarySnapshotUtil.test.ts +839 -0
- package/Tests/Utils/NetworkSite/CidrMatchUtil.test.ts +69 -0
- package/Tests/Utils/Rules/RulePatternMatchUtil.test.ts +274 -0
- package/Tests/Utils/Rum/ChunkMath.test.ts +286 -0
- package/Tests/Utils/Rum/Masking.test.ts +186 -0
- package/Tests/Utils/Rum/SessionIdentity.test.ts +272 -0
- package/Tests/Utils/Rum/SessionSampling.test.ts +164 -0
- package/Tests/Utils/Rum/UrlScrubber.test.ts +175 -0
- package/Tests/Utils/StatusPage/Report.test.ts +708 -0
- package/Tests/Utils/ValueFormatter.test.ts +299 -1
- package/Types/AI/AIRunStatus.ts +18 -7
- package/Types/AI/AIRunType.ts +18 -0
- package/Types/AI/FixVerificationStatus.ts +21 -0
- package/Types/AnalyticsDatabase/AnalyticsTableName.ts +16 -0
- package/Types/AutoRemediation/AiRemediationCommandPlan.ts +304 -0
- package/Types/AutoRemediation/AutoRemediationExecutionMode.ts +17 -0
- package/Types/AutoRemediation/AutoRemediationSuggestionStatus.ts +35 -0
- package/Types/AutoRemediation/AutoRemediationSuggestionType.ts +17 -0
- package/Types/AutoRemediation/AutoRemediationTriggerEntity.ts +11 -0
- package/Types/AutoRemediation/AutoRemediationVerificationStatus.ts +21 -0
- package/Types/CustomField/CustomFieldDropdownOption.ts +190 -0
- package/Types/Dashboard/DashboardComponentType.ts +2 -0
- package/Types/Dashboard/DashboardComponents/ComponentArgument.ts +4 -0
- package/Types/Dashboard/DashboardComponents/DashboardClockComponent.ts +45 -0
- package/Types/Dashboard/DashboardComponents/DashboardHtmlComponent.ts +27 -0
- package/Types/Dashboard/DashboardComponents/DashboardValueComponent.ts +8 -0
- package/Types/Dashboard/DashboardTemplates.ts +516 -0
- package/Types/Date.ts +6 -0
- package/Types/Email/EmailTemplateType.ts +2 -0
- package/Types/Kubernetes/KubernetesRightSizing.ts +353 -0
- package/Types/MeteredPlan/ProductType.ts +1 -0
- package/Types/Monitor/MonitorStepMetricMonitor.ts +27 -1
- package/Types/Monitor/MonitorSteps.ts +5 -0
- package/Types/Monitor/MonitorSummarySnapshot.ts +88 -0
- package/Types/Monitor/Recommendation/MonitorRecommendationCatalog.ts +52 -10
- package/Types/Monitor/Recommendation/MonitorRecommendationTypes.ts +7 -5
- package/Types/Monitor/Recommendation/MonitorRecommendationUtil.ts +101 -20
- package/Types/Monitor/RumAlertTemplates.ts +386 -0
- package/Types/Permission.ts +204 -24
- package/Types/Rum/SessionReplay.ts +452 -0
- package/Types/Rum/SessionReplayCaptureTrigger.ts +26 -0
- package/Types/Rum/SessionReplayConsentMode.ts +27 -0
- package/Types/Rum/SessionReplayMaskingMode.ts +86 -0
- package/Types/Rum/SessionReplayTriggerReason.ts +31 -0
- package/Types/Runbook/RunbookCredentialType.ts +6 -0
- package/Types/Runbook/RunbookStep.ts +81 -1
- package/Types/Runbook/RunbookStepType.ts +26 -0
- package/Types/Runbook/RunnerJobOrigin.ts +20 -0
- package/Types/Runbook/{RunbookAgentJobStatus.ts → RunnerJobStatus.ts} +2 -2
- package/Types/Runner/RunnerLiveStatus.ts +114 -0
- package/Types/StatusPage/StatusPageReport.ts +99 -0
- package/Types/Telemetry/TelemetryRetentionConfig.ts +18 -1
- package/Types/Text.ts +33 -0
- package/UI/Components/AutocompleteTextInput/AutocompleteTextInput.tsx +260 -75
- package/UI/Components/BulkUpdate/BulkLabelActions.tsx +99 -9
- package/UI/Components/BulkUpdate/BulkOwnerActions.tsx +11 -0
- package/UI/Components/CustomFields/CustomFieldsDetail.tsx +19 -14
- package/UI/Components/CustomFields/DropdownOptionsInput.tsx +144 -54
- package/UI/Components/Detail/Detail.tsx +164 -22
- package/UI/Components/Dropdown/Dropdown.tsx +2 -5
- package/UI/Components/Dropdown/DropdownMenuZIndex.ts +7 -0
- package/UI/Components/Dropdown/DropdownValueBadge.tsx +61 -0
- package/UI/Components/Filters/OperatorSelector.tsx +350 -39
- package/UI/Components/Forms/Fields/ColorPicker.tsx +60 -27
- package/UI/Components/Forms/Fields/IconPicker.tsx +89 -60
- package/UI/Components/Forms/Validation.ts +9 -4
- package/UI/Components/List/List.tsx +1 -0
- package/UI/Components/ModelTable/CustomFieldColumns.tsx +41 -32
- package/UI/Components/Pagination/Pagination.tsx +33 -10
- package/UI/Components/Table/Table.tsx +1 -0
- package/UI/Types/UseAnchoredFieldPopup.ts +321 -0
- package/UI/Utils/Dropdown.ts +26 -0
- package/UI/Utils/Timezone.ts +18 -2
- package/UI/Utils/UseClockTick.ts +78 -0
- package/Utils/AiRemediation/CommandPolicy.ts +398 -0
- package/Utils/Dashboard/ClockWidgetFormat.ts +604 -0
- package/Utils/Dashboard/Components/DashboardClockComponent.ts +181 -0
- package/Utils/Dashboard/Components/DashboardHtmlComponent.ts +162 -0
- package/Utils/Dashboard/Components/DashboardValueComponent.ts +12 -1
- package/Utils/Dashboard/Components/Index.ts +14 -0
- package/Utils/Dashboard/HtmlWidgetDocument.ts +309 -0
- package/Utils/Dashboard/ValueWidgetLayout.ts +471 -0
- package/Utils/Metrics/MetricSeriesScope.ts +301 -0
- package/Utils/Monitor/MonitorSummarySnapshotUtil.ts +593 -0
- package/Utils/NetworkSite/CidrMatchUtil.ts +30 -17
- package/Utils/Rules/RulePatternMatchUtil.ts +103 -0
- package/Utils/Rum/ChunkMath.ts +211 -0
- package/Utils/Rum/Masking.ts +168 -0
- package/Utils/Rum/SessionIdentity.ts +230 -0
- package/Utils/Rum/SessionSampling.ts +108 -0
- package/Utils/Rum/UrlScrubber.ts +185 -0
- package/Utils/Schema/ModelSchema.ts +27 -3
- package/Utils/StatusPage/Report.ts +304 -0
- package/Utils/ValueFormatter.ts +300 -54
- package/build/dist/Models/AnalyticsModels/ExceptionInstance.js +63 -0
- package/build/dist/Models/AnalyticsModels/ExceptionInstance.js.map +1 -1
- package/build/dist/Models/AnalyticsModels/Index.js +10 -0
- package/build/dist/Models/AnalyticsModels/Index.js.map +1 -1
- package/build/dist/Models/AnalyticsModels/Log.js +56 -0
- package/build/dist/Models/AnalyticsModels/Log.js.map +1 -1
- package/build/dist/Models/AnalyticsModels/RumSession.js +1159 -0
- package/build/dist/Models/AnalyticsModels/RumSession.js.map +1 -0
- package/build/dist/Models/AnalyticsModels/RumSessionChunk.js +670 -0
- package/build/dist/Models/AnalyticsModels/RumSessionChunk.js.map +1 -0
- package/build/dist/Models/AnalyticsModels/Span.js +56 -0
- package/build/dist/Models/AnalyticsModels/Span.js.map +1 -1
- package/build/dist/Models/DatabaseModels/AIAgentTaskPullRequest.js +54 -0
- package/build/dist/Models/DatabaseModels/AIAgentTaskPullRequest.js.map +1 -1
- package/build/dist/Models/DatabaseModels/AIRun.js +32 -0
- package/build/dist/Models/DatabaseModels/AIRun.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Alert.js +30 -0
- package/build/dist/Models/DatabaseModels/Alert.js.map +1 -1
- package/build/dist/Models/DatabaseModels/AlertCustomField.js +1 -1
- package/build/dist/Models/DatabaseModels/AlertCustomField.js.map +1 -1
- package/build/dist/Models/DatabaseModels/AlertFeed.js +1 -0
- package/build/dist/Models/DatabaseModels/AlertFeed.js.map +1 -1
- package/build/dist/Models/DatabaseModels/AutoRemediationRule.js +998 -0
- package/build/dist/Models/DatabaseModels/AutoRemediationRule.js.map +1 -0
- package/build/dist/Models/DatabaseModels/AutoRemediationSuggestion.js +917 -0
- package/build/dist/Models/DatabaseModels/AutoRemediationSuggestion.js.map +1 -0
- package/build/dist/Models/DatabaseModels/CodeRepository.js +132 -0
- package/build/dist/Models/DatabaseModels/CodeRepository.js.map +1 -1
- package/build/dist/Models/DatabaseModels/GlobalConfig.js +327 -0
- package/build/dist/Models/DatabaseModels/GlobalConfig.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Incident.js +30 -0
- package/build/dist/Models/DatabaseModels/Incident.js.map +1 -1
- package/build/dist/Models/DatabaseModels/IncidentCustomField.js +1 -1
- package/build/dist/Models/DatabaseModels/IncidentCustomField.js.map +1 -1
- package/build/dist/Models/DatabaseModels/IncidentFeed.js +1 -0
- package/build/dist/Models/DatabaseModels/IncidentFeed.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Index.js +20 -8
- package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
- package/build/dist/Models/DatabaseModels/InstanceHealthLog.js +8 -0
- package/build/dist/Models/DatabaseModels/InstanceHealthLog.js.map +1 -1
- package/build/dist/Models/DatabaseModels/MonitorCustomField.js +1 -1
- package/build/dist/Models/DatabaseModels/MonitorCustomField.js.map +1 -1
- package/build/dist/Models/DatabaseModels/MonitorStatus.js +1 -1
- package/build/dist/Models/DatabaseModels/MonitorStatus.js.map +1 -1
- package/build/dist/Models/DatabaseModels/NetworkDeviceLabelRule.js +2 -2
- package/build/dist/Models/DatabaseModels/NetworkDeviceLabelRule.js.map +1 -1
- package/build/dist/Models/DatabaseModels/NetworkDeviceOwnerRule.js +2 -2
- package/build/dist/Models/DatabaseModels/NetworkDeviceOwnerRule.js.map +1 -1
- package/build/dist/Models/DatabaseModels/NetworkSiteAssignmentRule.js +1 -1
- package/build/dist/Models/DatabaseModels/NetworkSiteAssignmentRule.js.map +1 -1
- package/build/dist/Models/DatabaseModels/OnCallDutyPolicyCustomField.js +1 -1
- package/build/dist/Models/DatabaseModels/OnCallDutyPolicyCustomField.js.map +1 -1
- package/build/dist/Models/DatabaseModels/OnCallDutyPolicyScheduleLayer.js +16 -4
- package/build/dist/Models/DatabaseModels/OnCallDutyPolicyScheduleLayer.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Project.js +235 -0
- package/build/dist/Models/DatabaseModels/Project.js.map +1 -1
- package/build/dist/Models/DatabaseModels/RumApplication.js +930 -0
- package/build/dist/Models/DatabaseModels/RumApplication.js.map +1 -1
- package/build/dist/Models/DatabaseModels/RumSessionErasureRequest.js +591 -0
- package/build/dist/Models/DatabaseModels/RumSessionErasureRequest.js.map +1 -0
- package/build/dist/Models/DatabaseModels/RumSessionPin.js +483 -0
- package/build/dist/Models/DatabaseModels/RumSessionPin.js.map +1 -0
- package/build/dist/Models/DatabaseModels/RumSessionReplayView.js +433 -0
- package/build/dist/Models/DatabaseModels/RumSessionReplayView.js.map +1 -0
- package/build/dist/Models/DatabaseModels/RunbookCredential.js +693 -0
- package/build/dist/Models/DatabaseModels/RunbookCredential.js.map +1 -0
- package/build/dist/Models/DatabaseModels/RunbookSecret.js +8 -8
- package/build/dist/Models/DatabaseModels/RunbookSecret.js.map +1 -1
- package/build/dist/Models/DatabaseModels/{RunbookAgent.js → Runner.js} +235 -70
- package/build/dist/Models/DatabaseModels/Runner.js.map +1 -0
- package/build/dist/Models/DatabaseModels/{RunbookAgentJob.js → RunnerJob.js} +173 -40
- package/build/dist/Models/DatabaseModels/RunnerJob.js.map +1 -0
- package/build/dist/Models/DatabaseModels/{RunbookAgentOwnerTeam.js → RunnerOwnerTeam.js} +57 -57
- package/build/dist/Models/DatabaseModels/RunnerOwnerTeam.js.map +1 -0
- package/build/dist/Models/DatabaseModels/{RunbookAgentOwnerUser.js → RunnerOwnerUser.js} +57 -57
- package/build/dist/Models/DatabaseModels/RunnerOwnerUser.js.map +1 -0
- package/build/dist/Models/DatabaseModels/ScheduledMaintenanceCustomField.js +1 -1
- package/build/dist/Models/DatabaseModels/ScheduledMaintenanceCustomField.js.map +1 -1
- package/build/dist/Models/DatabaseModels/StatusPageCustomField.js +1 -1
- package/build/dist/Models/DatabaseModels/StatusPageCustomField.js.map +1 -1
- package/build/dist/Models/DatabaseModels/TeamCustomField.js +1 -1
- package/build/dist/Models/DatabaseModels/TeamCustomField.js.map +1 -1
- package/build/dist/Models/DatabaseModels/TeamMemberCustomField.js +1 -1
- package/build/dist/Models/DatabaseModels/TeamMemberCustomField.js.map +1 -1
- package/build/dist/Server/API/AIAgentDataAPI.js +130 -45
- package/build/dist/Server/API/AIAgentDataAPI.js.map +1 -1
- package/build/dist/Server/API/AIAgentTaskAPI.js +26 -36
- package/build/dist/Server/API/AIAgentTaskAPI.js.map +1 -1
- package/build/dist/Server/API/AIAgentTaskLogAPI.js +11 -28
- package/build/dist/Server/API/AIAgentTaskLogAPI.js.map +1 -1
- package/build/dist/Server/API/AutoRemediationAPI.js +416 -0
- package/build/dist/Server/API/AutoRemediationAPI.js.map +1 -0
- package/build/dist/Server/API/BaseAnalyticsAPI.js +4 -1
- package/build/dist/Server/API/BaseAnalyticsAPI.js.map +1 -1
- package/build/dist/Server/API/CommonAPI.js +24 -0
- package/build/dist/Server/API/CommonAPI.js.map +1 -1
- package/build/dist/Server/API/DashboardAPI.js +265 -6
- package/build/dist/Server/API/DashboardAPI.js.map +1 -1
- package/build/dist/Server/API/TelemetryAPI.js +940 -3
- package/build/dist/Server/API/TelemetryAPI.js.map +1 -1
- package/build/dist/Server/API/UserIncomingCallNumberAPI.js +18 -0
- package/build/dist/Server/API/UserIncomingCallNumberAPI.js.map +1 -1
- package/build/dist/Server/DatabaseConfig.js +23 -4
- package/build/dist/Server/DatabaseConfig.js.map +1 -1
- package/build/dist/Server/EnvironmentConfig.js +8 -0
- package/build/dist/Server/EnvironmentConfig.js.map +1 -1
- package/build/dist/Server/Infrastructure/Postgres/LocalMigrationGenerationDataSource.js +11 -1
- package/build/dist/Server/Infrastructure/Postgres/LocalMigrationGenerationDataSource.js.map +1 -1
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785417351021-AddSessionReplay.js +106 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785417351021-AddSessionReplay.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785491583874-EnableSessionReplayByDefault.js +37 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785491583874-EnableSessionReplayByDefault.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785496223183-AddMonitorSummaryToIncidentAndAlert.js +18 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785496223183-AddMonitorSummaryToIncidentAndAlert.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785516996695-AddSessionReplayReliabilityColumns.js +29 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785516996695-AddSessionReplayReliabilityColumns.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785533806494-AddSessionReplayCorrelationColumns.js +35 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785533806494-AddSessionReplayCorrelationColumns.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785749674203-AddRedisAndPostgresHealthNotificationColumns.js +40 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785749674203-AddRedisAndPostgresHealthNotificationColumns.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785763818197-AddAutoRemediation.js +128 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785763818197-AddAutoRemediation.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785768089408-AddRemediationVerification.js +28 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785768089408-AddRemediationVerification.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785776960660-AddRunnerCapabilities.js +14 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785776960660-AddRunnerCapabilities.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785790000000-AddIncidentInvestigationGating.js +27 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785790000000-AddIncidentInvestigationGating.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785800000000-AddRunbookCredential.js +44 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785800000000-AddRunbookCredential.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785810000000-RenameRunbookAgentToRunner.js +88 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785810000000-RenameRunbookAgentToRunner.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785860000000-SessionReplayDefaultToSensitiveInputMasking.js +59 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785860000000-SessionReplayDefaultToSensitiveInputMasking.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785870000000-AddAiCommandRemediation.js +76 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785870000000-AddAiCommandRemediation.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785880000000-AlignRunnerSchemaWithEntities.js +214 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785880000000-AlignRunnerSchemaWithEntities.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785890000000-AddFixVerificationAndAutomaticCodeFixes.js +44 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785890000000-AddFixVerificationAndAutomaticCodeFixes.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +32 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
- package/build/dist/Server/Services/AIRunService.js +1 -4
- package/build/dist/Server/Services/AIRunService.js.map +1 -1
- package/build/dist/Server/Services/AIService.js +26 -0
- package/build/dist/Server/Services/AIService.js.map +1 -1
- package/build/dist/Server/Services/AlertService.js +37 -4
- package/build/dist/Server/Services/AlertService.js.map +1 -1
- package/build/dist/Server/Services/AlertSeverityService.js +24 -11
- package/build/dist/Server/Services/AlertSeverityService.js.map +1 -1
- package/build/dist/Server/Services/AlertStateService.js +24 -11
- package/build/dist/Server/Services/AlertStateService.js.map +1 -1
- package/build/dist/Server/Services/AutoRemediationRuleEngineService.js +917 -0
- package/build/dist/Server/Services/AutoRemediationRuleEngineService.js.map +1 -0
- package/build/dist/Server/Services/{RunbookAgentOwnerTeamService.js → AutoRemediationRuleService.js} +2 -2
- package/build/dist/Server/Services/AutoRemediationRuleService.js.map +1 -0
- package/build/dist/Server/Services/AutoRemediationSuggestionService.js +127 -0
- package/build/dist/Server/Services/AutoRemediationSuggestionService.js.map +1 -0
- package/build/dist/Server/Services/BillingService.js +45 -1
- package/build/dist/Server/Services/BillingService.js.map +1 -1
- package/build/dist/Server/Services/DatabaseService.js +72 -4
- package/build/dist/Server/Services/DatabaseService.js.map +1 -1
- package/build/dist/Server/Services/IncidentService.js +52 -4
- package/build/dist/Server/Services/IncidentService.js.map +1 -1
- package/build/dist/Server/Services/IncidentSeverityService.js +24 -11
- package/build/dist/Server/Services/IncidentSeverityService.js.map +1 -1
- package/build/dist/Server/Services/IncidentStateService.js +24 -11
- package/build/dist/Server/Services/IncidentStateService.js.map +1 -1
- package/build/dist/Server/Services/Index.js +18 -0
- package/build/dist/Server/Services/Index.js.map +1 -1
- package/build/dist/Server/Services/LlmProviderService.js +61 -8
- package/build/dist/Server/Services/LlmProviderService.js.map +1 -1
- package/build/dist/Server/Services/MonitorService.js +24 -0
- package/build/dist/Server/Services/MonitorService.js.map +1 -1
- package/build/dist/Server/Services/MonitorStatusService.js +25 -11
- package/build/dist/Server/Services/MonitorStatusService.js.map +1 -1
- package/build/dist/Server/Services/NetworkDeviceLabelRuleEngineService.js +12 -11
- package/build/dist/Server/Services/NetworkDeviceLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/NetworkDeviceLabelRuleService.js +43 -0
- package/build/dist/Server/Services/NetworkDeviceLabelRuleService.js.map +1 -1
- package/build/dist/Server/Services/NetworkDeviceOwnerRuleEngineService.js +12 -11
- package/build/dist/Server/Services/NetworkDeviceOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/NetworkDeviceOwnerRuleService.js +41 -0
- package/build/dist/Server/Services/NetworkDeviceOwnerRuleService.js.map +1 -1
- package/build/dist/Server/Services/NetworkDeviceService.js +129 -20
- package/build/dist/Server/Services/NetworkDeviceService.js.map +1 -1
- package/build/dist/Server/Services/NetworkSiteAssignmentRuleService.js +67 -10
- package/build/dist/Server/Services/NetworkSiteAssignmentRuleService.js.map +1 -1
- package/build/dist/Server/Services/NetworkSiteService.js +19 -8
- package/build/dist/Server/Services/NetworkSiteService.js.map +1 -1
- package/build/dist/Server/Services/ProjectService.js +43 -0
- package/build/dist/Server/Services/ProjectService.js.map +1 -1
- package/build/dist/Server/Services/RumApplicationService.js +202 -0
- package/build/dist/Server/Services/RumApplicationService.js.map +1 -1
- package/build/dist/Server/Services/RumSessionChunkService.js +9 -0
- package/build/dist/Server/Services/RumSessionChunkService.js.map +1 -0
- package/build/dist/Server/Services/RumSessionErasureRequestService.js +190 -0
- package/build/dist/Server/Services/RumSessionErasureRequestService.js.map +1 -0
- package/build/dist/Server/Services/RumSessionPinService.js +208 -0
- package/build/dist/Server/Services/RumSessionPinService.js.map +1 -0
- package/build/dist/Server/Services/RumSessionReplayViewService.js +180 -0
- package/build/dist/Server/Services/RumSessionReplayViewService.js.map +1 -0
- package/build/dist/Server/Services/RumSessionService.js +102 -0
- package/build/dist/Server/Services/RumSessionService.js.map +1 -0
- package/build/dist/Server/Services/RunbookCredentialService.js +67 -0
- package/build/dist/Server/Services/RunbookCredentialService.js.map +1 -0
- package/build/dist/Server/Services/{RunbookAgentJobService.js → RunnerJobService.js} +158 -46
- package/build/dist/Server/Services/RunnerJobService.js.map +1 -0
- package/build/dist/Server/Services/{RunbookAgentOwnerUserService.js → RunnerOwnerTeamService.js} +2 -2
- package/build/dist/Server/Services/RunnerOwnerTeamService.js.map +1 -0
- package/build/dist/Server/Services/RunnerOwnerUserService.js +9 -0
- package/build/dist/Server/Services/RunnerOwnerUserService.js.map +1 -0
- package/build/dist/Server/Services/RunnerService.js +163 -0
- package/build/dist/Server/Services/RunnerService.js.map +1 -0
- package/build/dist/Server/Services/ScheduledMaintenanceStateService.js +24 -11
- package/build/dist/Server/Services/ScheduledMaintenanceStateService.js.map +1 -1
- package/build/dist/Server/Services/ScheduledMaintenanceStateTimelineService.js +15 -1
- package/build/dist/Server/Services/ScheduledMaintenanceStateTimelineService.js.map +1 -1
- package/build/dist/Server/Services/ServiceService.js +8 -2
- package/build/dist/Server/Services/ServiceService.js.map +1 -1
- package/build/dist/Server/Services/StatusPageService.js +173 -16
- package/build/dist/Server/Services/StatusPageService.js.map +1 -1
- package/build/dist/Server/Services/StatusPageSubscriberNotificationTemplateService.js +17 -1
- package/build/dist/Server/Services/StatusPageSubscriberNotificationTemplateService.js.map +1 -1
- package/build/dist/Server/Services/TelemetryExceptionService.js +3 -16
- package/build/dist/Server/Services/TelemetryExceptionService.js.map +1 -1
- package/build/dist/Server/Services/TelemetryUsageBillingService.js +31 -3
- package/build/dist/Server/Services/TelemetryUsageBillingService.js.map +1 -1
- package/build/dist/Server/Services/TraceAggregationService.js +106 -2
- package/build/dist/Server/Services/TraceAggregationService.js.map +1 -1
- package/build/dist/Server/Types/Billing/MeteredPlan/AllMeteredPlans.js +16 -0
- package/build/dist/Server/Types/Billing/MeteredPlan/AllMeteredPlans.js.map +1 -1
- package/build/dist/Server/Types/Billing/MeteredPlan/ServerMeteredPlan.js +9 -0
- package/build/dist/Server/Types/Billing/MeteredPlan/ServerMeteredPlan.js.map +1 -1
- package/build/dist/Server/Utils/AI/Chat/ObservabilityAssistant.js +38 -6
- package/build/dist/Server/Utils/AI/Chat/ObservabilityAssistant.js.map +1 -1
- package/build/dist/Server/Utils/AI/CodeFix/CodeFixAgentAuth.js +104 -0
- package/build/dist/Server/Utils/AI/CodeFix/CodeFixAgentAuth.js.map +1 -0
- package/build/dist/Server/Utils/AI/CodeFix/CodeFixAgentAvailability.js +54 -0
- package/build/dist/Server/Utils/AI/CodeFix/CodeFixAgentAvailability.js.map +1 -0
- package/build/dist/Server/Utils/AI/CodeFix/CodeFixReadiness.js +11 -7
- package/build/dist/Server/Utils/AI/CodeFix/CodeFixReadiness.js.map +1 -1
- package/build/dist/Server/Utils/AI/CodeFix/CodeFixRunQueue.js +3 -4
- package/build/dist/Server/Utils/AI/CodeFix/CodeFixRunQueue.js.map +1 -1
- package/build/dist/Server/Utils/AI/Remediation/RemediationCommandTools.js +724 -0
- package/build/dist/Server/Utils/AI/Remediation/RemediationCommandTools.js.map +1 -0
- package/build/dist/Server/Utils/AI/Remediation/RemediationExecutionRunner.js +668 -0
- package/build/dist/Server/Utils/AI/Remediation/RemediationExecutionRunner.js.map +1 -0
- package/build/dist/Server/Utils/AI/Remediation/RemediationPlanRunner.js +657 -0
- package/build/dist/Server/Utils/AI/Remediation/RemediationPlanRunner.js.map +1 -0
- package/build/dist/Server/Utils/AI/SRE/AIInvestigationEngine.js +52 -7
- package/build/dist/Server/Utils/AI/SRE/AIInvestigationEngine.js.map +1 -1
- package/build/dist/Server/Utils/AI/SRE/AlertInvestigationRunner.js +53 -5
- package/build/dist/Server/Utils/AI/SRE/AlertInvestigationRunner.js.map +1 -1
- package/build/dist/Server/Utils/AI/SRE/ConfidenceSignal.js +25 -6
- package/build/dist/Server/Utils/AI/SRE/ConfidenceSignal.js.map +1 -1
- package/build/dist/Server/Utils/AI/SRE/FixFromIncidentTaskTrigger.js +131 -17
- package/build/dist/Server/Utils/AI/SRE/FixFromIncidentTaskTrigger.js.map +1 -1
- package/build/dist/Server/Utils/AI/SRE/IncidentInvestigationRunner.js +200 -5
- package/build/dist/Server/Utils/AI/SRE/IncidentInvestigationRunner.js.map +1 -1
- package/build/dist/Server/Utils/AI/SRE/Insights/Triage.js +2 -7
- package/build/dist/Server/Utils/AI/SRE/Insights/Triage.js.map +1 -1
- package/build/dist/Server/Utils/AI/SRE/InvestigationGrader.js +4 -17
- package/build/dist/Server/Utils/AI/SRE/InvestigationGrader.js.map +1 -1
- package/build/dist/Server/Utils/AI/SRE/InvestigationQueue.js +203 -19
- package/build/dist/Server/Utils/AI/SRE/InvestigationQueue.js.map +1 -1
- package/build/dist/Server/Utils/AI/SRE/PostedRootCause.js +89 -0
- package/build/dist/Server/Utils/AI/SRE/PostedRootCause.js.map +1 -0
- package/build/dist/Server/Utils/AI/SRE/RemediationHandoff.js +82 -0
- package/build/dist/Server/Utils/AI/SRE/RemediationHandoff.js.map +1 -0
- package/build/dist/Server/Utils/AI/SRE/SubjectCodeFixRun.js +4 -19
- package/build/dist/Server/Utils/AI/SRE/SubjectCodeFixRun.js.map +1 -1
- package/build/dist/Server/Utils/AI/Toolbox/CodeWriteTools.js +2 -2
- package/build/dist/Server/Utils/Alert/AlertPrivacyFilter.js +36 -0
- package/build/dist/Server/Utils/Alert/AlertPrivacyFilter.js.map +1 -1
- package/build/dist/Server/Utils/AutoRemediation/CommandPlanExecutor.js +498 -0
- package/build/dist/Server/Utils/AutoRemediation/CommandPlanExecutor.js.map +1 -0
- package/build/dist/Server/Utils/AutoRemediation/RemediationVerifier.js +492 -0
- package/build/dist/Server/Utils/AutoRemediation/RemediationVerifier.js.map +1 -0
- package/build/dist/Server/Utils/CorsOptions.js +47 -0
- package/build/dist/Server/Utils/CorsOptions.js.map +1 -0
- package/build/dist/Server/Utils/Database/RelationIdUtil.js +51 -0
- package/build/dist/Server/Utils/Database/RelationIdUtil.js.map +1 -0
- package/build/dist/Server/Utils/Incident/IncidentPrivacyFilter.js +38 -0
- package/build/dist/Server/Utils/Incident/IncidentPrivacyFilter.js.map +1 -1
- package/build/dist/Server/Utils/InstanceHealth/PostgresHealth.js +194 -0
- package/build/dist/Server/Utils/InstanceHealth/PostgresHealth.js.map +1 -0
- package/build/dist/Server/Utils/InstanceHealth/RedisHealth.js +292 -0
- package/build/dist/Server/Utils/InstanceHealth/RedisHealth.js.map +1 -0
- package/build/dist/Server/Utils/Monitor/Criteria/CompareCriteria.js +11 -0
- package/build/dist/Server/Utils/Monitor/Criteria/CompareCriteria.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorAlert.js +9 -0
- package/build/dist/Server/Utils/Monitor/MonitorAlert.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorIncident.js +9 -0
- package/build/dist/Server/Utils/Monitor/MonitorIncident.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorResource.js +16 -0
- package/build/dist/Server/Utils/Monitor/MonitorResource.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorSummaryCapture.js +92 -0
- package/build/dist/Server/Utils/Monitor/MonitorSummaryCapture.js.map +1 -0
- package/build/dist/Server/Utils/NetworkDevice/RulePatternValidator.js +27 -0
- package/build/dist/Server/Utils/NetworkDevice/RulePatternValidator.js.map +1 -0
- package/build/dist/Server/Utils/OpenAPI.js +2 -1
- package/build/dist/Server/Utils/OpenAPI.js.map +1 -1
- package/build/dist/Server/Utils/Runbook/RunbookExecutePermission.js +67 -0
- package/build/dist/Server/Utils/Runbook/RunbookExecutePermission.js.map +1 -0
- package/build/dist/Server/Utils/SessionReplay/SessionReplayErasureTombstone.js +98 -0
- package/build/dist/Server/Utils/SessionReplay/SessionReplayErasureTombstone.js.map +1 -0
- package/build/dist/Server/Utils/SessionReplay/SessionReplayGateCache.js +378 -0
- package/build/dist/Server/Utils/SessionReplay/SessionReplayGateCache.js.map +1 -0
- package/build/dist/Server/Utils/SessionReplay/SessionReplayGateCacheStore.js +137 -0
- package/build/dist/Server/Utils/SessionReplay/SessionReplayGateCacheStore.js.map +1 -0
- package/build/dist/Server/Utils/SessionReplay/SessionReplayReadService.js +998 -0
- package/build/dist/Server/Utils/SessionReplay/SessionReplayReadService.js.map +1 -0
- package/build/dist/Server/Utils/SessionReplay/SessionReplayRetention.js +59 -0
- package/build/dist/Server/Utils/SessionReplay/SessionReplayRetention.js.map +1 -0
- package/build/dist/Server/Utils/SessionReplay/SessionReplayTargeting.js +98 -0
- package/build/dist/Server/Utils/SessionReplay/SessionReplayTargeting.js.map +1 -0
- package/build/dist/Server/Utils/SessionReplay/SessionReplayUsage.js +69 -0
- package/build/dist/Server/Utils/SessionReplay/SessionReplayUsage.js.map +1 -0
- package/build/dist/Server/Utils/StartServer.js +40 -3
- package/build/dist/Server/Utils/StartServer.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/TelemetryFanInWriter.js +27 -6
- package/build/dist/Server/Utils/Telemetry/TelemetryFanInWriter.js.map +1 -1
- package/build/dist/Types/AI/AIRunStatus.js +17 -5
- package/build/dist/Types/AI/AIRunStatus.js.map +1 -1
- package/build/dist/Types/AI/AIRunType.js +18 -0
- package/build/dist/Types/AI/AIRunType.js.map +1 -1
- package/build/dist/Types/AI/FixVerificationStatus.js +22 -0
- package/build/dist/Types/AI/FixVerificationStatus.js.map +1 -0
- package/build/dist/Types/AnalyticsDatabase/AnalyticsTableName.js +16 -0
- package/build/dist/Types/AnalyticsDatabase/AnalyticsTableName.js.map +1 -1
- package/build/dist/Types/AutoRemediation/AiRemediationCommandPlan.js +192 -0
- package/build/dist/Types/AutoRemediation/AiRemediationCommandPlan.js.map +1 -0
- package/build/dist/Types/AutoRemediation/AutoRemediationExecutionMode.js +18 -0
- package/build/dist/Types/AutoRemediation/AutoRemediationExecutionMode.js.map +1 -0
- package/build/dist/Types/AutoRemediation/AutoRemediationSuggestionStatus.js +31 -0
- package/build/dist/Types/AutoRemediation/AutoRemediationSuggestionStatus.js.map +1 -0
- package/build/dist/Types/AutoRemediation/AutoRemediationSuggestionType.js +18 -0
- package/build/dist/Types/AutoRemediation/AutoRemediationSuggestionType.js.map +1 -0
- package/build/dist/Types/AutoRemediation/AutoRemediationTriggerEntity.js +12 -0
- package/build/dist/Types/AutoRemediation/AutoRemediationTriggerEntity.js.map +1 -0
- package/build/dist/Types/AutoRemediation/AutoRemediationVerificationStatus.js +22 -0
- package/build/dist/Types/AutoRemediation/AutoRemediationVerificationStatus.js.map +1 -0
- package/build/dist/Types/CustomField/CustomFieldDropdownOption.js +110 -0
- package/build/dist/Types/CustomField/CustomFieldDropdownOption.js.map +1 -0
- package/build/dist/Types/Dashboard/DashboardComponentType.js +2 -0
- package/build/dist/Types/Dashboard/DashboardComponentType.js.map +1 -1
- package/build/dist/Types/Dashboard/DashboardComponents/ComponentArgument.js +4 -0
- package/build/dist/Types/Dashboard/DashboardComponents/ComponentArgument.js.map +1 -1
- package/build/dist/Types/Dashboard/DashboardComponents/DashboardClockComponent.js +19 -0
- package/build/dist/Types/Dashboard/DashboardComponents/DashboardClockComponent.js.map +1 -0
- package/build/dist/Types/Dashboard/DashboardComponents/DashboardHtmlComponent.js +2 -0
- package/build/dist/Types/Dashboard/DashboardComponents/DashboardHtmlComponent.js.map +1 -0
- package/build/dist/Types/Dashboard/DashboardTemplates.js +487 -0
- package/build/dist/Types/Dashboard/DashboardTemplates.js.map +1 -1
- package/build/dist/Types/Date.js +6 -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/Kubernetes/KubernetesRightSizing.js +229 -0
- package/build/dist/Types/Kubernetes/KubernetesRightSizing.js.map +1 -0
- package/build/dist/Types/MeteredPlan/ProductType.js +1 -0
- package/build/dist/Types/MeteredPlan/ProductType.js.map +1 -1
- package/build/dist/Types/Monitor/MonitorStepMetricMonitor.js +12 -2
- package/build/dist/Types/Monitor/MonitorStepMetricMonitor.js.map +1 -1
- package/build/dist/Types/Monitor/MonitorSteps.js +5 -0
- package/build/dist/Types/Monitor/MonitorSteps.js.map +1 -1
- package/build/dist/Types/Monitor/MonitorSummarySnapshot.js +13 -0
- package/build/dist/Types/Monitor/MonitorSummarySnapshot.js.map +1 -0
- package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationCatalog.js +40 -8
- package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationCatalog.js.map +1 -1
- package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationTypes.js +4 -3
- package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationTypes.js.map +1 -1
- package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationUtil.js +50 -10
- package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationUtil.js.map +1 -1
- package/build/dist/Types/Monitor/RumAlertTemplates.js +297 -0
- package/build/dist/Types/Monitor/RumAlertTemplates.js.map +1 -0
- package/build/dist/Types/Permission.js +184 -24
- package/build/dist/Types/Permission.js.map +1 -1
- package/build/dist/Types/Rum/SessionReplay.js +155 -0
- package/build/dist/Types/Rum/SessionReplay.js.map +1 -0
- package/build/dist/Types/Rum/SessionReplayCaptureTrigger.js +26 -0
- package/build/dist/Types/Rum/SessionReplayCaptureTrigger.js.map +1 -0
- package/build/dist/Types/Rum/SessionReplayConsentMode.js +27 -0
- package/build/dist/Types/Rum/SessionReplayConsentMode.js.map +1 -0
- package/build/dist/Types/Rum/SessionReplayMaskingMode.js +79 -0
- package/build/dist/Types/Rum/SessionReplayMaskingMode.js.map +1 -0
- package/build/dist/Types/Rum/SessionReplayTriggerReason.js +28 -0
- package/build/dist/Types/Rum/SessionReplayTriggerReason.js.map +1 -0
- package/build/dist/Types/Runbook/RunbookCredentialType.js +7 -0
- package/build/dist/Types/Runbook/RunbookCredentialType.js.map +1 -0
- package/build/dist/Types/Runbook/RunbookStep.js +20 -1
- package/build/dist/Types/Runbook/RunbookStep.js.map +1 -1
- package/build/dist/Types/Runbook/RunbookStepType.js +24 -0
- package/build/dist/Types/Runbook/RunbookStepType.js.map +1 -1
- package/build/dist/Types/Runbook/RunnerJobOrigin.js +21 -0
- package/build/dist/Types/Runbook/RunnerJobOrigin.js.map +1 -0
- package/build/dist/Types/Runbook/RunnerJobStatus.js +22 -0
- package/build/dist/Types/Runbook/RunnerJobStatus.js.map +1 -0
- package/build/dist/Types/Runner/RunnerLiveStatus.js +69 -0
- package/build/dist/Types/Runner/RunnerLiveStatus.js.map +1 -0
- package/build/dist/Types/StatusPage/StatusPageReport.js +22 -0
- package/build/dist/Types/StatusPage/StatusPageReport.js.map +1 -0
- package/build/dist/Types/Telemetry/TelemetryRetentionConfig.js.map +1 -1
- package/build/dist/Types/Text.js +29 -0
- package/build/dist/Types/Text.js.map +1 -1
- package/build/dist/UI/Components/AutocompleteTextInput/AutocompleteTextInput.js +143 -28
- package/build/dist/UI/Components/AutocompleteTextInput/AutocompleteTextInput.js.map +1 -1
- package/build/dist/UI/Components/BulkUpdate/BulkLabelActions.js +82 -9
- package/build/dist/UI/Components/BulkUpdate/BulkLabelActions.js.map +1 -1
- package/build/dist/UI/Components/BulkUpdate/BulkOwnerActions.js +11 -0
- package/build/dist/UI/Components/BulkUpdate/BulkOwnerActions.js.map +1 -1
- package/build/dist/UI/Components/CustomFields/CustomFieldsDetail.js +11 -13
- package/build/dist/UI/Components/CustomFields/CustomFieldsDetail.js.map +1 -1
- package/build/dist/UI/Components/CustomFields/DropdownOptionsInput.js +76 -45
- package/build/dist/UI/Components/CustomFields/DropdownOptionsInput.js.map +1 -1
- package/build/dist/UI/Components/Detail/Detail.js +100 -8
- package/build/dist/UI/Components/Detail/Detail.js.map +1 -1
- package/build/dist/UI/Components/Dropdown/Dropdown.js +2 -5
- package/build/dist/UI/Components/Dropdown/Dropdown.js.map +1 -1
- package/build/dist/UI/Components/Dropdown/DropdownMenuZIndex.js +7 -0
- package/build/dist/UI/Components/Dropdown/DropdownMenuZIndex.js.map +1 -0
- package/build/dist/UI/Components/Dropdown/DropdownValueBadge.js +32 -0
- package/build/dist/UI/Components/Dropdown/DropdownValueBadge.js.map +1 -0
- package/build/dist/UI/Components/Filters/OperatorSelector.js +210 -20
- package/build/dist/UI/Components/Filters/OperatorSelector.js.map +1 -1
- package/build/dist/UI/Components/Forms/Fields/ColorPicker.js +26 -10
- package/build/dist/UI/Components/Forms/Fields/ColorPicker.js.map +1 -1
- package/build/dist/UI/Components/Forms/Fields/IconPicker.js +28 -13
- package/build/dist/UI/Components/Forms/Fields/IconPicker.js.map +1 -1
- package/build/dist/UI/Components/Forms/Validation.js +9 -5
- package/build/dist/UI/Components/Forms/Validation.js.map +1 -1
- package/build/dist/UI/Components/List/List.js +1 -1
- package/build/dist/UI/Components/List/List.js.map +1 -1
- package/build/dist/UI/Components/ModelTable/CustomFieldColumns.js +21 -19
- package/build/dist/UI/Components/ModelTable/CustomFieldColumns.js.map +1 -1
- package/build/dist/UI/Components/Pagination/Pagination.js +14 -3
- package/build/dist/UI/Components/Pagination/Pagination.js.map +1 -1
- package/build/dist/UI/Components/Table/Table.js +1 -1
- package/build/dist/UI/Components/Table/Table.js.map +1 -1
- package/build/dist/UI/Types/UseAnchoredFieldPopup.js +197 -0
- package/build/dist/UI/Types/UseAnchoredFieldPopup.js.map +1 -0
- package/build/dist/UI/Utils/Dropdown.js +18 -0
- package/build/dist/UI/Utils/Dropdown.js.map +1 -1
- package/build/dist/UI/Utils/Timezone.js +13 -2
- package/build/dist/UI/Utils/Timezone.js.map +1 -1
- package/build/dist/UI/Utils/UseClockTick.js +41 -0
- package/build/dist/UI/Utils/UseClockTick.js.map +1 -0
- package/build/dist/Utils/AiRemediation/CommandPolicy.js +303 -0
- package/build/dist/Utils/AiRemediation/CommandPolicy.js.map +1 -0
- package/build/dist/Utils/Dashboard/ClockWidgetFormat.js +232 -0
- package/build/dist/Utils/Dashboard/ClockWidgetFormat.js.map +1 -0
- package/build/dist/Utils/Dashboard/Components/DashboardClockComponent.js +146 -0
- package/build/dist/Utils/Dashboard/Components/DashboardClockComponent.js.map +1 -0
- package/build/dist/Utils/Dashboard/Components/DashboardHtmlComponent.js +133 -0
- package/build/dist/Utils/Dashboard/Components/DashboardHtmlComponent.js.map +1 -0
- package/build/dist/Utils/Dashboard/Components/DashboardValueComponent.js +10 -1
- package/build/dist/Utils/Dashboard/Components/DashboardValueComponent.js.map +1 -1
- package/build/dist/Utils/Dashboard/Components/Index.js +8 -0
- package/build/dist/Utils/Dashboard/Components/Index.js.map +1 -1
- package/build/dist/Utils/Dashboard/HtmlWidgetDocument.js +198 -0
- package/build/dist/Utils/Dashboard/HtmlWidgetDocument.js.map +1 -0
- package/build/dist/Utils/Dashboard/ValueWidgetLayout.js +276 -0
- package/build/dist/Utils/Dashboard/ValueWidgetLayout.js.map +1 -0
- package/build/dist/Utils/Metrics/MetricSeriesScope.js +203 -0
- package/build/dist/Utils/Metrics/MetricSeriesScope.js.map +1 -0
- package/build/dist/Utils/Monitor/MonitorSummarySnapshotUtil.js +382 -0
- package/build/dist/Utils/Monitor/MonitorSummarySnapshotUtil.js.map +1 -0
- package/build/dist/Utils/NetworkSite/CidrMatchUtil.js +13 -7
- package/build/dist/Utils/NetworkSite/CidrMatchUtil.js.map +1 -1
- package/build/dist/Utils/Rules/RulePatternMatchUtil.js +87 -0
- package/build/dist/Utils/Rules/RulePatternMatchUtil.js.map +1 -0
- package/build/dist/Utils/Rum/ChunkMath.js +147 -0
- package/build/dist/Utils/Rum/ChunkMath.js.map +1 -0
- package/build/dist/Utils/Rum/Masking.js +143 -0
- package/build/dist/Utils/Rum/Masking.js.map +1 -0
- package/build/dist/Utils/Rum/SessionIdentity.js +161 -0
- package/build/dist/Utils/Rum/SessionIdentity.js.map +1 -0
- package/build/dist/Utils/Rum/SessionSampling.js +91 -0
- package/build/dist/Utils/Rum/SessionSampling.js.map +1 -0
- package/build/dist/Utils/Rum/UrlScrubber.js +144 -0
- package/build/dist/Utils/Rum/UrlScrubber.js.map +1 -0
- package/build/dist/Utils/Schema/ModelSchema.js +28 -3
- package/build/dist/Utils/Schema/ModelSchema.js.map +1 -1
- package/build/dist/Utils/StatusPage/Report.js +194 -0
- package/build/dist/Utils/StatusPage/Report.js.map +1 -0
- package/build/dist/Utils/ValueFormatter.js +239 -46
- package/build/dist/Utils/ValueFormatter.js.map +1 -1
- package/jest.config.json +3 -0
- package/package.json +1 -1
- package/tsconfig.json +19 -1
- package/Server/Services/RunbookAgentService.ts +0 -93
- package/build/dist/Models/DatabaseModels/RunbookAgent.js.map +0 -1
- package/build/dist/Models/DatabaseModels/RunbookAgentJob.js.map +0 -1
- package/build/dist/Models/DatabaseModels/RunbookAgentOwnerTeam.js.map +0 -1
- package/build/dist/Models/DatabaseModels/RunbookAgentOwnerUser.js.map +0 -1
- package/build/dist/Server/Services/RunbookAgentJobService.js.map +0 -1
- package/build/dist/Server/Services/RunbookAgentOwnerTeamService.js.map +0 -1
- package/build/dist/Server/Services/RunbookAgentOwnerUserService.js.map +0 -1
- package/build/dist/Server/Services/RunbookAgentService.js +0 -91
- package/build/dist/Server/Services/RunbookAgentService.js.map +0 -1
- package/build/dist/Types/Runbook/RunbookAgentJobStatus.js +0 -22
- package/build/dist/Types/Runbook/RunbookAgentJobStatus.js.map +0 -1
|
@@ -0,0 +1,1255 @@
|
|
|
1
|
+
import { beforeEach, describe, expect, jest, test } from "@jest/globals";
|
|
2
|
+
import "@testing-library/jest-dom";
|
|
3
|
+
import {
|
|
4
|
+
act,
|
|
5
|
+
fireEvent,
|
|
6
|
+
render,
|
|
7
|
+
renderHook,
|
|
8
|
+
screen,
|
|
9
|
+
waitFor,
|
|
10
|
+
} from "@testing-library/react";
|
|
11
|
+
import * as React from "react";
|
|
12
|
+
import { FunctionComponent, ReactElement } from "react";
|
|
13
|
+
import getJestMockFunction, { MockFunction } from "../../MockType";
|
|
14
|
+
|
|
15
|
+
/*
|
|
16
|
+
* Scope: this is baseline coverage, not change coverage. Read the green count
|
|
17
|
+
* accordingly. useBulkOwnerActions is a shared hook that shipped with no tests
|
|
18
|
+
* at all, and all but two of the cases below characterise behaviour that
|
|
19
|
+
* already existed - they pass just as well against the pre-change hook. They
|
|
20
|
+
* are written now because this change is what makes the SLO lists depend on
|
|
21
|
+
* that behaviour.
|
|
22
|
+
*
|
|
23
|
+
* Exactly two tests pin this change: "opening Add Owner closes an open Remove
|
|
24
|
+
* Owner modal" and "opening Remove Owner closes an open Add Owner modal". The
|
|
25
|
+
* hook now clears the sibling modal's flag, and both fail without it.
|
|
26
|
+
*
|
|
27
|
+
* The model under test is the ServiceLevelObjectiveOwnerUser /
|
|
28
|
+
* ServiceLevelObjectiveOwnerTeam junction pair because the SLO lists are the
|
|
29
|
+
* adoption this change adds; the hook itself is model-agnostic.
|
|
30
|
+
*
|
|
31
|
+
* The hook is not a thin wrapper: it flattens every team's membership into a
|
|
32
|
+
* single de-duped people list, tags each option with a "user:"/"team:" prefix
|
|
33
|
+
* so one dropdown can drive two different junction tables, and then - per
|
|
34
|
+
* selected item - reads that item's existing owners so a second "Add Owner"
|
|
35
|
+
* run does not create duplicate rows. Every one of those steps is silent when
|
|
36
|
+
* it goes wrong: a wrong resourceIdField or a dropped prefix does not fail, it
|
|
37
|
+
* just queries nothing and reports the item as a success. So the suite drives
|
|
38
|
+
* the real modal, the real form and the real dropdown, and asserts on what
|
|
39
|
+
* actually reaches ModelAPI.
|
|
40
|
+
*/
|
|
41
|
+
|
|
42
|
+
/*
|
|
43
|
+
* react-i18next is not initialized in the test environment. Mock the hook so
|
|
44
|
+
* translate helpers echo their input and the component renders synchronously.
|
|
45
|
+
*/
|
|
46
|
+
jest.mock("react-i18next", () => {
|
|
47
|
+
return {
|
|
48
|
+
useTranslation: () => {
|
|
49
|
+
return {
|
|
50
|
+
t: (key: string, opts?: { defaultValue?: string }): string => {
|
|
51
|
+
return opts?.defaultValue ?? key;
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
/*
|
|
59
|
+
* Declared before jest.mock but dereferenced inside the factory: ts-jest
|
|
60
|
+
* hoists the jest.mock call above these initializers, so naming the mocks
|
|
61
|
+
* directly in the factory would capture undefined.
|
|
62
|
+
*/
|
|
63
|
+
const getListMock: MockFunction = getJestMockFunction();
|
|
64
|
+
const createMock: MockFunction = getJestMockFunction();
|
|
65
|
+
const deleteItemMock: MockFunction = getJestMockFunction();
|
|
66
|
+
|
|
67
|
+
jest.mock("../../../UI/Utils/ModelAPI/ModelAPI", () => {
|
|
68
|
+
return {
|
|
69
|
+
__esModule: true,
|
|
70
|
+
default: {
|
|
71
|
+
getList: (...args: Array<any>) => {
|
|
72
|
+
return getListMock(...args);
|
|
73
|
+
},
|
|
74
|
+
create: (...args: Array<any>) => {
|
|
75
|
+
return createMock(...args);
|
|
76
|
+
},
|
|
77
|
+
deleteItem: (...args: Array<any>) => {
|
|
78
|
+
return deleteItemMock(...args);
|
|
79
|
+
},
|
|
80
|
+
},
|
|
81
|
+
};
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
import useBulkOwnerActions, {
|
|
85
|
+
BulkOwnerActionsConfig,
|
|
86
|
+
BulkOwnerActionsResult,
|
|
87
|
+
} from "../../../UI/Components/BulkUpdate/BulkOwnerActions";
|
|
88
|
+
import {
|
|
89
|
+
BulkActionButtonSchema,
|
|
90
|
+
BulkActionFailed,
|
|
91
|
+
BulkActionOnClickProps,
|
|
92
|
+
ProgressInfo,
|
|
93
|
+
} from "../../../UI/Components/BulkUpdate/BulkUpdateForm";
|
|
94
|
+
import { ButtonStyleType } from "../../../UI/Components/Button/Button";
|
|
95
|
+
import ServiceLevelObjective from "../../../Models/DatabaseModels/ServiceLevelObjective";
|
|
96
|
+
import ServiceLevelObjectiveOwnerTeam from "../../../Models/DatabaseModels/ServiceLevelObjectiveOwnerTeam";
|
|
97
|
+
import ServiceLevelObjectiveOwnerUser from "../../../Models/DatabaseModels/ServiceLevelObjectiveOwnerUser";
|
|
98
|
+
import Team from "../../../Models/DatabaseModels/Team";
|
|
99
|
+
import TeamMember from "../../../Models/DatabaseModels/TeamMember";
|
|
100
|
+
import User from "../../../Models/DatabaseModels/User";
|
|
101
|
+
import Includes from "../../../Types/BaseDatabase/Includes";
|
|
102
|
+
import SortOrder from "../../../Types/BaseDatabase/SortOrder";
|
|
103
|
+
import { LIMIT_PER_PROJECT } from "../../../Types/Database/LimitMax";
|
|
104
|
+
import BadDataException from "../../../Types/Exception/BadDataException";
|
|
105
|
+
import Email from "../../../Types/Email";
|
|
106
|
+
import IconProp from "../../../Types/Icon/IconProp";
|
|
107
|
+
import Name from "../../../Types/Name";
|
|
108
|
+
import ObjectID from "../../../Types/ObjectID";
|
|
109
|
+
|
|
110
|
+
/*
|
|
111
|
+
* Rendering the real modal pulls in Formik and react-select, which are slow
|
|
112
|
+
* to mount on a loaded box; the testing-library default of 1s flakes there.
|
|
113
|
+
*/
|
|
114
|
+
const WAIT_TIMEOUT: number = 20000;
|
|
115
|
+
|
|
116
|
+
const PROJECT_ID: string = "11111111-1111-4111-8111-111111111111";
|
|
117
|
+
const SLO_ONE_ID: string = "22222222-2222-4222-8222-222222222221";
|
|
118
|
+
const SLO_TWO_ID: string = "22222222-2222-4222-8222-222222222222";
|
|
119
|
+
const ALICE_ID: string = "33333333-3333-4333-8333-333333333331";
|
|
120
|
+
const BOB_ID: string = "33333333-3333-4333-8333-333333333332";
|
|
121
|
+
const CAROL_ID: string = "33333333-3333-4333-8333-333333333333";
|
|
122
|
+
const TEAM_ONE_ID: string = "44444444-4444-4444-8444-444444444441";
|
|
123
|
+
const TEAM_TWO_ID: string = "44444444-4444-4444-8444-444444444442";
|
|
124
|
+
const OWNER_ROW_ID: string = "55555555-5555-4555-8555-555555555551";
|
|
125
|
+
const OWNER_ROW_TWO_ID: string = "55555555-5555-4555-8555-555555555552";
|
|
126
|
+
|
|
127
|
+
const SLO_OWNER_CONFIG: BulkOwnerActionsConfig = {
|
|
128
|
+
ownerUserModelType: ServiceLevelObjectiveOwnerUser,
|
|
129
|
+
ownerTeamModelType: ServiceLevelObjectiveOwnerTeam,
|
|
130
|
+
resourceIdField: "serviceLevelObjectiveId",
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
interface TeamMemberSeed {
|
|
134
|
+
userId: string;
|
|
135
|
+
name?: string;
|
|
136
|
+
email?: string;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
type MakeTeamMemberFunction = (seed: TeamMemberSeed) => TeamMember;
|
|
140
|
+
|
|
141
|
+
const makeTeamMember: MakeTeamMemberFunction = (
|
|
142
|
+
seed: TeamMemberSeed,
|
|
143
|
+
): TeamMember => {
|
|
144
|
+
const user: User = new User();
|
|
145
|
+
user._id = seed.userId;
|
|
146
|
+
|
|
147
|
+
if (seed.name) {
|
|
148
|
+
user.name = new Name(seed.name);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
if (seed.email) {
|
|
152
|
+
user.email = new Email(seed.email);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const member: TeamMember = new TeamMember();
|
|
156
|
+
member.user = user;
|
|
157
|
+
|
|
158
|
+
return member;
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
type MakeTeamFunction = (id: string, name: string) => Team;
|
|
162
|
+
|
|
163
|
+
const makeTeam: MakeTeamFunction = (id: string, name: string): Team => {
|
|
164
|
+
const team: Team = new Team();
|
|
165
|
+
team._id = id;
|
|
166
|
+
team.name = name;
|
|
167
|
+
|
|
168
|
+
return team;
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
type MakeSloFunction = (id?: string) => ServiceLevelObjective;
|
|
172
|
+
|
|
173
|
+
const makeSlo: MakeSloFunction = (id?: string): ServiceLevelObjective => {
|
|
174
|
+
const slo: ServiceLevelObjective = new ServiceLevelObjective();
|
|
175
|
+
|
|
176
|
+
if (id) {
|
|
177
|
+
slo._id = id;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
return slo;
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
interface OwnerRowSeed {
|
|
184
|
+
id?: string;
|
|
185
|
+
userId?: string;
|
|
186
|
+
teamId?: string;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
type MakeOwnerUserRowFunction = (
|
|
190
|
+
seed: OwnerRowSeed,
|
|
191
|
+
) => ServiceLevelObjectiveOwnerUser;
|
|
192
|
+
|
|
193
|
+
const makeOwnerUserRow: MakeOwnerUserRowFunction = (
|
|
194
|
+
seed: OwnerRowSeed,
|
|
195
|
+
): ServiceLevelObjectiveOwnerUser => {
|
|
196
|
+
const row: ServiceLevelObjectiveOwnerUser =
|
|
197
|
+
new ServiceLevelObjectiveOwnerUser();
|
|
198
|
+
|
|
199
|
+
if (seed.id) {
|
|
200
|
+
row._id = seed.id;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
if (seed.userId) {
|
|
204
|
+
row.userId = new ObjectID(seed.userId);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
return row;
|
|
208
|
+
};
|
|
209
|
+
|
|
210
|
+
type MakeOwnerTeamRowFunction = (
|
|
211
|
+
seed: OwnerRowSeed,
|
|
212
|
+
) => ServiceLevelObjectiveOwnerTeam;
|
|
213
|
+
|
|
214
|
+
const makeOwnerTeamRow: MakeOwnerTeamRowFunction = (
|
|
215
|
+
seed: OwnerRowSeed,
|
|
216
|
+
): ServiceLevelObjectiveOwnerTeam => {
|
|
217
|
+
const row: ServiceLevelObjectiveOwnerTeam =
|
|
218
|
+
new ServiceLevelObjectiveOwnerTeam();
|
|
219
|
+
|
|
220
|
+
if (seed.id) {
|
|
221
|
+
row._id = seed.id;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
if (seed.teamId) {
|
|
225
|
+
row.teamId = new ObjectID(seed.teamId);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
return row;
|
|
229
|
+
};
|
|
230
|
+
|
|
231
|
+
interface ListSeeds {
|
|
232
|
+
teamMembers?: Array<TeamMember>;
|
|
233
|
+
teams?: Array<Team>;
|
|
234
|
+
ownerUsers?: Array<ServiceLevelObjectiveOwnerUser>;
|
|
235
|
+
ownerTeams?: Array<ServiceLevelObjectiveOwnerTeam>;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
type MockListsFunction = (seeds: ListSeeds) => void;
|
|
239
|
+
|
|
240
|
+
/*
|
|
241
|
+
* All four reads go through the same ModelAPI.getList, so every assertion
|
|
242
|
+
* about "which table did it ask for" has to branch on modelType rather than
|
|
243
|
+
* on call order.
|
|
244
|
+
*/
|
|
245
|
+
const mockLists: MockListsFunction = (seeds: ListSeeds): void => {
|
|
246
|
+
getListMock.mockImplementation(async (listData: any): Promise<any> => {
|
|
247
|
+
let rows: Array<any> = [];
|
|
248
|
+
|
|
249
|
+
if (listData.modelType === TeamMember) {
|
|
250
|
+
rows = seeds.teamMembers || [];
|
|
251
|
+
} else if (listData.modelType === Team) {
|
|
252
|
+
rows = seeds.teams || [];
|
|
253
|
+
} else if (listData.modelType === ServiceLevelObjectiveOwnerUser) {
|
|
254
|
+
rows = seeds.ownerUsers || [];
|
|
255
|
+
} else if (listData.modelType === ServiceLevelObjectiveOwnerTeam) {
|
|
256
|
+
rows = seeds.ownerTeams || [];
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
return {
|
|
260
|
+
data: rows,
|
|
261
|
+
count: rows.length,
|
|
262
|
+
skip: 0,
|
|
263
|
+
limit: LIMIT_PER_PROJECT,
|
|
264
|
+
};
|
|
265
|
+
});
|
|
266
|
+
};
|
|
267
|
+
|
|
268
|
+
interface ProgressSnapshot {
|
|
269
|
+
totalItems: Array<string>;
|
|
270
|
+
inProgressItems: Array<string>;
|
|
271
|
+
successItems: Array<string>;
|
|
272
|
+
failed: Array<{ id: string; failedMessage: string }>;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
const progressSnapshots: Array<ProgressSnapshot> = [];
|
|
276
|
+
|
|
277
|
+
const onProgressInfo: MockFunction = getJestMockFunction();
|
|
278
|
+
const onBulkActionStart: MockFunction = getJestMockFunction();
|
|
279
|
+
const onBulkActionEnd: MockFunction = getJestMockFunction();
|
|
280
|
+
|
|
281
|
+
type IdsOfFunction = (items: Array<ServiceLevelObjective>) => Array<string>;
|
|
282
|
+
|
|
283
|
+
const idsOf: IdsOfFunction = (
|
|
284
|
+
items: Array<ServiceLevelObjective>,
|
|
285
|
+
): Array<string> => {
|
|
286
|
+
return items.map((item: ServiceLevelObjective) => {
|
|
287
|
+
return item._id || "no-id";
|
|
288
|
+
});
|
|
289
|
+
};
|
|
290
|
+
|
|
291
|
+
interface HarnessProps {
|
|
292
|
+
items: Array<ServiceLevelObjective>;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
/*
|
|
296
|
+
* The hook hands back action descriptors that render nothing plus a `modals`
|
|
297
|
+
* element, so the modals only exist once something mounts them - renderHook
|
|
298
|
+
* alone cannot reach the form.
|
|
299
|
+
*/
|
|
300
|
+
const Harness: FunctionComponent<HarnessProps> = (
|
|
301
|
+
props: HarnessProps,
|
|
302
|
+
): ReactElement => {
|
|
303
|
+
const { bulkActions, modals }: BulkOwnerActionsResult<ServiceLevelObjective> =
|
|
304
|
+
useBulkOwnerActions<ServiceLevelObjective>(SLO_OWNER_CONFIG);
|
|
305
|
+
|
|
306
|
+
return (
|
|
307
|
+
<div>
|
|
308
|
+
{bulkActions.map(
|
|
309
|
+
(action: BulkActionButtonSchema<ServiceLevelObjective>) => {
|
|
310
|
+
return (
|
|
311
|
+
<button
|
|
312
|
+
key={action.title}
|
|
313
|
+
type="button"
|
|
314
|
+
onClick={() => {
|
|
315
|
+
void action.onClick({
|
|
316
|
+
items: props.items,
|
|
317
|
+
onProgressInfo: onProgressInfo,
|
|
318
|
+
onBulkActionStart: onBulkActionStart,
|
|
319
|
+
onBulkActionEnd: onBulkActionEnd,
|
|
320
|
+
} as BulkActionOnClickProps<ServiceLevelObjective>);
|
|
321
|
+
}}
|
|
322
|
+
>
|
|
323
|
+
{`Trigger ${action.title}`}
|
|
324
|
+
</button>
|
|
325
|
+
);
|
|
326
|
+
},
|
|
327
|
+
)}
|
|
328
|
+
{modals}
|
|
329
|
+
</div>
|
|
330
|
+
);
|
|
331
|
+
};
|
|
332
|
+
|
|
333
|
+
type WaitForOwnerSourcesFunction = () => Promise<void>;
|
|
334
|
+
|
|
335
|
+
const waitForOwnerSources: WaitForOwnerSourcesFunction =
|
|
336
|
+
async (): Promise<void> => {
|
|
337
|
+
/*
|
|
338
|
+
* Drained inside act() first: waitFor's own await would otherwise let
|
|
339
|
+
* the mount fetch settle between checks, landing the dropdown state
|
|
340
|
+
* outside act and burying the run in warnings.
|
|
341
|
+
*/
|
|
342
|
+
await act(async () => {
|
|
343
|
+
await new Promise<void>((resolve: () => void) => {
|
|
344
|
+
setTimeout(resolve, 0);
|
|
345
|
+
});
|
|
346
|
+
});
|
|
347
|
+
|
|
348
|
+
await waitFor(
|
|
349
|
+
() => {
|
|
350
|
+
expect(getListMock).toHaveBeenCalledTimes(2);
|
|
351
|
+
},
|
|
352
|
+
{ timeout: WAIT_TIMEOUT },
|
|
353
|
+
);
|
|
354
|
+
};
|
|
355
|
+
|
|
356
|
+
type OpenOwnerModalFunction = (title: string) => Promise<void>;
|
|
357
|
+
|
|
358
|
+
const openOwnerModal: OpenOwnerModalFunction = async (
|
|
359
|
+
title: string,
|
|
360
|
+
): Promise<void> => {
|
|
361
|
+
fireEvent.click(screen.getByText(`Trigger ${title}`));
|
|
362
|
+
|
|
363
|
+
await waitFor(
|
|
364
|
+
() => {
|
|
365
|
+
expect(screen.getByTestId("modal-title")).toHaveTextContent(title);
|
|
366
|
+
},
|
|
367
|
+
{ timeout: WAIT_TIMEOUT },
|
|
368
|
+
);
|
|
369
|
+
};
|
|
370
|
+
|
|
371
|
+
type ClickOwnerActionFunction = (title: string) => void;
|
|
372
|
+
|
|
373
|
+
/*
|
|
374
|
+
* openOwnerModal is unusable for the exclusion tests: its getByTestId gate
|
|
375
|
+
* throws on a multiple match, so a stacked second modal makes the helper spin
|
|
376
|
+
* until the test times out and neither assertion ever runs. Clicking without
|
|
377
|
+
* the gate leaves the count assertion as the thing that reports the
|
|
378
|
+
* regression. Safe to read the DOM straight after: fireEvent is act-wrapped
|
|
379
|
+
* and the onClick sets both flags before its first await.
|
|
380
|
+
*/
|
|
381
|
+
const clickOwnerAction: ClickOwnerActionFunction = (title: string): void => {
|
|
382
|
+
fireEvent.click(screen.getByText(`Trigger ${title}`));
|
|
383
|
+
};
|
|
384
|
+
|
|
385
|
+
type SelectOwnerFunction = (optionLabel: string) => Promise<void>;
|
|
386
|
+
|
|
387
|
+
/*
|
|
388
|
+
* react-select closes its menu after each pick and hides already-selected
|
|
389
|
+
* options, so re-opening between picks is what makes multi-select reachable
|
|
390
|
+
* and keeps the option text unambiguous against the value pill.
|
|
391
|
+
*/
|
|
392
|
+
const selectOwner: SelectOwnerFunction = async (
|
|
393
|
+
optionLabel: string,
|
|
394
|
+
): Promise<void> => {
|
|
395
|
+
const combobox: HTMLElement = screen.getByRole("combobox");
|
|
396
|
+
fireEvent.keyDown(combobox, { key: "ArrowDown", code: "ArrowDown" });
|
|
397
|
+
fireEvent.click(
|
|
398
|
+
await screen.findByText(optionLabel, {}, { timeout: WAIT_TIMEOUT }),
|
|
399
|
+
);
|
|
400
|
+
};
|
|
401
|
+
|
|
402
|
+
type OpenOwnerMenuFunction = () => void;
|
|
403
|
+
|
|
404
|
+
const openOwnerMenu: OpenOwnerMenuFunction = (): void => {
|
|
405
|
+
const combobox: HTMLElement = screen.getByRole("combobox");
|
|
406
|
+
fireEvent.keyDown(combobox, { key: "ArrowDown", code: "ArrowDown" });
|
|
407
|
+
};
|
|
408
|
+
|
|
409
|
+
type SubmitOwnerModalFunction = () => void;
|
|
410
|
+
|
|
411
|
+
const submitOwnerModal: SubmitOwnerModalFunction = (): void => {
|
|
412
|
+
fireEvent.click(screen.getByTestId("modal-footer-submit-button"));
|
|
413
|
+
};
|
|
414
|
+
|
|
415
|
+
type GetListCallsForFunction = (modelType: unknown) => Array<any>;
|
|
416
|
+
|
|
417
|
+
const getListCallsFor: GetListCallsForFunction = (
|
|
418
|
+
modelType: unknown,
|
|
419
|
+
): Array<any> => {
|
|
420
|
+
return (getListMock.mock.calls as Array<Array<any>>)
|
|
421
|
+
.map((call: Array<any>) => {
|
|
422
|
+
return call[0];
|
|
423
|
+
})
|
|
424
|
+
.filter((listData: any) => {
|
|
425
|
+
return listData.modelType === modelType;
|
|
426
|
+
});
|
|
427
|
+
};
|
|
428
|
+
|
|
429
|
+
/*
|
|
430
|
+
* These mount the real Modal, Formik and react-select trees, so a cold
|
|
431
|
+
* ts-jest transform of that import graph can push individual tests past
|
|
432
|
+
* jest's 5s default - which CI, always starting cold, would report as a
|
|
433
|
+
* red build with no assertion having failed. The slowest test here runs
|
|
434
|
+
* in ~1.3s warm; 30s is the same ceiling App/jest.config.json already
|
|
435
|
+
* sets for its whole suite.
|
|
436
|
+
*/
|
|
437
|
+
jest.setTimeout(30000);
|
|
438
|
+
|
|
439
|
+
describe("useBulkOwnerActions", () => {
|
|
440
|
+
beforeEach(() => {
|
|
441
|
+
jest.clearAllMocks();
|
|
442
|
+
progressSnapshots.length = 0;
|
|
443
|
+
window.localStorage.clear();
|
|
444
|
+
window.sessionStorage.clear();
|
|
445
|
+
|
|
446
|
+
/*
|
|
447
|
+
* ProjectUtil.getCurrentProjectId() reads pathname.split("/")[2] before
|
|
448
|
+
* falling back to storage, so the URL is the whole "current project"
|
|
449
|
+
* fixture.
|
|
450
|
+
*/
|
|
451
|
+
window.history.replaceState({}, "", `/dashboard/${PROJECT_ID}/slos`);
|
|
452
|
+
|
|
453
|
+
/*
|
|
454
|
+
* The progress arrays are allocated once and handed to every callback by
|
|
455
|
+
* reference, so anything kept without copying reads back as the final
|
|
456
|
+
* state of the run.
|
|
457
|
+
*/
|
|
458
|
+
onProgressInfo.mockImplementation(
|
|
459
|
+
(progressInfo: ProgressInfo<ServiceLevelObjective>): void => {
|
|
460
|
+
progressSnapshots.push({
|
|
461
|
+
totalItems: idsOf(progressInfo.totalItems),
|
|
462
|
+
inProgressItems: idsOf(progressInfo.inProgressItems),
|
|
463
|
+
successItems: idsOf(progressInfo.successItems),
|
|
464
|
+
failed: progressInfo.failed.map(
|
|
465
|
+
(failure: BulkActionFailed<ServiceLevelObjective>) => {
|
|
466
|
+
return {
|
|
467
|
+
id: failure.item._id || "no-id",
|
|
468
|
+
failedMessage: failure.failedMessage as string,
|
|
469
|
+
};
|
|
470
|
+
},
|
|
471
|
+
),
|
|
472
|
+
});
|
|
473
|
+
},
|
|
474
|
+
);
|
|
475
|
+
|
|
476
|
+
mockLists({});
|
|
477
|
+
createMock.mockResolvedValue({});
|
|
478
|
+
deleteItemMock.mockResolvedValue({});
|
|
479
|
+
});
|
|
480
|
+
|
|
481
|
+
test("offers Add Owner then Remove Owner, in that order", async () => {
|
|
482
|
+
const { result } = renderHook(() => {
|
|
483
|
+
return useBulkOwnerActions<ServiceLevelObjective>(SLO_OWNER_CONFIG);
|
|
484
|
+
});
|
|
485
|
+
|
|
486
|
+
await waitForOwnerSources();
|
|
487
|
+
|
|
488
|
+
/*
|
|
489
|
+
* Consumers splice these straight into ModelTable's button list, which
|
|
490
|
+
* renders them in array order.
|
|
491
|
+
*/
|
|
492
|
+
expect(result.current.bulkActions).toHaveLength(2);
|
|
493
|
+
expect(result.current.bulkActions[0]!.title).toBe("Add Owner");
|
|
494
|
+
expect(result.current.bulkActions[1]!.title).toBe("Remove Owner");
|
|
495
|
+
});
|
|
496
|
+
|
|
497
|
+
test("gives both actions the user icons and a non-danger button style", async () => {
|
|
498
|
+
const { result } = renderHook(() => {
|
|
499
|
+
return useBulkOwnerActions<ServiceLevelObjective>(SLO_OWNER_CONFIG);
|
|
500
|
+
});
|
|
501
|
+
|
|
502
|
+
await waitForOwnerSources();
|
|
503
|
+
|
|
504
|
+
expect(result.current.bulkActions[0]!.icon).toBe(IconProp.UserPlus);
|
|
505
|
+
expect(result.current.bulkActions[0]!.buttonStyleType).toBe(
|
|
506
|
+
ButtonStyleType.NORMAL,
|
|
507
|
+
);
|
|
508
|
+
expect(result.current.bulkActions[1]!.icon).toBe(IconProp.UserMinus);
|
|
509
|
+
|
|
510
|
+
/*
|
|
511
|
+
* BulkUpdateForm splits danger-styled buttons into their own red menu
|
|
512
|
+
* group below a divider. Removing an owner is reversible, so it has to
|
|
513
|
+
* stay with the ordinary actions.
|
|
514
|
+
*/
|
|
515
|
+
expect(result.current.bulkActions[1]!.buttonStyleType).toBe(
|
|
516
|
+
ButtonStyleType.NORMAL,
|
|
517
|
+
);
|
|
518
|
+
});
|
|
519
|
+
|
|
520
|
+
test("fetches this project's team members and teams on mount", async () => {
|
|
521
|
+
render(<Harness items={[]} />);
|
|
522
|
+
|
|
523
|
+
await waitForOwnerSources();
|
|
524
|
+
|
|
525
|
+
const memberCall: any = getListCallsFor(TeamMember)[0];
|
|
526
|
+
expect(memberCall.query.projectId.toString()).toBe(PROJECT_ID);
|
|
527
|
+
expect(memberCall.limit).toBe(LIMIT_PER_PROJECT);
|
|
528
|
+
expect(memberCall.skip).toBe(0);
|
|
529
|
+
expect(memberCall.select).toEqual({
|
|
530
|
+
_id: true,
|
|
531
|
+
user: { _id: true, name: true, email: true },
|
|
532
|
+
});
|
|
533
|
+
|
|
534
|
+
const teamCall: any = getListCallsFor(Team)[0];
|
|
535
|
+
expect(teamCall.query.projectId.toString()).toBe(PROJECT_ID);
|
|
536
|
+
expect(teamCall.limit).toBe(LIMIT_PER_PROJECT);
|
|
537
|
+
expect(teamCall.select).toEqual({ _id: true, name: true });
|
|
538
|
+
expect(teamCall.sort).toEqual({ name: SortOrder.Ascending });
|
|
539
|
+
});
|
|
540
|
+
|
|
541
|
+
test("fetches team members and teams in parallel", async () => {
|
|
542
|
+
getListMock.mockImplementation((listData: any): Promise<any> => {
|
|
543
|
+
if (listData.modelType === TeamMember) {
|
|
544
|
+
// Never settles, so the team read can only happen if it did not await this one.
|
|
545
|
+
return new Promise((): void => {});
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
return Promise.resolve({ data: [], count: 0, skip: 0, limit: 0 });
|
|
549
|
+
});
|
|
550
|
+
|
|
551
|
+
render(<Harness items={[]} />);
|
|
552
|
+
|
|
553
|
+
/*
|
|
554
|
+
* A project with a large membership table would otherwise hold the Teams
|
|
555
|
+
* group out of the dropdown for as long as that read takes.
|
|
556
|
+
*/
|
|
557
|
+
await waitForOwnerSources();
|
|
558
|
+
expect(getListCallsFor(TeamMember)).toHaveLength(1);
|
|
559
|
+
expect(getListCallsFor(Team)).toHaveLength(1);
|
|
560
|
+
});
|
|
561
|
+
|
|
562
|
+
test("fetches nothing when there is no current project", async () => {
|
|
563
|
+
window.history.replaceState({}, "", "/dashboard");
|
|
564
|
+
|
|
565
|
+
render(<Harness items={[]} />);
|
|
566
|
+
|
|
567
|
+
await screen.findByText("Trigger Add Owner", {}, { timeout: WAIT_TIMEOUT });
|
|
568
|
+
|
|
569
|
+
/*
|
|
570
|
+
* Without the guard the query goes out with projectId undefined, which
|
|
571
|
+
* the API answers with every team member the caller can read.
|
|
572
|
+
*/
|
|
573
|
+
expect(getListMock).not.toHaveBeenCalled();
|
|
574
|
+
});
|
|
575
|
+
|
|
576
|
+
test("lists a user once even when they are on several teams", async () => {
|
|
577
|
+
mockLists({
|
|
578
|
+
teamMembers: [
|
|
579
|
+
makeTeamMember({ userId: ALICE_ID, name: "Alice" }),
|
|
580
|
+
makeTeamMember({ userId: BOB_ID, name: "Bob" }),
|
|
581
|
+
makeTeamMember({ userId: ALICE_ID, name: "Alice" }),
|
|
582
|
+
],
|
|
583
|
+
teams: [],
|
|
584
|
+
});
|
|
585
|
+
|
|
586
|
+
render(<Harness items={[]} />);
|
|
587
|
+
await waitForOwnerSources();
|
|
588
|
+
await openOwnerModal("Add Owner");
|
|
589
|
+
openOwnerMenu();
|
|
590
|
+
|
|
591
|
+
await screen.findByText("Bob", {}, { timeout: WAIT_TIMEOUT });
|
|
592
|
+
expect(screen.getAllByText("Alice")).toHaveLength(1);
|
|
593
|
+
});
|
|
594
|
+
|
|
595
|
+
test("sorts people case-insensitively by name", async () => {
|
|
596
|
+
mockLists({
|
|
597
|
+
teamMembers: [
|
|
598
|
+
makeTeamMember({ userId: CAROL_ID, name: "carol" }),
|
|
599
|
+
makeTeamMember({ userId: BOB_ID, name: "Bob" }),
|
|
600
|
+
makeTeamMember({ userId: ALICE_ID, name: "alice" }),
|
|
601
|
+
],
|
|
602
|
+
teams: [],
|
|
603
|
+
});
|
|
604
|
+
|
|
605
|
+
render(<Harness items={[]} />);
|
|
606
|
+
await waitForOwnerSources();
|
|
607
|
+
await openOwnerModal("Add Owner");
|
|
608
|
+
openOwnerMenu();
|
|
609
|
+
|
|
610
|
+
await screen.findByText("alice", {}, { timeout: WAIT_TIMEOUT });
|
|
611
|
+
|
|
612
|
+
const optionLabels: Array<string> = screen
|
|
613
|
+
.getAllByRole("option")
|
|
614
|
+
.map((option: HTMLElement) => {
|
|
615
|
+
return option.textContent || "";
|
|
616
|
+
});
|
|
617
|
+
|
|
618
|
+
/*
|
|
619
|
+
* A plain codepoint sort puts every capitalised name ahead of every
|
|
620
|
+
* lowercase one, so "Bob" would jump the queue ahead of "alice".
|
|
621
|
+
*/
|
|
622
|
+
expect(optionLabels).toEqual(["alice", "Bob", "carol"]);
|
|
623
|
+
});
|
|
624
|
+
|
|
625
|
+
test("falls back to a member's email when they have no name", async () => {
|
|
626
|
+
mockLists({
|
|
627
|
+
teamMembers: [
|
|
628
|
+
makeTeamMember({ userId: ALICE_ID, email: "alice@example.com" }),
|
|
629
|
+
],
|
|
630
|
+
teams: [],
|
|
631
|
+
});
|
|
632
|
+
|
|
633
|
+
render(<Harness items={[]} />);
|
|
634
|
+
await waitForOwnerSources();
|
|
635
|
+
await openOwnerModal("Add Owner");
|
|
636
|
+
openOwnerMenu();
|
|
637
|
+
|
|
638
|
+
expect(
|
|
639
|
+
await screen.findByText(
|
|
640
|
+
"alice@example.com",
|
|
641
|
+
{},
|
|
642
|
+
{ timeout: WAIT_TIMEOUT },
|
|
643
|
+
),
|
|
644
|
+
).toBeInTheDocument();
|
|
645
|
+
});
|
|
646
|
+
|
|
647
|
+
test("groups the options under People and Teams", async () => {
|
|
648
|
+
mockLists({
|
|
649
|
+
teamMembers: [makeTeamMember({ userId: ALICE_ID, name: "Alice" })],
|
|
650
|
+
teams: [makeTeam(TEAM_ONE_ID, "Team One")],
|
|
651
|
+
});
|
|
652
|
+
|
|
653
|
+
render(<Harness items={[]} />);
|
|
654
|
+
await waitForOwnerSources();
|
|
655
|
+
await openOwnerModal("Add Owner");
|
|
656
|
+
openOwnerMenu();
|
|
657
|
+
|
|
658
|
+
expect(
|
|
659
|
+
await screen.findByText("People", {}, { timeout: WAIT_TIMEOUT }),
|
|
660
|
+
).toBeInTheDocument();
|
|
661
|
+
expect(screen.getByText("Teams")).toBeInTheDocument();
|
|
662
|
+
expect(screen.getByText("Alice")).toBeInTheDocument();
|
|
663
|
+
expect(screen.getByText("Team One")).toBeInTheDocument();
|
|
664
|
+
});
|
|
665
|
+
|
|
666
|
+
test("offers every team in the project, in the order the API returned them", async () => {
|
|
667
|
+
mockLists({
|
|
668
|
+
teamMembers: [],
|
|
669
|
+
teams: [
|
|
670
|
+
makeTeam(TEAM_TWO_ID, "Zebra Team"),
|
|
671
|
+
makeTeam(TEAM_ONE_ID, "Apple Team"),
|
|
672
|
+
],
|
|
673
|
+
});
|
|
674
|
+
|
|
675
|
+
render(<Harness items={[]} />);
|
|
676
|
+
await waitForOwnerSources();
|
|
677
|
+
await openOwnerModal("Add Owner");
|
|
678
|
+
openOwnerMenu();
|
|
679
|
+
|
|
680
|
+
await screen.findByText("Zebra Team", {}, { timeout: WAIT_TIMEOUT });
|
|
681
|
+
|
|
682
|
+
/*
|
|
683
|
+
* Teams keep the server's ordering (the query asks for name ASC); only
|
|
684
|
+
* the people list is re-sorted in the hook, because it is stitched
|
|
685
|
+
* together from every team's membership.
|
|
686
|
+
*/
|
|
687
|
+
expect(
|
|
688
|
+
screen.getAllByRole("option").map((option: HTMLElement) => {
|
|
689
|
+
return option.textContent || "";
|
|
690
|
+
}),
|
|
691
|
+
).toEqual(["Zebra Team", "Apple Team"]);
|
|
692
|
+
});
|
|
693
|
+
|
|
694
|
+
test("omits the People group when the project has no team members", async () => {
|
|
695
|
+
mockLists({
|
|
696
|
+
teamMembers: [],
|
|
697
|
+
teams: [makeTeam(TEAM_ONE_ID, "Team One")],
|
|
698
|
+
});
|
|
699
|
+
|
|
700
|
+
render(<Harness items={[]} />);
|
|
701
|
+
await waitForOwnerSources();
|
|
702
|
+
await openOwnerModal("Add Owner");
|
|
703
|
+
openOwnerMenu();
|
|
704
|
+
|
|
705
|
+
await screen.findByText("Teams", {}, { timeout: WAIT_TIMEOUT });
|
|
706
|
+
|
|
707
|
+
/*
|
|
708
|
+
* An empty group still renders its heading, so the dropdown would show a
|
|
709
|
+
* "People" label with nothing under it.
|
|
710
|
+
*/
|
|
711
|
+
expect(screen.queryByText("People")).not.toBeInTheDocument();
|
|
712
|
+
});
|
|
713
|
+
|
|
714
|
+
test("omits the Teams group when the project has no teams", async () => {
|
|
715
|
+
mockLists({
|
|
716
|
+
teamMembers: [makeTeamMember({ userId: ALICE_ID, name: "Alice" })],
|
|
717
|
+
teams: [],
|
|
718
|
+
});
|
|
719
|
+
|
|
720
|
+
render(<Harness items={[]} />);
|
|
721
|
+
await waitForOwnerSources();
|
|
722
|
+
await openOwnerModal("Add Owner");
|
|
723
|
+
openOwnerMenu();
|
|
724
|
+
|
|
725
|
+
await screen.findByText("People", {}, { timeout: WAIT_TIMEOUT });
|
|
726
|
+
expect(screen.queryByText("Teams")).not.toBeInTheDocument();
|
|
727
|
+
});
|
|
728
|
+
|
|
729
|
+
test("creates one owner row per picked user and per picked team", async () => {
|
|
730
|
+
mockLists({
|
|
731
|
+
teamMembers: [makeTeamMember({ userId: ALICE_ID, name: "Alice" })],
|
|
732
|
+
teams: [makeTeam(TEAM_ONE_ID, "Team One")],
|
|
733
|
+
});
|
|
734
|
+
|
|
735
|
+
render(<Harness items={[makeSlo(SLO_ONE_ID)]} />);
|
|
736
|
+
await waitForOwnerSources();
|
|
737
|
+
await openOwnerModal("Add Owner");
|
|
738
|
+
await selectOwner("Alice");
|
|
739
|
+
await selectOwner("Team One");
|
|
740
|
+
submitOwnerModal();
|
|
741
|
+
|
|
742
|
+
await waitFor(
|
|
743
|
+
() => {
|
|
744
|
+
expect(createMock).toHaveBeenCalledTimes(2);
|
|
745
|
+
},
|
|
746
|
+
{ timeout: WAIT_TIMEOUT },
|
|
747
|
+
);
|
|
748
|
+
|
|
749
|
+
const userCall: any = (createMock.mock.calls[0] as Array<any>)[0];
|
|
750
|
+
expect(userCall.modelType).toBe(ServiceLevelObjectiveOwnerUser);
|
|
751
|
+
expect(userCall.model.userId.toString()).toBe(ALICE_ID);
|
|
752
|
+
expect(userCall.model.serviceLevelObjectiveId.toString()).toBe(SLO_ONE_ID);
|
|
753
|
+
expect(userCall.model.projectId.toString()).toBe(PROJECT_ID);
|
|
754
|
+
|
|
755
|
+
const teamCall: any = (createMock.mock.calls[1] as Array<any>)[0];
|
|
756
|
+
expect(teamCall.modelType).toBe(ServiceLevelObjectiveOwnerTeam);
|
|
757
|
+
expect(teamCall.model.teamId.toString()).toBe(TEAM_ONE_ID);
|
|
758
|
+
expect(teamCall.model.serviceLevelObjectiveId.toString()).toBe(SLO_ONE_ID);
|
|
759
|
+
expect(teamCall.model.projectId.toString()).toBe(PROJECT_ID);
|
|
760
|
+
});
|
|
761
|
+
|
|
762
|
+
test("creates a row for every selected item", async () => {
|
|
763
|
+
mockLists({
|
|
764
|
+
teamMembers: [makeTeamMember({ userId: ALICE_ID, name: "Alice" })],
|
|
765
|
+
teams: [],
|
|
766
|
+
});
|
|
767
|
+
|
|
768
|
+
render(<Harness items={[makeSlo(SLO_ONE_ID), makeSlo(SLO_TWO_ID)]} />);
|
|
769
|
+
await waitForOwnerSources();
|
|
770
|
+
await openOwnerModal("Add Owner");
|
|
771
|
+
await selectOwner("Alice");
|
|
772
|
+
submitOwnerModal();
|
|
773
|
+
|
|
774
|
+
await waitFor(
|
|
775
|
+
() => {
|
|
776
|
+
expect(createMock).toHaveBeenCalledTimes(2);
|
|
777
|
+
},
|
|
778
|
+
{ timeout: WAIT_TIMEOUT },
|
|
779
|
+
);
|
|
780
|
+
|
|
781
|
+
const resourceIds: Array<string> = (
|
|
782
|
+
createMock.mock.calls as Array<Array<any>>
|
|
783
|
+
).map((call: Array<any>) => {
|
|
784
|
+
return call[0].model.serviceLevelObjectiveId.toString();
|
|
785
|
+
});
|
|
786
|
+
|
|
787
|
+
expect(resourceIds).toEqual([SLO_ONE_ID, SLO_TWO_ID]);
|
|
788
|
+
});
|
|
789
|
+
|
|
790
|
+
test("skips an owner the item already has", async () => {
|
|
791
|
+
mockLists({
|
|
792
|
+
teamMembers: [makeTeamMember({ userId: ALICE_ID, name: "Alice" })],
|
|
793
|
+
teams: [makeTeam(TEAM_ONE_ID, "Team One")],
|
|
794
|
+
ownerUsers: [makeOwnerUserRow({ id: OWNER_ROW_ID, userId: ALICE_ID })],
|
|
795
|
+
ownerTeams: [],
|
|
796
|
+
});
|
|
797
|
+
|
|
798
|
+
render(<Harness items={[makeSlo(SLO_ONE_ID)]} />);
|
|
799
|
+
await waitForOwnerSources();
|
|
800
|
+
await openOwnerModal("Add Owner");
|
|
801
|
+
await selectOwner("Alice");
|
|
802
|
+
await selectOwner("Team One");
|
|
803
|
+
submitOwnerModal();
|
|
804
|
+
|
|
805
|
+
await waitFor(
|
|
806
|
+
() => {
|
|
807
|
+
expect(createMock).toHaveBeenCalledTimes(1);
|
|
808
|
+
},
|
|
809
|
+
{ timeout: WAIT_TIMEOUT },
|
|
810
|
+
);
|
|
811
|
+
|
|
812
|
+
/*
|
|
813
|
+
* Re-adding an existing owner is not a harmless duplicate: the owner
|
|
814
|
+
* lists on the resource render one row per junction record.
|
|
815
|
+
*/
|
|
816
|
+
const onlyCall: any = (createMock.mock.calls[0] as Array<any>)[0];
|
|
817
|
+
expect(onlyCall.modelType).toBe(ServiceLevelObjectiveOwnerTeam);
|
|
818
|
+
});
|
|
819
|
+
|
|
820
|
+
test("reads the item's existing user owners with the resource-scoped query", async () => {
|
|
821
|
+
mockLists({
|
|
822
|
+
teamMembers: [makeTeamMember({ userId: ALICE_ID, name: "Alice" })],
|
|
823
|
+
teams: [],
|
|
824
|
+
});
|
|
825
|
+
|
|
826
|
+
render(<Harness items={[makeSlo(SLO_ONE_ID)]} />);
|
|
827
|
+
await waitForOwnerSources();
|
|
828
|
+
await openOwnerModal("Add Owner");
|
|
829
|
+
await selectOwner("Alice");
|
|
830
|
+
submitOwnerModal();
|
|
831
|
+
|
|
832
|
+
await waitFor(
|
|
833
|
+
() => {
|
|
834
|
+
expect(createMock).toHaveBeenCalledTimes(1);
|
|
835
|
+
},
|
|
836
|
+
{ timeout: WAIT_TIMEOUT },
|
|
837
|
+
);
|
|
838
|
+
|
|
839
|
+
const ownerUserCall: any = getListCallsFor(
|
|
840
|
+
ServiceLevelObjectiveOwnerUser,
|
|
841
|
+
)[0];
|
|
842
|
+
|
|
843
|
+
/*
|
|
844
|
+
* The foreign key is a config string. Spelling it wrong compiles, and
|
|
845
|
+
* then this query matches every owner row in the project.
|
|
846
|
+
*/
|
|
847
|
+
expect(ownerUserCall.query.serviceLevelObjectiveId.toString()).toBe(
|
|
848
|
+
SLO_ONE_ID,
|
|
849
|
+
);
|
|
850
|
+
expect(ownerUserCall.query.projectId.toString()).toBe(PROJECT_ID);
|
|
851
|
+
expect(ownerUserCall.select).toEqual({ userId: true });
|
|
852
|
+
expect(ownerUserCall.limit).toBe(LIMIT_PER_PROJECT);
|
|
853
|
+
expect(ownerUserCall.skip).toBe(0);
|
|
854
|
+
});
|
|
855
|
+
|
|
856
|
+
test("does not touch the team owner table when only a user was picked", async () => {
|
|
857
|
+
mockLists({
|
|
858
|
+
teamMembers: [makeTeamMember({ userId: ALICE_ID, name: "Alice" })],
|
|
859
|
+
teams: [makeTeam(TEAM_ONE_ID, "Team One")],
|
|
860
|
+
});
|
|
861
|
+
|
|
862
|
+
render(<Harness items={[makeSlo(SLO_ONE_ID)]} />);
|
|
863
|
+
await waitForOwnerSources();
|
|
864
|
+
await openOwnerModal("Add Owner");
|
|
865
|
+
await selectOwner("Alice");
|
|
866
|
+
submitOwnerModal();
|
|
867
|
+
|
|
868
|
+
await waitFor(
|
|
869
|
+
() => {
|
|
870
|
+
expect(createMock).toHaveBeenCalledTimes(1);
|
|
871
|
+
},
|
|
872
|
+
{ timeout: WAIT_TIMEOUT },
|
|
873
|
+
);
|
|
874
|
+
|
|
875
|
+
expect(getListCallsFor(ServiceLevelObjectiveOwnerUser)).toHaveLength(1);
|
|
876
|
+
expect(getListCallsFor(ServiceLevelObjectiveOwnerTeam)).toHaveLength(0);
|
|
877
|
+
});
|
|
878
|
+
|
|
879
|
+
test("does not touch the user owner table when only a team was picked", async () => {
|
|
880
|
+
mockLists({
|
|
881
|
+
teamMembers: [makeTeamMember({ userId: ALICE_ID, name: "Alice" })],
|
|
882
|
+
teams: [makeTeam(TEAM_ONE_ID, "Team One")],
|
|
883
|
+
});
|
|
884
|
+
|
|
885
|
+
render(<Harness items={[makeSlo(SLO_ONE_ID)]} />);
|
|
886
|
+
await waitForOwnerSources();
|
|
887
|
+
await openOwnerModal("Add Owner");
|
|
888
|
+
await selectOwner("Team One");
|
|
889
|
+
submitOwnerModal();
|
|
890
|
+
|
|
891
|
+
await waitFor(
|
|
892
|
+
() => {
|
|
893
|
+
expect(createMock).toHaveBeenCalledTimes(1);
|
|
894
|
+
},
|
|
895
|
+
{ timeout: WAIT_TIMEOUT },
|
|
896
|
+
);
|
|
897
|
+
|
|
898
|
+
expect(getListCallsFor(ServiceLevelObjectiveOwnerTeam)).toHaveLength(1);
|
|
899
|
+
expect(getListCallsFor(ServiceLevelObjectiveOwnerUser)).toHaveLength(0);
|
|
900
|
+
});
|
|
901
|
+
|
|
902
|
+
test("deletes the junction rows that match the removed owners", async () => {
|
|
903
|
+
mockLists({
|
|
904
|
+
teamMembers: [makeTeamMember({ userId: ALICE_ID, name: "Alice" })],
|
|
905
|
+
teams: [makeTeam(TEAM_ONE_ID, "Team One")],
|
|
906
|
+
ownerUsers: [makeOwnerUserRow({ id: OWNER_ROW_ID, userId: ALICE_ID })],
|
|
907
|
+
ownerTeams: [
|
|
908
|
+
makeOwnerTeamRow({ id: OWNER_ROW_TWO_ID, teamId: TEAM_ONE_ID }),
|
|
909
|
+
],
|
|
910
|
+
});
|
|
911
|
+
|
|
912
|
+
render(<Harness items={[makeSlo(SLO_ONE_ID)]} />);
|
|
913
|
+
await waitForOwnerSources();
|
|
914
|
+
await openOwnerModal("Remove Owner");
|
|
915
|
+
await selectOwner("Alice");
|
|
916
|
+
await selectOwner("Team One");
|
|
917
|
+
submitOwnerModal();
|
|
918
|
+
|
|
919
|
+
await waitFor(
|
|
920
|
+
() => {
|
|
921
|
+
expect(deleteItemMock).toHaveBeenCalledTimes(2);
|
|
922
|
+
},
|
|
923
|
+
{ timeout: WAIT_TIMEOUT },
|
|
924
|
+
);
|
|
925
|
+
|
|
926
|
+
const userDelete: any = (deleteItemMock.mock.calls[0] as Array<any>)[0];
|
|
927
|
+
expect(userDelete.modelType).toBe(ServiceLevelObjectiveOwnerUser);
|
|
928
|
+
expect(userDelete.id.toString()).toBe(OWNER_ROW_ID);
|
|
929
|
+
|
|
930
|
+
const teamDelete: any = (deleteItemMock.mock.calls[1] as Array<any>)[0];
|
|
931
|
+
expect(teamDelete.modelType).toBe(ServiceLevelObjectiveOwnerTeam);
|
|
932
|
+
expect(teamDelete.id.toString()).toBe(OWNER_ROW_TWO_ID);
|
|
933
|
+
|
|
934
|
+
expect(createMock).not.toHaveBeenCalled();
|
|
935
|
+
});
|
|
936
|
+
|
|
937
|
+
test("looks the removable rows up by the selected owner ids", async () => {
|
|
938
|
+
mockLists({
|
|
939
|
+
teamMembers: [makeTeamMember({ userId: ALICE_ID, name: "Alice" })],
|
|
940
|
+
teams: [],
|
|
941
|
+
ownerUsers: [makeOwnerUserRow({ id: OWNER_ROW_ID, userId: ALICE_ID })],
|
|
942
|
+
});
|
|
943
|
+
|
|
944
|
+
render(<Harness items={[makeSlo(SLO_ONE_ID)]} />);
|
|
945
|
+
await waitForOwnerSources();
|
|
946
|
+
await openOwnerModal("Remove Owner");
|
|
947
|
+
await selectOwner("Alice");
|
|
948
|
+
submitOwnerModal();
|
|
949
|
+
|
|
950
|
+
await waitFor(
|
|
951
|
+
() => {
|
|
952
|
+
expect(deleteItemMock).toHaveBeenCalledTimes(1);
|
|
953
|
+
},
|
|
954
|
+
{ timeout: WAIT_TIMEOUT },
|
|
955
|
+
);
|
|
956
|
+
|
|
957
|
+
const lookup: any = getListCallsFor(ServiceLevelObjectiveOwnerUser)[0];
|
|
958
|
+
expect(lookup.query.serviceLevelObjectiveId.toString()).toBe(SLO_ONE_ID);
|
|
959
|
+
expect(lookup.query.userId).toBeInstanceOf(Includes);
|
|
960
|
+
expect(
|
|
961
|
+
(lookup.query.userId.values as Array<ObjectID>).map((id: ObjectID) => {
|
|
962
|
+
return id.toString();
|
|
963
|
+
}),
|
|
964
|
+
).toEqual([ALICE_ID]);
|
|
965
|
+
expect(lookup.select).toEqual({ _id: true });
|
|
966
|
+
});
|
|
967
|
+
|
|
968
|
+
test("skips a junction row that came back without an id", async () => {
|
|
969
|
+
mockLists({
|
|
970
|
+
teamMembers: [makeTeamMember({ userId: ALICE_ID, name: "Alice" })],
|
|
971
|
+
teams: [],
|
|
972
|
+
ownerUsers: [
|
|
973
|
+
makeOwnerUserRow({ userId: ALICE_ID }),
|
|
974
|
+
makeOwnerUserRow({ id: OWNER_ROW_ID, userId: ALICE_ID }),
|
|
975
|
+
],
|
|
976
|
+
});
|
|
977
|
+
|
|
978
|
+
render(<Harness items={[makeSlo(SLO_ONE_ID)]} />);
|
|
979
|
+
await waitForOwnerSources();
|
|
980
|
+
await openOwnerModal("Remove Owner");
|
|
981
|
+
await selectOwner("Alice");
|
|
982
|
+
submitOwnerModal();
|
|
983
|
+
|
|
984
|
+
await waitFor(
|
|
985
|
+
() => {
|
|
986
|
+
expect(onBulkActionEnd).toHaveBeenCalledTimes(1);
|
|
987
|
+
},
|
|
988
|
+
{ timeout: WAIT_TIMEOUT },
|
|
989
|
+
);
|
|
990
|
+
|
|
991
|
+
/*
|
|
992
|
+
* A select that drops _id would otherwise send DELETE with an undefined
|
|
993
|
+
* id, which the API resolves to "delete by query".
|
|
994
|
+
*/
|
|
995
|
+
expect(deleteItemMock).toHaveBeenCalledTimes(1);
|
|
996
|
+
expect((deleteItemMock.mock.calls[0] as Array<any>)[0].id.toString()).toBe(
|
|
997
|
+
OWNER_ROW_ID,
|
|
998
|
+
);
|
|
999
|
+
});
|
|
1000
|
+
|
|
1001
|
+
test("counts an item that has none of the removed owners as a success", async () => {
|
|
1002
|
+
mockLists({
|
|
1003
|
+
teamMembers: [makeTeamMember({ userId: ALICE_ID, name: "Alice" })],
|
|
1004
|
+
teams: [],
|
|
1005
|
+
ownerUsers: [],
|
|
1006
|
+
});
|
|
1007
|
+
|
|
1008
|
+
render(<Harness items={[makeSlo(SLO_ONE_ID)]} />);
|
|
1009
|
+
await waitForOwnerSources();
|
|
1010
|
+
await openOwnerModal("Remove Owner");
|
|
1011
|
+
await selectOwner("Alice");
|
|
1012
|
+
submitOwnerModal();
|
|
1013
|
+
|
|
1014
|
+
await waitFor(
|
|
1015
|
+
() => {
|
|
1016
|
+
expect(onBulkActionEnd).toHaveBeenCalledTimes(1);
|
|
1017
|
+
},
|
|
1018
|
+
{ timeout: WAIT_TIMEOUT },
|
|
1019
|
+
);
|
|
1020
|
+
|
|
1021
|
+
expect(deleteItemMock).not.toHaveBeenCalled();
|
|
1022
|
+
expect(progressSnapshots).toHaveLength(1);
|
|
1023
|
+
expect(progressSnapshots[0]!.successItems).toEqual([SLO_ONE_ID]);
|
|
1024
|
+
expect(progressSnapshots[0]!.failed).toEqual([]);
|
|
1025
|
+
});
|
|
1026
|
+
|
|
1027
|
+
test("keeps going after one item fails and reports why", async () => {
|
|
1028
|
+
mockLists({
|
|
1029
|
+
teamMembers: [makeTeamMember({ userId: ALICE_ID, name: "Alice" })],
|
|
1030
|
+
teams: [],
|
|
1031
|
+
});
|
|
1032
|
+
|
|
1033
|
+
createMock.mockImplementation(async (data: any): Promise<any> => {
|
|
1034
|
+
if (data.model.serviceLevelObjectiveId.toString() === SLO_ONE_ID) {
|
|
1035
|
+
throw new BadDataException("Owner could not be added");
|
|
1036
|
+
}
|
|
1037
|
+
|
|
1038
|
+
return {};
|
|
1039
|
+
});
|
|
1040
|
+
|
|
1041
|
+
render(<Harness items={[makeSlo(SLO_ONE_ID), makeSlo(SLO_TWO_ID)]} />);
|
|
1042
|
+
await waitForOwnerSources();
|
|
1043
|
+
await openOwnerModal("Add Owner");
|
|
1044
|
+
await selectOwner("Alice");
|
|
1045
|
+
submitOwnerModal();
|
|
1046
|
+
|
|
1047
|
+
await waitFor(
|
|
1048
|
+
() => {
|
|
1049
|
+
expect(onBulkActionEnd).toHaveBeenCalledTimes(1);
|
|
1050
|
+
},
|
|
1051
|
+
{ timeout: WAIT_TIMEOUT },
|
|
1052
|
+
);
|
|
1053
|
+
|
|
1054
|
+
const finalSnapshot: ProgressSnapshot = progressSnapshots[1]!;
|
|
1055
|
+
expect(finalSnapshot.successItems).toEqual([SLO_TWO_ID]);
|
|
1056
|
+
expect(finalSnapshot.failed).toEqual([
|
|
1057
|
+
{ id: SLO_ONE_ID, failedMessage: "Owner could not be added" },
|
|
1058
|
+
]);
|
|
1059
|
+
});
|
|
1060
|
+
|
|
1061
|
+
test("fails an item with no id without calling the API for it", async () => {
|
|
1062
|
+
mockLists({
|
|
1063
|
+
teamMembers: [makeTeamMember({ userId: ALICE_ID, name: "Alice" })],
|
|
1064
|
+
teams: [],
|
|
1065
|
+
});
|
|
1066
|
+
|
|
1067
|
+
render(<Harness items={[makeSlo(), makeSlo(SLO_ONE_ID)]} />);
|
|
1068
|
+
await waitForOwnerSources();
|
|
1069
|
+
await openOwnerModal("Add Owner");
|
|
1070
|
+
await selectOwner("Alice");
|
|
1071
|
+
submitOwnerModal();
|
|
1072
|
+
|
|
1073
|
+
await waitFor(
|
|
1074
|
+
() => {
|
|
1075
|
+
expect(onBulkActionEnd).toHaveBeenCalledTimes(1);
|
|
1076
|
+
},
|
|
1077
|
+
{ timeout: WAIT_TIMEOUT },
|
|
1078
|
+
);
|
|
1079
|
+
|
|
1080
|
+
const finalSnapshot: ProgressSnapshot = progressSnapshots[1]!;
|
|
1081
|
+
expect(finalSnapshot.failed).toEqual([
|
|
1082
|
+
{ id: "no-id", failedMessage: "Item ID not found" },
|
|
1083
|
+
]);
|
|
1084
|
+
expect(finalSnapshot.successItems).toEqual([SLO_ONE_ID]);
|
|
1085
|
+
|
|
1086
|
+
/*
|
|
1087
|
+
* An id-less item must not reach the junction query: with the resource
|
|
1088
|
+
* id missing the filter collapses to the whole project.
|
|
1089
|
+
*/
|
|
1090
|
+
expect(getListCallsFor(ServiceLevelObjectiveOwnerUser)).toHaveLength(1);
|
|
1091
|
+
expect(createMock).toHaveBeenCalledTimes(1);
|
|
1092
|
+
});
|
|
1093
|
+
|
|
1094
|
+
test("fails every item when the project is gone by the time the form is submitted", async () => {
|
|
1095
|
+
mockLists({
|
|
1096
|
+
teamMembers: [makeTeamMember({ userId: ALICE_ID, name: "Alice" })],
|
|
1097
|
+
teams: [],
|
|
1098
|
+
});
|
|
1099
|
+
|
|
1100
|
+
render(<Harness items={[makeSlo(SLO_ONE_ID)]} />);
|
|
1101
|
+
await waitForOwnerSources();
|
|
1102
|
+
await openOwnerModal("Add Owner");
|
|
1103
|
+
await selectOwner("Alice");
|
|
1104
|
+
|
|
1105
|
+
window.history.replaceState({}, "", "/dashboard");
|
|
1106
|
+
|
|
1107
|
+
submitOwnerModal();
|
|
1108
|
+
|
|
1109
|
+
await waitFor(
|
|
1110
|
+
() => {
|
|
1111
|
+
expect(onBulkActionEnd).toHaveBeenCalledTimes(1);
|
|
1112
|
+
},
|
|
1113
|
+
{ timeout: WAIT_TIMEOUT },
|
|
1114
|
+
);
|
|
1115
|
+
|
|
1116
|
+
expect(progressSnapshots[0]!.failed).toEqual([
|
|
1117
|
+
{ id: SLO_ONE_ID, failedMessage: "Project not found" },
|
|
1118
|
+
]);
|
|
1119
|
+
expect(createMock).not.toHaveBeenCalled();
|
|
1120
|
+
});
|
|
1121
|
+
|
|
1122
|
+
test("brackets the run with onBulkActionStart and onBulkActionEnd", async () => {
|
|
1123
|
+
mockLists({
|
|
1124
|
+
teamMembers: [makeTeamMember({ userId: ALICE_ID, name: "Alice" })],
|
|
1125
|
+
teams: [],
|
|
1126
|
+
});
|
|
1127
|
+
|
|
1128
|
+
render(<Harness items={[makeSlo(SLO_ONE_ID), makeSlo(SLO_TWO_ID)]} />);
|
|
1129
|
+
await waitForOwnerSources();
|
|
1130
|
+
await openOwnerModal("Add Owner");
|
|
1131
|
+
await selectOwner("Alice");
|
|
1132
|
+
submitOwnerModal();
|
|
1133
|
+
|
|
1134
|
+
await waitFor(
|
|
1135
|
+
() => {
|
|
1136
|
+
expect(onBulkActionEnd).toHaveBeenCalledTimes(1);
|
|
1137
|
+
},
|
|
1138
|
+
{ timeout: WAIT_TIMEOUT },
|
|
1139
|
+
);
|
|
1140
|
+
|
|
1141
|
+
expect(onBulkActionStart).toHaveBeenCalledTimes(1);
|
|
1142
|
+
expect(onProgressInfo).toHaveBeenCalledTimes(2);
|
|
1143
|
+
expect(onBulkActionStart.mock.invocationCallOrder[0]!).toBeLessThan(
|
|
1144
|
+
onProgressInfo.mock.invocationCallOrder[0]!,
|
|
1145
|
+
);
|
|
1146
|
+
expect(onBulkActionEnd.mock.invocationCallOrder[0]!).toBeGreaterThan(
|
|
1147
|
+
onProgressInfo.mock.invocationCallOrder[1]!,
|
|
1148
|
+
);
|
|
1149
|
+
});
|
|
1150
|
+
|
|
1151
|
+
test("moves each item from in-progress to success as it is processed", async () => {
|
|
1152
|
+
mockLists({
|
|
1153
|
+
teamMembers: [makeTeamMember({ userId: ALICE_ID, name: "Alice" })],
|
|
1154
|
+
teams: [],
|
|
1155
|
+
});
|
|
1156
|
+
|
|
1157
|
+
render(<Harness items={[makeSlo(SLO_ONE_ID), makeSlo(SLO_TWO_ID)]} />);
|
|
1158
|
+
await waitForOwnerSources();
|
|
1159
|
+
await openOwnerModal("Add Owner");
|
|
1160
|
+
await selectOwner("Alice");
|
|
1161
|
+
submitOwnerModal();
|
|
1162
|
+
|
|
1163
|
+
await waitFor(
|
|
1164
|
+
() => {
|
|
1165
|
+
expect(onBulkActionEnd).toHaveBeenCalledTimes(1);
|
|
1166
|
+
},
|
|
1167
|
+
{ timeout: WAIT_TIMEOUT },
|
|
1168
|
+
);
|
|
1169
|
+
|
|
1170
|
+
/*
|
|
1171
|
+
* The item being worked on is spliced out of inProgressItems before its
|
|
1172
|
+
* own callback fires, so the progress bar never double-counts it.
|
|
1173
|
+
*/
|
|
1174
|
+
expect(progressSnapshots).toEqual([
|
|
1175
|
+
{
|
|
1176
|
+
totalItems: [SLO_ONE_ID, SLO_TWO_ID],
|
|
1177
|
+
inProgressItems: [SLO_TWO_ID],
|
|
1178
|
+
successItems: [SLO_ONE_ID],
|
|
1179
|
+
failed: [],
|
|
1180
|
+
},
|
|
1181
|
+
{
|
|
1182
|
+
totalItems: [SLO_ONE_ID, SLO_TWO_ID],
|
|
1183
|
+
inProgressItems: [],
|
|
1184
|
+
successItems: [SLO_ONE_ID, SLO_TWO_ID],
|
|
1185
|
+
failed: [],
|
|
1186
|
+
},
|
|
1187
|
+
]);
|
|
1188
|
+
});
|
|
1189
|
+
|
|
1190
|
+
test("opening Add Owner closes an open Remove Owner modal", async () => {
|
|
1191
|
+
mockLists({
|
|
1192
|
+
teamMembers: [makeTeamMember({ userId: ALICE_ID, name: "Alice" })],
|
|
1193
|
+
teams: [],
|
|
1194
|
+
});
|
|
1195
|
+
|
|
1196
|
+
render(<Harness items={[makeSlo(SLO_ONE_ID)]} />);
|
|
1197
|
+
await waitForOwnerSources();
|
|
1198
|
+
await openOwnerModal("Remove Owner");
|
|
1199
|
+
clickOwnerAction("Add Owner");
|
|
1200
|
+
|
|
1201
|
+
const openTitles: Array<HTMLElement> = screen.getAllByTestId("modal-title");
|
|
1202
|
+
|
|
1203
|
+
/*
|
|
1204
|
+
* Both dialogs share one bulkActionProps, and the first submit nulls it -
|
|
1205
|
+
* so a second one left stacked behind would swallow its own submit.
|
|
1206
|
+
*/
|
|
1207
|
+
expect(openTitles).toHaveLength(1);
|
|
1208
|
+
expect(openTitles[0]!).toHaveTextContent("Add Owner");
|
|
1209
|
+
});
|
|
1210
|
+
|
|
1211
|
+
test("opening Remove Owner closes an open Add Owner modal", async () => {
|
|
1212
|
+
mockLists({
|
|
1213
|
+
teamMembers: [makeTeamMember({ userId: ALICE_ID, name: "Alice" })],
|
|
1214
|
+
teams: [],
|
|
1215
|
+
});
|
|
1216
|
+
|
|
1217
|
+
render(<Harness items={[makeSlo(SLO_ONE_ID)]} />);
|
|
1218
|
+
await waitForOwnerSources();
|
|
1219
|
+
await openOwnerModal("Add Owner");
|
|
1220
|
+
clickOwnerAction("Remove Owner");
|
|
1221
|
+
|
|
1222
|
+
const openTitles: Array<HTMLElement> = screen.getAllByTestId("modal-title");
|
|
1223
|
+
|
|
1224
|
+
expect(openTitles).toHaveLength(1);
|
|
1225
|
+
expect(openTitles[0]!).toHaveTextContent("Remove Owner");
|
|
1226
|
+
});
|
|
1227
|
+
|
|
1228
|
+
test("blocks a submit with nothing selected", async () => {
|
|
1229
|
+
mockLists({
|
|
1230
|
+
teamMembers: [makeTeamMember({ userId: ALICE_ID, name: "Alice" })],
|
|
1231
|
+
teams: [makeTeam(TEAM_ONE_ID, "Team One")],
|
|
1232
|
+
});
|
|
1233
|
+
|
|
1234
|
+
render(<Harness items={[makeSlo(SLO_ONE_ID)]} />);
|
|
1235
|
+
await waitForOwnerSources();
|
|
1236
|
+
await openOwnerModal("Add Owner");
|
|
1237
|
+
submitOwnerModal();
|
|
1238
|
+
|
|
1239
|
+
expect(
|
|
1240
|
+
await screen.findByText(
|
|
1241
|
+
"Select Owners is required.",
|
|
1242
|
+
{},
|
|
1243
|
+
{ timeout: WAIT_TIMEOUT },
|
|
1244
|
+
),
|
|
1245
|
+
).toBeInTheDocument();
|
|
1246
|
+
|
|
1247
|
+
/*
|
|
1248
|
+
* Without the required rule an empty submit still walks every selected
|
|
1249
|
+
* item, reporting a batch of successes that changed nothing.
|
|
1250
|
+
*/
|
|
1251
|
+
expect(createMock).not.toHaveBeenCalled();
|
|
1252
|
+
expect(onBulkActionStart).not.toHaveBeenCalled();
|
|
1253
|
+
expect(getListMock).toHaveBeenCalledTimes(2);
|
|
1254
|
+
});
|
|
1255
|
+
});
|