@oneuptime/common 14.0.10 → 14.0.11
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/AIConversation.ts +127 -1
- package/Models/DatabaseModels/CephCluster.ts +12 -0
- package/Models/DatabaseModels/CloudResource.ts +12 -0
- package/Models/DatabaseModels/DatabaseServer.ts +12 -0
- package/Models/DatabaseModels/DockerHost.ts +12 -0
- package/Models/DatabaseModels/DockerSwarmCluster.ts +12 -0
- package/Models/DatabaseModels/GlobalOidc.ts +0 -4
- package/Models/DatabaseModels/GlobalOidcProject.ts +0 -4
- package/Models/DatabaseModels/GlobalSso.ts +0 -4
- package/Models/DatabaseModels/GlobalSsoProject.ts +0 -4
- package/Models/DatabaseModels/Host.ts +12 -0
- package/Models/DatabaseModels/IncidentForm.ts +594 -0
- package/Models/DatabaseModels/IncidentFormSubmission.ts +283 -0
- package/Models/DatabaseModels/IncidentTemplate.ts +59 -0
- package/Models/DatabaseModels/Index.ts +14 -0
- package/Models/DatabaseModels/IoTFleet.ts +12 -0
- package/Models/DatabaseModels/KubernetesCluster.ts +12 -0
- package/Models/DatabaseModels/MessageQueue.ts +1102 -0
- package/Models/DatabaseModels/MessageQueueLabelRule.ts +553 -0
- package/Models/DatabaseModels/MessageQueueOwnerRule.ts +633 -0
- package/Models/DatabaseModels/MessageQueueOwnerTeam.ts +491 -0
- package/Models/DatabaseModels/MessageQueueOwnerUser.ts +490 -0
- package/Models/DatabaseModels/PodmanHost.ts +12 -0
- package/Models/DatabaseModels/Project.ts +59 -0
- package/Models/DatabaseModels/ProjectOidc.ts +0 -4
- package/Models/DatabaseModels/ProjectSso.ts +0 -4
- package/Models/DatabaseModels/ProxmoxCluster.ts +12 -0
- package/Models/DatabaseModels/RumApplication.ts +12 -0
- package/Models/DatabaseModels/ServerlessFunction.ts +12 -0
- package/Models/DatabaseModels/Service.ts +12 -0
- package/Models/DatabaseModels/StatusPageOidc.ts +0 -4
- package/Models/DatabaseModels/StatusPageSso.ts +0 -4
- package/Models/DatabaseModels/TeamComplianceSetting.ts +47 -2
- package/Models/DatabaseModels/VMwareVCenter.ts +12 -0
- package/Server/API/AIChatAPI.ts +13 -114
- package/Server/API/AIInvestigationAPI.ts +3 -3
- package/Server/API/AIInvestigationConversationAPI.ts +266 -0
- package/Server/API/IncidentFormAPI.ts +376 -0
- package/Server/API/ProjectOIDC.ts +16 -25
- package/Server/API/ProjectSSO.ts +16 -24
- package/Server/API/StatusPageAPI.ts +42 -77
- package/Server/Enterprise/EnterpriseEdition.ts +93 -28
- package/Server/Enterprise/EnterpriseFeature.ts +25 -3
- package/Server/Enterprise/EnterpriseLicenseSnapshot.ts +1 -1
- package/Server/Enterprise/EnterpriseServerModule.ts +4 -1
- package/Server/EnvironmentConfig.ts +1 -1
- package/Server/Infrastructure/Postgres/SchemaMigrations/1796400000000-AddIncidentForms.ts +129 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1796500000000-AddTeamComplianceRuleNotificationChannels.ts +52 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1796600000000-AddAIInvestigationConversationAndTimeLimits.ts +75 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1796700000000-AddMessageQueueTables.ts +477 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +8 -0
- package/Server/Middleware/IncidentFormRateLimit.ts +847 -0
- package/Server/Middleware/UserAuthorization.ts +16 -38
- package/Server/Services/AIService.ts +10 -13
- package/Server/Services/IncidentCustomFieldService.ts +112 -2
- package/Server/Services/IncidentEpisodeMemberService.ts +24 -4
- package/Server/Services/IncidentEpisodeService.ts +10 -1
- package/Server/Services/IncidentFormService.ts +1566 -0
- package/Server/Services/IncidentFormSubmissionService.ts +97 -0
- package/Server/Services/IncidentGroupingEngineService.ts +45 -8
- package/Server/Services/IncidentService.ts +123 -5
- package/Server/Services/IncidentTemplateService.ts +22 -0
- package/Server/Services/Index.ts +14 -0
- package/Server/Services/MessageQueueLabelRuleEngineService.ts +321 -0
- package/Server/Services/MessageQueueLabelRuleService.ts +14 -0
- package/Server/Services/MessageQueueOwnerRuleEngineService.ts +412 -0
- package/Server/Services/MessageQueueOwnerRuleService.ts +14 -0
- package/Server/Services/MessageQueueOwnerTeamService.ts +62 -0
- package/Server/Services/MessageQueueOwnerUserService.ts +62 -0
- package/Server/Services/MessageQueueService.ts +1463 -0
- package/Server/Services/OpenTelemetryIngestService.ts +37 -4
- package/Server/Services/ProjectService.ts +0 -59
- package/Server/Services/StatusPagePrivateUserService.ts +1 -4
- package/Server/Services/StatusPageService.ts +1 -51
- package/Server/Services/TeamComplianceSettingService.ts +163 -42
- package/Server/Services/UserNotificationRuleService.ts +8 -1
- package/Server/Services/WorkspaceNotificationSummaryService.ts +12 -3
- package/Server/Types/Database/Permissions/CreatePermission.ts +17 -3
- package/Server/Types/Database/Permissions/EditionPermission.ts +140 -38
- package/Server/Types/Database/Permissions/OwnerTableRegistry.ts +16 -0
- package/Server/Types/Database/Permissions/TablePermission.ts +3 -3
- package/Server/Types/Database/Permissions/UpdatePermission.ts +20 -6
- package/Server/Utils/AI/Chat/AgentContextCompactor.ts +200 -0
- package/Server/Utils/AI/Chat/ChatAgentRunner.ts +307 -48
- package/Server/Utils/AI/Chat/ChatRunCancellation.ts +156 -0
- package/Server/Utils/AI/Chat/ObservabilityAssistant.ts +78 -18
- package/Server/Utils/AI/Chat/ObservabilityChatPrompt.ts +1 -1
- package/Server/Utils/AI/Chat/ToolOutputPager.ts +322 -0
- package/Server/Utils/AI/ClusterAccess/KubectlInvestigationToolkit.ts +88 -30
- package/Server/Utils/AI/ClusterAccess/KubectlJobRunner.ts +13 -1
- package/Server/Utils/AI/CodeFix/CodeFixReadiness.ts +0 -32
- package/Server/Utils/AI/CodeFix/FixRunBudget.ts +27 -25
- package/Server/Utils/AI/Remediation/RemediationCommandTools.ts +7 -1
- package/Server/Utils/AI/Remediation/RemediationExecutionRunner.ts +34 -14
- package/Server/Utils/AI/ResourceAccess/InfrastructureInvestigationToolkit.ts +69 -24
- package/Server/Utils/AI/ResourceAccess/ResourceCommandJobRunner.ts +9 -0
- package/Server/Utils/AI/SRE/AIInvestigationEngine.ts +53 -10
- package/Server/Utils/AI/SRE/AlertInvestigationRunner.ts +27 -10
- package/Server/Utils/AI/SRE/IncidentInvestigationRunner.ts +27 -10
- package/Server/Utils/AI/SRE/InvestigationQueue.ts +16 -19
- package/Server/Utils/AI/SRE/InvestigationThread.ts +646 -0
- package/Server/Utils/AI/SRE/InvestigationThreadService.ts +715 -0
- package/Server/Utils/AI/Toolbox/Serializer.ts +10 -3
- package/Server/Utils/EditionEnforcement.ts +19 -202
- package/Server/Utils/LLM/LLMService.ts +259 -63
- package/Server/Utils/RelaxedScimTeamLocksReport.ts +245 -0
- package/Server/Utils/Rules/RuleRun/RuleRunRegistry.ts +25 -0
- package/Server/Utils/SameOriginRequest.ts +203 -0
- package/Server/Utils/TeamMember/ProjectLeaveResourceCleanup.ts +2 -0
- package/Server/Utils/Telemetry/EntityRegistry.ts +4 -1
- package/Server/Utils/Telemetry/MessageQueueDiscovery.ts +1402 -0
- package/Server/Utils/Telemetry/ResourceEntityFilter.ts +4 -1
- package/Server/Utils/VendorAssets.ts +3 -3
- package/Server/Utils/Workspace/MicrosoftTeams/Actions/Incident.ts +3 -1
- package/Server/Utils/Workspace/MicrosoftTeams/Actions/IncidentEpisode.ts +3 -1
- package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.ts +10 -1
- package/Tests/App/Accounts/IncidentFormPage.test.tsx +2036 -0
- package/Tests/App/Accounts/IncidentFormServerMessages.test.ts +119 -0
- package/Tests/App/Accounts/IncidentFormUtils.test.ts +1157 -0
- package/Tests/App/Accounts/LoginPasskey.test.tsx +6 -4
- package/Tests/App/Accounts/LoginSso.test.tsx +724 -0
- package/Tests/App/AdminDashboard/AdminAuthenticationRequireSso.test.tsx +338 -0
- package/Tests/App/AdminDashboard/AdminAuthenticationSsoCardLocales.test.tsx +331 -0
- package/Tests/App/AdminDashboard/AdminEnterprisePluginPage.test.tsx +47 -33
- package/Tests/App/AdminDashboard/GlobalSsoOidcPages.test.tsx +1021 -0
- package/Tests/App/Dashboard/AffectedResourcesDisplay.test.tsx +876 -78
- package/Tests/App/Dashboard/AffectedResourcesSlo.test.tsx +20 -3
- package/Tests/App/Dashboard/CephProxmoxVMwareDocumentationCards.test.tsx +359 -0
- package/Tests/App/Dashboard/CephSetupGuide.test.ts +961 -0
- package/Tests/App/Dashboard/CloudDocumentationCard.test.tsx +381 -95
- package/Tests/App/Dashboard/CloudSetupGuide.test.ts +1463 -0
- package/Tests/App/Dashboard/ClusterAccessNotice.test.tsx +174 -12
- package/Tests/App/Dashboard/ContainerSetupGuideCards.test.tsx +345 -0
- package/Tests/App/Dashboard/CoreListEmptyStates.test.tsx +501 -0
- package/Tests/App/Dashboard/DashboardLazyPages.test.tsx +0 -1
- package/Tests/App/Dashboard/DatabaseDocumentationCard.test.tsx +400 -0
- package/Tests/App/Dashboard/DatabaseDocumentationMarkdown.test.ts +5 -0
- package/Tests/App/Dashboard/DatabaseSetupGuide.test.ts +1869 -0
- package/Tests/App/Dashboard/DatabaseTelemetryScope.test.ts +44 -0
- package/Tests/App/Dashboard/DatabaseTelemetryTabs.test.tsx +50 -9
- package/Tests/App/Dashboard/DockerSetupGuide.test.ts +899 -0
- package/Tests/App/Dashboard/DockerSwarmSetupGuide.test.ts +964 -0
- package/Tests/App/Dashboard/EnterpriseFeatureUpgrade.test.tsx +141 -7
- package/Tests/App/Dashboard/EnterprisePluginPage.test.tsx +52 -39
- package/Tests/App/Dashboard/EventOverviewPages.test.tsx +7 -1
- package/Tests/App/Dashboard/GettingStartedTaskRoutes.test.tsx +331 -0
- package/Tests/App/Dashboard/HomeOverviewStatsFirstRun.test.tsx +925 -0
- package/Tests/App/Dashboard/HostDocumentationCard.test.tsx +225 -0
- package/Tests/App/Dashboard/HostSetupGuide.test.ts +1183 -0
- package/Tests/App/Dashboard/IdentityEnterpriseShells.test.tsx +69 -45
- package/Tests/App/Dashboard/IncidentCreateTemplateCustomFieldSettings.test.tsx +745 -0
- package/Tests/App/Dashboard/IncidentCreateTemplateOwners.test.tsx +414 -0
- package/Tests/App/Dashboard/IncidentCustomFieldCreateSettingsForm.test.ts +1042 -0
- package/Tests/App/Dashboard/IncidentCustomFieldSettingsCard.test.tsx +1816 -0
- package/Tests/App/Dashboard/IncidentFormPlan.test.ts +89 -0
- package/Tests/App/Dashboard/IncidentFormShareLinkCard.test.tsx +846 -0
- package/Tests/App/Dashboard/IncidentFormsPages.test.tsx +1324 -0
- package/Tests/App/Dashboard/IncidentTemplateCustomFieldSettings.test.tsx +630 -0
- package/Tests/App/Dashboard/IncidentsSideMenu.test.tsx +13 -0
- package/Tests/App/Dashboard/IncomingEmailMonitorLinkVerifyHint.test.tsx +104 -0
- package/Tests/App/Dashboard/InvestigationConversation.test.tsx +1107 -0
- package/Tests/App/Dashboard/InvestigationConversationData.test.ts +546 -0
- package/Tests/App/Dashboard/InvestigationEvidenceList.test.tsx +170 -5
- package/Tests/App/Dashboard/InvestigationNotStarted.test.tsx +207 -2
- package/Tests/App/Dashboard/InvestigationPanel.test.tsx +729 -34
- package/Tests/App/Dashboard/InvestigationPanelStatus.test.tsx +9 -21
- package/Tests/App/Dashboard/InvestigationReportView.test.tsx +274 -37
- package/Tests/App/Dashboard/InvestigationStatusBadge.test.tsx +130 -0
- package/Tests/App/Dashboard/IoTDocumentationCard.test.tsx +218 -0
- package/Tests/App/Dashboard/IoTSetupGuide.test.ts +1124 -0
- package/Tests/App/Dashboard/KubernetesClusterAiAccessSettings.test.ts +20 -6
- package/Tests/App/Dashboard/KubernetesClusterAiDocumentationMarkdown.test.ts +107 -83
- package/Tests/App/Dashboard/KubernetesSetupGuide.test.ts +787 -0
- package/Tests/App/Dashboard/MessageQueueBreadcrumbs.test.tsx +228 -0
- package/Tests/App/Dashboard/MessageQueueBrokerHealth.test.tsx +1538 -0
- package/Tests/App/Dashboard/MessageQueueBrokerHealthMetricChart.test.tsx +969 -0
- package/Tests/App/Dashboard/MessageQueueBrokerHealthReads.test.ts +889 -0
- package/Tests/App/Dashboard/MessageQueueBrokerMetricsReach.test.ts +236 -0
- package/Tests/App/Dashboard/MessageQueueDocumentationCard.test.tsx +479 -0
- package/Tests/App/Dashboard/MessageQueueListPages.test.tsx +1232 -0
- package/Tests/App/Dashboard/MessageQueueMetricDescriptions.test.ts +244 -0
- package/Tests/App/Dashboard/MessageQueueMonitorLink.test.ts +952 -0
- package/Tests/App/Dashboard/MessageQueueMonitorLinkMonitorCreate.test.tsx +859 -0
- package/Tests/App/Dashboard/MessageQueueOverview.test.tsx +1773 -0
- package/Tests/App/Dashboard/MessageQueueOverviewPresentation.test.ts +196 -0
- package/Tests/App/Dashboard/MessageQueuePresentation.test.ts +799 -0
- package/Tests/App/Dashboard/MessageQueueProducersConsumers.test.tsx +680 -0
- package/Tests/App/Dashboard/MessageQueueRoutes.test.tsx +383 -0
- package/Tests/App/Dashboard/MessageQueueRulePages.test.tsx +278 -0
- package/Tests/App/Dashboard/MessageQueueSetupGuide.test.ts +2778 -0
- package/Tests/App/Dashboard/MessageQueueSideMenus.test.tsx +273 -0
- package/Tests/App/Dashboard/MessageQueueSpanPopulations.test.ts +930 -0
- package/Tests/App/Dashboard/MessageQueueSpanStore.ts +351 -0
- package/Tests/App/Dashboard/MessageQueueTelemetryScope.test.ts +375 -0
- package/Tests/App/Dashboard/MessageQueueTelemetryScopeTabs.test.tsx +668 -0
- package/Tests/App/Dashboard/MessageQueueViewPages.test.tsx +685 -0
- package/Tests/App/Dashboard/MonitorAndHomeNotOperationalMenus.test.tsx +342 -0
- package/Tests/App/Dashboard/MonitorCreateFirstRunDefaults.test.tsx +623 -0
- package/Tests/App/Dashboard/MonitorCreateFromMonitorBackedDevice.test.tsx +442 -0
- package/Tests/App/Dashboard/MonitorLogsPageViewSummary.test.tsx +814 -0
- package/Tests/App/Dashboard/MonitorSetupCardBodies.test.tsx +246 -0
- package/Tests/App/Dashboard/NavigationSearchKeywords.test.tsx +8 -0
- package/Tests/App/Dashboard/OnboardingSsoEmptyState.test.tsx +27 -12
- package/Tests/App/Dashboard/PlanGatedPage.test.tsx +292 -0
- package/Tests/App/Dashboard/PodmanSetupGuide.test.ts +948 -0
- package/Tests/App/Dashboard/ProductOrientation.test.tsx +5 -4
- package/Tests/App/Dashboard/ProductSettingsSectionCollapsed.test.tsx +266 -0
- package/Tests/App/Dashboard/ProxmoxSetupGuide.test.ts +1318 -0
- package/Tests/App/Dashboard/ResourceAiAgentAttentionServerParity.test.ts +555 -0
- package/Tests/App/Dashboard/ResourceAiAgentPage.test.tsx +298 -9
- package/Tests/App/Dashboard/ResourceAiAgentStatus.test.ts +453 -0
- package/Tests/App/Dashboard/ResourceArchiveSettings.test.tsx +16 -0
- package/Tests/App/Dashboard/ResourceConnectionGuideCard.test.tsx +444 -0
- package/Tests/App/Dashboard/ResourceConnectionGuideOverviewsInfra.test.tsx +798 -0
- package/Tests/App/Dashboard/ResourceConnectionGuideOverviewsPlatforms.test.tsx +717 -0
- package/Tests/App/Dashboard/ResourceConnectionGuides.test.ts +981 -0
- package/Tests/App/Dashboard/ResourceConnectionState.test.ts +132 -0
- package/Tests/App/Dashboard/RumDocumentationCard.test.tsx +293 -0
- package/Tests/App/Dashboard/RumSessionReplayRetentionSettings.test.tsx +467 -0
- package/Tests/App/Dashboard/RumSetupGuide.test.ts +758 -0
- package/Tests/App/Dashboard/ScheduledMaintenanceOverviewPage.test.tsx +25 -0
- package/Tests/App/Dashboard/ServerlessDocumentationCard.test.tsx +254 -0
- package/Tests/App/Dashboard/ServerlessSetupGuide.test.ts +1074 -0
- package/Tests/App/Dashboard/SetupGuide.test.ts +246 -0
- package/Tests/App/Dashboard/SetupGuideCard.test.tsx +756 -0
- package/Tests/App/Dashboard/SloListSideMenu.test.tsx +120 -0
- package/Tests/App/Dashboard/SsoPages.test.tsx +833 -0
- package/Tests/App/Dashboard/TelemetryDocumentation.test.tsx +253 -0
- package/Tests/App/Dashboard/TelemetryRetentionShells.test.tsx +730 -0
- package/Tests/App/Dashboard/VMwareSetupGuide.test.ts +1033 -0
- package/Tests/App/StatusPage/StatusPageSsoEmptyState.test.tsx +87 -7
- package/Tests/Models/DatabaseModels/DatabaseServerModels.test.ts +28 -9
- package/Tests/Models/DatabaseModels/IncidentFormModel.test.ts +1250 -0
- package/Tests/Models/DatabaseModels/MessageQueueModels.test.ts +1983 -0
- package/Tests/Models/DatabaseModels/StaticRuleCriteriaInheritance.test.ts +4 -2
- package/Tests/Models/DatabaseModels/TeamComplianceSettingModel.test.ts +190 -14
- package/Tests/Models/IncidentTemplateCustomFieldSettingsColumn.test.ts +291 -0
- package/Tests/Server/API/AIInvestigationConversationAPI.test.ts +412 -0
- package/Tests/Server/API/GlobalConfigLicense.test.ts +38 -9
- package/Tests/Server/API/IncidentFormAPI.test.ts +942 -0
- package/Tests/Server/API/IncidentFormPublicRoutes.test.ts +1653 -0
- package/Tests/Server/API/KubernetesClusterAiAccessAPI.test.ts +2 -1
- package/Tests/Server/API/{SsoProviderListingsEdition.test.ts → SsoProviderListings.test.ts} +164 -110
- package/Tests/Server/Enterprise/EnterpriseEdition.test.ts +76 -54
- package/Tests/Server/Enterprise/EnterpriseFeatureActive.test.ts +125 -42
- package/Tests/Server/Enterprise/EnterpriseLicenseSnapshot.test.ts +36 -10
- package/Tests/Server/Enterprise/EnterpriseModelFeatureMap.test.ts +51 -9
- package/Tests/Server/Enterprise/FakeEnterpriseModule.ts +13 -8
- package/Tests/Server/Enterprise/SsoInCommunityEdition.test.ts +540 -0
- package/Tests/Server/Infrastructure/Postgres/AddConfigurableRuleCriteriaMigration.test.ts +3 -0
- package/Tests/Server/Infrastructure/Postgres/AddIncidentFormsMigration.test.ts +438 -0
- package/Tests/Server/Infrastructure/Postgres/AddTeamComplianceRuleNotificationChannelsMigration.test.ts +255 -0
- package/Tests/Server/Infrastructure/Postgres/MessageQueueTablesMigration.test.ts +637 -0
- package/Tests/Server/Middleware/IncidentFormRateLimit.test.ts +1630 -0
- package/Tests/Server/Middleware/UserAuthorization.test.ts +16 -17
- package/Tests/Server/Middleware/UserAuthorizationSsoEnforcement.test.ts +544 -0
- package/Tests/Server/Services/AIServiceDailyBudget.test.ts +37 -8
- package/Tests/Server/Services/IncidentCreatedFeedTitle.test.ts +212 -0
- package/Tests/Server/Services/IncidentCustomFieldDeleteFormQuestions.test.ts +297 -0
- package/Tests/Server/Services/IncidentFormOwnersCreatedNotification.test.ts +497 -0
- package/Tests/Server/Services/IncidentFormPostgres.test.ts +958 -0
- package/Tests/Server/Services/IncidentFormPublicForm.test.ts +1260 -0
- package/Tests/Server/Services/IncidentFormPublicSubmission.test.ts +2520 -0
- package/Tests/Server/Services/IncidentFormRegistration.test.ts +159 -0
- package/Tests/Server/Services/IncidentFormService.test.ts +663 -0
- package/Tests/Server/Services/IncidentFormSubmissionService.test.ts +430 -0
- package/Tests/Server/Services/IncidentFormSubmissionTemplateBranch.test.ts +473 -0
- package/Tests/Server/Services/IncidentGroupingTemplateSubstitution.test.ts +81 -0
- package/Tests/Server/Services/IncidentTemplateCustomFieldSettings.test.ts +262 -0
- package/Tests/Server/Services/IncidentTemplateOwnersOnDeclare.test.ts +566 -0
- package/Tests/Server/Services/IncidentTitleMarkdownSinks.test.ts +640 -0
- package/Tests/Server/Services/LlmLogServiceTokenAggregateParams.test.ts +3 -3
- package/Tests/Server/Services/MessageQueueOwnerServices.test.ts +440 -0
- package/Tests/Server/Services/MessageQueueRegistries.test.ts +577 -0
- package/Tests/Server/Services/MessageQueueRuleEngines.test.ts +900 -0
- package/Tests/Server/Services/MessageQueueService.test.ts +2210 -0
- package/Tests/Server/Services/MessageQueueSqlPostgres.test.ts +1271 -0
- package/Tests/Server/Services/OpenTelemetryResourceRetentionMemo.test.ts +28 -1
- package/Tests/Server/Services/OpenTelemetryRetentionOverrideEdition.test.ts +474 -0
- package/Tests/Server/Services/OpenTelemetryServiceResolutionCache.test.ts +21 -0
- package/Tests/Server/Services/OwnerRowUniqueness.test.ts +3 -0
- package/Tests/Server/Services/ProjectServiceAuditLogLicense.test.ts +0 -1
- package/Tests/Server/Services/RuleRun/LabelRuleEnginesGroupBRun.test.ts +56 -6
- package/Tests/Server/Services/RuleRun/OwnerRuleEnginesGroupBRun.test.ts +30 -1
- package/Tests/Server/Services/SsoRequirementReads.test.ts +454 -0
- package/Tests/Server/Services/SsoRequirementWrites.test.ts +529 -0
- package/Tests/Server/Services/StaticRuleCriteriaRuntimeCoverage.test.ts +3 -3
- package/Tests/Server/Services/StatusPagePrivateUserInvitationPolicy.test.ts +107 -89
- package/Tests/Server/Services/TeamComplianceSettingPostgres.test.ts +1068 -176
- package/Tests/Server/Services/TeamComplianceSettingService.test.ts +1962 -200
- package/Tests/Server/Types/Database/Permissions/EditionPermission.test.ts +654 -297
- package/Tests/Server/Types/Database/Permissions/RetentionOverrideColumns.test.ts +784 -0
- package/Tests/Server/Types/Database/Permissions/SsoScalePlanGate.test.ts +418 -0
- package/Tests/Server/Utils/AI/AIAlertGating.test.ts +0 -1
- package/Tests/Server/Utils/AI/AIInvestigationEngineRunLimits.test.ts +136 -0
- package/Tests/Server/Utils/AI/AIInvestigationQueue.test.ts +15 -14
- package/Tests/Server/Utils/AI/AgentContextCompactor.test.ts +351 -0
- package/Tests/Server/Utils/AI/ChatAgentRunnerSharedThread.test.ts +842 -0
- package/Tests/Server/Utils/AI/ChatRunCancellation.test.ts +195 -0
- package/Tests/Server/Utils/AI/CodeFixReadiness.test.ts +10 -57
- package/Tests/Server/Utils/AI/FixRunBudget.test.ts +20 -24
- package/Tests/Server/Utils/AI/Insights/InvestigationQueueInsightSubject.test.ts +7 -30
- package/Tests/Server/Utils/AI/InvestigationClusterAccessWiring.test.ts +225 -29
- package/Tests/Server/Utils/AI/InvestigationInfrastructureAccessWiring.test.ts +266 -25
- package/Tests/Server/Utils/AI/InvestigationThread.test.ts +580 -0
- package/Tests/Server/Utils/AI/InvestigationThreadService.test.ts +801 -0
- package/Tests/Server/Utils/AI/KubectlInvestigationToolkit.test.ts +525 -43
- package/Tests/Server/Utils/AI/KubectlJobRunner.test.ts +4 -2
- package/Tests/Server/Utils/AI/LLMServiceUnreachableProvider.test.ts +435 -0
- package/Tests/Server/Utils/AI/ObservabilityAssistantLimits.test.ts +462 -0
- package/Tests/Server/Utils/AI/RemediationExecutionRunner.test.ts +14 -25
- package/Tests/Server/Utils/AI/RemediationExecutionRunnerResourceMode.test.ts +2 -0
- package/Tests/Server/Utils/AI/ResourceAccess/InfrastructureInvestigationToolkit.test.ts +297 -15
- package/Tests/Server/Utils/AI/ResourceAccess/ResourceCommandJobRunner.test.ts +10 -6
- package/Tests/Server/Utils/AI/ToolOutputPager.test.ts +382 -0
- package/Tests/Server/Utils/AI/ToolResultSerializer.test.ts +23 -4
- package/Tests/Server/Utils/AI/Toolbox/LogTools.test.ts +25 -6
- package/Tests/Server/Utils/AI/Toolbox/Serializer.test.ts +14 -3
- package/Tests/Server/Utils/EditionEnforcement.test.ts +107 -147
- package/Tests/Server/Utils/{CommunityEditionSsoReport.test.ts → RelaxedScimTeamLocksReport.test.ts} +212 -208
- package/Tests/Server/Utils/SameOriginRequest.test.ts +372 -0
- package/Tests/Server/Utils/Telemetry/EntityRegistry.test.ts +20 -0
- package/Tests/Server/Utils/Telemetry/MessageQueueDiscovery.test.ts +2590 -0
- package/Tests/Server/Utils/Telemetry/MessageQueueSpanQueryTwin.ts +246 -0
- package/Tests/Server/Utils/Telemetry/TelemetryEntity.test.ts +23 -0
- package/Tests/Types/AI/AIAgentRunLimits.test.ts +255 -0
- package/Tests/Types/Code/JsonSyntax.test.ts +1300 -0
- package/Tests/Types/CustomField/CustomFieldCreateSettings.test.ts +1113 -0
- package/Tests/Types/CustomField/CustomFieldMappingCatalog.test.ts +91 -0
- package/Tests/Types/CustomField/CustomFieldValueValidator.test.ts +30 -0
- package/Tests/Types/Incident/IncidentFormIpAllowlist.test.ts +227 -0
- package/Tests/Types/Incident/IncidentFormPublic.test.ts +1916 -0
- package/Tests/Types/MessageQueue/MessageQueueEntityKey.test.ts +916 -0
- package/Tests/Types/MessageQueue/MessageQueueIdentity.test.ts +567 -0
- package/Tests/Types/MessageQueue/MessageQueueManualIdentity.test.ts +686 -0
- package/Tests/Types/MessageQueue/MessageQueueMetricCatalog.test.ts +1726 -0
- package/Tests/Types/MessageQueue/MessageQueueMetricResolution.test.ts +1758 -0
- package/Tests/Types/MessageQueue/MessagingInstrumentationFixtures.test.ts +4686 -0
- package/Tests/Types/MessageQueue/MessagingSystem.test.ts +840 -0
- package/Tests/Types/MessageQueue/MessagingTelemetryFixtures.ts +3287 -0
- package/Tests/Types/MessageQueue/MessagingTelemetryResolver.test.ts +2966 -0
- package/Tests/Types/Monitor/MessageQueueAlertTemplates.test.ts +5401 -0
- package/Tests/Types/Monitor/MetricEngineFold.ts +154 -0
- package/Tests/Types/ResourceAiAgent/ResourceAiAccess.test.ts +5 -3
- package/Tests/Types/Team/ComplianceRule.test.ts +588 -37
- package/Tests/Types/Team/TeamComplianceStatus.test.ts +64 -11
- package/Tests/Types/XML.test.ts +51 -0
- package/Tests/UI/Components/CodeEditor/CodeEditor.test.tsx +2362 -0
- package/Tests/UI/Components/CodeEditor/CodeEditorCommands.test.ts +810 -0
- package/Tests/UI/Components/CodeEditor/CodeEditorHighlight.test.ts +338 -0
- package/Tests/UI/Components/CodeEditor/CodeEditorLanguages.test.ts +222 -0
- package/Tests/UI/Components/CodeEditor/CodeEditorStyles.test.ts +807 -0
- package/Tests/UI/Components/CodeEditor/NoMonaco.test.ts +245 -0
- package/Tests/UI/Components/CodeEditor/YamlEditor.test.tsx +729 -0
- package/Tests/UI/Components/CopyTextButton.test.tsx +76 -0
- package/Tests/UI/Components/EditionLabelLapseCopy.ts +51 -14
- package/Tests/UI/Components/EditionLabelLicenseStatus.test.tsx +131 -23
- package/Tests/UI/Components/ErrorMessageAction.test.tsx +142 -0
- package/Tests/UI/Components/FacetSidebarInScope.test.tsx +459 -0
- package/Tests/UI/Components/FacetValuesInScope.test.ts +270 -0
- package/Tests/UI/Components/Forms/FormFieldCodeEditors.test.tsx +294 -0
- package/Tests/UI/Components/Forms/FormFieldMarkdown.test.tsx +126 -0
- package/Tests/UI/Components/Forms/FormFieldYaml.test.tsx +22 -75
- package/Tests/UI/Components/Forms/ModelFormOnBeforeCreateMiscData.test.tsx +254 -0
- package/Tests/UI/Components/Icon.test.tsx +32 -0
- package/Tests/UI/Components/Input.test.tsx +31 -0
- package/Tests/UI/Components/LockedFilterChipScope.test.tsx +501 -0
- package/Tests/UI/Components/MarkdownConverters.test.ts +253 -1
- package/Tests/UI/Components/MarkdownEditor.test.tsx +2785 -2
- package/Tests/UI/Components/MarkdownEditorHistory.test.ts +243 -0
- package/Tests/UI/Components/MarkdownListEditing.test.ts +1118 -0
- package/Tests/UI/Components/MarkdownPaste.test.ts +1180 -0
- package/Tests/UI/Components/MarkdownViewerCopy.test.tsx +466 -0
- package/Tests/UI/Components/MarkdownVisualEditing.test.ts +1089 -0
- package/Tests/UI/Components/ModelTable/BaseModelTableEmptyStateAction.test.tsx +623 -0
- package/Tests/UI/Components/ResetObjectID.test.tsx +282 -0
- package/Tests/UI/Components/RuleCriteria/RuleCriteriaModelTable.test.tsx +3 -3
- package/Tests/UI/Components/Table/EmptyTableMessage.test.ts +439 -0
- package/Tests/UI/Components/Table/TableEmptyState.test.tsx +352 -0
- package/Tests/UI/Components/TableRowMobileTitles.test.tsx +78 -0
- package/Tests/UI/Components/TextArea.test.tsx +19 -0
- package/Tests/UI/Components/Workflow/ModelColumnEditor.render.test.tsx +12 -29
- package/Tests/UI/Components/fixtures/MarkdownPasteFixtures.ts +460 -0
- package/Tests/UI/EsbuildConfig.test.ts +115 -39
- package/Tests/UI/EsbuildEnterpriseAlias.test.ts +4 -4
- package/Tests/UI/Monitor/MonitorLogSummaryRender.test.tsx +377 -0
- package/Tests/UI/Utils/Breadcrumb/fixtures/RealBreadcrumbTrails.ts +81 -1
- package/Tests/UI/Utils/Breadcrumb/fixtures/RealRoutePatterns.ts +17 -0
- package/Tests/Utils/LabelRuleImportExport.test.ts +5 -0
- package/Tests/Utils/Markdown/DashboardMarkdownRenderer.ts +81 -0
- package/Tests/Utils/Markdown/UntrustedMarkdown.test.ts +1339 -0
- package/Tests/Utils/Monitor/MonitorLogSummaryUtil.test.ts +862 -0
- package/Types/AI/AIAgentRunLimits.ts +146 -0
- package/Types/Code/CodeType.ts +2 -0
- package/Types/Code/JsonSyntax.ts +923 -0
- package/Types/CustomField/CustomFieldCreateSettings.ts +549 -0
- package/Types/CustomField/CustomFieldMappingCatalog.ts +77 -0
- package/Types/CustomField/CustomFieldValueValidator.ts +10 -7
- package/Types/EnterpriseLicense/EnterpriseLicensePeriods.ts +1 -1
- package/Types/Icon/IconProp.ts +2 -0
- package/Types/Incident/IncidentFormIpAllowlist.ts +206 -0
- package/Types/Incident/IncidentFormPublic.ts +1145 -0
- package/Types/Kubernetes/KubernetesClusterAiAccess.ts +10 -3
- package/Types/MessageQueue/MessageQueueIdentity.ts +256 -0
- package/Types/MessageQueue/MessageQueueManualIdentity.ts +325 -0
- package/Types/MessageQueue/MessageQueueMetricCatalog.ts +1357 -0
- package/Types/MessageQueue/MessagingSystem.ts +518 -0
- package/Types/MessageQueue/MessagingTelemetryResolver.ts +2311 -0
- package/Types/Monitor/MessageQueueAlertTemplates.ts +2128 -0
- package/Types/Permission.ts +310 -0
- package/Types/ResourceAiAgent/ResourceAiAccess.ts +10 -4
- package/Types/Rules/RuleCriteriaFieldRegistry.ts +12 -0
- package/Types/Rules/RuleRun.ts +4 -0
- package/Types/Team/ComplianceNotificationChannel.ts +4 -3
- package/Types/Team/ComplianceRule.ts +71 -18
- package/Types/Team/ComplianceRuleType.ts +2 -2
- package/Types/Team/TeamComplianceStatus.ts +6 -2
- package/Types/Telemetry/EntityType.ts +16 -0
- package/Types/Telemetry/LockedFilterDetail.ts +22 -0
- package/Types/XML.ts +26 -0
- package/UI/Components/CodeEditor/CodeEditor.css +379 -0
- package/UI/Components/CodeEditor/CodeEditor.tsx +1128 -294
- package/UI/Components/CodeEditor/CodeEditorCommands.ts +774 -0
- package/UI/Components/CodeEditor/CodeEditorHighlight.ts +106 -0
- package/UI/Components/CodeEditor/CodeEditorLanguages.ts +164 -0
- package/UI/Components/CodeEditor/YamlEditor.tsx +28 -326
- package/UI/Components/CopyTextButton/CopyTextButton.tsx +5 -1
- package/UI/Components/CustomFields/CustomFieldModelFormFields.tsx +6 -25
- package/UI/Components/EditionLabel/EditionLabel.tsx +14 -13
- package/UI/Components/ErrorMessage/ErrorMessage.tsx +11 -1
- package/UI/Components/Forms/Fields/FormField.tsx +8 -0
- package/UI/Components/Forms/Types/Field.ts +8 -0
- package/UI/Components/Icon/Icon.tsx +18 -0
- package/UI/Components/Input/Input.tsx +11 -4
- package/UI/Components/LogsViewer/LogsViewer.tsx +4 -0
- package/UI/Components/LogsViewer/components/LogsFacetSidebar.tsx +21 -3
- package/UI/Components/Markdown.tsx/MarkdownConverters.ts +0 -0
- package/UI/Components/Markdown.tsx/MarkdownEditor.tsx +877 -79
- package/UI/Components/Markdown.tsx/MarkdownEditorHistory.ts +284 -0
- package/UI/Components/Markdown.tsx/MarkdownListEditing.ts +1362 -0
- package/UI/Components/Markdown.tsx/MarkdownPaste.ts +1326 -0
- package/UI/Components/Markdown.tsx/MarkdownViewer.tsx +106 -10
- package/UI/Components/Markdown.tsx/MarkdownVisualEditing.ts +1032 -0
- package/UI/Components/ModelTable/BaseModelTable.tsx +85 -7
- package/UI/Components/ResetObjectID/ResetObjectID.tsx +35 -9
- package/UI/Components/Table/EmptyTableMessage.ts +81 -0
- package/UI/Components/Table/Table.tsx +50 -21
- package/UI/Components/Table/TableRow.tsx +9 -1
- package/UI/Components/TelemetryViewer/FacetVisibility.ts +97 -2
- package/UI/Components/TelemetryViewer/TelemetryViewer.tsx +13 -0
- package/UI/Components/TelemetryViewer/components/LockedFilterChip.tsx +214 -7
- package/UI/Components/TelemetryViewer/components/TelemetryFacetSidebar.tsx +21 -3
- package/UI/Components/TextArea/TextArea.tsx +9 -2
- package/UI/Components/Workflow/ModelFieldPicker.tsx +10 -12
- package/UI/Styles/Theme.css +8 -0
- package/UI/esbuild-config.js +2 -32
- package/Utils/LabelRuleImportExport.ts +2 -0
- package/Utils/Markdown/UntrustedMarkdown.ts +1513 -0
- package/Utils/Monitor/IncomingEmailMonitorRequestUtil.ts +41 -0
- package/Utils/Monitor/MonitorLogSummaryUtil.ts +212 -0
- package/Utils/Telemetry/EntityKey.ts +48 -0
- package/build/dist/Models/DatabaseModels/AIConversation.js +125 -1
- package/build/dist/Models/DatabaseModels/AIConversation.js.map +1 -1
- package/build/dist/Models/DatabaseModels/CephCluster.js +12 -0
- package/build/dist/Models/DatabaseModels/CephCluster.js.map +1 -1
- package/build/dist/Models/DatabaseModels/CloudResource.js +12 -0
- package/build/dist/Models/DatabaseModels/CloudResource.js.map +1 -1
- package/build/dist/Models/DatabaseModels/DatabaseServer.js +12 -0
- package/build/dist/Models/DatabaseModels/DatabaseServer.js.map +1 -1
- package/build/dist/Models/DatabaseModels/DockerHost.js +12 -0
- package/build/dist/Models/DatabaseModels/DockerHost.js.map +1 -1
- package/build/dist/Models/DatabaseModels/DockerSwarmCluster.js +12 -0
- package/build/dist/Models/DatabaseModels/DockerSwarmCluster.js.map +1 -1
- package/build/dist/Models/DatabaseModels/GlobalOidc.js +0 -4
- package/build/dist/Models/DatabaseModels/GlobalOidc.js.map +1 -1
- package/build/dist/Models/DatabaseModels/GlobalOidcProject.js +0 -4
- package/build/dist/Models/DatabaseModels/GlobalOidcProject.js.map +1 -1
- package/build/dist/Models/DatabaseModels/GlobalSso.js +0 -4
- package/build/dist/Models/DatabaseModels/GlobalSso.js.map +1 -1
- package/build/dist/Models/DatabaseModels/GlobalSsoProject.js +0 -4
- package/build/dist/Models/DatabaseModels/GlobalSsoProject.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Host.js +12 -0
- package/build/dist/Models/DatabaseModels/Host.js.map +1 -1
- package/build/dist/Models/DatabaseModels/IncidentForm.js +605 -0
- package/build/dist/Models/DatabaseModels/IncidentForm.js.map +1 -0
- package/build/dist/Models/DatabaseModels/IncidentFormSubmission.js +299 -0
- package/build/dist/Models/DatabaseModels/IncidentFormSubmission.js.map +1 -0
- package/build/dist/Models/DatabaseModels/IncidentTemplate.js +60 -0
- package/build/dist/Models/DatabaseModels/IncidentTemplate.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Index.js +14 -0
- package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
- package/build/dist/Models/DatabaseModels/IoTFleet.js +12 -0
- package/build/dist/Models/DatabaseModels/IoTFleet.js.map +1 -1
- package/build/dist/Models/DatabaseModels/KubernetesCluster.js +12 -0
- package/build/dist/Models/DatabaseModels/KubernetesCluster.js.map +1 -1
- package/build/dist/Models/DatabaseModels/MessageQueue.js +1106 -0
- package/build/dist/Models/DatabaseModels/MessageQueue.js.map +1 -0
- package/build/dist/Models/DatabaseModels/MessageQueueLabelRule.js +562 -0
- package/build/dist/Models/DatabaseModels/MessageQueueLabelRule.js.map +1 -0
- package/build/dist/Models/DatabaseModels/MessageQueueOwnerRule.js +643 -0
- package/build/dist/Models/DatabaseModels/MessageQueueOwnerRule.js.map +1 -0
- package/build/dist/Models/DatabaseModels/MessageQueueOwnerTeam.js +506 -0
- package/build/dist/Models/DatabaseModels/MessageQueueOwnerTeam.js.map +1 -0
- package/build/dist/Models/DatabaseModels/MessageQueueOwnerUser.js +505 -0
- package/build/dist/Models/DatabaseModels/MessageQueueOwnerUser.js.map +1 -0
- package/build/dist/Models/DatabaseModels/PodmanHost.js +12 -0
- package/build/dist/Models/DatabaseModels/PodmanHost.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Project.js +61 -0
- package/build/dist/Models/DatabaseModels/Project.js.map +1 -1
- package/build/dist/Models/DatabaseModels/ProjectOidc.js +0 -4
- package/build/dist/Models/DatabaseModels/ProjectOidc.js.map +1 -1
- package/build/dist/Models/DatabaseModels/ProjectSso.js +0 -4
- package/build/dist/Models/DatabaseModels/ProjectSso.js.map +1 -1
- package/build/dist/Models/DatabaseModels/ProxmoxCluster.js +12 -0
- package/build/dist/Models/DatabaseModels/ProxmoxCluster.js.map +1 -1
- package/build/dist/Models/DatabaseModels/RumApplication.js +12 -0
- package/build/dist/Models/DatabaseModels/RumApplication.js.map +1 -1
- package/build/dist/Models/DatabaseModels/ServerlessFunction.js +12 -0
- package/build/dist/Models/DatabaseModels/ServerlessFunction.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Service.js +12 -0
- package/build/dist/Models/DatabaseModels/Service.js.map +1 -1
- package/build/dist/Models/DatabaseModels/StatusPageOidc.js +0 -4
- package/build/dist/Models/DatabaseModels/StatusPageOidc.js.map +1 -1
- package/build/dist/Models/DatabaseModels/StatusPageSso.js +0 -4
- package/build/dist/Models/DatabaseModels/StatusPageSso.js.map +1 -1
- package/build/dist/Models/DatabaseModels/TeamComplianceSetting.js +49 -3
- package/build/dist/Models/DatabaseModels/TeamComplianceSetting.js.map +1 -1
- package/build/dist/Models/DatabaseModels/VMwareVCenter.js +12 -0
- package/build/dist/Models/DatabaseModels/VMwareVCenter.js.map +1 -1
- package/build/dist/Server/API/AIChatAPI.js +9 -103
- package/build/dist/Server/API/AIChatAPI.js.map +1 -1
- package/build/dist/Server/API/AIInvestigationAPI.js +3 -3
- package/build/dist/Server/API/AIInvestigationAPI.js.map +1 -1
- package/build/dist/Server/API/AIInvestigationConversationAPI.js +162 -0
- package/build/dist/Server/API/AIInvestigationConversationAPI.js.map +1 -0
- package/build/dist/Server/API/IncidentFormAPI.js +245 -0
- package/build/dist/Server/API/IncidentFormAPI.js.map +1 -0
- package/build/dist/Server/API/ProjectOIDC.js +16 -24
- package/build/dist/Server/API/ProjectOIDC.js.map +1 -1
- package/build/dist/Server/API/ProjectSSO.js +16 -24
- package/build/dist/Server/API/ProjectSSO.js.map +1 -1
- package/build/dist/Server/API/StatusPageAPI.js +42 -75
- package/build/dist/Server/API/StatusPageAPI.js.map +1 -1
- package/build/dist/Server/Enterprise/EnterpriseEdition.js +79 -25
- package/build/dist/Server/Enterprise/EnterpriseEdition.js.map +1 -1
- package/build/dist/Server/Enterprise/EnterpriseFeature.js +24 -3
- package/build/dist/Server/Enterprise/EnterpriseFeature.js.map +1 -1
- package/build/dist/Server/Enterprise/EnterpriseLicenseSnapshot.js +1 -1
- package/build/dist/Server/Enterprise/EnterpriseServerModule.js.map +1 -1
- package/build/dist/Server/EnvironmentConfig.js +1 -1
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1796400000000-AddIncidentForms.js +63 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1796400000000-AddIncidentForms.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1796500000000-AddTeamComplianceRuleNotificationChannels.js +41 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1796500000000-AddTeamComplianceRuleNotificationChannels.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1796600000000-AddAIInvestigationConversationAndTimeLimits.js +40 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1796600000000-AddAIInvestigationConversationAndTimeLimits.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1796700000000-AddMessageQueueTables.js +183 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1796700000000-AddMessageQueueTables.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +8 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
- package/build/dist/Server/Middleware/IncidentFormRateLimit.js +559 -0
- package/build/dist/Server/Middleware/IncidentFormRateLimit.js.map +1 -0
- package/build/dist/Server/Middleware/UserAuthorization.js +11 -30
- package/build/dist/Server/Middleware/UserAuthorization.js.map +1 -1
- package/build/dist/Server/Services/AIService.js +10 -13
- package/build/dist/Server/Services/AIService.js.map +1 -1
- package/build/dist/Server/Services/IncidentCustomFieldService.js +83 -0
- package/build/dist/Server/Services/IncidentCustomFieldService.js.map +1 -1
- package/build/dist/Server/Services/IncidentEpisodeMemberService.js +8 -4
- package/build/dist/Server/Services/IncidentEpisodeMemberService.js.map +1 -1
- package/build/dist/Server/Services/IncidentEpisodeService.js +10 -1
- package/build/dist/Server/Services/IncidentEpisodeService.js.map +1 -1
- package/build/dist/Server/Services/IncidentFormService.js +1202 -0
- package/build/dist/Server/Services/IncidentFormService.js.map +1 -0
- package/build/dist/Server/Services/IncidentFormSubmissionService.js +91 -0
- package/build/dist/Server/Services/IncidentFormSubmissionService.js.map +1 -0
- package/build/dist/Server/Services/IncidentGroupingEngineService.js +20 -8
- package/build/dist/Server/Services/IncidentGroupingEngineService.js.map +1 -1
- package/build/dist/Server/Services/IncidentService.js +106 -4
- package/build/dist/Server/Services/IncidentService.js.map +1 -1
- package/build/dist/Server/Services/IncidentTemplateService.js +18 -0
- package/build/dist/Server/Services/IncidentTemplateService.js.map +1 -1
- package/build/dist/Server/Services/Index.js +14 -0
- package/build/dist/Server/Services/Index.js.map +1 -1
- package/build/dist/Server/Services/MessageQueueLabelRuleEngineService.js +262 -0
- package/build/dist/Server/Services/MessageQueueLabelRuleEngineService.js.map +1 -0
- package/build/dist/Server/Services/MessageQueueLabelRuleService.js +13 -0
- package/build/dist/Server/Services/MessageQueueLabelRuleService.js.map +1 -0
- package/build/dist/Server/Services/MessageQueueOwnerRuleEngineService.js +334 -0
- package/build/dist/Server/Services/MessageQueueOwnerRuleEngineService.js.map +1 -0
- package/build/dist/Server/Services/MessageQueueOwnerRuleService.js +13 -0
- package/build/dist/Server/Services/MessageQueueOwnerRuleService.js.map +1 -0
- package/build/dist/Server/Services/MessageQueueOwnerTeamService.js +62 -0
- package/build/dist/Server/Services/MessageQueueOwnerTeamService.js.map +1 -0
- package/build/dist/Server/Services/MessageQueueOwnerUserService.js +62 -0
- package/build/dist/Server/Services/MessageQueueOwnerUserService.js.map +1 -0
- package/build/dist/Server/Services/MessageQueueService.js +1140 -0
- package/build/dist/Server/Services/MessageQueueService.js.map +1 -0
- package/build/dist/Server/Services/OpenTelemetryIngestService.js +25 -4
- package/build/dist/Server/Services/OpenTelemetryIngestService.js.map +1 -1
- package/build/dist/Server/Services/ProjectService.js +0 -54
- package/build/dist/Server/Services/ProjectService.js.map +1 -1
- package/build/dist/Server/Services/StatusPagePrivateUserService.js +1 -4
- package/build/dist/Server/Services/StatusPagePrivateUserService.js.map +1 -1
- package/build/dist/Server/Services/StatusPageService.js +0 -46
- package/build/dist/Server/Services/StatusPageService.js.map +1 -1
- package/build/dist/Server/Services/TeamComplianceSettingService.js +120 -31
- package/build/dist/Server/Services/TeamComplianceSettingService.js.map +1 -1
- package/build/dist/Server/Services/UserNotificationRuleService.js +8 -1
- package/build/dist/Server/Services/UserNotificationRuleService.js.map +1 -1
- package/build/dist/Server/Services/WorkspaceNotificationSummaryService.js +12 -3
- package/build/dist/Server/Services/WorkspaceNotificationSummaryService.js.map +1 -1
- package/build/dist/Server/Types/Database/Permissions/CreatePermission.js +6 -3
- package/build/dist/Server/Types/Database/Permissions/CreatePermission.js.map +1 -1
- package/build/dist/Server/Types/Database/Permissions/EditionPermission.js +109 -37
- package/build/dist/Server/Types/Database/Permissions/EditionPermission.js.map +1 -1
- package/build/dist/Server/Types/Database/Permissions/OwnerTableRegistry.js +16 -0
- package/build/dist/Server/Types/Database/Permissions/OwnerTableRegistry.js.map +1 -1
- package/build/dist/Server/Types/Database/Permissions/TablePermission.js +3 -3
- package/build/dist/Server/Types/Database/Permissions/UpdatePermission.js +9 -6
- package/build/dist/Server/Types/Database/Permissions/UpdatePermission.js.map +1 -1
- package/build/dist/Server/Utils/AI/Chat/AgentContextCompactor.js +128 -0
- package/build/dist/Server/Utils/AI/Chat/AgentContextCompactor.js.map +1 -0
- package/build/dist/Server/Utils/AI/Chat/ChatAgentRunner.js +192 -50
- package/build/dist/Server/Utils/AI/Chat/ChatAgentRunner.js.map +1 -1
- package/build/dist/Server/Utils/AI/Chat/ChatRunCancellation.js +133 -0
- package/build/dist/Server/Utils/AI/Chat/ChatRunCancellation.js.map +1 -0
- package/build/dist/Server/Utils/AI/Chat/ObservabilityAssistant.js +53 -13
- package/build/dist/Server/Utils/AI/Chat/ObservabilityAssistant.js.map +1 -1
- package/build/dist/Server/Utils/AI/Chat/ObservabilityChatPrompt.js +1 -1
- package/build/dist/Server/Utils/AI/Chat/ToolOutputPager.js +206 -0
- package/build/dist/Server/Utils/AI/Chat/ToolOutputPager.js.map +1 -0
- package/build/dist/Server/Utils/AI/ClusterAccess/KubectlInvestigationToolkit.js +53 -26
- package/build/dist/Server/Utils/AI/ClusterAccess/KubectlInvestigationToolkit.js.map +1 -1
- package/build/dist/Server/Utils/AI/ClusterAccess/KubectlJobRunner.js +4 -2
- package/build/dist/Server/Utils/AI/ClusterAccess/KubectlJobRunner.js.map +1 -1
- package/build/dist/Server/Utils/AI/CodeFix/CodeFixReadiness.js +1 -29
- package/build/dist/Server/Utils/AI/CodeFix/CodeFixReadiness.js.map +1 -1
- package/build/dist/Server/Utils/AI/CodeFix/FixRunBudget.js +24 -24
- package/build/dist/Server/Utils/AI/CodeFix/FixRunBudget.js.map +1 -1
- package/build/dist/Server/Utils/AI/Remediation/RemediationCommandTools.js +7 -2
- package/build/dist/Server/Utils/AI/Remediation/RemediationCommandTools.js.map +1 -1
- package/build/dist/Server/Utils/AI/Remediation/RemediationExecutionRunner.js +29 -14
- package/build/dist/Server/Utils/AI/Remediation/RemediationExecutionRunner.js.map +1 -1
- package/build/dist/Server/Utils/AI/ResourceAccess/InfrastructureInvestigationToolkit.js +38 -14
- package/build/dist/Server/Utils/AI/ResourceAccess/InfrastructureInvestigationToolkit.js.map +1 -1
- package/build/dist/Server/Utils/AI/ResourceAccess/ResourceCommandJobRunner.js +2 -0
- package/build/dist/Server/Utils/AI/ResourceAccess/ResourceCommandJobRunner.js.map +1 -1
- package/build/dist/Server/Utils/AI/SRE/AIInvestigationEngine.js +40 -10
- package/build/dist/Server/Utils/AI/SRE/AIInvestigationEngine.js.map +1 -1
- package/build/dist/Server/Utils/AI/SRE/AlertInvestigationRunner.js +19 -7
- package/build/dist/Server/Utils/AI/SRE/AlertInvestigationRunner.js.map +1 -1
- package/build/dist/Server/Utils/AI/SRE/IncidentInvestigationRunner.js +19 -7
- package/build/dist/Server/Utils/AI/SRE/IncidentInvestigationRunner.js.map +1 -1
- package/build/dist/Server/Utils/AI/SRE/InvestigationQueue.js +15 -18
- package/build/dist/Server/Utils/AI/SRE/InvestigationQueue.js.map +1 -1
- package/build/dist/Server/Utils/AI/SRE/InvestigationThread.js +412 -0
- package/build/dist/Server/Utils/AI/SRE/InvestigationThread.js.map +1 -0
- package/build/dist/Server/Utils/AI/SRE/InvestigationThreadService.js +495 -0
- package/build/dist/Server/Utils/AI/SRE/InvestigationThreadService.js.map +1 -0
- package/build/dist/Server/Utils/AI/Toolbox/Serializer.js +10 -3
- package/build/dist/Server/Utils/AI/Toolbox/Serializer.js.map +1 -1
- package/build/dist/Server/Utils/EditionEnforcement.js +20 -158
- package/build/dist/Server/Utils/EditionEnforcement.js.map +1 -1
- package/build/dist/Server/Utils/LLM/LLMService.js +193 -54
- package/build/dist/Server/Utils/LLM/LLMService.js.map +1 -1
- package/build/dist/Server/Utils/RelaxedScimTeamLocksReport.js +160 -0
- package/build/dist/Server/Utils/RelaxedScimTeamLocksReport.js.map +1 -0
- package/build/dist/Server/Utils/Rules/RuleRun/RuleRunRegistry.js +25 -0
- package/build/dist/Server/Utils/Rules/RuleRun/RuleRunRegistry.js.map +1 -1
- package/build/dist/Server/Utils/SameOriginRequest.js +151 -0
- package/build/dist/Server/Utils/SameOriginRequest.js.map +1 -0
- package/build/dist/Server/Utils/TeamMember/ProjectLeaveResourceCleanup.js +2 -0
- package/build/dist/Server/Utils/TeamMember/ProjectLeaveResourceCleanup.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/EntityRegistry.js +4 -1
- package/build/dist/Server/Utils/Telemetry/EntityRegistry.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/MessageQueueDiscovery.js +1015 -0
- package/build/dist/Server/Utils/Telemetry/MessageQueueDiscovery.js.map +1 -0
- package/build/dist/Server/Utils/Telemetry/ResourceEntityFilter.js +4 -1
- package/build/dist/Server/Utils/Telemetry/ResourceEntityFilter.js.map +1 -1
- package/build/dist/Server/Utils/VendorAssets.js +3 -3
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/Incident.js +3 -1
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/Incident.js.map +1 -1
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/IncidentEpisode.js +3 -1
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/IncidentEpisode.js.map +1 -1
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js +10 -1
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js.map +1 -1
- package/build/dist/Types/AI/AIAgentRunLimits.js +91 -0
- package/build/dist/Types/AI/AIAgentRunLimits.js.map +1 -0
- package/build/dist/Types/Code/CodeType.js +2 -0
- package/build/dist/Types/Code/CodeType.js.map +1 -1
- package/build/dist/Types/Code/JsonSyntax.js +604 -0
- package/build/dist/Types/Code/JsonSyntax.js.map +1 -0
- package/build/dist/Types/CustomField/CustomFieldCreateSettings.js +310 -0
- package/build/dist/Types/CustomField/CustomFieldCreateSettings.js.map +1 -0
- package/build/dist/Types/CustomField/CustomFieldMappingCatalog.js +38 -0
- package/build/dist/Types/CustomField/CustomFieldMappingCatalog.js.map +1 -1
- package/build/dist/Types/CustomField/CustomFieldValueValidator.js +10 -7
- package/build/dist/Types/CustomField/CustomFieldValueValidator.js.map +1 -1
- package/build/dist/Types/EnterpriseLicense/EnterpriseLicensePeriods.js +1 -1
- package/build/dist/Types/Icon/IconProp.js +2 -0
- package/build/dist/Types/Icon/IconProp.js.map +1 -1
- package/build/dist/Types/Incident/IncidentFormIpAllowlist.js +119 -0
- package/build/dist/Types/Incident/IncidentFormIpAllowlist.js.map +1 -0
- package/build/dist/Types/Incident/IncidentFormPublic.js +678 -0
- package/build/dist/Types/Incident/IncidentFormPublic.js.map +1 -0
- package/build/dist/Types/Kubernetes/KubernetesClusterAiAccess.js +10 -3
- package/build/dist/Types/Kubernetes/KubernetesClusterAiAccess.js.map +1 -1
- package/build/dist/Types/MessageQueue/MessageQueueIdentity.js +184 -0
- package/build/dist/Types/MessageQueue/MessageQueueIdentity.js.map +1 -0
- package/build/dist/Types/MessageQueue/MessageQueueManualIdentity.js +190 -0
- package/build/dist/Types/MessageQueue/MessageQueueManualIdentity.js.map +1 -0
- package/build/dist/Types/MessageQueue/MessageQueueMetricCatalog.js +1057 -0
- package/build/dist/Types/MessageQueue/MessageQueueMetricCatalog.js.map +1 -0
- package/build/dist/Types/MessageQueue/MessagingSystem.js +394 -0
- package/build/dist/Types/MessageQueue/MessagingSystem.js.map +1 -0
- package/build/dist/Types/MessageQueue/MessagingTelemetryResolver.js +1768 -0
- package/build/dist/Types/MessageQueue/MessagingTelemetryResolver.js.map +1 -0
- package/build/dist/Types/Monitor/MessageQueueAlertTemplates.js +1207 -0
- package/build/dist/Types/Monitor/MessageQueueAlertTemplates.js.map +1 -0
- package/build/dist/Types/Permission.js +274 -0
- package/build/dist/Types/Permission.js.map +1 -1
- package/build/dist/Types/ResourceAiAgent/ResourceAiAccess.js +10 -4
- package/build/dist/Types/ResourceAiAgent/ResourceAiAccess.js.map +1 -1
- package/build/dist/Types/Rules/RuleCriteriaFieldRegistry.js +12 -0
- package/build/dist/Types/Rules/RuleCriteriaFieldRegistry.js.map +1 -1
- package/build/dist/Types/Rules/RuleRun.js +4 -0
- package/build/dist/Types/Rules/RuleRun.js.map +1 -1
- package/build/dist/Types/Team/ComplianceNotificationChannel.js +4 -3
- package/build/dist/Types/Team/ComplianceNotificationChannel.js.map +1 -1
- package/build/dist/Types/Team/ComplianceRule.js +48 -14
- package/build/dist/Types/Team/ComplianceRule.js.map +1 -1
- package/build/dist/Types/Team/ComplianceRuleType.js +2 -2
- package/build/dist/Types/Telemetry/EntityType.js +16 -0
- package/build/dist/Types/Telemetry/EntityType.js.map +1 -1
- package/build/dist/Types/XML.js +23 -0
- package/build/dist/Types/XML.js.map +1 -1
- package/build/dist/UI/Components/CodeEditor/CodeEditor.js +641 -266
- package/build/dist/UI/Components/CodeEditor/CodeEditor.js.map +1 -1
- package/build/dist/UI/Components/CodeEditor/CodeEditorCommands.js +464 -0
- package/build/dist/UI/Components/CodeEditor/CodeEditorCommands.js.map +1 -0
- package/build/dist/UI/Components/CodeEditor/CodeEditorHighlight.js +69 -0
- package/build/dist/UI/Components/CodeEditor/CodeEditorHighlight.js.map +1 -0
- package/build/dist/UI/Components/CodeEditor/CodeEditorLanguages.js +108 -0
- package/build/dist/UI/Components/CodeEditor/CodeEditorLanguages.js.map +1 -0
- package/build/dist/UI/Components/CodeEditor/YamlEditor.js +14 -186
- package/build/dist/UI/Components/CodeEditor/YamlEditor.js.map +1 -1
- package/build/dist/UI/Components/CopyTextButton/CopyTextButton.js +5 -1
- package/build/dist/UI/Components/CopyTextButton/CopyTextButton.js.map +1 -1
- package/build/dist/UI/Components/CustomFields/CustomFieldModelFormFields.js +5 -14
- package/build/dist/UI/Components/CustomFields/CustomFieldModelFormFields.js.map +1 -1
- package/build/dist/UI/Components/EditionLabel/EditionLabel.js +14 -13
- package/build/dist/UI/Components/EditionLabel/EditionLabel.js.map +1 -1
- package/build/dist/UI/Components/ErrorMessage/ErrorMessage.js +1 -1
- package/build/dist/UI/Components/ErrorMessage/ErrorMessage.js.map +1 -1
- package/build/dist/UI/Components/Forms/Fields/FormField.js +8 -3
- package/build/dist/UI/Components/Forms/Fields/FormField.js.map +1 -1
- package/build/dist/UI/Components/Icon/Icon.js +8 -0
- package/build/dist/UI/Components/Icon/Icon.js.map +1 -1
- package/build/dist/UI/Components/Input/Input.js +11 -3
- package/build/dist/UI/Components/Input/Input.js.map +1 -1
- package/build/dist/UI/Components/LogsViewer/LogsViewer.js +2 -1
- package/build/dist/UI/Components/LogsViewer/LogsViewer.js.map +1 -1
- package/build/dist/UI/Components/LogsViewer/components/LogsFacetSidebar.js +14 -4
- package/build/dist/UI/Components/LogsViewer/components/LogsFacetSidebar.js.map +1 -1
- package/build/dist/UI/Components/Markdown.tsx/MarkdownConverters.js +0 -0
- package/build/dist/UI/Components/Markdown.tsx/MarkdownConverters.js.map +1 -1
- package/build/dist/UI/Components/Markdown.tsx/MarkdownEditor.js +710 -65
- package/build/dist/UI/Components/Markdown.tsx/MarkdownEditor.js.map +1 -1
- package/build/dist/UI/Components/Markdown.tsx/MarkdownEditorHistory.js +238 -0
- package/build/dist/UI/Components/Markdown.tsx/MarkdownEditorHistory.js.map +1 -0
- package/build/dist/UI/Components/Markdown.tsx/MarkdownListEditing.js +1028 -0
- package/build/dist/UI/Components/Markdown.tsx/MarkdownListEditing.js.map +1 -0
- package/build/dist/UI/Components/Markdown.tsx/MarkdownPaste.js +1088 -0
- package/build/dist/UI/Components/Markdown.tsx/MarkdownPaste.js.map +1 -0
- package/build/dist/UI/Components/Markdown.tsx/MarkdownViewer.js +70 -10
- package/build/dist/UI/Components/Markdown.tsx/MarkdownViewer.js.map +1 -1
- package/build/dist/UI/Components/Markdown.tsx/MarkdownVisualEditing.js +887 -0
- package/build/dist/UI/Components/Markdown.tsx/MarkdownVisualEditing.js.map +1 -0
- package/build/dist/UI/Components/ModelTable/BaseModelTable.js +57 -6
- package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
- package/build/dist/UI/Components/ResetObjectID/ResetObjectID.js +7 -5
- package/build/dist/UI/Components/ResetObjectID/ResetObjectID.js.map +1 -1
- package/build/dist/UI/Components/Table/EmptyTableMessage.js +51 -0
- package/build/dist/UI/Components/Table/EmptyTableMessage.js.map +1 -0
- package/build/dist/UI/Components/Table/Table.js +30 -11
- package/build/dist/UI/Components/Table/Table.js.map +1 -1
- package/build/dist/UI/Components/Table/TableRow.js +9 -2
- package/build/dist/UI/Components/Table/TableRow.js.map +1 -1
- package/build/dist/UI/Components/TelemetryViewer/FacetVisibility.js +63 -1
- package/build/dist/UI/Components/TelemetryViewer/FacetVisibility.js.map +1 -1
- package/build/dist/UI/Components/TelemetryViewer/TelemetryViewer.js +4 -2
- package/build/dist/UI/Components/TelemetryViewer/TelemetryViewer.js.map +1 -1
- package/build/dist/UI/Components/TelemetryViewer/components/LockedFilterChip.js +91 -10
- package/build/dist/UI/Components/TelemetryViewer/components/LockedFilterChip.js.map +1 -1
- package/build/dist/UI/Components/TelemetryViewer/components/TelemetryFacetSidebar.js +14 -4
- package/build/dist/UI/Components/TelemetryViewer/components/TelemetryFacetSidebar.js.map +1 -1
- package/build/dist/UI/Components/TextArea/TextArea.js +9 -3
- package/build/dist/UI/Components/TextArea/TextArea.js.map +1 -1
- package/build/dist/UI/Components/Workflow/ModelFieldPicker.js +1 -2
- package/build/dist/UI/Components/Workflow/ModelFieldPicker.js.map +1 -1
- package/build/dist/Utils/LabelRuleImportExport.js +2 -0
- package/build/dist/Utils/LabelRuleImportExport.js.map +1 -1
- package/build/dist/Utils/Markdown/UntrustedMarkdown.js +988 -0
- package/build/dist/Utils/Markdown/UntrustedMarkdown.js.map +1 -0
- package/build/dist/Utils/Monitor/IncomingEmailMonitorRequestUtil.js +34 -0
- package/build/dist/Utils/Monitor/IncomingEmailMonitorRequestUtil.js.map +1 -0
- package/build/dist/Utils/Monitor/MonitorLogSummaryUtil.js +148 -0
- package/build/dist/Utils/Monitor/MonitorLogSummaryUtil.js.map +1 -0
- package/build/dist/Utils/Telemetry/EntityKey.js +36 -0
- package/build/dist/Utils/Telemetry/EntityKey.js.map +1 -1
- package/package.json +1 -3
- package/Server/Utils/CommunityEditionSsoReport.ts +0 -361
- package/Tests/App/Accounts/LoginSsoEdition.test.tsx +0 -616
- package/Tests/App/AdminDashboard/AdminAuthenticationSsoEdition.test.tsx +0 -217
- package/Tests/App/AdminDashboard/GlobalSSOEnterpriseShells.test.tsx +0 -271
- package/Tests/App/Dashboard/CloudDocumentationMarkdown.test.ts +0 -215
- package/Tests/App/Dashboard/TelemetryResourceRetentionSettings.test.tsx +0 -784
- package/Tests/Server/Middleware/UserAuthorizationEditionEnforcement.test.ts +0 -518
- package/Tests/Server/Services/SsoRequirementReadMasking.test.ts +0 -419
- package/Tests/Server/Services/SsoRequirementWriteGuard.test.ts +0 -769
- package/Tests/UI/Components/CodeEditor.test.tsx +0 -638
- package/Tests/UI/Components/MonacoLoader.test.ts +0 -67
- package/Tests/UI/Components/MonacoRuntime.test.ts +0 -121
- package/Tests/UI/Components/Telemetry/TelemetryRetentionConfigForm.test.tsx +0 -329
- package/Tests/UI/Components/YamlEditor.test.tsx +0 -847
- package/UI/Components/CodeEditor/MonacoLoader.ts +0 -36
- package/UI/Components/Telemetry/TelemetryRetentionConfigForm.tsx +0 -319
- package/UI/Components/Telemetry/TelemetryRetentionConfigSummary.tsx +0 -223
- package/build/dist/Server/Utils/CommunityEditionSsoReport.js +0 -223
- package/build/dist/Server/Utils/CommunityEditionSsoReport.js.map +0 -1
- package/build/dist/UI/Components/CodeEditor/MonacoLoader.js +0 -34
- package/build/dist/UI/Components/CodeEditor/MonacoLoader.js.map +0 -1
- package/build/dist/UI/Components/Telemetry/TelemetryRetentionConfigForm.js +0 -171
- package/build/dist/UI/Components/Telemetry/TelemetryRetentionConfigForm.js.map +0 -1
- package/build/dist/UI/Components/Telemetry/TelemetryRetentionConfigSummary.js +0 -119
- package/build/dist/UI/Components/Telemetry/TelemetryRetentionConfigSummary.js.map +0 -1
|
@@ -0,0 +1,1089 @@
|
|
|
1
|
+
import { afterEach, describe, expect, it } from "@jest/globals";
|
|
2
|
+
import {
|
|
3
|
+
htmlToMarkdown,
|
|
4
|
+
markdownToHtml,
|
|
5
|
+
} from "../../../UI/Components/Markdown.tsx/MarkdownConverters";
|
|
6
|
+
import {
|
|
7
|
+
caretAtEndOf,
|
|
8
|
+
deleteSelectionForInsert,
|
|
9
|
+
insertBlocksAtCaret,
|
|
10
|
+
isCaretOnEmptyLine,
|
|
11
|
+
moveCaretIntoEmptyListAhead,
|
|
12
|
+
} from "../../../UI/Components/Markdown.tsx/MarkdownVisualEditing";
|
|
13
|
+
|
|
14
|
+
/*
|
|
15
|
+
* Inserting blocks into the visual editor by hand. Chromium's and Safari's
|
|
16
|
+
* insertHTML fold the first block of an insert into the line the caret is in
|
|
17
|
+
* (a pasted code block saved as "Run:npm install"), so the editor splits the
|
|
18
|
+
* line at the caret and puts the blocks between its halves itself -- except
|
|
19
|
+
* on an empty line, where insertHTML is right in every browser.
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
let editable: HTMLDivElement | null = null;
|
|
23
|
+
|
|
24
|
+
const mountHtml: (html: string) => HTMLDivElement = (
|
|
25
|
+
html: string,
|
|
26
|
+
): HTMLDivElement => {
|
|
27
|
+
const root: HTMLDivElement = document.createElement("div");
|
|
28
|
+
root.setAttribute("contenteditable", "true");
|
|
29
|
+
root.innerHTML = html;
|
|
30
|
+
document.body.appendChild(root);
|
|
31
|
+
editable = root;
|
|
32
|
+
return root;
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
const mountMarkdown: (markdown: string) => HTMLDivElement = (
|
|
36
|
+
markdown: string,
|
|
37
|
+
): HTMLDivElement => {
|
|
38
|
+
return mountHtml(markdownToHtml(markdown));
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
afterEach(() => {
|
|
42
|
+
editable?.remove();
|
|
43
|
+
editable = null;
|
|
44
|
+
window.getSelection()?.removeAllRanges();
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
// A collapsed range `offset` characters into the first text node holding `text`.
|
|
48
|
+
const caretAt: (root: HTMLElement, text: string, offset: number) => Range = (
|
|
49
|
+
root: HTMLElement,
|
|
50
|
+
text: string,
|
|
51
|
+
offset: number,
|
|
52
|
+
): Range => {
|
|
53
|
+
const walker: TreeWalker = document.createTreeWalker(
|
|
54
|
+
root,
|
|
55
|
+
NodeFilter.SHOW_TEXT,
|
|
56
|
+
);
|
|
57
|
+
let node: Node | null = walker.nextNode();
|
|
58
|
+
while (node && !(node.textContent || "").includes(text)) {
|
|
59
|
+
node = walker.nextNode();
|
|
60
|
+
}
|
|
61
|
+
if (!node) {
|
|
62
|
+
throw new Error(`no text "${text}"`);
|
|
63
|
+
}
|
|
64
|
+
const range: Range = document.createRange();
|
|
65
|
+
range.setStart(node, (node.textContent || "").indexOf(text) + offset);
|
|
66
|
+
range.collapse(true);
|
|
67
|
+
return range;
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
const caretOn: (node: Node, offset: number) => Range = (
|
|
71
|
+
node: Node,
|
|
72
|
+
offset: number,
|
|
73
|
+
): Range => {
|
|
74
|
+
const range: Range = document.createRange();
|
|
75
|
+
range.setStart(node, offset);
|
|
76
|
+
range.collapse(true);
|
|
77
|
+
return range;
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
const fragmentOf: (html: string) => DocumentFragment = (
|
|
81
|
+
html: string,
|
|
82
|
+
): DocumentFragment => {
|
|
83
|
+
const template: HTMLTemplateElement = document.createElement("template");
|
|
84
|
+
template.innerHTML = html;
|
|
85
|
+
return template.content;
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
const CODE_BLOCK: string = "<pre><code>code block</code></pre>";
|
|
89
|
+
|
|
90
|
+
describe("isCaretOnEmptyLine", () => {
|
|
91
|
+
it("is true in the empty editor", () => {
|
|
92
|
+
const root: HTMLDivElement = mountHtml("");
|
|
93
|
+
|
|
94
|
+
expect(isCaretOnEmptyLine(root, caretOn(root, 0))).toBe(true);
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
it("is true on a blank line straight inside the editor", () => {
|
|
98
|
+
const root: HTMLDivElement = mountHtml("<p>Run:</p><p><br></p>");
|
|
99
|
+
const blank: Element = root.lastElementChild as Element;
|
|
100
|
+
|
|
101
|
+
expect(isCaretOnEmptyLine(root, caretOn(blank, 0))).toBe(true);
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
it("is true on the empty <div> a browser writes for a new line", () => {
|
|
105
|
+
const root: HTMLDivElement = mountHtml("Run:<div><br></div>");
|
|
106
|
+
const blank: Element = root.lastElementChild as Element;
|
|
107
|
+
|
|
108
|
+
expect(isCaretOnEmptyLine(root, caretOn(blank, 0))).toBe(true);
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
/*
|
|
112
|
+
* Where Chromium and Safari fold a block into the line: at its end, in its
|
|
113
|
+
* middle, and at its start too (the last block then runs into the text).
|
|
114
|
+
*/
|
|
115
|
+
it("is false anywhere in a line with text", () => {
|
|
116
|
+
const root: HTMLDivElement = mountHtml("<p>hello world</p>");
|
|
117
|
+
|
|
118
|
+
expect(isCaretOnEmptyLine(root, caretAt(root, "hello", 5))).toBe(false);
|
|
119
|
+
expect(isCaretOnEmptyLine(root, caretAt(root, "world", 0))).toBe(false);
|
|
120
|
+
expect(isCaretOnEmptyLine(root, caretAt(root, "hello", 0))).toBe(false);
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
it("is false on a line holding only a space, or only an image", () => {
|
|
124
|
+
const spaced: HTMLDivElement = mountHtml("<p> </p>");
|
|
125
|
+
expect(
|
|
126
|
+
isCaretOnEmptyLine(spaced, caretOn(spaced.firstChild as Node, 0)),
|
|
127
|
+
).toBe(false);
|
|
128
|
+
spaced.remove();
|
|
129
|
+
|
|
130
|
+
const imaged: HTMLDivElement = mountHtml('<p><img src="a.png"></p>');
|
|
131
|
+
expect(
|
|
132
|
+
isCaretOnEmptyLine(imaged, caretOn(imaged.firstChild as Node, 0)),
|
|
133
|
+
).toBe(false);
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
it("is false in an empty list item, which is not a line of its own", () => {
|
|
137
|
+
const root: HTMLDivElement = mountHtml("<ul><li><br></li></ul>");
|
|
138
|
+
const item: Element = root.querySelector("li") as Element;
|
|
139
|
+
|
|
140
|
+
expect(isCaretOnEmptyLine(root, caretOn(item, 0))).toBe(false);
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
it("is false between the blocks of an editor that has text", () => {
|
|
144
|
+
const root: HTMLDivElement = mountHtml("<p>a</p><p>b</p>");
|
|
145
|
+
|
|
146
|
+
expect(isCaretOnEmptyLine(root, caretOn(root, 1))).toBe(false);
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
it("is false for a selection", () => {
|
|
150
|
+
const root: HTMLDivElement = mountHtml("<p><br></p>");
|
|
151
|
+
const range: Range = document.createRange();
|
|
152
|
+
range.selectNodeContents(root);
|
|
153
|
+
|
|
154
|
+
expect(isCaretOnEmptyLine(root, range)).toBe(false);
|
|
155
|
+
});
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
describe("insertBlocksAtCaret", () => {
|
|
159
|
+
it("puts a block after the line when the caret is at its end", () => {
|
|
160
|
+
const root: HTMLDivElement = mountMarkdown("hello");
|
|
161
|
+
|
|
162
|
+
insertBlocksAtCaret(
|
|
163
|
+
root,
|
|
164
|
+
caretAt(root, "hello", 5),
|
|
165
|
+
fragmentOf(CODE_BLOCK),
|
|
166
|
+
);
|
|
167
|
+
|
|
168
|
+
expect(root.innerHTML).toBe(`<p>hello</p>${CODE_BLOCK}`);
|
|
169
|
+
expect(htmlToMarkdown(root.innerHTML)).toBe(
|
|
170
|
+
"hello\n\n```\ncode block\n```",
|
|
171
|
+
);
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
it("splits the line when the caret is in its middle, dropping the space at the split", () => {
|
|
175
|
+
const root: HTMLDivElement = mountMarkdown("Run this then check");
|
|
176
|
+
|
|
177
|
+
insertBlocksAtCaret(
|
|
178
|
+
root,
|
|
179
|
+
caretAt(root, "then", 0),
|
|
180
|
+
fragmentOf("<pre><code>npm install oneuptime</code></pre>"),
|
|
181
|
+
);
|
|
182
|
+
|
|
183
|
+
expect(root.innerHTML).toBe(
|
|
184
|
+
"<p>Run this</p><pre><code>npm install oneuptime</code></pre><p>then check</p>",
|
|
185
|
+
);
|
|
186
|
+
expect(htmlToMarkdown(root.innerHTML)).toBe(
|
|
187
|
+
"Run this\n\n```\nnpm install oneuptime\n```\n\nthen check",
|
|
188
|
+
);
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
it("keeps a non-breaking space at the split, which is shown", () => {
|
|
192
|
+
const root: HTMLDivElement = mountHtml("<p>a\u00a0b</p>");
|
|
193
|
+
|
|
194
|
+
insertBlocksAtCaret(root, caretAt(root, "b", 0), fragmentOf("<hr>"));
|
|
195
|
+
|
|
196
|
+
expect(root.innerHTML).toBe("<p>a </p><hr><p>b</p>");
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
it("leaves no empty line behind at the start of a line", () => {
|
|
200
|
+
const root: HTMLDivElement = mountMarkdown("hello");
|
|
201
|
+
|
|
202
|
+
insertBlocksAtCaret(
|
|
203
|
+
root,
|
|
204
|
+
caretAt(root, "hello", 0),
|
|
205
|
+
fragmentOf(CODE_BLOCK),
|
|
206
|
+
);
|
|
207
|
+
|
|
208
|
+
expect(root.innerHTML).toBe(`${CODE_BLOCK}<p>hello</p>`);
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
it("splits a heading into two headings", () => {
|
|
212
|
+
const root: HTMLDivElement = mountMarkdown("## Title");
|
|
213
|
+
|
|
214
|
+
insertBlocksAtCaret(root, caretAt(root, "Title", 2), fragmentOf("<hr>"));
|
|
215
|
+
|
|
216
|
+
expect(htmlToMarkdown(root.innerHTML)).toBe("## Ti\n\n---\n\n## tle");
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
it("splits the formatting the caret is in along with the line", () => {
|
|
220
|
+
const root: HTMLDivElement = mountHtml("<p><strong>bold</strong> text</p>");
|
|
221
|
+
|
|
222
|
+
insertBlocksAtCaret(root, caretAt(root, "bold", 2), fragmentOf("<hr>"));
|
|
223
|
+
|
|
224
|
+
expect(root.innerHTML).toBe(
|
|
225
|
+
"<p><strong>bo</strong></p><hr><p><strong>ld</strong> text</p>",
|
|
226
|
+
);
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
/*
|
|
230
|
+
* With the caret at the very end of a bold word -- where a click on its
|
|
231
|
+
* last letter, or the arrow keys, leave it -- the split copied the <strong>
|
|
232
|
+
* into the second half with nothing in it, which was saved as
|
|
233
|
+
* "**** then check".
|
|
234
|
+
*/
|
|
235
|
+
it("leaves no empty copy of the bold word the caret is at the end of", () => {
|
|
236
|
+
const root: HTMLDivElement = mountHtml(
|
|
237
|
+
"<p>Run <strong>this</strong> then check</p>",
|
|
238
|
+
);
|
|
239
|
+
|
|
240
|
+
insertBlocksAtCaret(root, caretAt(root, "this", 4), fragmentOf(CODE_BLOCK));
|
|
241
|
+
|
|
242
|
+
expect(root.innerHTML).toBe(
|
|
243
|
+
`<p>Run <strong>this</strong></p>${CODE_BLOCK}<p>then check</p>`,
|
|
244
|
+
);
|
|
245
|
+
expect(htmlToMarkdown(root.innerHTML)).toBe(
|
|
246
|
+
"Run **this**\n\n```\ncode block\n```\n\nthen check",
|
|
247
|
+
);
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
// At the very start of one, the emptied <strong> stayed behind: "Run ****".
|
|
251
|
+
it("leaves no emptied bold word behind when the caret is at its start", () => {
|
|
252
|
+
const root: HTMLDivElement = mountHtml(
|
|
253
|
+
"<p>Run <strong>this</strong> then check</p>",
|
|
254
|
+
);
|
|
255
|
+
|
|
256
|
+
insertBlocksAtCaret(root, caretAt(root, "this", 0), fragmentOf(CODE_BLOCK));
|
|
257
|
+
|
|
258
|
+
expect(root.innerHTML).toBe(
|
|
259
|
+
`<p>Run</p>${CODE_BLOCK}<p><strong>this</strong> then check</p>`,
|
|
260
|
+
);
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
/*
|
|
264
|
+
* An empty link was saved as its address -- a second link, the note never
|
|
265
|
+
* had one -- and an empty strikethrough as "~~~~", which opens a code
|
|
266
|
+
* fence that runs to the end of the note.
|
|
267
|
+
*/
|
|
268
|
+
it.each([
|
|
269
|
+
[
|
|
270
|
+
"link",
|
|
271
|
+
"See [docs](https://x.test/) now",
|
|
272
|
+
"docs",
|
|
273
|
+
"See [docs](https://x.test/)\n\n```\ncode block\n```\n\nnow",
|
|
274
|
+
],
|
|
275
|
+
["italic text", "a *b* c", "b", "a *b*\n\n```\ncode block\n```\n\nc"],
|
|
276
|
+
[
|
|
277
|
+
"inline code",
|
|
278
|
+
"Run `npm i` now",
|
|
279
|
+
"npm i",
|
|
280
|
+
"Run `npm i`\n\n```\ncode block\n```\n\nnow",
|
|
281
|
+
],
|
|
282
|
+
[
|
|
283
|
+
"struck-through text",
|
|
284
|
+
"old ~~gone~~ new",
|
|
285
|
+
"gone",
|
|
286
|
+
"old ~~gone~~\n\n```\ncode block\n```\n\nnew",
|
|
287
|
+
],
|
|
288
|
+
])(
|
|
289
|
+
"leaves no empty copy of the %s the caret is at the end of",
|
|
290
|
+
(_what: string, markdown: string, word: string, expected: string) => {
|
|
291
|
+
const root: HTMLDivElement = mountMarkdown(markdown);
|
|
292
|
+
|
|
293
|
+
insertBlocksAtCaret(
|
|
294
|
+
root,
|
|
295
|
+
caretAt(root, word, word.length),
|
|
296
|
+
fragmentOf(CODE_BLOCK),
|
|
297
|
+
);
|
|
298
|
+
|
|
299
|
+
expect(htmlToMarkdown(root.innerHTML)).toBe(expected);
|
|
300
|
+
},
|
|
301
|
+
);
|
|
302
|
+
|
|
303
|
+
it("leaves no empty copy of a link the caret is at the start of", () => {
|
|
304
|
+
const root: HTMLDivElement = mountMarkdown(
|
|
305
|
+
"See [docs](https://x.test/) now",
|
|
306
|
+
);
|
|
307
|
+
|
|
308
|
+
insertBlocksAtCaret(root, caretAt(root, "docs", 0), fragmentOf(CODE_BLOCK));
|
|
309
|
+
|
|
310
|
+
expect(htmlToMarkdown(root.innerHTML)).toBe(
|
|
311
|
+
"See\n\n```\ncode block\n```\n\n[docs](https://x.test/) now",
|
|
312
|
+
);
|
|
313
|
+
});
|
|
314
|
+
|
|
315
|
+
it("leaves no empty copy of formatting nested in formatting", () => {
|
|
316
|
+
const root: HTMLDivElement = mountHtml(
|
|
317
|
+
"<p>a <strong><em>b</em></strong> c</p>",
|
|
318
|
+
);
|
|
319
|
+
|
|
320
|
+
insertBlocksAtCaret(root, caretAt(root, "b", 1), fragmentOf("<hr>"));
|
|
321
|
+
|
|
322
|
+
expect(root.innerHTML).toBe(
|
|
323
|
+
"<p>a <strong><em>b</em></strong></p><hr><p>c</p>",
|
|
324
|
+
);
|
|
325
|
+
});
|
|
326
|
+
|
|
327
|
+
it("leaves no empty copy of the bold word in a list item either", () => {
|
|
328
|
+
const root: HTMLDivElement = mountMarkdown("- run **this** now");
|
|
329
|
+
|
|
330
|
+
insertBlocksAtCaret(root, caretAt(root, "this", 4), fragmentOf(CODE_BLOCK));
|
|
331
|
+
|
|
332
|
+
expect(htmlToMarkdown(root.innerHTML)).toBe(
|
|
333
|
+
"- run **this**\n\n ```\n code block\n ```\n\n now",
|
|
334
|
+
);
|
|
335
|
+
expect(root.querySelectorAll("strong")).toHaveLength(1);
|
|
336
|
+
});
|
|
337
|
+
|
|
338
|
+
it("leaves no emptied bold word behind in a list item either", () => {
|
|
339
|
+
const root: HTMLDivElement = mountMarkdown("- run **this** now");
|
|
340
|
+
|
|
341
|
+
insertBlocksAtCaret(root, caretAt(root, "this", 0), fragmentOf(CODE_BLOCK));
|
|
342
|
+
|
|
343
|
+
expect(htmlToMarkdown(root.innerHTML)).toBe(
|
|
344
|
+
"- run\n\n ```\n code block\n ```\n\n **this** now",
|
|
345
|
+
);
|
|
346
|
+
});
|
|
347
|
+
|
|
348
|
+
// What a selection taking a whole bold word leaves at the caret.
|
|
349
|
+
it("drops formatting emptied before the split", () => {
|
|
350
|
+
const root: HTMLDivElement = mountHtml("<p>Run <strong></strong> then</p>");
|
|
351
|
+
const line: Element = root.firstElementChild as Element;
|
|
352
|
+
|
|
353
|
+
insertBlocksAtCaret(root, caretOn(line, 2), fragmentOf("<hr>"));
|
|
354
|
+
|
|
355
|
+
expect(root.innerHTML).toBe("<p>Run</p><hr><p>then</p>");
|
|
356
|
+
});
|
|
357
|
+
|
|
358
|
+
it("keeps a block inserted in a list item inside that item", () => {
|
|
359
|
+
const root: HTMLDivElement = mountMarkdown("- item one\n- item two");
|
|
360
|
+
|
|
361
|
+
insertBlocksAtCaret(
|
|
362
|
+
root,
|
|
363
|
+
caretAt(root, "item one", 8),
|
|
364
|
+
fragmentOf(CODE_BLOCK),
|
|
365
|
+
);
|
|
366
|
+
|
|
367
|
+
expect(htmlToMarkdown(root.innerHTML)).toBe(
|
|
368
|
+
"- item one\n\n ```\n code block\n ```\n- item two",
|
|
369
|
+
);
|
|
370
|
+
});
|
|
371
|
+
|
|
372
|
+
it("splits the text of a list item the caret is in the middle of", () => {
|
|
373
|
+
const root: HTMLDivElement = mountHtml("<ul><li>one two</li></ul>");
|
|
374
|
+
|
|
375
|
+
insertBlocksAtCaret(root, caretAt(root, "two", 0), fragmentOf("<hr>"));
|
|
376
|
+
|
|
377
|
+
expect(root.innerHTML).toBe("<ul><li>one<hr>two</li></ul>");
|
|
378
|
+
});
|
|
379
|
+
|
|
380
|
+
it("keeps a block inserted in a quote inside the quote", () => {
|
|
381
|
+
const root: HTMLDivElement = mountHtml(
|
|
382
|
+
"<blockquote><p>quoted</p></blockquote>",
|
|
383
|
+
);
|
|
384
|
+
|
|
385
|
+
insertBlocksAtCaret(root, caretAt(root, "quoted", 6), fragmentOf("<hr>"));
|
|
386
|
+
|
|
387
|
+
expect(root.innerHTML).toBe("<blockquote><p>quoted</p><hr></blockquote>");
|
|
388
|
+
});
|
|
389
|
+
|
|
390
|
+
it("puts blocks after a code block rather than inside it", () => {
|
|
391
|
+
const root: HTMLDivElement = mountMarkdown("```\ncode\n```\n\nafter");
|
|
392
|
+
|
|
393
|
+
insertBlocksAtCaret(root, caretAt(root, "code", 2), fragmentOf("<hr>"));
|
|
394
|
+
|
|
395
|
+
expect(htmlToMarkdown(root.innerHTML)).toBe(
|
|
396
|
+
"```\ncode\n```\n\n---\n\nafter",
|
|
397
|
+
);
|
|
398
|
+
});
|
|
399
|
+
|
|
400
|
+
// Chromium leaves the first line typed into an empty editor as bare text.
|
|
401
|
+
it("splits bare text straight inside the editor", () => {
|
|
402
|
+
const root: HTMLDivElement = mountHtml("Run: now<div>next</div>");
|
|
403
|
+
|
|
404
|
+
insertBlocksAtCaret(root, caretAt(root, "now", 0), fragmentOf(CODE_BLOCK));
|
|
405
|
+
|
|
406
|
+
expect(root.innerHTML).toBe(`Run:${CODE_BLOCK}now<div>next</div>`);
|
|
407
|
+
});
|
|
408
|
+
|
|
409
|
+
it("goes between the editor's blocks when the caret is between them", () => {
|
|
410
|
+
const root: HTMLDivElement = mountHtml("<p>a</p><p>b</p>");
|
|
411
|
+
|
|
412
|
+
insertBlocksAtCaret(root, caretOn(root, 1), fragmentOf("<hr>"));
|
|
413
|
+
|
|
414
|
+
expect(root.innerHTML).toBe("<p>a</p><hr><p>b</p>");
|
|
415
|
+
});
|
|
416
|
+
|
|
417
|
+
it("returns a caret at the end of what it inserted, or null for nothing", () => {
|
|
418
|
+
const root: HTMLDivElement = mountMarkdown("hello");
|
|
419
|
+
const caret: Range | null = insertBlocksAtCaret(
|
|
420
|
+
root,
|
|
421
|
+
caretAt(root, "hello", 5),
|
|
422
|
+
fragmentOf("<hr><p>last</p>"),
|
|
423
|
+
);
|
|
424
|
+
|
|
425
|
+
expect(root.innerHTML).toBe("<p>hello</p><hr><p>last</p>");
|
|
426
|
+
expect(caret?.collapsed).toBe(true);
|
|
427
|
+
expect(caret?.startContainer).toBe(root.lastElementChild?.firstChild);
|
|
428
|
+
expect(caret?.startOffset).toBe("last".length);
|
|
429
|
+
expect(
|
|
430
|
+
insertBlocksAtCaret(
|
|
431
|
+
root,
|
|
432
|
+
caretAt(root, "last", 0),
|
|
433
|
+
document.createDocumentFragment(),
|
|
434
|
+
),
|
|
435
|
+
).toBeNull();
|
|
436
|
+
});
|
|
437
|
+
});
|
|
438
|
+
|
|
439
|
+
/*
|
|
440
|
+
* A list inserted in a list item -- pasted, or the Task List button's task
|
|
441
|
+
* -- joins that item's list. Kept inside the item, as a code block inserted
|
|
442
|
+
* there is, it was a list nested in it: pasted into the empty item Enter
|
|
443
|
+
* leaves, it showed two bullets ("- - a"), the double bullet of issue #4114.
|
|
444
|
+
*/
|
|
445
|
+
describe("insertBlocksAtCaret, a list in a list item", () => {
|
|
446
|
+
const LIST: string = "<ul><li>a</li><li>b</li></ul>";
|
|
447
|
+
|
|
448
|
+
it("puts a list inserted into an empty item in that item's place", () => {
|
|
449
|
+
const root: HTMLDivElement = mountHtml(
|
|
450
|
+
"<ul><li>first</li><li><br></li></ul>",
|
|
451
|
+
);
|
|
452
|
+
const empty: Element = root.querySelectorAll("li")[1] as Element;
|
|
453
|
+
|
|
454
|
+
const caret: Range | null = insertBlocksAtCaret(
|
|
455
|
+
root,
|
|
456
|
+
caretOn(empty, 0),
|
|
457
|
+
fragmentOf(LIST),
|
|
458
|
+
);
|
|
459
|
+
|
|
460
|
+
expect(root.innerHTML).toBe("<ul><li>first</li><li>a</li><li>b</li></ul>");
|
|
461
|
+
expect(htmlToMarkdown(root.innerHTML)).toBe("- first\n- a\n- b");
|
|
462
|
+
expect(caretText(caret as Range)).toBe("b");
|
|
463
|
+
expect(caret?.startContainer.parentElement).toBe(
|
|
464
|
+
root.querySelector("li:last-child"),
|
|
465
|
+
);
|
|
466
|
+
});
|
|
467
|
+
|
|
468
|
+
it("puts a list inserted at the end of an item after it", () => {
|
|
469
|
+
const root: HTMLDivElement = mountMarkdown("- item one\n- item two");
|
|
470
|
+
|
|
471
|
+
insertBlocksAtCaret(root, caretAt(root, "item one", 8), fragmentOf(LIST));
|
|
472
|
+
|
|
473
|
+
expect(htmlToMarkdown(root.innerHTML)).toBe(
|
|
474
|
+
"- item one\n- a\n- b\n- item two",
|
|
475
|
+
);
|
|
476
|
+
});
|
|
477
|
+
|
|
478
|
+
it("splits the item a list is inserted into the middle of", () => {
|
|
479
|
+
const root: HTMLDivElement = mountMarkdown("- item one\n- item two");
|
|
480
|
+
|
|
481
|
+
insertBlocksAtCaret(root, caretAt(root, "one", 0), fragmentOf(LIST));
|
|
482
|
+
|
|
483
|
+
expect(htmlToMarkdown(root.innerHTML)).toBe(
|
|
484
|
+
"- item\n- a\n- b\n- one\n- item two",
|
|
485
|
+
);
|
|
486
|
+
});
|
|
487
|
+
|
|
488
|
+
it("puts a list inserted at the start of an item before it", () => {
|
|
489
|
+
const root: HTMLDivElement = mountMarkdown("- item one\n- item two");
|
|
490
|
+
|
|
491
|
+
insertBlocksAtCaret(root, caretAt(root, "item one", 0), fragmentOf(LIST));
|
|
492
|
+
|
|
493
|
+
expect(htmlToMarkdown(root.innerHTML)).toBe(
|
|
494
|
+
"- a\n- b\n- item one\n- item two",
|
|
495
|
+
);
|
|
496
|
+
});
|
|
497
|
+
|
|
498
|
+
/*
|
|
499
|
+
* What the item held after the caret -- its own nested list -- goes under
|
|
500
|
+
* the last item inserted, so the text keeps its order. Left where it was,
|
|
501
|
+
* the item it stayed in held nothing else: "- - child".
|
|
502
|
+
*/
|
|
503
|
+
it("keeps the nested list of the item after the items inserted at its end", () => {
|
|
504
|
+
const root: HTMLDivElement = mountMarkdown("- parent\n - child\n- next");
|
|
505
|
+
|
|
506
|
+
const caret: Range | null = insertBlocksAtCaret(
|
|
507
|
+
root,
|
|
508
|
+
caretAt(root, "parent", 6),
|
|
509
|
+
fragmentOf(LIST),
|
|
510
|
+
);
|
|
511
|
+
|
|
512
|
+
expect(htmlToMarkdown(root.innerHTML)).toBe(
|
|
513
|
+
"- parent\n- a\n- b\n - child\n- next",
|
|
514
|
+
);
|
|
515
|
+
expect(caretText(caret as Range)).toBe("b");
|
|
516
|
+
});
|
|
517
|
+
|
|
518
|
+
// In a loose item the item's own text is its first paragraph.
|
|
519
|
+
it("splits the paragraph of a loose item a list is inserted into the middle of", () => {
|
|
520
|
+
const root: HTMLDivElement = mountHtml(
|
|
521
|
+
"<ul><li><p>one two</p><p>more</p></li></ul>",
|
|
522
|
+
);
|
|
523
|
+
|
|
524
|
+
insertBlocksAtCaret(root, caretAt(root, "two", 0), fragmentOf(LIST));
|
|
525
|
+
|
|
526
|
+
expect(root.innerHTML).toBe(
|
|
527
|
+
"<ul><li><p>one</p></li><li>a</li><li>b</li><li><p>two</p><p>more</p></li></ul>",
|
|
528
|
+
);
|
|
529
|
+
});
|
|
530
|
+
|
|
531
|
+
it("puts the next paragraph of a loose item under the last item inserted at its end", () => {
|
|
532
|
+
const root: HTMLDivElement = mountHtml(
|
|
533
|
+
"<ul><li><p>one two</p><p>more</p></li></ul>",
|
|
534
|
+
);
|
|
535
|
+
|
|
536
|
+
insertBlocksAtCaret(root, caretAt(root, "one two", 7), fragmentOf(LIST));
|
|
537
|
+
|
|
538
|
+
expect(root.innerHTML).toBe(
|
|
539
|
+
"<ul><li><p>one two</p></li><li>a</li><li>b<p>more</p></li></ul>",
|
|
540
|
+
);
|
|
541
|
+
});
|
|
542
|
+
|
|
543
|
+
it("puts a list inserted at the end of a nested item beside that item", () => {
|
|
544
|
+
const root: HTMLDivElement = mountMarkdown("- parent\n - child\n- next");
|
|
545
|
+
|
|
546
|
+
insertBlocksAtCaret(root, caretAt(root, "child", 5), fragmentOf(LIST));
|
|
547
|
+
|
|
548
|
+
expect(htmlToMarkdown(root.innerHTML)).toBe(
|
|
549
|
+
"- parent\n - child\n - a\n - b\n- next",
|
|
550
|
+
);
|
|
551
|
+
});
|
|
552
|
+
|
|
553
|
+
it("keeps a nested list inserted nested under its own item", () => {
|
|
554
|
+
const root: HTMLDivElement = mountHtml(
|
|
555
|
+
"<ul><li>item one</li><li><br></li></ul>",
|
|
556
|
+
);
|
|
557
|
+
const empty: Element = root.querySelectorAll("li")[1] as Element;
|
|
558
|
+
|
|
559
|
+
const caret: Range | null = insertBlocksAtCaret(
|
|
560
|
+
root,
|
|
561
|
+
caretOn(empty, 0),
|
|
562
|
+
fragmentOf(markdownToHtml("- a\n - a1\n- b")),
|
|
563
|
+
);
|
|
564
|
+
|
|
565
|
+
expect(htmlToMarkdown(root.innerHTML)).toBe("- item one\n- a\n - a1\n- b");
|
|
566
|
+
expect(caretText(caret as Range)).toBe("b");
|
|
567
|
+
});
|
|
568
|
+
|
|
569
|
+
it("numbers the items of a list inserted into a numbered one", () => {
|
|
570
|
+
const root: HTMLDivElement = mountHtml(
|
|
571
|
+
"<ol><li>first</li><li><br></li></ol>",
|
|
572
|
+
);
|
|
573
|
+
const empty: Element = root.querySelectorAll("li")[1] as Element;
|
|
574
|
+
|
|
575
|
+
insertBlocksAtCaret(root, caretOn(empty, 0), fragmentOf(LIST));
|
|
576
|
+
|
|
577
|
+
expect(htmlToMarkdown(root.innerHTML)).toBe("1. first\n2. a\n3. b");
|
|
578
|
+
});
|
|
579
|
+
|
|
580
|
+
// The Task List button, at the end of a task: the next task, not a sub-task.
|
|
581
|
+
it("puts the Task List button's task beside the task the caret ends", () => {
|
|
582
|
+
const root: HTMLDivElement = mountMarkdown("- [ ] task one");
|
|
583
|
+
|
|
584
|
+
const caret: Range | null = insertBlocksAtCaret(
|
|
585
|
+
root,
|
|
586
|
+
caretAt(root, "task one", 8),
|
|
587
|
+
fragmentOf(
|
|
588
|
+
'<ul class="task-list"><li class="task-list-item"><input type="checkbox" disabled> Task</li></ul>',
|
|
589
|
+
),
|
|
590
|
+
);
|
|
591
|
+
|
|
592
|
+
expect(htmlToMarkdown(root.innerHTML)).toBe("- [ ] task one\n- [ ] Task");
|
|
593
|
+
expect(caretText(caret as Range)).toBe(" Task");
|
|
594
|
+
});
|
|
595
|
+
|
|
596
|
+
/*
|
|
597
|
+
* Chromium leaves the selection on the editor, just before the list, once
|
|
598
|
+
* the Bullet List button has made one in the empty editor.
|
|
599
|
+
*/
|
|
600
|
+
it("puts a list inserted just before an empty list in its first item's place", () => {
|
|
601
|
+
const root: HTMLDivElement = mountHtml("<ul><li><br></li></ul>");
|
|
602
|
+
|
|
603
|
+
insertBlocksAtCaret(root, caretOn(root, 0), fragmentOf(LIST));
|
|
604
|
+
|
|
605
|
+
expect(root.innerHTML).toBe("<ul><li>a</li><li>b</li></ul>");
|
|
606
|
+
});
|
|
607
|
+
|
|
608
|
+
it("leaves no empty copy of a bold word at the end of the item", () => {
|
|
609
|
+
const root: HTMLDivElement = mountMarkdown("- run **this** now");
|
|
610
|
+
|
|
611
|
+
insertBlocksAtCaret(root, caretAt(root, "this", 4), fragmentOf(LIST));
|
|
612
|
+
|
|
613
|
+
expect(htmlToMarkdown(root.innerHTML)).toBe(
|
|
614
|
+
"- run **this**\n- a\n- b\n- now",
|
|
615
|
+
);
|
|
616
|
+
});
|
|
617
|
+
|
|
618
|
+
it("still keeps a code block inserted in an item inside that item", () => {
|
|
619
|
+
const root: HTMLDivElement = mountHtml(
|
|
620
|
+
"<ul><li>item one</li><li><br></li></ul>",
|
|
621
|
+
);
|
|
622
|
+
const empty: Element = root.querySelectorAll("li")[1] as Element;
|
|
623
|
+
|
|
624
|
+
insertBlocksAtCaret(root, caretOn(empty, 0), fragmentOf(CODE_BLOCK));
|
|
625
|
+
|
|
626
|
+
expect(root.querySelector("li:last-child pre")).not.toBeNull();
|
|
627
|
+
});
|
|
628
|
+
|
|
629
|
+
it("still keeps a list inserted in a quote in an item inside that quote", () => {
|
|
630
|
+
const root: HTMLDivElement = mountHtml(
|
|
631
|
+
"<ul><li>item<blockquote><p>quoted</p></blockquote></li></ul>",
|
|
632
|
+
);
|
|
633
|
+
|
|
634
|
+
insertBlocksAtCaret(root, caretAt(root, "quoted", 6), fragmentOf(LIST));
|
|
635
|
+
|
|
636
|
+
expect(root.querySelector("blockquote ul")).not.toBeNull();
|
|
637
|
+
expect(root.querySelectorAll("ul > li")).toHaveLength(3);
|
|
638
|
+
});
|
|
639
|
+
|
|
640
|
+
// A list with other blocks is not only list items: it goes in as before.
|
|
641
|
+
it("inserts a list followed by a paragraph as it did", () => {
|
|
642
|
+
const root: HTMLDivElement = mountHtml(
|
|
643
|
+
"<ul><li>item one</li><li><br></li></ul>",
|
|
644
|
+
);
|
|
645
|
+
const empty: Element = root.querySelectorAll("li")[1] as Element;
|
|
646
|
+
|
|
647
|
+
insertBlocksAtCaret(
|
|
648
|
+
root,
|
|
649
|
+
caretOn(empty, 0),
|
|
650
|
+
fragmentOf(`${LIST}<p>after</p>`),
|
|
651
|
+
);
|
|
652
|
+
|
|
653
|
+
expect(root.querySelector("li:last-child > p")?.textContent).toBe("after");
|
|
654
|
+
});
|
|
655
|
+
});
|
|
656
|
+
|
|
657
|
+
/*
|
|
658
|
+
* After the Bullet or Numbered List button in the empty editor, Chromium
|
|
659
|
+
* leaves the selection on the editor itself, before the new list, while it
|
|
660
|
+
* shows (and types into) the caret in the list's empty first item.
|
|
661
|
+
*/
|
|
662
|
+
describe("moveCaretIntoEmptyListAhead", () => {
|
|
663
|
+
it("moves a caret just before a new bulleted list into its empty first item", () => {
|
|
664
|
+
const root: HTMLDivElement = mountHtml("<ul><li><br></li></ul>");
|
|
665
|
+
const range: Range = caretOn(root, 0);
|
|
666
|
+
|
|
667
|
+
expect(moveCaretIntoEmptyListAhead(root, range)).toBe(true);
|
|
668
|
+
expect(range.collapsed).toBe(true);
|
|
669
|
+
expect(range.startContainer).toBe(root.querySelector("li"));
|
|
670
|
+
expect(range.startOffset).toBe(0);
|
|
671
|
+
});
|
|
672
|
+
|
|
673
|
+
it("moves it into a new numbered list's empty first item too", () => {
|
|
674
|
+
const root: HTMLDivElement = mountHtml("<ol><li><br></li></ol>");
|
|
675
|
+
const range: Range = caretOn(root, 0);
|
|
676
|
+
|
|
677
|
+
expect(moveCaretIntoEmptyListAhead(root, range)).toBe(true);
|
|
678
|
+
expect(range.startContainer).toBe(root.querySelector("li"));
|
|
679
|
+
});
|
|
680
|
+
|
|
681
|
+
it("leaves a caret before a list whose first item has text", () => {
|
|
682
|
+
const root: HTMLDivElement = mountHtml("<ul><li>first</li></ul>");
|
|
683
|
+
const range: Range = caretOn(root, 0);
|
|
684
|
+
|
|
685
|
+
expect(moveCaretIntoEmptyListAhead(root, range)).toBe(false);
|
|
686
|
+
expect(range.startContainer).toBe(root);
|
|
687
|
+
});
|
|
688
|
+
|
|
689
|
+
it("leaves a caret on the editor that is not before a list", () => {
|
|
690
|
+
const root: HTMLDivElement = mountHtml("<p>Run:</p><ul><li><br></li></ul>");
|
|
691
|
+
const range: Range = caretOn(root, 0);
|
|
692
|
+
|
|
693
|
+
expect(moveCaretIntoEmptyListAhead(root, range)).toBe(false);
|
|
694
|
+
expect(range.startContainer).toBe(root);
|
|
695
|
+
});
|
|
696
|
+
|
|
697
|
+
it("leaves a caret that is already inside a line", () => {
|
|
698
|
+
const root: HTMLDivElement = mountHtml("<ul><li>first</li></ul>");
|
|
699
|
+
const range: Range = caretAt(root, "first", 2);
|
|
700
|
+
|
|
701
|
+
expect(moveCaretIntoEmptyListAhead(root, range)).toBe(false);
|
|
702
|
+
expect(caretText(range)).toBe("fi");
|
|
703
|
+
});
|
|
704
|
+
|
|
705
|
+
it("leaves a selection alone", () => {
|
|
706
|
+
const root: HTMLDivElement = mountHtml("<ul><li><br></li></ul>");
|
|
707
|
+
const range: Range = document.createRange();
|
|
708
|
+
range.setStart(root, 0);
|
|
709
|
+
range.setEnd(root, 1);
|
|
710
|
+
|
|
711
|
+
expect(moveCaretIntoEmptyListAhead(root, range)).toBe(false);
|
|
712
|
+
expect(range.collapsed).toBe(false);
|
|
713
|
+
});
|
|
714
|
+
});
|
|
715
|
+
|
|
716
|
+
describe("caretAtEndOf", () => {
|
|
717
|
+
it("is after the last character of what was inserted", () => {
|
|
718
|
+
const root: HTMLDivElement = mountHtml(CODE_BLOCK);
|
|
719
|
+
const caret: Range = caretAtEndOf(root.firstChild as Node);
|
|
720
|
+
|
|
721
|
+
expect(caret.collapsed).toBe(true);
|
|
722
|
+
expect(caret.startContainer.textContent).toBe("code block");
|
|
723
|
+
expect(caret.startOffset).toBe("code block".length);
|
|
724
|
+
});
|
|
725
|
+
|
|
726
|
+
it("is before the <br> that keeps an empty line open", () => {
|
|
727
|
+
const root: HTMLDivElement = mountHtml("<p><br></p>");
|
|
728
|
+
const line: Node = root.firstChild as Node;
|
|
729
|
+
const caret: Range = caretAtEndOf(line);
|
|
730
|
+
|
|
731
|
+
expect(caret.startContainer).toBe(line);
|
|
732
|
+
expect(caret.startOffset).toBe(0);
|
|
733
|
+
});
|
|
734
|
+
});
|
|
735
|
+
|
|
736
|
+
// A range from `startOffset` into the text holding `start` to `endOffset` into the text holding `end`.
|
|
737
|
+
const rangeBetween: (
|
|
738
|
+
root: HTMLElement,
|
|
739
|
+
start: string,
|
|
740
|
+
startOffset: number,
|
|
741
|
+
end: string,
|
|
742
|
+
endOffset: number,
|
|
743
|
+
) => Range = (
|
|
744
|
+
root: HTMLElement,
|
|
745
|
+
start: string,
|
|
746
|
+
startOffset: number,
|
|
747
|
+
end: string,
|
|
748
|
+
endOffset: number,
|
|
749
|
+
): Range => {
|
|
750
|
+
const range: Range = caretAt(root, start, startOffset);
|
|
751
|
+
const endPoint: Range = caretAt(root, end, endOffset);
|
|
752
|
+
range.setEnd(endPoint.startContainer, endPoint.startOffset);
|
|
753
|
+
return range;
|
|
754
|
+
};
|
|
755
|
+
|
|
756
|
+
// What the caret is next to: the text before it in its text node, and its line.
|
|
757
|
+
const caretText: (range: Range) => string = (range: Range): string => {
|
|
758
|
+
return (range.startContainer.textContent || "").slice(0, range.startOffset);
|
|
759
|
+
};
|
|
760
|
+
|
|
761
|
+
describe("deleteSelectionForInsert", () => {
|
|
762
|
+
/*
|
|
763
|
+
* Range.deleteContents alone left both items and the caret between them,
|
|
764
|
+
* straight inside the <ul>: a link pasted there showed in the editor and
|
|
765
|
+
* never reached the saved markdown.
|
|
766
|
+
*/
|
|
767
|
+
it("joins what is left of the second list item to the first, with the caret at the join", () => {
|
|
768
|
+
const root: HTMLDivElement = mountMarkdown("- alpha\n- beta\n- gamma");
|
|
769
|
+
const range: Range = rangeBetween(root, "alpha", 2, "beta", 2);
|
|
770
|
+
|
|
771
|
+
deleteSelectionForInsert(root, range);
|
|
772
|
+
|
|
773
|
+
expect(root.innerHTML).toBe("<ul><li>alta</li><li>gamma</li></ul>");
|
|
774
|
+
expect(range.collapsed).toBe(true);
|
|
775
|
+
expect(range.startContainer.parentElement?.tagName).toBe("LI");
|
|
776
|
+
expect(caretText(range)).toBe("al");
|
|
777
|
+
});
|
|
778
|
+
|
|
779
|
+
it("joins two paragraphs the same way", () => {
|
|
780
|
+
const root: HTMLDivElement = mountMarkdown("first para\n\nsecond para");
|
|
781
|
+
const range: Range = rangeBetween(root, "first", 2, "second", 2);
|
|
782
|
+
|
|
783
|
+
deleteSelectionForInsert(root, range);
|
|
784
|
+
|
|
785
|
+
expect(root.innerHTML).toBe("<p>ficond para</p>");
|
|
786
|
+
expect(caretText(range)).toBe("fi");
|
|
787
|
+
});
|
|
788
|
+
|
|
789
|
+
/*
|
|
790
|
+
* A triple click selects an item up to the very start of the next one; a
|
|
791
|
+
* paste then replaces that item and leaves the next alone.
|
|
792
|
+
*/
|
|
793
|
+
it("leaves the next line alone when the selection stops at its start", () => {
|
|
794
|
+
const root: HTMLDivElement = mountMarkdown("- alpha\n- beta\n- gamma");
|
|
795
|
+
const items: NodeListOf<HTMLLIElement> = root.querySelectorAll("li");
|
|
796
|
+
const range: Range = document.createRange();
|
|
797
|
+
range.setStart(items[1]?.firstChild as Node, 0);
|
|
798
|
+
range.setEnd(items[2] as Node, 0);
|
|
799
|
+
|
|
800
|
+
deleteSelectionForInsert(root, range);
|
|
801
|
+
|
|
802
|
+
expect(htmlToMarkdown(root.innerHTML)).toBe("- alpha\n- \n- gamma");
|
|
803
|
+
expect(range.startContainer.parentElement).toBe(items[1]);
|
|
804
|
+
});
|
|
805
|
+
|
|
806
|
+
it("takes the joined item's nested list along to the item it joins", () => {
|
|
807
|
+
const root: HTMLDivElement = mountMarkdown(
|
|
808
|
+
"- alpha\n - sub\n - deep\n- beta",
|
|
809
|
+
);
|
|
810
|
+
|
|
811
|
+
deleteSelectionForInsert(root, rangeBetween(root, "alpha", 2, "sub", 2));
|
|
812
|
+
|
|
813
|
+
expect(htmlToMarkdown(root.innerHTML)).toBe("- alb\n - deep\n- beta");
|
|
814
|
+
});
|
|
815
|
+
|
|
816
|
+
/*
|
|
817
|
+
* A nested item joined to its parent keeps its place in the text: what it
|
|
818
|
+
* held comes right after the join, ahead of the nested items that followed
|
|
819
|
+
* it. Added at the end of the parent, "deep" came out after "gamma".
|
|
820
|
+
*/
|
|
821
|
+
it("keeps what a nested item held ahead of the items that followed it", () => {
|
|
822
|
+
const root: HTMLDivElement = mountMarkdown(
|
|
823
|
+
"- alpha\n - beta\n - deep\n - gamma\n- omega",
|
|
824
|
+
);
|
|
825
|
+
|
|
826
|
+
deleteSelectionForInsert(root, rangeBetween(root, "alpha", 2, "beta", 2));
|
|
827
|
+
|
|
828
|
+
expect(htmlToMarkdown(root.innerHTML)).toBe(
|
|
829
|
+
"- alta\n - deep\n - gamma\n- omega",
|
|
830
|
+
);
|
|
831
|
+
});
|
|
832
|
+
|
|
833
|
+
it("keeps a code block a nested item held ahead of the items that followed it", () => {
|
|
834
|
+
const root: HTMLDivElement = mountMarkdown(
|
|
835
|
+
"- alpha\n - beta\n\n ```\n code\n ```\n - gamma",
|
|
836
|
+
);
|
|
837
|
+
|
|
838
|
+
deleteSelectionForInsert(root, rangeBetween(root, "alpha", 2, "beta", 2));
|
|
839
|
+
|
|
840
|
+
const markdown: string = htmlToMarkdown(root.innerHTML);
|
|
841
|
+
expect(markdown.indexOf("code")).toBeLessThan(markdown.indexOf("gamma"));
|
|
842
|
+
expect(markdown.startsWith("- alta\n")).toBe(true);
|
|
843
|
+
});
|
|
844
|
+
|
|
845
|
+
it("removes the list item it empties, and the list with it", () => {
|
|
846
|
+
const root: HTMLDivElement = mountMarkdown("first para\n\n- alpha");
|
|
847
|
+
|
|
848
|
+
deleteSelectionForInsert(root, rangeBetween(root, "first", 2, "alpha", 5));
|
|
849
|
+
|
|
850
|
+
expect(root.innerHTML).toBe("<p>fi</p>");
|
|
851
|
+
});
|
|
852
|
+
|
|
853
|
+
it("moves a caret that starts between list items into the item after it", () => {
|
|
854
|
+
const root: HTMLDivElement = mountMarkdown("- alpha\n- beta");
|
|
855
|
+
const list: Element = root.querySelector("ul") as Element;
|
|
856
|
+
const selection: Range = document.createRange();
|
|
857
|
+
selection.setStart(list, 1);
|
|
858
|
+
selection.setEnd(list.lastElementChild?.firstChild as Node, 2);
|
|
859
|
+
|
|
860
|
+
deleteSelectionForInsert(root, selection);
|
|
861
|
+
|
|
862
|
+
expect(selection.startContainer.nodeName).toBe("LI");
|
|
863
|
+
expect(htmlToMarkdown(root.innerHTML)).toBe("- alpha\n- ta");
|
|
864
|
+
});
|
|
865
|
+
|
|
866
|
+
it("does nothing to a caret", () => {
|
|
867
|
+
const root: HTMLDivElement = mountMarkdown("- alpha\n- beta");
|
|
868
|
+
const range: Range = caretAt(root, "alpha", 2);
|
|
869
|
+
|
|
870
|
+
deleteSelectionForInsert(root, range);
|
|
871
|
+
|
|
872
|
+
expect(htmlToMarkdown(root.innerHTML)).toBe("- alpha\n- beta");
|
|
873
|
+
expect(caretText(range)).toBe("al");
|
|
874
|
+
});
|
|
875
|
+
|
|
876
|
+
/*
|
|
877
|
+
* The item whose text the selection took, above the nested item it ended
|
|
878
|
+
* in, stayed as an empty bullet: "- alep\n- \n- gamma".
|
|
879
|
+
*/
|
|
880
|
+
it("removes the item a selection into its nested item emptied", () => {
|
|
881
|
+
const root: HTMLDivElement = mountMarkdown(
|
|
882
|
+
"- alpha\n- beta\n - deep\n- gamma",
|
|
883
|
+
);
|
|
884
|
+
|
|
885
|
+
deleteSelectionForInsert(root, rangeBetween(root, "alpha", 2, "deep", 2));
|
|
886
|
+
|
|
887
|
+
expect(htmlToMarkdown(root.innerHTML)).toBe("- alep\n- gamma");
|
|
888
|
+
});
|
|
889
|
+
|
|
890
|
+
// An empty item the selection did not reach is still a bullet someone left.
|
|
891
|
+
it("keeps a list that still has an item, even an empty one", () => {
|
|
892
|
+
const root: HTMLDivElement = mountHtml(
|
|
893
|
+
"<p>para start</p><ul><li>beta</li><li><br></li></ul>",
|
|
894
|
+
);
|
|
895
|
+
|
|
896
|
+
deleteSelectionForInsert(root, rangeBetween(root, "para", 2, "beta", 2));
|
|
897
|
+
|
|
898
|
+
expect(root.innerHTML).toBe("<p>pata</p><ul><li><br></li></ul>");
|
|
899
|
+
});
|
|
900
|
+
|
|
901
|
+
it("removes the quote a selection into its first line emptied", () => {
|
|
902
|
+
const root: HTMLDivElement = mountMarkdown(
|
|
903
|
+
"intro\n\n> quoted text\n\nafter",
|
|
904
|
+
);
|
|
905
|
+
|
|
906
|
+
deleteSelectionForInsert(root, rangeBetween(root, "intro", 2, "quoted", 3));
|
|
907
|
+
|
|
908
|
+
expect(root.querySelector("blockquote")).toBeNull();
|
|
909
|
+
expect(htmlToMarkdown(root.innerHTML)).toBe("inted text\n\nafter");
|
|
910
|
+
});
|
|
911
|
+
|
|
912
|
+
/*
|
|
913
|
+
* What is left of the code block's line joins as text, as typing over the
|
|
914
|
+
* selection does; its other lines stay a code block. Its <code> moved
|
|
915
|
+
* whole, the rest was inline code -- every line after it in one span --
|
|
916
|
+
* and the emptied block an empty fence.
|
|
917
|
+
*/
|
|
918
|
+
it("joins what is left of a code block's line as text, and keeps its other lines", () => {
|
|
919
|
+
const root: HTMLDivElement = mountMarkdown(
|
|
920
|
+
"intro\n\n```\ncode line\nsecond\n```",
|
|
921
|
+
);
|
|
922
|
+
const range: Range = rangeBetween(root, "intro", 2, "code line", 4);
|
|
923
|
+
|
|
924
|
+
deleteSelectionForInsert(root, range);
|
|
925
|
+
|
|
926
|
+
expect(htmlToMarkdown(root.innerHTML)).toBe("in line\n\n```\nsecond\n```");
|
|
927
|
+
expect(root.querySelector("p code")).toBeNull();
|
|
928
|
+
expect(caretText(range)).toBe("in");
|
|
929
|
+
});
|
|
930
|
+
|
|
931
|
+
it("removes a one-line code block the selection runs into", () => {
|
|
932
|
+
const root: HTMLDivElement = mountMarkdown("intro\n\n```\ncode line\n```");
|
|
933
|
+
|
|
934
|
+
deleteSelectionForInsert(
|
|
935
|
+
root,
|
|
936
|
+
rangeBetween(root, "intro", 2, "code line", 4),
|
|
937
|
+
);
|
|
938
|
+
|
|
939
|
+
expect(root.querySelector("pre")).toBeNull();
|
|
940
|
+
expect(htmlToMarkdown(root.innerHTML)).toBe("in line");
|
|
941
|
+
});
|
|
942
|
+
|
|
943
|
+
it("removes a code block the selection takes all of", () => {
|
|
944
|
+
const root: HTMLDivElement = mountMarkdown("intro\n\n```\ncode line\n```");
|
|
945
|
+
|
|
946
|
+
deleteSelectionForInsert(
|
|
947
|
+
root,
|
|
948
|
+
rangeBetween(root, "intro", 2, "code line", 9),
|
|
949
|
+
);
|
|
950
|
+
|
|
951
|
+
expect(root.innerHTML).toBe("<p>in</p>");
|
|
952
|
+
});
|
|
953
|
+
|
|
954
|
+
/*
|
|
955
|
+
* Ctrl+A in Chromium and Safari selects from the first text to the last:
|
|
956
|
+
* the line it starts in is emptied too, and stays, holding the caret.
|
|
957
|
+
*/
|
|
958
|
+
it("keeps the line holding the caret when it empties everything", () => {
|
|
959
|
+
const root: HTMLDivElement = mountMarkdown("- alpha\n- beta\n - deep");
|
|
960
|
+
const range: Range = rangeBetween(root, "alpha", 0, "deep", 4);
|
|
961
|
+
|
|
962
|
+
deleteSelectionForInsert(root, range);
|
|
963
|
+
|
|
964
|
+
expect(root.innerHTML).toBe("<ul><li></li></ul>");
|
|
965
|
+
expect(root.querySelector("li")?.contains(range.startContainer)).toBe(true);
|
|
966
|
+
});
|
|
967
|
+
|
|
968
|
+
/*
|
|
969
|
+
* A selection ending at the end of a bold word leaves the <strong> empty:
|
|
970
|
+
* pasted into, the line saved as "Rsee **that****** then check".
|
|
971
|
+
*/
|
|
972
|
+
it("removes the formatting a selection ended in when it empties it", () => {
|
|
973
|
+
const root: HTMLDivElement = mountMarkdown("Run **this** then check");
|
|
974
|
+
|
|
975
|
+
deleteSelectionForInsert(root, rangeBetween(root, "Run", 1, "this", 4));
|
|
976
|
+
|
|
977
|
+
expect(root.innerHTML).toBe("<p>R then check</p>");
|
|
978
|
+
});
|
|
979
|
+
|
|
980
|
+
// What is typed next carries on in the formatting the caret is in.
|
|
981
|
+
it("keeps emptied formatting the caret is in", () => {
|
|
982
|
+
const root: HTMLDivElement = mountMarkdown("Run **this** then check");
|
|
983
|
+
const range: Range = rangeBetween(root, "this", 0, "this", 4);
|
|
984
|
+
|
|
985
|
+
deleteSelectionForInsert(root, range);
|
|
986
|
+
|
|
987
|
+
expect(root.querySelector("strong")?.contains(range.startContainer)).toBe(
|
|
988
|
+
true,
|
|
989
|
+
);
|
|
990
|
+
});
|
|
991
|
+
});
|
|
992
|
+
|
|
993
|
+
/*
|
|
994
|
+
* A selection that runs from one table cell into another is deleted the way
|
|
995
|
+
* typing over it does: both cells stay, and every row keeps its columns.
|
|
996
|
+
* Joined like two lines, the second cell's text moved into the first, the
|
|
997
|
+
* emptied cell went, and the cells after it each moved a column left.
|
|
998
|
+
*/
|
|
999
|
+
describe("deleteSelectionForInsert across table cells", () => {
|
|
1000
|
+
const TABLE: string =
|
|
1001
|
+
"| A | B | C |\n| --- | --- | --- |\n| Cell 1 | Cell 2 | Cell 3 |\n| Cell 4 | Cell 5 | Cell 6 |";
|
|
1002
|
+
|
|
1003
|
+
// The text of each row's cells.
|
|
1004
|
+
const rowsOf: (root: HTMLElement) => Array<Array<string>> = (
|
|
1005
|
+
root: HTMLElement,
|
|
1006
|
+
): Array<Array<string>> => {
|
|
1007
|
+
return Array.from(root.querySelectorAll("tr")).map(
|
|
1008
|
+
(row: HTMLTableRowElement): Array<string> => {
|
|
1009
|
+
return Array.from(row.children).map((cell: Element): string => {
|
|
1010
|
+
return cell.textContent || "";
|
|
1011
|
+
});
|
|
1012
|
+
},
|
|
1013
|
+
);
|
|
1014
|
+
};
|
|
1015
|
+
|
|
1016
|
+
it("keeps both cells of a selection from one cell into the next", () => {
|
|
1017
|
+
const root: HTMLDivElement = mountMarkdown(TABLE);
|
|
1018
|
+
const range: Range = rangeBetween(root, "Cell 1", 2, "Cell 2", 2);
|
|
1019
|
+
|
|
1020
|
+
deleteSelectionForInsert(root, range);
|
|
1021
|
+
|
|
1022
|
+
expect(rowsOf(root)).toEqual([
|
|
1023
|
+
["A", "B", "C"],
|
|
1024
|
+
["Ce", "ll 2", "Cell 3"],
|
|
1025
|
+
["Cell 4", "Cell 5", "Cell 6"],
|
|
1026
|
+
]);
|
|
1027
|
+
expect(range.startContainer.parentElement?.tagName).toBe("TD");
|
|
1028
|
+
expect(caretText(range)).toBe("Ce");
|
|
1029
|
+
});
|
|
1030
|
+
|
|
1031
|
+
it("keeps every column of a selection from the header into the body", () => {
|
|
1032
|
+
const root: HTMLDivElement = mountMarkdown(TABLE);
|
|
1033
|
+
|
|
1034
|
+
deleteSelectionForInsert(root, rangeBetween(root, "C", 0, "Cell 1", 4));
|
|
1035
|
+
|
|
1036
|
+
expect(rowsOf(root)).toEqual([
|
|
1037
|
+
["A", "B", ""],
|
|
1038
|
+
[" 1", "Cell 2", "Cell 3"],
|
|
1039
|
+
["Cell 4", "Cell 5", "Cell 6"],
|
|
1040
|
+
]);
|
|
1041
|
+
});
|
|
1042
|
+
|
|
1043
|
+
it("keeps every column of a selection from one row into the next", () => {
|
|
1044
|
+
const root: HTMLDivElement = mountMarkdown(TABLE);
|
|
1045
|
+
|
|
1046
|
+
deleteSelectionForInsert(
|
|
1047
|
+
root,
|
|
1048
|
+
rangeBetween(root, "Cell 3", 2, "Cell 4", 2),
|
|
1049
|
+
);
|
|
1050
|
+
|
|
1051
|
+
expect(rowsOf(root)).toEqual([
|
|
1052
|
+
["A", "B", "C"],
|
|
1053
|
+
["Cell 1", "Cell 2", "Ce"],
|
|
1054
|
+
["ll 4", "Cell 5", "Cell 6"],
|
|
1055
|
+
]);
|
|
1056
|
+
});
|
|
1057
|
+
|
|
1058
|
+
it("keeps a table a selection from the line above it ends in", () => {
|
|
1059
|
+
const root: HTMLDivElement = mountMarkdown(`intro\n\n${TABLE}`);
|
|
1060
|
+
|
|
1061
|
+
deleteSelectionForInsert(root, rangeBetween(root, "intro", 2, "Cell 1", 4));
|
|
1062
|
+
|
|
1063
|
+
expect(root.querySelector("p")?.textContent).toBe("in");
|
|
1064
|
+
expect(rowsOf(root)).toContainEqual([" 1", "Cell 2", "Cell 3"]);
|
|
1065
|
+
});
|
|
1066
|
+
|
|
1067
|
+
/*
|
|
1068
|
+
* Ctrl+A in Chromium and Safari ends the selection inside the last cell's
|
|
1069
|
+
* text: the table it empties goes, rather than being saved empty.
|
|
1070
|
+
*/
|
|
1071
|
+
it("removes a table the selection empties, when the caret is not in it", () => {
|
|
1072
|
+
const root: HTMLDivElement = mountMarkdown(`intro\n\n${TABLE}`);
|
|
1073
|
+
|
|
1074
|
+
deleteSelectionForInsert(root, rangeBetween(root, "intro", 0, "Cell 6", 6));
|
|
1075
|
+
|
|
1076
|
+
expect(root.querySelector("table")).toBeNull();
|
|
1077
|
+
expect(root.textContent).toBe("");
|
|
1078
|
+
});
|
|
1079
|
+
|
|
1080
|
+
// Chromium's own rule: a cell's text joins the line after the table.
|
|
1081
|
+
it("still joins the line after a table to the cell a selection starts in", () => {
|
|
1082
|
+
const root: HTMLDivElement = mountMarkdown(`${TABLE}\n\nafter`);
|
|
1083
|
+
|
|
1084
|
+
deleteSelectionForInsert(root, rangeBetween(root, "Cell 6", 2, "after", 2));
|
|
1085
|
+
|
|
1086
|
+
expect(rowsOf(root)[2]).toEqual(["Cell 4", "Cell 5", "Ceter"]);
|
|
1087
|
+
expect(root.querySelector("p")).toBeNull();
|
|
1088
|
+
});
|
|
1089
|
+
});
|