@oneuptime/common 13.0.0 → 13.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/DatabaseModels/Alert.ts +55 -0
- package/Models/DatabaseModels/CloudResource.ts +45 -7
- package/Models/DatabaseModels/CodeRepository.ts +85 -0
- package/Models/DatabaseModels/GoogleSecOpsConnection.ts +57 -7
- package/Models/DatabaseModels/GoogleSecOpsConnectionRun.ts +263 -0
- package/Models/DatabaseModels/Incident.ts +55 -0
- package/Models/DatabaseModels/Index.ts +16 -0
- package/Models/DatabaseModels/ScheduledMaintenance.ts +55 -0
- package/Models/DatabaseModels/User.ts +51 -2
- package/Models/DatabaseModels/UserNotificationEmailRollupItem.ts +43 -2
- package/Models/DatabaseModels/UserWebAuthn.ts +17 -0
- package/Models/DatabaseModels/VMwareResource.ts +1149 -0
- package/Models/DatabaseModels/VMwareVCenter.ts +1122 -0
- package/Models/DatabaseModels/VMwareVCenterFeed.ts +625 -0
- package/Models/DatabaseModels/VMwareVCenterLabelRule.ts +514 -0
- package/Models/DatabaseModels/VMwareVCenterOwnerRule.ts +596 -0
- package/Models/DatabaseModels/VMwareVCenterOwnerTeam.ts +485 -0
- package/Models/DatabaseModels/VMwareVCenterOwnerUser.ts +484 -0
- package/Models/DatabaseModels/WorkflowVariable.ts +22 -1
- package/Server/API/AIAgentDataAPI.ts +79 -4
- package/Server/API/AIAgentGitHubAPI.ts +523 -0
- package/Server/API/AIChatAPI.ts +20 -1
- package/Server/API/BillingAPI.ts +33 -0
- package/Server/API/DashboardAPI.ts +10 -0
- package/Server/API/GitHubAPI.ts +47 -5
- package/Server/API/GoogleSecOpsConnectionAPI.ts +79 -0
- package/Server/API/UserWebAuthnAPI.ts +21 -1
- package/Server/API/VMwareResourceAPI.ts +143 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1791800000000-SplitWebAuthnChallengeByPurpose.ts +68 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1791900000000-AddSeverityAndStateToNotificationEmailRollup.ts +26 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1792000000000-AddVMwareTables.ts +636 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1792100000000-AddGitHubCommandSettingsToCodeRepository.ts +47 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1792200000000-AddUserWebAuthnPurpose.ts +17 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1792300000000-AddGoogleSecOpsDiagnostics.ts +83 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +12 -0
- package/Server/Middleware/IdentityRateLimit.ts +101 -0
- package/Server/Services/AIRunService.ts +13 -0
- package/Server/Services/BillingPaymentMethodService.ts +99 -28
- package/Server/Services/BillingService.ts +287 -20
- package/Server/Services/CloudResourceInstanceService.ts +70 -0
- package/Server/Services/ExceptionAggregationService.ts +1 -0
- package/Server/Services/GoogleSecOpsConnectionRunService.ts +10 -0
- package/Server/Services/GoogleSecOpsConnectionService.ts +12 -0
- package/Server/Services/Index.ts +16 -0
- package/Server/Services/LogAggregationService.ts +1 -0
- package/Server/Services/MetricAggregationService.ts +1 -0
- package/Server/Services/MobilePasskeyLoginService.ts +216 -0
- package/Server/Services/MonitorService.ts +51 -1
- package/Server/Services/MonitorTemplateService.ts +91 -29
- package/Server/Services/NetworkDeviceAutoImportRuleEngineService.ts +132 -1
- package/Server/Services/NetworkDeviceAutoImportRuleService.ts +176 -2
- package/Server/Services/OpenTelemetryIngestService.ts +17 -0
- package/Server/Services/PayAsYouGoBillingService.ts +446 -0
- package/Server/Services/ProjectService.ts +46 -2
- package/Server/Services/ServerlessFunctionInstanceService.ts +71 -0
- package/Server/Services/TeamMemberService.ts +96 -36
- package/Server/Services/TelemetryIngestionKeyService.ts +80 -10
- package/Server/Services/TelemetryUsageBillingService.ts +95 -5
- package/Server/Services/TraceAggregationService.ts +5 -4
- package/Server/Services/UserWebAuthnService.ts +592 -133
- package/Server/Services/VMwareResourceService.ts +648 -0
- package/Server/Services/VMwareVCenterFeedService.ts +99 -0
- package/Server/Services/VMwareVCenterLabelRuleEngineService.ts +240 -0
- package/Server/Services/VMwareVCenterLabelRuleService.ts +14 -0
- package/Server/Services/VMwareVCenterOwnerRuleEngineService.ts +252 -0
- package/Server/Services/VMwareVCenterOwnerRuleService.ts +14 -0
- package/Server/Services/VMwareVCenterOwnerTeamService.ts +139 -0
- package/Server/Services/VMwareVCenterOwnerUserService.ts +133 -0
- package/Server/Services/VMwareVCenterService.ts +629 -0
- package/Server/Services/WorkflowVariableService.ts +203 -0
- package/Server/Types/Billing/MeteredPlan/ActiveMonitoringMeteredPlan.ts +17 -0
- package/Server/Types/Billing/MeteredPlan/TelemetryMeteredPlan.ts +31 -1
- package/Server/Utils/CodeRepository/GitHub/GitHub.ts +7 -0
- package/Server/Utils/CodeRepository/GitHub/GitHubAgentTaskTrigger.ts +341 -0
- package/Server/Utils/CodeRepository/GitHub/GitHubCommandAuthorizer.ts +274 -0
- package/Server/Utils/CodeRepository/GitHub/GitHubCommandParser.ts +375 -0
- package/Server/Utils/CodeRepository/GitHub/GitHubConversation.ts +846 -0
- package/Server/Utils/CodeRepository/GitHub/GitHubReplyComposer.ts +360 -0
- package/Server/Utils/CodeRepository/GitHub/GitHubRunReply.ts +421 -0
- package/Server/Utils/CodeRepository/GitHub/GitHubWebhookEvents.ts +140 -0
- package/Server/Utils/CodeRepository/GitHub/GitHubWebhookHandler.ts +906 -0
- package/Server/Utils/Dashboard/PublicDashboardResourceListPolicy.ts +143 -0
- package/Server/Utils/DataSource/EgressGuard.ts +160 -15
- package/Server/Utils/Database/TruncateColumnValue.ts +1 -1
- package/Server/Utils/EmailRollup/EmailRollupFlushRunner.ts +2 -0
- package/Server/Utils/EmailRollup/EmailRollupRenderer.ts +33 -0
- package/Server/Utils/EmailRollup/EmailRollupWriter.ts +44 -0
- package/Server/Utils/LogRedaction.ts +2 -1
- package/Server/Utils/Monitor/MonitorAlert.ts +1 -1
- package/Server/Utils/Monitor/MonitorCriteriaEvaluator.ts +302 -3
- package/Server/Utils/Monitor/MonitorMaintenanceSuppression.ts +26 -4
- package/Server/Utils/Monitor/MonitorResourceContext.ts +5 -3
- package/Server/Utils/Monitor/MonitorStepResourceIdentity.ts +14 -0
- package/Server/Utils/Monitor/MonitorTemplateUtil.ts +1 -0
- package/Server/Utils/Monitor/SeriesResourceLabels.ts +26 -0
- package/Server/Utils/Monitor/SeriesResourceLinker.ts +28 -5
- package/Server/Utils/ResourceFeed/ResourceFeedUtil.ts +3 -3
- package/Server/Utils/SecurityEvent/ConnectorErrorMessage.ts +14 -9
- package/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsClient.ts +116 -84
- package/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsPoller.ts +594 -195
- package/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsRunExecutor.ts +466 -0
- package/Server/Utils/Telemetry/EntityRegistry.ts +5 -0
- package/Server/Utils/Telemetry/ResourceHeartbeat.ts +2 -1
- package/Server/Utils/Telemetry/TelemetryEntity.ts +181 -1
- package/Server/Utils/Telemetry/VMwareSnapshotScan.ts +1352 -0
- package/Tests/App/Accounts/LoginPasskey.test.tsx +529 -0
- package/Tests/App/Accounts/MobilePasskey.test.tsx +620 -0
- package/Tests/App/Accounts/PasswordRequirements.test.tsx +254 -0
- package/Tests/App/Accounts/RegisterPassword.test.tsx +553 -0
- package/Tests/App/Dashboard/AskAiAvailability.test.ts +224 -0
- package/Tests/App/Dashboard/AskAiDisabled.test.tsx +432 -0
- package/Tests/App/Dashboard/BackupCodes.test.tsx +414 -0
- package/Tests/App/Dashboard/BillingPaidUsageFlow.test.tsx +530 -0
- package/Tests/App/Dashboard/BillingPaymentMethodForm.test.tsx +195 -0
- package/Tests/App/Dashboard/BreadcrumbCoverage.test.tsx +199 -0
- package/Tests/App/Dashboard/CloudDocumentationCard.test.tsx +198 -0
- package/Tests/App/Dashboard/CloudDocumentationMarkdown.test.ts +215 -0
- package/Tests/App/Dashboard/CloudFleetSummary.test.ts +183 -0
- package/Tests/App/Dashboard/CloudFleetSummaryComponent.test.tsx +248 -0
- package/Tests/App/Dashboard/CloudResourceTelemetryScope.test.ts +215 -0
- package/Tests/App/Dashboard/CriteriaFilterDefaults.test.ts +3 -0
- package/Tests/App/Dashboard/DashboardHeaderRequests.test.tsx +441 -0
- package/Tests/App/Dashboard/DashboardLazyPages.test.tsx +458 -0
- package/Tests/App/Dashboard/DashboardToolbarPopupLayering.test.tsx +566 -0
- package/Tests/App/Dashboard/DiscoveryScanLivePage.test.tsx +376 -0
- package/Tests/App/Dashboard/DiscoveryScanLiveUpdates.test.tsx +642 -0
- package/Tests/App/Dashboard/DiscoveryScanProgress.test.tsx +267 -0
- package/Tests/App/Dashboard/DiscoveryScanWizardValidation.test.tsx +69 -231
- package/Tests/App/Dashboard/GoogleSecOpsConnectionsErrors.test.tsx +244 -0
- package/Tests/App/Dashboard/GoogleSecOpsDiagnostics.test.tsx +724 -0
- package/Tests/App/Dashboard/MonitorTemplateSyncFields.test.tsx +539 -0
- package/Tests/App/Dashboard/OnCallLayerCardOverrides.test.tsx +24 -7
- package/Tests/App/Dashboard/OnCallOverridePresentation.test.ts +496 -0
- package/Tests/App/Dashboard/OnCallScheduleOverrideClarity.test.tsx +677 -0
- package/Tests/App/Dashboard/OnCallSchedulePreviewOverrides.test.tsx +31 -3
- package/Tests/App/Dashboard/PaidUsageConsent.test.tsx +180 -0
- package/Tests/App/Dashboard/PasskeySettings.test.tsx +1220 -0
- package/Tests/App/Dashboard/PayAsYouGoConsentGate.test.tsx +176 -275
- package/Tests/App/Dashboard/PayAsYouGoNotices.test.tsx +380 -233
- package/Tests/App/Dashboard/ProductMenuBreadcrumbs.test.tsx +3 -23
- package/Tests/App/Dashboard/ResourceFeed.test.tsx +1 -0
- package/Tests/App/Dashboard/ResourceFeedPageWiring.test.ts +8 -1
- package/Tests/App/Dashboard/TwoFactorStatus.test.tsx +260 -0
- package/Tests/App/Dashboard/VMwareDashboardWidgets.test.ts +573 -0
- package/Tests/App/Dashboard/WidgetCatalog.test.ts +2 -0
- package/Tests/App/Dashboard/WorkflowVariablesTable.test.tsx +768 -0
- package/Tests/App/StatusPage/StatusPageOverviewLiveAndSearch.test.tsx +532 -40
- package/Tests/App/StatusPage/StatusPageResourceSearchBox.test.tsx +19 -2
- package/Tests/Fixtures/MobilePasskeyUser.json +8 -0
- package/Tests/Models/DatabaseModels/ResourceFeedModels.test.ts +25 -6
- package/Tests/Models/DatabaseModels/VMwareModels.test.ts +1134 -0
- package/Tests/Models/RunnerVersionLabel.test.ts +4 -2
- package/Tests/Server/API/AIChatProvidersAIEnabled.test.ts +259 -0
- package/Tests/Server/API/AIChatRouteAuthorization.test.ts +31 -2
- package/Tests/Server/API/BillingPayAsYouGoStatus.test.ts +116 -0
- package/Tests/Server/API/DashboardPublicResourceListAPI.test.ts +29 -1
- package/Tests/Server/API/EnterpriseLicenseReportUserCount.test.ts +13 -2
- package/Tests/Server/API/GitHubWebhookSignature.test.ts +368 -0
- package/Tests/Server/API/GoogleSecOpsConnectionAPI.test.ts +248 -0
- package/Tests/Server/API/UserWebAuthnAuthenticationOptionsRoute.test.ts +330 -0
- package/Tests/Server/API/UserWebAuthnPasskeyAPI.test.ts +172 -0
- package/Tests/Server/API/VMwareResourceAPI.test.ts +546 -0
- package/Tests/Server/Infrastructure/Postgres/UserNotificationEmailRollupMetadataMigration.test.ts +85 -0
- package/Tests/Server/Infrastructure/Postgres/UserNotificationEmailRollupTableMigration.test.ts +34 -3
- package/Tests/Server/Middleware/PasskeyRateLimit.test.ts +141 -0
- package/Tests/Server/Services/AutoImportRuleRearmRecentScans.test.ts +343 -0
- package/Tests/Server/Services/AutoImportRuleWriteRearmsScans.test.ts +381 -0
- package/Tests/Server/Services/BillingPaymentMethodServiceSync.test.ts +175 -0
- package/Tests/Server/Services/BillingService.test.ts +26 -11
- package/Tests/Server/Services/BillingServiceMeteredPaymentAuthorization.test.ts +245 -0
- package/Tests/Server/Services/BillingServicePaymentMethodReads.test.ts +362 -0
- package/Tests/Server/Services/CloudResourceInstanceStalePrune.test.ts +188 -0
- package/Tests/Server/Services/DiscoveryScanClaimHookFreeSafety.test.ts +16 -2
- package/Tests/Server/Services/GoogleSecOpsDiagnosticsModel.test.ts +153 -0
- package/Tests/Server/Services/HookFreeWriteLengthClamp.test.ts +13 -0
- package/Tests/Server/Services/InventoryItemPromotionGate.test.ts +5 -0
- package/Tests/Server/Services/InventoryUpsertSchemaParity.test.ts +36 -0
- package/Tests/Server/Services/InventoryUpsertTruncationGuard.test.ts +151 -0
- package/Tests/Server/Services/MobilePasskeyLoginIntegration.test.ts +231 -0
- package/Tests/Server/Services/MobilePasskeyLoginService.test.ts +315 -0
- package/Tests/Server/Services/MonitorPayAsYouGoBilling.test.ts +302 -0
- package/Tests/Server/Services/MonitorTemplateServiceFieldSync.test.ts +994 -0
- package/Tests/Server/Services/NetworkDeviceAutoImportRuleService.test.ts +22 -0
- package/Tests/Server/Services/OpenTelemetryResourceRetentionMemo.test.ts +7 -1
- package/Tests/Server/Services/PayAsYouGoBillingService.test.ts +857 -0
- package/Tests/Server/Services/PayAsYouGoStripeRateLimitBudget.test.ts +379 -0
- package/Tests/Server/Services/ProjectServiceExtendTrial.test.ts +99 -1
- package/Tests/Server/Services/ProjectServiceSubscriptionSeats.test.ts +134 -0
- package/Tests/Server/Services/ResourceFeedServices.test.ts +3 -2
- package/Tests/Server/Services/ResourceUpdateLastSeenLivenessFallback.test.ts +32 -6
- package/Tests/Server/Services/SecurityEventLastErrorColumnWidth.test.ts +363 -175
- package/Tests/Server/Services/ServerlessFunctionInstanceStalePrune.test.ts +200 -0
- package/Tests/Server/Services/TeamMemberAutoAcceptInvitation.test.ts +3 -0
- package/Tests/Server/Services/TeamMemberBillingSeatSync.test.ts +762 -0
- package/Tests/Server/Services/TeamMemberInviteRegistrationToken.test.ts +3 -0
- package/Tests/Server/Services/TelemetryIngestionKeyPolicyResolution.test.ts +72 -0
- package/Tests/Server/Services/TelemetryIngestionKeyValidation.test.ts +17 -4
- package/Tests/Server/Services/TelemetryPayAsYouGoBilling.test.ts +355 -0
- package/Tests/Server/Services/TraceAnalyticsResourceDisplayNames.test.ts +41 -4
- package/Tests/Server/Services/UserNotificationEmailRollupModels.test.ts +37 -0
- package/Tests/Server/Services/UserWebAuthnPasskeyIntegration.test.ts +401 -0
- package/Tests/Server/Services/UserWebAuthnPasskeyService.test.ts +769 -0
- package/Tests/Server/Services/UserWebAuthnUserVerification.test.ts +649 -0
- package/Tests/Server/Services/VMwareResourceService.test.ts +945 -0
- package/Tests/Server/Services/VMwareVCenterService.test.ts +722 -0
- package/Tests/Server/Services/WorkflowVariableRenameUniqueness.test.ts +842 -0
- package/Tests/Server/TestingUtils/PasskeyHttpIntegration.ts +102 -0
- package/Tests/Server/TestingUtils/SecurityKey.ts +464 -0
- package/Tests/Server/TestingUtils/WebAuthnServiceMocks.ts +60 -0
- package/Tests/Server/Types/Billing/PayAsYouGoMeteredAuthorization.test.ts +573 -0
- package/Tests/Server/Types/Database/Permissions/ProjectCustomerSupportAccessColumn.test.ts +261 -0
- package/Tests/Server/Types/Database/Permissions/WorkflowVariableColumnPermission.test.ts +95 -0
- package/Tests/Server/Utils/CodeRepository/GitHubAgentTaskTrigger.test.ts +2101 -0
- package/Tests/Server/Utils/CodeRepository/GitHubCommandAuthorizer.test.ts +883 -0
- package/Tests/Server/Utils/CodeRepository/GitHubCommandParser.test.ts +1474 -0
- package/Tests/Server/Utils/CodeRepository/GitHubConversation.test.ts +1526 -0
- package/Tests/Server/Utils/CodeRepository/GitHubReplyComposer.test.ts +1389 -0
- package/Tests/Server/Utils/CodeRepository/GitHubRunReply.test.ts +1707 -0
- package/Tests/Server/Utils/CodeRepository/GitHubWebhookHandler.test.ts +2202 -0
- package/Tests/Server/Utils/Dashboard/PublicDashboardResourceListPolicy.test.ts +345 -0
- package/Tests/Server/Utils/DataSource/EgressGuard.test.ts +896 -0
- package/Tests/Server/Utils/EmailRollup/EmailRollupMetadataIntegration.test.ts +246 -0
- package/Tests/Server/Utils/EmailRollup/EmailRollupRenderer.test.ts +299 -1
- package/Tests/Server/Utils/EmailRollup/EmailRollupTestHarness.ts +6 -0
- package/Tests/Server/Utils/EmailRollup/EmailRollupWriter.test.ts +185 -0
- package/Tests/Server/Utils/LogRedaction.test.ts +33 -0
- package/Tests/Server/Utils/Monitor/CapturedMetricAttributeUtil.test.ts +2 -1
- package/Tests/Server/Utils/Monitor/Criteria/TelemetryStepMetricAlias.test.ts +10 -0
- package/Tests/Server/Utils/Monitor/MonitorAlertResourceLinking.test.ts +66 -1
- package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluator.test.ts +362 -0
- package/Tests/Server/Utils/Monitor/MonitorDependencySuppressionCreatorSkip.test.ts +1 -0
- package/Tests/Server/Utils/Monitor/MonitorIncidentResourceLinking.test.ts +60 -1
- package/Tests/Server/Utils/Monitor/MonitorMaintenanceSuppression.test.ts +60 -0
- package/Tests/Server/Utils/Monitor/MonitorRootCauseTargetResolution.test.ts +423 -0
- package/Tests/Server/Utils/Monitor/MonitorStepResourceIdentity.test.ts +6 -0
- package/Tests/Server/Utils/Monitor/MonitorSummaryPersistence.test.ts +1 -0
- package/Tests/Server/Utils/Monitor/PerSeriesSecondEntityAlerting.test.ts +1 -0
- package/Tests/Server/Utils/Monitor/SeriesResourceLinker.test.ts +46 -2
- package/Tests/Server/Utils/SecurityEvent/ConnectorErrorMessage.test.ts +81 -45
- package/Tests/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsRunExecutor.test.ts +711 -0
- package/Tests/Server/Utils/SecurityEvent/GoogleSecOpsClickhouseIntegration.test.ts +223 -0
- package/Tests/Server/Utils/SecurityEvent/GoogleSecOpsClient.test.ts +69 -1
- package/Tests/Server/Utils/SecurityEvent/GoogleSecOpsDiagnostics.test.ts +838 -0
- package/Tests/Server/Utils/SecurityEvent/GoogleSecOpsErrorHandling.test.ts +241 -28
- package/Tests/Server/Utils/SecurityEvent/GoogleSecOpsHttpIntegration.test.ts +651 -0
- package/Tests/Server/Utils/SecurityEvent/GoogleSecOpsPoller.test.ts +11 -0
- package/Tests/Server/Utils/SecurityEvent/GoogleSecOpsPollerFailureTaxonomy.test.ts +13 -12
- package/Tests/Server/Utils/SecurityEvent/GoogleSecOpsPollerHardening.test.ts +112 -127
- package/Tests/Server/Utils/SecurityEvent/GoogleSecOpsRequestContract.test.ts +12 -18
- package/Tests/Server/Utils/SecurityEvent/GoogleSecOpsResponseParsing.test.ts +43 -0
- package/Tests/Server/Utils/Telemetry/TelemetryEntity.test.ts +580 -0
- package/Tests/Server/Utils/Telemetry/VMwareSnapshotScan.test.ts +1748 -0
- package/Tests/Types/Cloud/CloudPlatform.test.ts +574 -0
- package/Tests/Types/Monitor/MetricAndProfileDefaultCriteria.test.ts +2 -0
- package/Tests/Types/Monitor/MonitorCriteriaMetricVariables.test.ts +9 -0
- package/Tests/Types/Monitor/MonitorStepDefaultTelemetryConfig.test.ts +1 -0
- package/Tests/Types/Monitor/MonitorStepInfraMonitorUtils.test.ts +53 -8
- package/Tests/Types/Monitor/MonitorStepInfrastructureMonitors.test.ts +97 -0
- package/Tests/Types/Monitor/MonitorStepMetricViewConfigUtil.test.ts +1 -0
- package/Tests/Types/Monitor/MonitorStepTemplateSyncFields.test.ts +107 -0
- package/Tests/Types/Monitor/MonitorTemplateSyncField.test.ts +172 -0
- package/Tests/Types/Monitor/MonitorType.test.ts +1 -0
- package/Tests/Types/Monitor/MonitorTypeKeywords.test.ts +2 -0
- package/Tests/Types/Monitor/Recommendation/MonitorRecommendationAlertDebuggability.test.ts +1 -0
- package/Tests/Types/Monitor/Recommendation/MonitorRecommendationCatalog.test.ts +9 -0
- package/Tests/Types/Monitor/Recommendation/MonitorRecommendationCoverage.test.ts +1 -1
- package/Tests/Types/Monitor/Recommendation/MonitorRecommendationNotificationMode.test.ts +1 -1
- package/Tests/Types/Monitor/SeriesContext/SeriesDebugHints.test.ts +131 -0
- package/Tests/Types/Monitor/SeriesContext/SeriesLabelDisplay.test.ts +10 -0
- package/Tests/Types/Monitor/VMwareAlertTemplates.test.ts +1608 -0
- package/Tests/Types/Monitor/VMwareMetricCatalog.test.ts +488 -0
- package/Tests/Types/OnCallDutyPolicy/OverrideProvenance.test.ts +295 -0
- package/Tests/Types/Runner/RunnerLiveStatus.test.ts +2 -2
- package/Tests/Types/SignupPassword.test.ts +205 -0
- package/Tests/Types/StatusPage/StatusPageLanguage.test.ts +44 -0
- package/Tests/Types/SupportedLanguages.test.ts +119 -0
- package/Tests/Types/Telemetry/EntityTypeGroups.test.ts +19 -0
- package/Tests/UI/ColorPickerBuild.test.ts +86 -0
- package/Tests/UI/Components/Breadcrumbs.test.tsx +32 -0
- package/Tests/UI/Components/Forms/ModelFormPreservesUserInput.test.tsx +937 -0
- package/Tests/UI/Components/Forms/ModelFormWriteOnlyColumnSelect.test.tsx +230 -0
- package/Tests/UI/Components/Forms/ValidationFormSteps.test.ts +3 -4
- package/Tests/UI/Components/LabelRuleImportExport.test.tsx +907 -0
- package/Tests/UI/Components/ModelTable/ModelTableCreateAfterEdit.test.tsx +514 -0
- package/Tests/UI/Components/MonitorGraphs/Uptime.test.tsx +301 -0
- package/Tests/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.test.ts +2 -1
- package/Tests/UI/Components/TooltipLazyContent.test.tsx +373 -0
- package/Tests/UI/MicrosoftTeams/MicrosoftTeamsMessagingEndpointGuidance.test.tsx +43 -12
- package/Tests/UI/ReactDomBuild.test.ts +104 -0
- package/Tests/UI/ReactRouterSingletonBuild.test.ts +11 -1
- package/Tests/UI/Utils/Breadcrumb/fixtures/RealBreadcrumbTrails.ts +148 -0
- package/Tests/UI/Utils/Breadcrumb/fixtures/RealRoutePatterns.ts +29 -0
- package/Tests/UI/Utils/DashboardStackingLayers.test.ts +197 -0
- package/Tests/UI/Utils/LabelRuleImportExport.test.ts +546 -0
- package/Tests/UI/Utils/ModelAPITenantHeader.test.ts +109 -2
- package/Tests/UI/Utils/UseDashboardGridDnd.test.tsx +7 -2
- package/Tests/UI/Utils/UserEmailRegistrationStatus.test.tsx +295 -0
- package/Tests/UI/Utils/WebAuthn.test.ts +265 -0
- package/Tests/Utils/Dashboard/Components/DashboardComponentDefaults.test.ts +5 -0
- package/Tests/Utils/Dashboard/Components/DashboardVMwareListComponents.test.ts +548 -0
- package/Tests/Utils/Dashboard/DashboardResourceListSharedArgs.test.ts +17 -3
- package/Tests/Utils/LabelRuleImportExport.test.ts +583 -0
- package/Tests/Utils/Monitor/MonitorSummarySnapshotUtil.test.ts +1 -0
- package/Tests/Utils/Monitor/MonitorTemplateSyncUtil.test.ts +590 -0
- package/Tests/Utils/RequestFailedDetails.test.ts +325 -0
- package/Tests/Utils/Telemetry/CloudInstanceIdentity.test.ts +255 -0
- package/Tests/Utils/Telemetry/EntityRelationship.test.ts +167 -0
- package/Tests/Utils/WebAuthnTestUtil.ts +79 -0
- package/Tests/__mocks__/simplewebauthn.js +33 -4
- package/Types/AI/CodeFixTaskContext.ts +122 -0
- package/Types/AI/CodeFixTaskType.ts +62 -0
- package/Types/Accounts/AccountsLanguage.ts +1 -0
- package/Types/AdminDashboard/AdminDashboardLanguage.ts +1 -0
- package/Types/Calendar/CalendarEvent.ts +16 -0
- package/Types/Cloud/CloudPlatform.ts +372 -0
- package/Types/CodeRepository/GitHubCommand.ts +69 -0
- package/Types/Dashboard/DashboardComponentType.ts +2 -0
- package/Types/Dashboard/DashboardComponents/ComponentArgument.ts +1 -0
- package/Types/Dashboard/DashboardComponents/DashboardVMwareHostListComponent.ts +23 -0
- package/Types/Dashboard/DashboardComponents/DashboardVMwareVirtualMachineListComponent.ts +30 -0
- package/Types/Dashboard/DashboardLanguage.ts +1 -0
- package/Types/Dashboard/DashboardTemplates.ts +314 -0
- package/Types/Docs/DocsLanguage.ts +1 -0
- package/Types/Exception/EgressGuardException.ts +65 -0
- package/Types/Icon/IconProp.ts +1 -0
- package/Types/Monitor/MetricMonitor/MetricMonitorResponse.ts +36 -0
- package/Types/Monitor/MonitorCriteriaInstance.ts +1 -0
- package/Types/Monitor/MonitorStep.ts +78 -17
- package/Types/Monitor/MonitorStepMetricViewConfigUtil.ts +1 -0
- package/Types/Monitor/MonitorStepVMwareMonitor.ts +127 -0
- package/Types/Monitor/MonitorTemplateSyncField.ts +291 -0
- package/Types/Monitor/MonitorType.ts +24 -0
- package/Types/Monitor/Recommendation/MonitorRecommendationCatalog.ts +33 -0
- package/Types/Monitor/Recommendation/MonitorRecommendationTypes.ts +2 -0
- package/Types/Monitor/Recommendation/MonitorRecommendationUtil.ts +3 -0
- package/Types/Monitor/SeriesContext/SeriesDebugHints.ts +158 -0
- package/Types/Monitor/SeriesContext/SeriesLabelDisplay.ts +61 -0
- package/Types/Monitor/VMwareAlertTemplates.ts +1070 -0
- package/Types/Monitor/VMwareMetricCatalog.ts +914 -0
- package/Types/OnCallDutyPolicy/ScheduleShiftUtil.ts +29 -0
- package/Types/OnCallDutyPolicy/UserOverrideUtil.ts +16 -0
- package/Types/Password.ts +84 -5
- package/Types/Permission.ts +265 -0
- package/Types/Probe/RequestFailedDetails.ts +7 -0
- package/Types/Runner/RunnerLiveStatus.ts +1 -1
- package/Types/SecurityEvent/GoogleSecOpsDiagnostics.ts +56 -0
- package/Types/StatusPage/StatusPageLanguage.ts +1 -0
- package/Types/Telemetry/EntityType.ts +21 -0
- package/Types/Telemetry/ServiceType.ts +1 -0
- package/Typings/Index.d.ts +63 -0
- package/UI/Components/Breadcrumbs/Breadcrumbs.tsx +2 -2
- package/UI/Components/Calendar/Calendar.css +78 -0
- package/UI/Components/Calendar/Calendar.tsx +28 -3
- package/UI/Components/Forms/BasicForm.tsx +44 -2
- package/UI/Components/Forms/Fields/ColorPicker.tsx +2 -1
- package/UI/Components/Forms/Fields/FormField.tsx +16 -3
- package/UI/Components/Forms/ModelForm.tsx +159 -5
- package/UI/Components/Forms/Types/Field.ts +8 -1
- package/UI/Components/Graphs/DayUptimeGraph.tsx +8 -10
- package/UI/Components/Icon/Icon.tsx +16 -0
- package/UI/Components/Input/Input.tsx +42 -7
- package/UI/Components/LabelRule/ImportLabelRulesModal.tsx +441 -0
- package/UI/Components/LabelRule/LabelRuleTable.tsx +142 -0
- package/UI/Components/ModelTable/BaseModelTable.tsx +22 -5
- package/UI/Components/ModelTable/ModelTable.tsx +14 -6
- package/UI/Components/MonitorGraphs/Uptime.tsx +17 -27
- package/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.ts +3 -1
- package/UI/Components/Tooltip/Tooltip.tsx +52 -6
- package/UI/Utils/DashboardStackingLayers.ts +85 -0
- package/UI/Utils/LabelRuleImportExport.ts +310 -0
- package/UI/Utils/ModelAPI/ModelAPI.ts +4 -3
- package/UI/Utils/TelemetryService.ts +4 -3
- package/UI/Utils/UseDashboardGridDnd.ts +4 -1
- package/UI/Utils/UserEmailRegistrationStatus.ts +33 -5
- package/UI/Utils/WebAuthn.ts +220 -0
- package/UI/esbuild-config.js +4 -0
- package/Utils/API.ts +34 -0
- package/Utils/Dashboard/Components/DashboardVMwareHostListComponent.ts +38 -0
- package/Utils/Dashboard/Components/DashboardVMwareResourceListShared.ts +70 -0
- package/Utils/Dashboard/Components/DashboardVMwareVirtualMachineListComponent.ts +76 -0
- package/Utils/Dashboard/Components/Index.ts +16 -0
- package/Utils/LabelRuleImportExport.ts +496 -0
- package/Utils/Monitor/MonitorTemplateSyncUtil.ts +164 -0
- package/Utils/NetworkDiscovery/DiscoveryScanStatus.ts +8 -0
- package/Utils/Telemetry/CloudInstanceIdentity.ts +94 -0
- package/Utils/Telemetry/EntityKey.ts +19 -0
- package/Utils/Telemetry/EntityRelationship.ts +19 -0
- package/build/dist/Models/DatabaseModels/Alert.js +54 -0
- package/build/dist/Models/DatabaseModels/Alert.js.map +1 -1
- package/build/dist/Models/DatabaseModels/CloudResource.js +44 -7
- package/build/dist/Models/DatabaseModels/CloudResource.js.map +1 -1
- package/build/dist/Models/DatabaseModels/CodeRepository.js +87 -0
- package/build/dist/Models/DatabaseModels/CodeRepository.js.map +1 -1
- package/build/dist/Models/DatabaseModels/GoogleSecOpsConnection.js +60 -7
- package/build/dist/Models/DatabaseModels/GoogleSecOpsConnection.js.map +1 -1
- package/build/dist/Models/DatabaseModels/GoogleSecOpsConnectionRun.js +287 -0
- package/build/dist/Models/DatabaseModels/GoogleSecOpsConnectionRun.js.map +1 -0
- package/build/dist/Models/DatabaseModels/Incident.js +54 -0
- package/build/dist/Models/DatabaseModels/Incident.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Index.js +16 -0
- package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
- package/build/dist/Models/DatabaseModels/ScheduledMaintenance.js +54 -0
- package/build/dist/Models/DatabaseModels/ScheduledMaintenance.js.map +1 -1
- package/build/dist/Models/DatabaseModels/User.js +57 -4
- package/build/dist/Models/DatabaseModels/User.js.map +1 -1
- package/build/dist/Models/DatabaseModels/UserNotificationEmailRollupItem.js +47 -2
- package/build/dist/Models/DatabaseModels/UserNotificationEmailRollupItem.js.map +1 -1
- package/build/dist/Models/DatabaseModels/UserWebAuthn.js +18 -0
- package/build/dist/Models/DatabaseModels/UserWebAuthn.js.map +1 -1
- package/build/dist/Models/DatabaseModels/VMwareResource.js +1201 -0
- package/build/dist/Models/DatabaseModels/VMwareResource.js.map +1 -0
- package/build/dist/Models/DatabaseModels/VMwareVCenter.js +1149 -0
- package/build/dist/Models/DatabaseModels/VMwareVCenter.js.map +1 -0
- package/build/dist/Models/DatabaseModels/VMwareVCenterFeed.js +648 -0
- package/build/dist/Models/DatabaseModels/VMwareVCenterFeed.js.map +1 -0
- package/build/dist/Models/DatabaseModels/VMwareVCenterLabelRule.js +522 -0
- package/build/dist/Models/DatabaseModels/VMwareVCenterLabelRule.js.map +1 -0
- package/build/dist/Models/DatabaseModels/VMwareVCenterOwnerRule.js +603 -0
- package/build/dist/Models/DatabaseModels/VMwareVCenterOwnerRule.js.map +1 -0
- package/build/dist/Models/DatabaseModels/VMwareVCenterOwnerTeam.js +503 -0
- package/build/dist/Models/DatabaseModels/VMwareVCenterOwnerTeam.js.map +1 -0
- package/build/dist/Models/DatabaseModels/VMwareVCenterOwnerUser.js +502 -0
- package/build/dist/Models/DatabaseModels/VMwareVCenterOwnerUser.js.map +1 -0
- package/build/dist/Models/DatabaseModels/WorkflowVariable.js +22 -1
- package/build/dist/Models/DatabaseModels/WorkflowVariable.js.map +1 -1
- package/build/dist/Server/API/AIAgentDataAPI.js +63 -3
- package/build/dist/Server/API/AIAgentDataAPI.js.map +1 -1
- package/build/dist/Server/API/AIAgentGitHubAPI.js +363 -0
- package/build/dist/Server/API/AIAgentGitHubAPI.js.map +1 -0
- package/build/dist/Server/API/AIChatAPI.js +19 -1
- package/build/dist/Server/API/AIChatAPI.js.map +1 -1
- package/build/dist/Server/API/BillingAPI.js +22 -0
- package/build/dist/Server/API/BillingAPI.js.map +1 -1
- package/build/dist/Server/API/DashboardAPI.js +10 -0
- package/build/dist/Server/API/DashboardAPI.js.map +1 -1
- package/build/dist/Server/API/GitHubAPI.js +33 -5
- package/build/dist/Server/API/GitHubAPI.js.map +1 -1
- package/build/dist/Server/API/GoogleSecOpsConnectionAPI.js +56 -0
- package/build/dist/Server/API/GoogleSecOpsConnectionAPI.js.map +1 -0
- package/build/dist/Server/API/UserWebAuthnAPI.js +17 -1
- package/build/dist/Server/API/UserWebAuthnAPI.js.map +1 -1
- package/build/dist/Server/API/VMwareResourceAPI.js +106 -0
- package/build/dist/Server/API/VMwareResourceAPI.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791800000000-SplitWebAuthnChallengeByPurpose.js +41 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791800000000-SplitWebAuthnChallengeByPurpose.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791900000000-AddSeverityAndStateToNotificationEmailRollup.js +14 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791900000000-AddSeverityAndStateToNotificationEmailRollup.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1792000000000-AddVMwareTables.js +241 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1792000000000-AddVMwareTables.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1792100000000-AddGitHubCommandSettingsToCodeRepository.js +36 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1792100000000-AddGitHubCommandSettingsToCodeRepository.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1792200000000-AddUserWebAuthnPurpose.js +12 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1792200000000-AddUserWebAuthnPurpose.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1792300000000-AddGoogleSecOpsDiagnostics.js +34 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1792300000000-AddGoogleSecOpsDiagnostics.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +12 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
- package/build/dist/Server/Middleware/IdentityRateLimit.js +80 -0
- package/build/dist/Server/Middleware/IdentityRateLimit.js.map +1 -1
- package/build/dist/Server/Services/AIRunService.js +14 -1
- package/build/dist/Server/Services/AIRunService.js.map +1 -1
- package/build/dist/Server/Services/BillingPaymentMethodService.js +71 -21
- package/build/dist/Server/Services/BillingPaymentMethodService.js.map +1 -1
- package/build/dist/Server/Services/BillingService.js +210 -22
- package/build/dist/Server/Services/BillingService.js.map +1 -1
- package/build/dist/Server/Services/CloudResourceInstanceService.js +66 -0
- package/build/dist/Server/Services/CloudResourceInstanceService.js.map +1 -1
- package/build/dist/Server/Services/ExceptionAggregationService.js +1 -0
- package/build/dist/Server/Services/ExceptionAggregationService.js.map +1 -1
- package/build/dist/Server/Services/GoogleSecOpsConnectionRunService.js +9 -0
- package/build/dist/Server/Services/GoogleSecOpsConnectionRunService.js.map +1 -0
- package/build/dist/Server/Services/GoogleSecOpsConnectionService.js +7 -0
- package/build/dist/Server/Services/GoogleSecOpsConnectionService.js.map +1 -1
- package/build/dist/Server/Services/Index.js +16 -0
- package/build/dist/Server/Services/Index.js.map +1 -1
- package/build/dist/Server/Services/LogAggregationService.js +1 -0
- package/build/dist/Server/Services/LogAggregationService.js.map +1 -1
- package/build/dist/Server/Services/MetricAggregationService.js +1 -0
- package/build/dist/Server/Services/MetricAggregationService.js.map +1 -1
- package/build/dist/Server/Services/MobilePasskeyLoginService.js +137 -0
- package/build/dist/Server/Services/MobilePasskeyLoginService.js.map +1 -0
- package/build/dist/Server/Services/MonitorService.js +34 -1
- package/build/dist/Server/Services/MonitorService.js.map +1 -1
- package/build/dist/Server/Services/MonitorTemplateService.js +64 -26
- package/build/dist/Server/Services/MonitorTemplateService.js.map +1 -1
- package/build/dist/Server/Services/NetworkDeviceAutoImportRuleEngineService.js +124 -1
- package/build/dist/Server/Services/NetworkDeviceAutoImportRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/NetworkDeviceAutoImportRuleService.js +142 -2
- package/build/dist/Server/Services/NetworkDeviceAutoImportRuleService.js.map +1 -1
- package/build/dist/Server/Services/OpenTelemetryIngestService.js +28 -13
- package/build/dist/Server/Services/OpenTelemetryIngestService.js.map +1 -1
- package/build/dist/Server/Services/PayAsYouGoBillingService.js +297 -0
- package/build/dist/Server/Services/PayAsYouGoBillingService.js.map +1 -0
- package/build/dist/Server/Services/ProjectService.js +38 -2
- package/build/dist/Server/Services/ProjectService.js.map +1 -1
- package/build/dist/Server/Services/ServerlessFunctionInstanceService.js +66 -0
- package/build/dist/Server/Services/ServerlessFunctionInstanceService.js.map +1 -1
- package/build/dist/Server/Services/TeamMemberService.js +85 -28
- package/build/dist/Server/Services/TeamMemberService.js.map +1 -1
- package/build/dist/Server/Services/TelemetryIngestionKeyService.js +61 -10
- package/build/dist/Server/Services/TelemetryIngestionKeyService.js.map +1 -1
- package/build/dist/Server/Services/TelemetryUsageBillingService.js +62 -5
- package/build/dist/Server/Services/TelemetryUsageBillingService.js.map +1 -1
- package/build/dist/Server/Services/TraceAggregationService.js +5 -4
- package/build/dist/Server/Services/TraceAggregationService.js.map +1 -1
- package/build/dist/Server/Services/UserWebAuthnService.js +345 -113
- package/build/dist/Server/Services/UserWebAuthnService.js.map +1 -1
- package/build/dist/Server/Services/VMwareResourceService.js +395 -0
- package/build/dist/Server/Services/VMwareResourceService.js.map +1 -0
- package/build/dist/Server/Services/VMwareVCenterFeedService.js +89 -0
- package/build/dist/Server/Services/VMwareVCenterFeedService.js.map +1 -0
- package/build/dist/Server/Services/VMwareVCenterLabelRuleEngineService.js +197 -0
- package/build/dist/Server/Services/VMwareVCenterLabelRuleEngineService.js.map +1 -0
- package/build/dist/Server/Services/VMwareVCenterLabelRuleService.js +13 -0
- package/build/dist/Server/Services/VMwareVCenterLabelRuleService.js.map +1 -0
- package/build/dist/Server/Services/VMwareVCenterOwnerRuleEngineService.js +214 -0
- package/build/dist/Server/Services/VMwareVCenterOwnerRuleEngineService.js.map +1 -0
- package/build/dist/Server/Services/VMwareVCenterOwnerRuleService.js +13 -0
- package/build/dist/Server/Services/VMwareVCenterOwnerRuleService.js.map +1 -0
- package/build/dist/Server/Services/VMwareVCenterOwnerTeamService.js +129 -0
- package/build/dist/Server/Services/VMwareVCenterOwnerTeamService.js.map +1 -0
- package/build/dist/Server/Services/VMwareVCenterOwnerUserService.js +122 -0
- package/build/dist/Server/Services/VMwareVCenterOwnerUserService.js.map +1 -0
- package/build/dist/Server/Services/VMwareVCenterService.js +533 -0
- package/build/dist/Server/Services/VMwareVCenterService.js.map +1 -0
- package/build/dist/Server/Services/WorkflowVariableService.js +169 -0
- package/build/dist/Server/Services/WorkflowVariableService.js.map +1 -1
- package/build/dist/Server/Types/Billing/MeteredPlan/ActiveMonitoringMeteredPlan.js +12 -1
- package/build/dist/Server/Types/Billing/MeteredPlan/ActiveMonitoringMeteredPlan.js.map +1 -1
- package/build/dist/Server/Types/Billing/MeteredPlan/TelemetryMeteredPlan.js +25 -2
- package/build/dist/Server/Types/Billing/MeteredPlan/TelemetryMeteredPlan.js.map +1 -1
- package/build/dist/Server/Utils/CodeRepository/GitHub/GitHub.js.map +1 -1
- package/build/dist/Server/Utils/CodeRepository/GitHub/GitHubAgentTaskTrigger.js +275 -0
- package/build/dist/Server/Utils/CodeRepository/GitHub/GitHubAgentTaskTrigger.js.map +1 -0
- package/build/dist/Server/Utils/CodeRepository/GitHub/GitHubCommandAuthorizer.js +226 -0
- package/build/dist/Server/Utils/CodeRepository/GitHub/GitHubCommandAuthorizer.js.map +1 -0
- package/build/dist/Server/Utils/CodeRepository/GitHub/GitHubCommandParser.js +297 -0
- package/build/dist/Server/Utils/CodeRepository/GitHub/GitHubCommandParser.js.map +1 -0
- package/build/dist/Server/Utils/CodeRepository/GitHub/GitHubConversation.js +582 -0
- package/build/dist/Server/Utils/CodeRepository/GitHub/GitHubConversation.js.map +1 -0
- package/build/dist/Server/Utils/CodeRepository/GitHub/GitHubReplyComposer.js +275 -0
- package/build/dist/Server/Utils/CodeRepository/GitHub/GitHubReplyComposer.js.map +1 -0
- package/build/dist/Server/Utils/CodeRepository/GitHub/GitHubRunReply.js +365 -0
- package/build/dist/Server/Utils/CodeRepository/GitHub/GitHubRunReply.js.map +1 -0
- package/build/dist/Server/Utils/CodeRepository/GitHub/GitHubWebhookEvents.js +103 -0
- package/build/dist/Server/Utils/CodeRepository/GitHub/GitHubWebhookEvents.js.map +1 -0
- package/build/dist/Server/Utils/CodeRepository/GitHub/GitHubWebhookHandler.js +661 -0
- package/build/dist/Server/Utils/CodeRepository/GitHub/GitHubWebhookHandler.js.map +1 -0
- package/build/dist/Server/Utils/Dashboard/PublicDashboardResourceListPolicy.js +113 -0
- package/build/dist/Server/Utils/Dashboard/PublicDashboardResourceListPolicy.js.map +1 -1
- package/build/dist/Server/Utils/DataSource/EgressGuard.js +99 -15
- package/build/dist/Server/Utils/DataSource/EgressGuard.js.map +1 -1
- package/build/dist/Server/Utils/EmailRollup/EmailRollupFlushRunner.js +2 -0
- package/build/dist/Server/Utils/EmailRollup/EmailRollupFlushRunner.js.map +1 -1
- package/build/dist/Server/Utils/EmailRollup/EmailRollupRenderer.js +18 -0
- package/build/dist/Server/Utils/EmailRollup/EmailRollupRenderer.js.map +1 -1
- package/build/dist/Server/Utils/EmailRollup/EmailRollupWriter.js +31 -2
- package/build/dist/Server/Utils/EmailRollup/EmailRollupWriter.js.map +1 -1
- package/build/dist/Server/Utils/LogRedaction.js +2 -1
- package/build/dist/Server/Utils/LogRedaction.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorAlert.js +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js +219 -4
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorMaintenanceSuppression.js +12 -4
- package/build/dist/Server/Utils/Monitor/MonitorMaintenanceSuppression.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorResourceContext.js +5 -3
- package/build/dist/Server/Utils/Monitor/MonitorResourceContext.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorStepResourceIdentity.js +22 -9
- package/build/dist/Server/Utils/Monitor/MonitorStepResourceIdentity.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorTemplateUtil.js +1 -0
- package/build/dist/Server/Utils/Monitor/MonitorTemplateUtil.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/SeriesResourceLabels.js +21 -0
- package/build/dist/Server/Utils/Monitor/SeriesResourceLabels.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/SeriesResourceLinker.js +21 -6
- package/build/dist/Server/Utils/Monitor/SeriesResourceLinker.js.map +1 -1
- package/build/dist/Server/Utils/ResourceFeed/ResourceFeedUtil.js +3 -3
- package/build/dist/Server/Utils/SecurityEvent/ConnectorErrorMessage.js +9 -9
- package/build/dist/Server/Utils/SecurityEvent/ConnectorErrorMessage.js.map +1 -1
- package/build/dist/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsClient.js +92 -71
- package/build/dist/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsClient.js.map +1 -1
- package/build/dist/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsPoller.js +428 -143
- package/build/dist/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsPoller.js.map +1 -1
- package/build/dist/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsRunExecutor.js +376 -0
- package/build/dist/Server/Utils/SecurityEvent/GoogleSecOps/GoogleSecOpsRunExecutor.js.map +1 -0
- package/build/dist/Server/Utils/Telemetry/EntityRegistry.js +5 -0
- package/build/dist/Server/Utils/Telemetry/EntityRegistry.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/ResourceHeartbeat.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/TelemetryEntity.js +136 -1
- package/build/dist/Server/Utils/Telemetry/TelemetryEntity.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/VMwareSnapshotScan.js +933 -0
- package/build/dist/Server/Utils/Telemetry/VMwareSnapshotScan.js.map +1 -0
- package/build/dist/Types/AI/CodeFixTaskContext.js +40 -0
- package/build/dist/Types/AI/CodeFixTaskContext.js.map +1 -1
- package/build/dist/Types/AI/CodeFixTaskType.js +57 -0
- package/build/dist/Types/AI/CodeFixTaskType.js.map +1 -1
- package/build/dist/Types/Accounts/AccountsLanguage.js +1 -0
- package/build/dist/Types/Accounts/AccountsLanguage.js.map +1 -1
- package/build/dist/Types/AdminDashboard/AdminDashboardLanguage.js +1 -0
- package/build/dist/Types/AdminDashboard/AdminDashboardLanguage.js.map +1 -1
- package/build/dist/Types/Cloud/CloudPlatform.js +277 -0
- package/build/dist/Types/Cloud/CloudPlatform.js.map +1 -0
- package/build/dist/Types/CodeRepository/GitHubCommand.js +52 -0
- package/build/dist/Types/CodeRepository/GitHubCommand.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 +1 -0
- package/build/dist/Types/Dashboard/DashboardComponents/ComponentArgument.js.map +1 -1
- package/build/dist/Types/Dashboard/DashboardComponents/DashboardVMwareHostListComponent.js +2 -0
- package/build/dist/Types/Dashboard/DashboardComponents/DashboardVMwareHostListComponent.js.map +1 -0
- package/build/dist/Types/Dashboard/DashboardComponents/DashboardVMwareVirtualMachineListComponent.js +2 -0
- package/build/dist/Types/Dashboard/DashboardComponents/DashboardVMwareVirtualMachineListComponent.js.map +1 -0
- package/build/dist/Types/Dashboard/DashboardLanguage.js +1 -0
- package/build/dist/Types/Dashboard/DashboardLanguage.js.map +1 -1
- package/build/dist/Types/Dashboard/DashboardTemplates.js +286 -0
- package/build/dist/Types/Dashboard/DashboardTemplates.js.map +1 -1
- package/build/dist/Types/Docs/DocsLanguage.js +1 -0
- package/build/dist/Types/Docs/DocsLanguage.js.map +1 -1
- package/build/dist/Types/Exception/EgressGuardException.js +59 -0
- package/build/dist/Types/Exception/EgressGuardException.js.map +1 -0
- package/build/dist/Types/Icon/IconProp.js +1 -0
- package/build/dist/Types/Icon/IconProp.js.map +1 -1
- package/build/dist/Types/Monitor/MonitorCriteriaInstance.js +1 -0
- package/build/dist/Types/Monitor/MonitorCriteriaInstance.js.map +1 -1
- package/build/dist/Types/Monitor/MonitorStep.js +61 -18
- package/build/dist/Types/Monitor/MonitorStep.js.map +1 -1
- package/build/dist/Types/Monitor/MonitorStepMetricViewConfigUtil.js +1 -0
- package/build/dist/Types/Monitor/MonitorStepMetricViewConfigUtil.js.map +1 -1
- package/build/dist/Types/Monitor/MonitorStepVMwareMonitor.js +71 -0
- package/build/dist/Types/Monitor/MonitorStepVMwareMonitor.js.map +1 -0
- package/build/dist/Types/Monitor/MonitorTemplateSyncField.js +211 -0
- package/build/dist/Types/Monitor/MonitorTemplateSyncField.js.map +1 -0
- package/build/dist/Types/Monitor/MonitorType.js +23 -0
- package/build/dist/Types/Monitor/MonitorType.js.map +1 -1
- package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationCatalog.js +28 -0
- package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationCatalog.js.map +1 -1
- package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationTypes.js +1 -0
- package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationTypes.js.map +1 -1
- package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationUtil.js +2 -0
- package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationUtil.js.map +1 -1
- package/build/dist/Types/Monitor/SeriesContext/SeriesDebugHints.js +120 -0
- package/build/dist/Types/Monitor/SeriesContext/SeriesDebugHints.js.map +1 -1
- package/build/dist/Types/Monitor/SeriesContext/SeriesLabelDisplay.js +60 -0
- package/build/dist/Types/Monitor/SeriesContext/SeriesLabelDisplay.js.map +1 -1
- package/build/dist/Types/Monitor/VMwareAlertTemplates.js +775 -0
- package/build/dist/Types/Monitor/VMwareAlertTemplates.js.map +1 -0
- package/build/dist/Types/Monitor/VMwareMetricCatalog.js +799 -0
- package/build/dist/Types/Monitor/VMwareMetricCatalog.js.map +1 -0
- package/build/dist/Types/OnCallDutyPolicy/ScheduleShiftUtil.js +25 -0
- package/build/dist/Types/OnCallDutyPolicy/ScheduleShiftUtil.js.map +1 -1
- package/build/dist/Types/OnCallDutyPolicy/UserOverrideUtil.js +5 -0
- package/build/dist/Types/OnCallDutyPolicy/UserOverrideUtil.js.map +1 -1
- package/build/dist/Types/Password.js +63 -5
- package/build/dist/Types/Password.js.map +1 -1
- package/build/dist/Types/Permission.js +234 -0
- package/build/dist/Types/Permission.js.map +1 -1
- package/build/dist/Types/Probe/RequestFailedDetails.js +7 -0
- package/build/dist/Types/Probe/RequestFailedDetails.js.map +1 -1
- package/build/dist/Types/SecurityEvent/GoogleSecOpsDiagnostics.js +2 -0
- package/build/dist/Types/SecurityEvent/GoogleSecOpsDiagnostics.js.map +1 -0
- package/build/dist/Types/StatusPage/StatusPageLanguage.js +1 -0
- package/build/dist/Types/StatusPage/StatusPageLanguage.js.map +1 -1
- package/build/dist/Types/Telemetry/EntityType.js +21 -0
- package/build/dist/Types/Telemetry/EntityType.js.map +1 -1
- package/build/dist/Types/Telemetry/ServiceType.js +1 -0
- package/build/dist/Types/Telemetry/ServiceType.js.map +1 -1
- package/build/dist/UI/Components/Breadcrumbs/Breadcrumbs.js +2 -2
- package/build/dist/UI/Components/Breadcrumbs/Breadcrumbs.js.map +1 -1
- package/build/dist/UI/Components/Calendar/Calendar.js +24 -4
- package/build/dist/UI/Components/Calendar/Calendar.js.map +1 -1
- package/build/dist/UI/Components/Forms/BasicForm.js +28 -3
- package/build/dist/UI/Components/Forms/BasicForm.js.map +1 -1
- package/build/dist/UI/Components/Forms/Fields/ColorPicker.js +1 -1
- package/build/dist/UI/Components/Forms/Fields/ColorPicker.js.map +1 -1
- package/build/dist/UI/Components/Forms/Fields/FormField.js +10 -3
- package/build/dist/UI/Components/Forms/Fields/FormField.js.map +1 -1
- package/build/dist/UI/Components/Forms/ModelForm.js +89 -6
- package/build/dist/UI/Components/Forms/ModelForm.js.map +1 -1
- package/build/dist/UI/Components/Graphs/DayUptimeGraph.js +5 -6
- package/build/dist/UI/Components/Graphs/DayUptimeGraph.js.map +1 -1
- package/build/dist/UI/Components/Icon/Icon.js +14 -0
- package/build/dist/UI/Components/Icon/Icon.js.map +1 -1
- package/build/dist/UI/Components/Input/Input.js +37 -8
- package/build/dist/UI/Components/Input/Input.js.map +1 -1
- package/build/dist/UI/Components/LabelRule/ImportLabelRulesModal.js +228 -0
- package/build/dist/UI/Components/LabelRule/ImportLabelRulesModal.js.map +1 -0
- package/build/dist/UI/Components/LabelRule/LabelRuleTable.js +102 -0
- package/build/dist/UI/Components/LabelRule/LabelRuleTable.js.map +1 -0
- package/build/dist/UI/Components/ModelTable/BaseModelTable.js +15 -2
- package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
- package/build/dist/UI/Components/ModelTable/ModelTable.js +13 -5
- package/build/dist/UI/Components/ModelTable/ModelTable.js.map +1 -1
- package/build/dist/UI/Components/MonitorGraphs/Uptime.js +14 -15
- package/build/dist/UI/Components/MonitorGraphs/Uptime.js.map +1 -1
- package/build/dist/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.js +2 -0
- package/build/dist/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.js.map +1 -1
- package/build/dist/UI/Components/Tooltip/Tooltip.js +33 -4
- package/build/dist/UI/Components/Tooltip/Tooltip.js.map +1 -1
- package/build/dist/UI/Utils/DashboardStackingLayers.js +44 -0
- package/build/dist/UI/Utils/DashboardStackingLayers.js.map +1 -0
- package/build/dist/UI/Utils/LabelRuleImportExport.js +195 -0
- package/build/dist/UI/Utils/LabelRuleImportExport.js.map +1 -0
- package/build/dist/UI/Utils/ModelAPI/ModelAPI.js +4 -4
- package/build/dist/UI/Utils/ModelAPI/ModelAPI.js.map +1 -1
- package/build/dist/UI/Utils/TelemetryService.js +3 -2
- package/build/dist/UI/Utils/TelemetryService.js.map +1 -1
- package/build/dist/UI/Utils/UseDashboardGridDnd.js +2 -1
- package/build/dist/UI/Utils/UseDashboardGridDnd.js.map +1 -1
- package/build/dist/UI/Utils/UserEmailRegistrationStatus.js +21 -4
- package/build/dist/UI/Utils/UserEmailRegistrationStatus.js.map +1 -1
- package/build/dist/UI/Utils/WebAuthn.js +121 -0
- package/build/dist/UI/Utils/WebAuthn.js.map +1 -0
- package/build/dist/Utils/API.js +29 -0
- package/build/dist/Utils/API.js.map +1 -1
- package/build/dist/Utils/Dashboard/Components/DashboardVMwareHostListComponent.js +33 -0
- package/build/dist/Utils/Dashboard/Components/DashboardVMwareHostListComponent.js.map +1 -0
- package/build/dist/Utils/Dashboard/Components/DashboardVMwareResourceListShared.js +54 -0
- package/build/dist/Utils/Dashboard/Components/DashboardVMwareResourceListShared.js.map +1 -0
- package/build/dist/Utils/Dashboard/Components/DashboardVMwareVirtualMachineListComponent.js +60 -0
- package/build/dist/Utils/Dashboard/Components/DashboardVMwareVirtualMachineListComponent.js.map +1 -0
- 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/LabelRuleImportExport.js +356 -0
- package/build/dist/Utils/LabelRuleImportExport.js.map +1 -0
- package/build/dist/Utils/Monitor/MonitorTemplateSyncUtil.js +110 -0
- package/build/dist/Utils/Monitor/MonitorTemplateSyncUtil.js.map +1 -0
- package/build/dist/Utils/NetworkDiscovery/DiscoveryScanStatus.js +6 -0
- package/build/dist/Utils/NetworkDiscovery/DiscoveryScanStatus.js.map +1 -1
- package/build/dist/Utils/Telemetry/CloudInstanceIdentity.js +88 -0
- package/build/dist/Utils/Telemetry/CloudInstanceIdentity.js.map +1 -0
- package/build/dist/Utils/Telemetry/EntityKey.js +15 -0
- package/build/dist/Utils/Telemetry/EntityKey.js.map +1 -1
- package/build/dist/Utils/Telemetry/EntityRelationship.js +13 -0
- package/build/dist/Utils/Telemetry/EntityRelationship.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,937 @@
|
|
|
1
|
+
import "@testing-library/jest-dom";
|
|
2
|
+
import {
|
|
3
|
+
cleanup,
|
|
4
|
+
fireEvent,
|
|
5
|
+
render,
|
|
6
|
+
screen,
|
|
7
|
+
waitFor,
|
|
8
|
+
} from "@testing-library/react";
|
|
9
|
+
import userEvent from "@testing-library/user-event";
|
|
10
|
+
import { UserEvent } from "@testing-library/user-event/dist/types/setup/setup";
|
|
11
|
+
import * as React from "react";
|
|
12
|
+
import {
|
|
13
|
+
afterEach,
|
|
14
|
+
beforeEach,
|
|
15
|
+
describe,
|
|
16
|
+
expect,
|
|
17
|
+
jest,
|
|
18
|
+
test,
|
|
19
|
+
} from "@jest/globals";
|
|
20
|
+
|
|
21
|
+
/*
|
|
22
|
+
* Nobody could invite a user.
|
|
23
|
+
*
|
|
24
|
+
* Type a valid email into the invite form, press Tab, and the email vanished -
|
|
25
|
+
* placeholder and all. Type again and characters disappeared as they were
|
|
26
|
+
* entered; the reporter's recording ends with a lone "@" in an otherwise empty
|
|
27
|
+
* box.
|
|
28
|
+
*
|
|
29
|
+
* The form was not losing the value. It was being destroyed and rebuilt:
|
|
30
|
+
*
|
|
31
|
+
* 1. The Email field calls back into the page on every keystroke so the page
|
|
32
|
+
* can check whether that address already has a OneUptime account.
|
|
33
|
+
* 2. When the check resolves, the page sets state and re-renders - and its
|
|
34
|
+
* `fields` array is an inline literal in JSX, so ModelForm sees a brand
|
|
35
|
+
* new array identity.
|
|
36
|
+
* 3. ModelForm's field-preparation effect is keyed on that identity, so it
|
|
37
|
+
* re-ran and re-fetched the Team dropdown's options.
|
|
38
|
+
* 4. While that request was in flight ModelForm returned <Loader/> INSTEAD OF
|
|
39
|
+
* the form. A different element in the same position unmounts the subtree,
|
|
40
|
+
* and a form's values live in that subtree - in BasicForm's refs and in
|
|
41
|
+
* each Input's own state, because Input is DOM-uncontrolled.
|
|
42
|
+
* 5. The request finished, the form remounted from empty initial values, and
|
|
43
|
+
* everything typed in the meantime was gone.
|
|
44
|
+
*
|
|
45
|
+
* Nothing here is specific to the invite form. Practically every ModelForm in
|
|
46
|
+
* the product writes its fields as an inline literal, so any page that changes
|
|
47
|
+
* state while someone types into its form had the same bug waiting.
|
|
48
|
+
*
|
|
49
|
+
* These tests drive the real ModelForm against the real TeamMember/Team models
|
|
50
|
+
* and assert on the DOM the user is actually looking at.
|
|
51
|
+
*/
|
|
52
|
+
|
|
53
|
+
let permissionsForTest: Array<unknown> = [];
|
|
54
|
+
|
|
55
|
+
/*
|
|
56
|
+
* ModelForm reads the merged list for its model-level gate but the global and
|
|
57
|
+
* project snapshots directly for per-column checks, so all three have to agree
|
|
58
|
+
* or fields get stripped for reasons unrelated to what is being tested.
|
|
59
|
+
*/
|
|
60
|
+
jest.mock("../../../../UI/Utils/Permission", () => {
|
|
61
|
+
return {
|
|
62
|
+
__esModule: true,
|
|
63
|
+
default: {
|
|
64
|
+
getAllPermissions: (): Array<unknown> => {
|
|
65
|
+
return permissionsForTest;
|
|
66
|
+
},
|
|
67
|
+
getProjectPermissions: (): null => {
|
|
68
|
+
return null;
|
|
69
|
+
},
|
|
70
|
+
getGlobalPermissions: (): { globalPermissions: Array<unknown> } => {
|
|
71
|
+
return { globalPermissions: permissionsForTest };
|
|
72
|
+
},
|
|
73
|
+
},
|
|
74
|
+
};
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
jest.mock("../../../../UI/Utils/User", () => {
|
|
78
|
+
return {
|
|
79
|
+
__esModule: true,
|
|
80
|
+
default: {
|
|
81
|
+
isMasterAdmin: (): boolean => {
|
|
82
|
+
return false;
|
|
83
|
+
},
|
|
84
|
+
getUserId: (): null => {
|
|
85
|
+
return null;
|
|
86
|
+
},
|
|
87
|
+
},
|
|
88
|
+
};
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
jest.mock("../../../../UI/Utils/Translation", () => {
|
|
92
|
+
return {
|
|
93
|
+
__esModule: true,
|
|
94
|
+
default: () => {
|
|
95
|
+
return {
|
|
96
|
+
translateString: (value: string | undefined): string | undefined => {
|
|
97
|
+
return value;
|
|
98
|
+
},
|
|
99
|
+
translateValue: (value: unknown): unknown => {
|
|
100
|
+
return value;
|
|
101
|
+
},
|
|
102
|
+
};
|
|
103
|
+
},
|
|
104
|
+
};
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
/*
|
|
108
|
+
* Every list request the form makes, and how it is allowed to finish.
|
|
109
|
+
*
|
|
110
|
+
* "deferred" hands back a promise the test resolves by hand, which is the only
|
|
111
|
+
* way to observe the window the bug lived in. "immediate" still crosses a
|
|
112
|
+
* macrotask boundary, because React 18 batches everything inside one task -
|
|
113
|
+
* resolving synchronously would hide the very loading render being tested.
|
|
114
|
+
*/
|
|
115
|
+
interface ListRequest {
|
|
116
|
+
tableName: string;
|
|
117
|
+
resolve: () => void;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
let listRequests: Array<ListRequest> = [];
|
|
121
|
+
let listMode: "immediate" | "deferred" = "immediate";
|
|
122
|
+
let listRowsByTableName: Record<string, Array<unknown>> = {};
|
|
123
|
+
|
|
124
|
+
jest.mock("../../../../UI/Utils/ModelAPI/ModelAPI", () => {
|
|
125
|
+
return {
|
|
126
|
+
__esModule: true,
|
|
127
|
+
default: {
|
|
128
|
+
getItem: async (): Promise<null> => {
|
|
129
|
+
return null;
|
|
130
|
+
},
|
|
131
|
+
getList: async (data: {
|
|
132
|
+
modelType: { new (): { tableName: string | null } };
|
|
133
|
+
}): Promise<{
|
|
134
|
+
data: Array<unknown>;
|
|
135
|
+
count: number;
|
|
136
|
+
skip: number;
|
|
137
|
+
limit: number;
|
|
138
|
+
}> => {
|
|
139
|
+
const tableName: string = new data.modelType().tableName || "";
|
|
140
|
+
|
|
141
|
+
let releaseRequest: () => void = (): void => {};
|
|
142
|
+
|
|
143
|
+
const requestFinished: Promise<void> = new Promise<void>(
|
|
144
|
+
(innerResolve: () => void) => {
|
|
145
|
+
releaseRequest = innerResolve;
|
|
146
|
+
},
|
|
147
|
+
);
|
|
148
|
+
|
|
149
|
+
listRequests.push({ tableName: tableName, resolve: releaseRequest });
|
|
150
|
+
|
|
151
|
+
if (listMode === "immediate") {
|
|
152
|
+
setTimeout(releaseRequest, 0);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
await requestFinished;
|
|
156
|
+
|
|
157
|
+
const rows: Array<unknown> = listRowsByTableName[tableName] || [];
|
|
158
|
+
|
|
159
|
+
return { data: rows, count: rows.length, skip: 0, limit: 50 };
|
|
160
|
+
},
|
|
161
|
+
createOrUpdate: async (): Promise<null> => {
|
|
162
|
+
return null;
|
|
163
|
+
},
|
|
164
|
+
},
|
|
165
|
+
};
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
import ModelForm, { FormType } from "../../../../UI/Components/Forms/ModelForm";
|
|
169
|
+
import BasicForm from "../../../../UI/Components/Forms/BasicForm";
|
|
170
|
+
import FormFieldSchemaType from "../../../../UI/Components/Forms/Types/FormFieldSchemaType";
|
|
171
|
+
import Fields from "../../../../UI/Components/Forms/Types/Fields";
|
|
172
|
+
import FormValues from "../../../../UI/Components/Forms/Types/FormValues";
|
|
173
|
+
import PermissionGate from "../../../../UI/Utils/PermissionGate";
|
|
174
|
+
import TeamMember from "../../../../Models/DatabaseModels/TeamMember";
|
|
175
|
+
import Team from "../../../../Models/DatabaseModels/Team";
|
|
176
|
+
import Label from "../../../../Models/DatabaseModels/Label";
|
|
177
|
+
import Email from "../../../../Types/Email";
|
|
178
|
+
import ObjectID from "../../../../Types/ObjectID";
|
|
179
|
+
import Permission from "../../../../Types/Permission";
|
|
180
|
+
import getJestMockFunction, { MockFunction } from "../../../MockType";
|
|
181
|
+
|
|
182
|
+
const EMAIL_PLACEHOLDER: string = "member@company.com";
|
|
183
|
+
const TEAM_PLACEHOLDER: string = "Select a team";
|
|
184
|
+
const VALID_EMAIL: string = "member@company.com";
|
|
185
|
+
|
|
186
|
+
type SetRegisteredStatusFunction = (value: boolean | null) => void;
|
|
187
|
+
|
|
188
|
+
interface InviteFormHarnessProps {
|
|
189
|
+
onReady: (setRegisteredStatus: SetRegisteredStatusFunction) => void;
|
|
190
|
+
// Mirrors the real page adding a second entity dropdown to the same form.
|
|
191
|
+
showLabelField?: boolean | undefined;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/*
|
|
195
|
+
* As close to App/FeatureSet/Dashboard/src/Pages/Users/Index.tsx as a test can
|
|
196
|
+
* get: page-level state, a `fields` array written inline in JSX so it is a new
|
|
197
|
+
* identity on every render, an Email field that reports every keystroke back to
|
|
198
|
+
* the page, and a required Team dropdown whose options come from the API.
|
|
199
|
+
*
|
|
200
|
+
* The real page debounces the account check by 400ms; here it resolves
|
|
201
|
+
* synchronously so the test pins the behaviour rather than the timing.
|
|
202
|
+
*/
|
|
203
|
+
const InviteFormHarness: React.FunctionComponent<InviteFormHarnessProps> = (
|
|
204
|
+
props: InviteFormHarnessProps,
|
|
205
|
+
): React.ReactElement => {
|
|
206
|
+
const [isEmailRegistered, setIsEmailRegistered] = React.useState<
|
|
207
|
+
boolean | null
|
|
208
|
+
>(null);
|
|
209
|
+
|
|
210
|
+
const { onReady } = props;
|
|
211
|
+
|
|
212
|
+
React.useEffect(() => {
|
|
213
|
+
onReady(setIsEmailRegistered);
|
|
214
|
+
}, [onReady]);
|
|
215
|
+
|
|
216
|
+
return (
|
|
217
|
+
<ModelForm<TeamMember>
|
|
218
|
+
modelType={TeamMember}
|
|
219
|
+
name="Invite New User"
|
|
220
|
+
id="invite-user-form"
|
|
221
|
+
formType={FormType.Create}
|
|
222
|
+
submitButtonText="Invite"
|
|
223
|
+
onSuccess={() => {}}
|
|
224
|
+
fields={[
|
|
225
|
+
{
|
|
226
|
+
field: { user: true },
|
|
227
|
+
title: "Email",
|
|
228
|
+
fieldType: FormFieldSchemaType.Email,
|
|
229
|
+
required: true,
|
|
230
|
+
placeholder: EMAIL_PLACEHOLDER,
|
|
231
|
+
overrideFieldKey: "email",
|
|
232
|
+
onChange: (value: string) => {
|
|
233
|
+
setIsEmailRegistered(Email.isValid(value) ? true : null);
|
|
234
|
+
},
|
|
235
|
+
},
|
|
236
|
+
{
|
|
237
|
+
field: { user: true },
|
|
238
|
+
title: "Name",
|
|
239
|
+
fieldType: FormFieldSchemaType.Text,
|
|
240
|
+
required: false,
|
|
241
|
+
placeholder: "John Smith",
|
|
242
|
+
overrideFieldKey: "name",
|
|
243
|
+
showIf: (): boolean => {
|
|
244
|
+
return isEmailRegistered === false;
|
|
245
|
+
},
|
|
246
|
+
},
|
|
247
|
+
...(props.showLabelField
|
|
248
|
+
? [
|
|
249
|
+
{
|
|
250
|
+
field: { team: true },
|
|
251
|
+
title: "Label",
|
|
252
|
+
fieldType: FormFieldSchemaType.Dropdown,
|
|
253
|
+
required: false,
|
|
254
|
+
overrideFieldKey: "labelPicker",
|
|
255
|
+
dropdownModal: {
|
|
256
|
+
type: Label,
|
|
257
|
+
labelField: "name",
|
|
258
|
+
valueField: "_id",
|
|
259
|
+
},
|
|
260
|
+
placeholder: "Select a label",
|
|
261
|
+
},
|
|
262
|
+
]
|
|
263
|
+
: []),
|
|
264
|
+
{
|
|
265
|
+
field: { team: true },
|
|
266
|
+
title: "Team",
|
|
267
|
+
fieldType: FormFieldSchemaType.Dropdown,
|
|
268
|
+
required: true,
|
|
269
|
+
dropdownModal: {
|
|
270
|
+
type: Team,
|
|
271
|
+
labelField: "name",
|
|
272
|
+
valueField: "_id",
|
|
273
|
+
},
|
|
274
|
+
placeholder: TEAM_PLACEHOLDER,
|
|
275
|
+
},
|
|
276
|
+
]}
|
|
277
|
+
/>
|
|
278
|
+
);
|
|
279
|
+
};
|
|
280
|
+
|
|
281
|
+
/*
|
|
282
|
+
* Page state changes are driven through waitFor rather than act on purpose.
|
|
283
|
+
* act() flushes the whole cascade in one go, which batches the unmount and the
|
|
284
|
+
* remount into a single commit - the form never actually leaves the DOM, and
|
|
285
|
+
* the bug these tests exist for becomes invisible. waitFor yields between
|
|
286
|
+
* attempts, so the intermediate commits (and the timers the option fetch waits
|
|
287
|
+
* on) land the way they do in a browser.
|
|
288
|
+
*/
|
|
289
|
+
type SettleFunction = (change: () => void) => Promise<void>;
|
|
290
|
+
|
|
291
|
+
const settle: SettleFunction = async (change: () => void): Promise<void> => {
|
|
292
|
+
await waitFor(() => {
|
|
293
|
+
change();
|
|
294
|
+
});
|
|
295
|
+
};
|
|
296
|
+
|
|
297
|
+
type GetEmailInputFunction = () => HTMLInputElement;
|
|
298
|
+
|
|
299
|
+
const getEmailInput: GetEmailInputFunction = (): HTMLInputElement => {
|
|
300
|
+
return screen.getByPlaceholderText(EMAIL_PLACEHOLDER) as HTMLInputElement;
|
|
301
|
+
};
|
|
302
|
+
|
|
303
|
+
type MakeTeamFunction = (name: string) => Team;
|
|
304
|
+
|
|
305
|
+
const makeTeam: MakeTeamFunction = (name: string): Team => {
|
|
306
|
+
const team: Team = new Team();
|
|
307
|
+
team._id = ObjectID.generate().toString();
|
|
308
|
+
team.name = name;
|
|
309
|
+
return team;
|
|
310
|
+
};
|
|
311
|
+
|
|
312
|
+
describe("ModelForm preserves what the user typed while inviting a user", () => {
|
|
313
|
+
beforeEach(() => {
|
|
314
|
+
permissionsForTest = [Permission.ProjectOwner, Permission.ProjectAdmin];
|
|
315
|
+
PermissionGate.clearPermissionPropsCache();
|
|
316
|
+
window.localStorage.clear();
|
|
317
|
+
|
|
318
|
+
listRequests = [];
|
|
319
|
+
listMode = "immediate";
|
|
320
|
+
listRowsByTableName = {
|
|
321
|
+
Team: [makeTeam("Owners"), makeTeam("Engineering")],
|
|
322
|
+
Label: [],
|
|
323
|
+
};
|
|
324
|
+
});
|
|
325
|
+
|
|
326
|
+
afterEach(() => {
|
|
327
|
+
cleanup();
|
|
328
|
+
jest.restoreAllMocks();
|
|
329
|
+
});
|
|
330
|
+
|
|
331
|
+
/*
|
|
332
|
+
* The bug exactly as reported. The email is typed, the page's own state flips
|
|
333
|
+
* when the address becomes valid, and the field must still hold what was
|
|
334
|
+
* typed. Before the fix the whole form was unmounted at that moment and the
|
|
335
|
+
* input came back empty.
|
|
336
|
+
*/
|
|
337
|
+
test("keeps the typed email when the page re-renders mid-typing", async () => {
|
|
338
|
+
const user: UserEvent = userEvent.setup();
|
|
339
|
+
|
|
340
|
+
render(<InviteFormHarness onReady={() => {}} />);
|
|
341
|
+
|
|
342
|
+
await waitFor(() => {
|
|
343
|
+
expect(screen.getByPlaceholderText(EMAIL_PLACEHOLDER)).toBeTruthy();
|
|
344
|
+
});
|
|
345
|
+
|
|
346
|
+
await user.type(getEmailInput(), VALID_EMAIL);
|
|
347
|
+
|
|
348
|
+
// Whatever the page did with that keystroke, the field still reads back.
|
|
349
|
+
await waitFor(() => {
|
|
350
|
+
expect(getEmailInput().value).toBe(VALID_EMAIL);
|
|
351
|
+
});
|
|
352
|
+
|
|
353
|
+
expect(getEmailInput().value).toBe(VALID_EMAIL);
|
|
354
|
+
});
|
|
355
|
+
|
|
356
|
+
/*
|
|
357
|
+
* Tab is what the reporter pressed. It only marks the field touched, but it
|
|
358
|
+
* is also roughly when the account check came back - so the sequence is worth
|
|
359
|
+
* pinning end to end.
|
|
360
|
+
*/
|
|
361
|
+
test("keeps the typed email across a Tab out of the field", async () => {
|
|
362
|
+
const user: UserEvent = userEvent.setup();
|
|
363
|
+
|
|
364
|
+
let setRegisteredStatus: SetRegisteredStatusFunction = () => {};
|
|
365
|
+
|
|
366
|
+
render(
|
|
367
|
+
<InviteFormHarness
|
|
368
|
+
onReady={(setter: SetRegisteredStatusFunction) => {
|
|
369
|
+
setRegisteredStatus = setter;
|
|
370
|
+
}}
|
|
371
|
+
/>,
|
|
372
|
+
);
|
|
373
|
+
|
|
374
|
+
await waitFor(() => {
|
|
375
|
+
expect(screen.getByPlaceholderText(EMAIL_PLACEHOLDER)).toBeTruthy();
|
|
376
|
+
});
|
|
377
|
+
|
|
378
|
+
await user.type(getEmailInput(), VALID_EMAIL);
|
|
379
|
+
await user.tab();
|
|
380
|
+
|
|
381
|
+
/*
|
|
382
|
+
* The account check resolving is a page-level state change, exactly as in
|
|
383
|
+
* useUserEmailRegistrationStatus once the debounce fires.
|
|
384
|
+
*/
|
|
385
|
+
await settle(() => {
|
|
386
|
+
setRegisteredStatus(true);
|
|
387
|
+
});
|
|
388
|
+
|
|
389
|
+
await waitFor(() => {
|
|
390
|
+
expect(getEmailInput().value).toBe(VALID_EMAIL);
|
|
391
|
+
});
|
|
392
|
+
});
|
|
393
|
+
|
|
394
|
+
/*
|
|
395
|
+
* The second half of the report: after the first wipe the user retyped, and
|
|
396
|
+
* the very first character flipped the page's state back (true -> null),
|
|
397
|
+
* which wiped the field again. Retyping has to work.
|
|
398
|
+
*/
|
|
399
|
+
test("keeps every character while the page state flips back and forth", async () => {
|
|
400
|
+
const user: UserEvent = userEvent.setup();
|
|
401
|
+
|
|
402
|
+
let setRegisteredStatus: SetRegisteredStatusFunction = () => {};
|
|
403
|
+
|
|
404
|
+
render(
|
|
405
|
+
<InviteFormHarness
|
|
406
|
+
onReady={(setter: SetRegisteredStatusFunction) => {
|
|
407
|
+
setRegisteredStatus = setter;
|
|
408
|
+
}}
|
|
409
|
+
/>,
|
|
410
|
+
);
|
|
411
|
+
|
|
412
|
+
await waitFor(() => {
|
|
413
|
+
expect(screen.getByPlaceholderText(EMAIL_PLACEHOLDER)).toBeTruthy();
|
|
414
|
+
});
|
|
415
|
+
|
|
416
|
+
await user.type(getEmailInput(), VALID_EMAIL);
|
|
417
|
+
|
|
418
|
+
await settle(() => {
|
|
419
|
+
setRegisteredStatus(true);
|
|
420
|
+
});
|
|
421
|
+
|
|
422
|
+
// Now edit the address, which makes it briefly invalid: true -> null.
|
|
423
|
+
await user.type(getEmailInput(), ".uk");
|
|
424
|
+
|
|
425
|
+
await waitFor(() => {
|
|
426
|
+
expect(getEmailInput().value).toBe(`${VALID_EMAIL}.uk`);
|
|
427
|
+
});
|
|
428
|
+
|
|
429
|
+
await settle(() => {
|
|
430
|
+
setRegisteredStatus(false);
|
|
431
|
+
});
|
|
432
|
+
|
|
433
|
+
/*
|
|
434
|
+
* The conditional Name field appears - which changes the rendered field
|
|
435
|
+
* list - and the email must still survive that.
|
|
436
|
+
*/
|
|
437
|
+
await waitFor(() => {
|
|
438
|
+
expect(screen.getByPlaceholderText("John Smith")).toBeTruthy();
|
|
439
|
+
});
|
|
440
|
+
|
|
441
|
+
expect(getEmailInput().value).toBe(`${VALID_EMAIL}.uk`);
|
|
442
|
+
});
|
|
443
|
+
|
|
444
|
+
/*
|
|
445
|
+
* The field list legitimately changes when the account check resolves - the
|
|
446
|
+
* Name field is only asked for when the address has no account yet. Values
|
|
447
|
+
* already entered must survive that too.
|
|
448
|
+
*/
|
|
449
|
+
test("keeps the typed email when a conditional field appears", async () => {
|
|
450
|
+
const user: UserEvent = userEvent.setup();
|
|
451
|
+
|
|
452
|
+
let setRegisteredStatus: SetRegisteredStatusFunction = () => {};
|
|
453
|
+
|
|
454
|
+
render(
|
|
455
|
+
<InviteFormHarness
|
|
456
|
+
onReady={(setter: SetRegisteredStatusFunction) => {
|
|
457
|
+
setRegisteredStatus = setter;
|
|
458
|
+
}}
|
|
459
|
+
/>,
|
|
460
|
+
);
|
|
461
|
+
|
|
462
|
+
await waitFor(() => {
|
|
463
|
+
expect(screen.getByPlaceholderText(EMAIL_PLACEHOLDER)).toBeTruthy();
|
|
464
|
+
});
|
|
465
|
+
|
|
466
|
+
await user.type(getEmailInput(), VALID_EMAIL);
|
|
467
|
+
|
|
468
|
+
expect(screen.queryByPlaceholderText("John Smith")).toBeNull();
|
|
469
|
+
|
|
470
|
+
await settle(() => {
|
|
471
|
+
setRegisteredStatus(false);
|
|
472
|
+
});
|
|
473
|
+
|
|
474
|
+
await waitFor(() => {
|
|
475
|
+
expect(screen.getByPlaceholderText("John Smith")).toBeTruthy();
|
|
476
|
+
});
|
|
477
|
+
|
|
478
|
+
expect(getEmailInput().value).toBe(VALID_EMAIL);
|
|
479
|
+
});
|
|
480
|
+
|
|
481
|
+
/*
|
|
482
|
+
* The mechanism, asserted directly: once the form is on screen, nothing may
|
|
483
|
+
* put a loader in its place. That swap is what threw the input away.
|
|
484
|
+
*/
|
|
485
|
+
test("never replaces a form the user is filling in with a loader", async () => {
|
|
486
|
+
const user: UserEvent = userEvent.setup();
|
|
487
|
+
|
|
488
|
+
let setRegisteredStatus: SetRegisteredStatusFunction = () => {};
|
|
489
|
+
|
|
490
|
+
render(
|
|
491
|
+
<InviteFormHarness
|
|
492
|
+
onReady={(setter: SetRegisteredStatusFunction) => {
|
|
493
|
+
setRegisteredStatus = setter;
|
|
494
|
+
}}
|
|
495
|
+
/>,
|
|
496
|
+
);
|
|
497
|
+
|
|
498
|
+
await waitFor(() => {
|
|
499
|
+
expect(screen.getByPlaceholderText(EMAIL_PLACEHOLDER)).toBeTruthy();
|
|
500
|
+
});
|
|
501
|
+
|
|
502
|
+
const inputBeforeRerender: HTMLInputElement = getEmailInput();
|
|
503
|
+
|
|
504
|
+
await user.type(getEmailInput(), VALID_EMAIL);
|
|
505
|
+
|
|
506
|
+
await settle(() => {
|
|
507
|
+
setRegisteredStatus(true);
|
|
508
|
+
});
|
|
509
|
+
|
|
510
|
+
expect(screen.queryByTestId("bar-loader")).toBeNull();
|
|
511
|
+
|
|
512
|
+
/*
|
|
513
|
+
* The strongest form of the assertion: it is the same DOM node. A remount
|
|
514
|
+
* would hand back a different element even if it happened to be refilled.
|
|
515
|
+
*/
|
|
516
|
+
expect(getEmailInput()).toBe(inputBeforeRerender);
|
|
517
|
+
});
|
|
518
|
+
|
|
519
|
+
/*
|
|
520
|
+
* The loader is still right when there is genuinely nothing to show. Losing
|
|
521
|
+
* it entirely would flash an empty form before the Team list arrives.
|
|
522
|
+
*/
|
|
523
|
+
test("still shows the loader while the form is loading for the first time", async () => {
|
|
524
|
+
listMode = "deferred";
|
|
525
|
+
|
|
526
|
+
render(<InviteFormHarness onReady={() => {}} />);
|
|
527
|
+
|
|
528
|
+
await waitFor(() => {
|
|
529
|
+
expect(screen.getByTestId("bar-loader")).toBeTruthy();
|
|
530
|
+
});
|
|
531
|
+
|
|
532
|
+
expect(screen.queryByPlaceholderText(EMAIL_PLACEHOLDER)).toBeNull();
|
|
533
|
+
|
|
534
|
+
await waitFor(() => {
|
|
535
|
+
expect(listRequests.length).toBe(1);
|
|
536
|
+
});
|
|
537
|
+
|
|
538
|
+
await settle(() => {
|
|
539
|
+
listRequests.forEach((request: ListRequest) => {
|
|
540
|
+
request.resolve();
|
|
541
|
+
});
|
|
542
|
+
});
|
|
543
|
+
|
|
544
|
+
await waitFor(() => {
|
|
545
|
+
expect(screen.getByPlaceholderText(EMAIL_PLACEHOLDER)).toBeTruthy();
|
|
546
|
+
});
|
|
547
|
+
|
|
548
|
+
expect(screen.queryByTestId("bar-loader")).toBeNull();
|
|
549
|
+
});
|
|
550
|
+
|
|
551
|
+
/*
|
|
552
|
+
* The re-run was not only destructive, it was expensive: the invite form
|
|
553
|
+
* issued a Team list request per keystroke. Options for a dropdown depend on
|
|
554
|
+
* the model and its label/value columns and nothing else, so they are fetched
|
|
555
|
+
* once.
|
|
556
|
+
*/
|
|
557
|
+
test("does not re-request dropdown options when the page re-renders", async () => {
|
|
558
|
+
const user: UserEvent = userEvent.setup();
|
|
559
|
+
|
|
560
|
+
let setRegisteredStatus: SetRegisteredStatusFunction = () => {};
|
|
561
|
+
|
|
562
|
+
render(
|
|
563
|
+
<InviteFormHarness
|
|
564
|
+
onReady={(setter: SetRegisteredStatusFunction) => {
|
|
565
|
+
setRegisteredStatus = setter;
|
|
566
|
+
}}
|
|
567
|
+
/>,
|
|
568
|
+
);
|
|
569
|
+
|
|
570
|
+
await waitFor(() => {
|
|
571
|
+
expect(screen.getByPlaceholderText(EMAIL_PLACEHOLDER)).toBeTruthy();
|
|
572
|
+
});
|
|
573
|
+
|
|
574
|
+
expect(listRequests.length).toBe(1);
|
|
575
|
+
|
|
576
|
+
await user.type(getEmailInput(), VALID_EMAIL);
|
|
577
|
+
|
|
578
|
+
const flipStatus: SetRegisteredStatusFunction = setRegisteredStatus;
|
|
579
|
+
|
|
580
|
+
for (const status of [true, null, false, true]) {
|
|
581
|
+
await settle(() => {
|
|
582
|
+
flipStatus(status);
|
|
583
|
+
});
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
await waitFor(() => {
|
|
587
|
+
expect(getEmailInput().value).toBe(VALID_EMAIL);
|
|
588
|
+
});
|
|
589
|
+
|
|
590
|
+
expect(listRequests.length).toBe(1);
|
|
591
|
+
});
|
|
592
|
+
|
|
593
|
+
/*
|
|
594
|
+
* The options still have to arrive, and they still have to arrive after the
|
|
595
|
+
* page has re-rendered a few times - caching that served a stale or empty
|
|
596
|
+
* list would turn a data-loss bug into a cannot-pick-a-team bug.
|
|
597
|
+
*/
|
|
598
|
+
test("still offers the teams after the page has re-rendered", async () => {
|
|
599
|
+
const user: UserEvent = userEvent.setup();
|
|
600
|
+
|
|
601
|
+
let setRegisteredStatus: SetRegisteredStatusFunction = () => {};
|
|
602
|
+
|
|
603
|
+
render(
|
|
604
|
+
<InviteFormHarness
|
|
605
|
+
onReady={(setter: SetRegisteredStatusFunction) => {
|
|
606
|
+
setRegisteredStatus = setter;
|
|
607
|
+
}}
|
|
608
|
+
/>,
|
|
609
|
+
);
|
|
610
|
+
|
|
611
|
+
await waitFor(() => {
|
|
612
|
+
expect(screen.getByPlaceholderText(EMAIL_PLACEHOLDER)).toBeTruthy();
|
|
613
|
+
});
|
|
614
|
+
|
|
615
|
+
await user.type(getEmailInput(), VALID_EMAIL);
|
|
616
|
+
|
|
617
|
+
await settle(() => {
|
|
618
|
+
setRegisteredStatus(true);
|
|
619
|
+
});
|
|
620
|
+
|
|
621
|
+
const teamDropdown: HTMLElement =
|
|
622
|
+
screen.getByPlaceholderText(TEAM_PLACEHOLDER);
|
|
623
|
+
|
|
624
|
+
fireEvent.focus(teamDropdown);
|
|
625
|
+
|
|
626
|
+
expect(await screen.findByText("Engineering")).toBeTruthy();
|
|
627
|
+
expect(screen.getByText("Owners")).toBeTruthy();
|
|
628
|
+
|
|
629
|
+
// And the email the user was in the middle of typing is untouched by it.
|
|
630
|
+
expect(getEmailInput().value).toBe(VALID_EMAIL);
|
|
631
|
+
});
|
|
632
|
+
|
|
633
|
+
/*
|
|
634
|
+
* The cache is keyed on what the request actually depends on, so a second
|
|
635
|
+
* dropdown over a DIFFERENT model must still fetch its own options rather
|
|
636
|
+
* than inheriting the first one's.
|
|
637
|
+
*/
|
|
638
|
+
test("fetches separately for each distinct dropdown model", async () => {
|
|
639
|
+
render(<InviteFormHarness onReady={() => {}} showLabelField={true} />);
|
|
640
|
+
|
|
641
|
+
await waitFor(() => {
|
|
642
|
+
expect(screen.getByPlaceholderText(EMAIL_PLACEHOLDER)).toBeTruthy();
|
|
643
|
+
});
|
|
644
|
+
|
|
645
|
+
await waitFor(() => {
|
|
646
|
+
expect(listRequests.length).toBe(2);
|
|
647
|
+
});
|
|
648
|
+
|
|
649
|
+
const tableNames: Array<string> = listRequests
|
|
650
|
+
.map((request: ListRequest) => {
|
|
651
|
+
return request.tableName;
|
|
652
|
+
})
|
|
653
|
+
.sort();
|
|
654
|
+
|
|
655
|
+
expect(tableNames).toEqual(["Label", "Team"]);
|
|
656
|
+
});
|
|
657
|
+
|
|
658
|
+
/*
|
|
659
|
+
* A slow first run must not be able to come back and undo a newer one. The
|
|
660
|
+
* effect is re-entrant by construction - it re-runs on every parent render -
|
|
661
|
+
* so without a generation guard an older in-flight request can clear a
|
|
662
|
+
* loading flag the newer run still owns and leave the form half-built.
|
|
663
|
+
*/
|
|
664
|
+
test("ignores a stale field-preparation run that finishes late", async () => {
|
|
665
|
+
listMode = "deferred";
|
|
666
|
+
|
|
667
|
+
let setRegisteredStatus: SetRegisteredStatusFunction = () => {};
|
|
668
|
+
|
|
669
|
+
render(
|
|
670
|
+
<InviteFormHarness
|
|
671
|
+
onReady={(setter: SetRegisteredStatusFunction) => {
|
|
672
|
+
setRegisteredStatus = setter;
|
|
673
|
+
}}
|
|
674
|
+
/>,
|
|
675
|
+
);
|
|
676
|
+
|
|
677
|
+
await waitFor(() => {
|
|
678
|
+
expect(listRequests.length).toBe(1);
|
|
679
|
+
});
|
|
680
|
+
|
|
681
|
+
// Re-render the page while the very first options request is still open.
|
|
682
|
+
await settle(() => {
|
|
683
|
+
setRegisteredStatus(false);
|
|
684
|
+
});
|
|
685
|
+
|
|
686
|
+
// Let every request that was opened finish, oldest first.
|
|
687
|
+
await settle(() => {
|
|
688
|
+
listRequests.forEach((request: ListRequest) => {
|
|
689
|
+
request.resolve();
|
|
690
|
+
});
|
|
691
|
+
});
|
|
692
|
+
|
|
693
|
+
await waitFor(() => {
|
|
694
|
+
expect(screen.getByPlaceholderText(EMAIL_PLACEHOLDER)).toBeTruthy();
|
|
695
|
+
});
|
|
696
|
+
|
|
697
|
+
// The form settles on the newest field list, not the stale one.
|
|
698
|
+
await waitFor(() => {
|
|
699
|
+
expect(screen.getByPlaceholderText("John Smith")).toBeTruthy();
|
|
700
|
+
});
|
|
701
|
+
|
|
702
|
+
expect(screen.queryByTestId("bar-loader")).toBeNull();
|
|
703
|
+
});
|
|
704
|
+
});
|
|
705
|
+
|
|
706
|
+
/*
|
|
707
|
+
* BasicForm is where the values actually live, so the guarantee is asserted at
|
|
708
|
+
* that level too - independently of how ModelForm happens to drive it today.
|
|
709
|
+
*/
|
|
710
|
+
describe("BasicForm never re-seeds a form the user has edited", () => {
|
|
711
|
+
afterEach(() => {
|
|
712
|
+
cleanup();
|
|
713
|
+
});
|
|
714
|
+
|
|
715
|
+
const NAME_PLACEHOLDER: string = "Enter a name";
|
|
716
|
+
|
|
717
|
+
type BuildFieldsFunction = () => Fields<FormValues<any>>;
|
|
718
|
+
|
|
719
|
+
const buildFields: BuildFieldsFunction = (): Fields<FormValues<any>> => {
|
|
720
|
+
return [
|
|
721
|
+
{
|
|
722
|
+
field: { name: true },
|
|
723
|
+
title: "Name",
|
|
724
|
+
fieldType: FormFieldSchemaType.Text,
|
|
725
|
+
required: false,
|
|
726
|
+
placeholder: NAME_PLACEHOLDER,
|
|
727
|
+
},
|
|
728
|
+
];
|
|
729
|
+
};
|
|
730
|
+
|
|
731
|
+
/*
|
|
732
|
+
* Both props change identity on every render at almost every call site - the
|
|
733
|
+
* fields because they are written inline, and initialValues because
|
|
734
|
+
* BasicModelForm spreads them into a fresh object each time. Neither may
|
|
735
|
+
* disturb a form in progress.
|
|
736
|
+
*/
|
|
737
|
+
test("keeps typed values when fields and initialValues change identity", async () => {
|
|
738
|
+
const user: UserEvent = userEvent.setup();
|
|
739
|
+
|
|
740
|
+
let rerender: () => void = () => {};
|
|
741
|
+
|
|
742
|
+
const Harness: React.FunctionComponent = (): React.ReactElement => {
|
|
743
|
+
const [, setTick] = React.useState<number>(0);
|
|
744
|
+
|
|
745
|
+
rerender = () => {
|
|
746
|
+
setTick((tick: number) => {
|
|
747
|
+
return tick + 1;
|
|
748
|
+
});
|
|
749
|
+
};
|
|
750
|
+
|
|
751
|
+
return (
|
|
752
|
+
<BasicForm
|
|
753
|
+
id="identity-churn-form"
|
|
754
|
+
initialValues={{}}
|
|
755
|
+
fields={buildFields()}
|
|
756
|
+
onSubmit={() => {}}
|
|
757
|
+
footer={<></>}
|
|
758
|
+
/>
|
|
759
|
+
);
|
|
760
|
+
};
|
|
761
|
+
|
|
762
|
+
render(<Harness />);
|
|
763
|
+
|
|
764
|
+
await waitFor(() => {
|
|
765
|
+
expect(screen.getByPlaceholderText(NAME_PLACEHOLDER)).toBeTruthy();
|
|
766
|
+
});
|
|
767
|
+
|
|
768
|
+
const input: HTMLInputElement = screen.getByPlaceholderText(
|
|
769
|
+
NAME_PLACEHOLDER,
|
|
770
|
+
) as HTMLInputElement;
|
|
771
|
+
|
|
772
|
+
await user.type(input, "Engineering");
|
|
773
|
+
|
|
774
|
+
const triggerRerender: () => void = rerender;
|
|
775
|
+
|
|
776
|
+
for (let i: number = 0; i < 5; i++) {
|
|
777
|
+
await settle(() => {
|
|
778
|
+
triggerRerender();
|
|
779
|
+
});
|
|
780
|
+
}
|
|
781
|
+
|
|
782
|
+
expect(
|
|
783
|
+
(screen.getByPlaceholderText(NAME_PLACEHOLDER) as HTMLInputElement).value,
|
|
784
|
+
).toBe("Engineering");
|
|
785
|
+
});
|
|
786
|
+
|
|
787
|
+
/*
|
|
788
|
+
* A third way keystrokes went missing, on a different path to the one above:
|
|
789
|
+
* while ANY dropdown in the form was fetching its options, every field in the
|
|
790
|
+
* form was disabled - and Input renders `disabled` as `readOnly`, so a text
|
|
791
|
+
* box stayed focusable and simply ate what was typed into it, with nothing on
|
|
792
|
+
* screen to say why. Only the dropdowns waiting on those options should wait.
|
|
793
|
+
*/
|
|
794
|
+
test("keeps text fields usable while a dropdown re-fetches its options", async () => {
|
|
795
|
+
const user: UserEvent = userEvent.setup();
|
|
796
|
+
|
|
797
|
+
/*
|
|
798
|
+
* Resolves the first time so the form gets on screen, then hangs - which is
|
|
799
|
+
* the window that matters. A refetch happens on top of an already-rendered
|
|
800
|
+
* form, so the fields the user can see are the ones that used to go
|
|
801
|
+
* read-only.
|
|
802
|
+
*/
|
|
803
|
+
let fetchCount: number = 0;
|
|
804
|
+
|
|
805
|
+
const fetchDropdownOptions: () => Promise<Array<never>> = (): Promise<
|
|
806
|
+
Array<never>
|
|
807
|
+
> => {
|
|
808
|
+
fetchCount++;
|
|
809
|
+
|
|
810
|
+
if (fetchCount === 1) {
|
|
811
|
+
return Promise.resolve([]);
|
|
812
|
+
}
|
|
813
|
+
|
|
814
|
+
return new Promise<Array<never>>(() => {});
|
|
815
|
+
};
|
|
816
|
+
|
|
817
|
+
let rerender: () => void = () => {};
|
|
818
|
+
|
|
819
|
+
const Harness: React.FunctionComponent = (): React.ReactElement => {
|
|
820
|
+
const [, setTick] = React.useState<number>(0);
|
|
821
|
+
|
|
822
|
+
rerender = () => {
|
|
823
|
+
setTick((tick: number) => {
|
|
824
|
+
return tick + 1;
|
|
825
|
+
});
|
|
826
|
+
};
|
|
827
|
+
|
|
828
|
+
return (
|
|
829
|
+
<BasicForm
|
|
830
|
+
id="options-loading-form"
|
|
831
|
+
initialValues={{}}
|
|
832
|
+
fields={[
|
|
833
|
+
{
|
|
834
|
+
field: { name: true },
|
|
835
|
+
title: "Name",
|
|
836
|
+
fieldType: FormFieldSchemaType.Text,
|
|
837
|
+
required: false,
|
|
838
|
+
placeholder: NAME_PLACEHOLDER,
|
|
839
|
+
},
|
|
840
|
+
{
|
|
841
|
+
field: { team: true },
|
|
842
|
+
title: "Team",
|
|
843
|
+
fieldType: FormFieldSchemaType.Dropdown,
|
|
844
|
+
required: false,
|
|
845
|
+
placeholder: "Select a team",
|
|
846
|
+
fetchDropdownOptions: fetchDropdownOptions,
|
|
847
|
+
},
|
|
848
|
+
]}
|
|
849
|
+
onSubmit={() => {}}
|
|
850
|
+
footer={<></>}
|
|
851
|
+
/>
|
|
852
|
+
);
|
|
853
|
+
};
|
|
854
|
+
|
|
855
|
+
render(<Harness />);
|
|
856
|
+
|
|
857
|
+
await waitFor(() => {
|
|
858
|
+
expect(screen.getByPlaceholderText(NAME_PLACEHOLDER)).toBeTruthy();
|
|
859
|
+
});
|
|
860
|
+
|
|
861
|
+
// A new inline fields array sends the dropdown back to fetch, and it hangs.
|
|
862
|
+
await settle(() => {
|
|
863
|
+
rerender();
|
|
864
|
+
});
|
|
865
|
+
|
|
866
|
+
await waitFor(() => {
|
|
867
|
+
expect(fetchCount).toBeGreaterThan(1);
|
|
868
|
+
});
|
|
869
|
+
|
|
870
|
+
const input: HTMLInputElement = screen.getByPlaceholderText(
|
|
871
|
+
NAME_PLACEHOLDER,
|
|
872
|
+
) as HTMLInputElement;
|
|
873
|
+
|
|
874
|
+
await user.type(input, "Engineering");
|
|
875
|
+
|
|
876
|
+
expect(
|
|
877
|
+
(screen.getByPlaceholderText(NAME_PLACEHOLDER) as HTMLInputElement).value,
|
|
878
|
+
).toBe("Engineering");
|
|
879
|
+
});
|
|
880
|
+
|
|
881
|
+
/*
|
|
882
|
+
* The other side of the same guard. formFields starts empty and is filled in
|
|
883
|
+
* by an effect, so the initial-values pass must not latch before the field
|
|
884
|
+
* list arrives - or every default value and every dropdown/date
|
|
885
|
+
* normalisation would be skipped.
|
|
886
|
+
*/
|
|
887
|
+
test("still applies default values once the field list arrives", async () => {
|
|
888
|
+
const onSubmit: MockFunction = getJestMockFunction();
|
|
889
|
+
|
|
890
|
+
render(
|
|
891
|
+
<BasicForm
|
|
892
|
+
id="default-value-form"
|
|
893
|
+
initialValues={{}}
|
|
894
|
+
fields={[
|
|
895
|
+
{
|
|
896
|
+
field: { name: true },
|
|
897
|
+
title: "Name",
|
|
898
|
+
fieldType: FormFieldSchemaType.Text,
|
|
899
|
+
required: false,
|
|
900
|
+
placeholder: NAME_PLACEHOLDER,
|
|
901
|
+
defaultValue: "Default Team",
|
|
902
|
+
},
|
|
903
|
+
{
|
|
904
|
+
field: { description: true },
|
|
905
|
+
title: "Description",
|
|
906
|
+
fieldType: FormFieldSchemaType.Text,
|
|
907
|
+
required: false,
|
|
908
|
+
placeholder: "Describe it",
|
|
909
|
+
getDefaultValue: (): string => {
|
|
910
|
+
return "Derived default";
|
|
911
|
+
},
|
|
912
|
+
},
|
|
913
|
+
]}
|
|
914
|
+
onSubmit={(values: FormValues<any>) => {
|
|
915
|
+
onSubmit(values);
|
|
916
|
+
}}
|
|
917
|
+
submitButtonText="Save"
|
|
918
|
+
footer={<></>}
|
|
919
|
+
/>,
|
|
920
|
+
);
|
|
921
|
+
|
|
922
|
+
await waitFor(() => {
|
|
923
|
+
expect(screen.getByPlaceholderText(NAME_PLACEHOLDER)).toBeTruthy();
|
|
924
|
+
});
|
|
925
|
+
|
|
926
|
+
await userEvent.click(screen.getByText("Save"));
|
|
927
|
+
|
|
928
|
+
await waitFor(() => {
|
|
929
|
+
expect(onSubmit).toHaveBeenCalled();
|
|
930
|
+
});
|
|
931
|
+
|
|
932
|
+
const submitted: FormValues<any> = onSubmit.mock.calls[0]![0];
|
|
933
|
+
|
|
934
|
+
expect(submitted["name"]).toBe("Default Team");
|
|
935
|
+
expect(submitted["description"]).toBe("Derived default");
|
|
936
|
+
});
|
|
937
|
+
});
|