@oneuptime/common 13.0.8 → 14.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Models/AnalyticsModels/AuditLog.ts +23 -15
- package/Models/DatabaseModels/GlobalConfig.ts +24 -0
- package/Models/DatabaseModels/Index.ts +4 -0
- package/Models/DatabaseModels/Monitor.ts +3 -2
- package/Models/DatabaseModels/MonitorTemplate.ts +2 -1
- package/Models/DatabaseModels/ServiceLevelObjectiveFeed.ts +2 -0
- package/Models/DatabaseModels/ServiceLevelObjectiveLabelRule.ts +522 -0
- package/Models/DatabaseModels/ServiceLevelObjectiveMonitorRule.ts +38 -4
- package/Models/DatabaseModels/ServiceLevelObjectiveOwnerRule.ts +603 -0
- package/Scripts/generate-service-worker.js +65 -4
- package/Server/API/BaseAPI.ts +26 -5
- package/Server/API/GlobalConfigAPI.ts +228 -462
- package/Server/API/ProjectOIDC.ts +25 -16
- package/Server/API/ProjectSSO.ts +24 -16
- package/Server/API/StatusPageAPI.ts +100 -42
- package/Server/API/TeamMemberAPI.ts +10 -1
- package/Server/Enterprise/EnterpriseEdition.ts +649 -0
- package/Server/Enterprise/EnterpriseFeature.ts +48 -0
- package/Server/Enterprise/EnterpriseLicenseSnapshot.ts +192 -0
- package/Server/Enterprise/EnterpriseServerModule.ts +233 -0
- package/Server/EnvironmentConfig.ts +147 -2
- package/Server/Infrastructure/Postgres/SchemaMigrations/1793900000000-AddEnterpriseEditionFirstSeenAt.ts +25 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1794100000000-AddSloLabelAndOwnerRules.ts +248 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1794200000000-AddSloMonitorRuleMonitorType.ts +19 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +6 -0
- package/Server/Middleware/UserAuthorization.ts +38 -16
- package/Server/Services/AuditLogService.ts +84 -1079
- package/Server/Services/DatabaseService.ts +10 -0
- package/Server/Services/EnterpriseLicenseService.ts +38 -0
- package/Server/Services/GlobalConfigService.ts +80 -1
- package/Server/Services/Index.ts +4 -0
- package/Server/Services/MonitorProbeService.ts +116 -20
- package/Server/Services/MonitorService.ts +59 -6
- package/Server/Services/MonitorStatusTimelineService.ts +284 -0
- package/Server/Services/MonitorTemplateService.ts +26 -0
- package/Server/Services/ProjectService.ts +284 -0
- package/Server/Services/RumSessionPinService.ts +25 -6
- package/Server/Services/ServiceLevelObjectiveLabelRuleEngineService.ts +385 -0
- package/Server/Services/ServiceLevelObjectiveLabelRuleService.ts +51 -0
- package/Server/Services/ServiceLevelObjectiveMonitorRuleEngineService.ts +92 -16
- package/Server/Services/ServiceLevelObjectiveMonitorRuleService.ts +36 -1
- package/Server/Services/ServiceLevelObjectiveOwnerRuleEngineService.ts +521 -0
- package/Server/Services/ServiceLevelObjectiveOwnerRuleService.ts +51 -0
- package/Server/Services/ServiceLevelObjectiveService.ts +28 -0
- package/Server/Services/StatusPagePrivateUserService.ts +7 -3
- package/Server/Services/StatusPageService.ts +78 -1
- package/Server/Services/TeamMemberService.ts +11 -0
- package/Server/Services/TeamService.ts +10 -0
- package/Server/Services/UserService.ts +10 -17
- package/Server/Types/Database/Permissions/CreatePermission.ts +15 -0
- package/Server/Types/Database/Permissions/EditionPermission.ts +208 -18
- package/Server/Types/Database/Permissions/TablePermission.ts +10 -3
- package/Server/Types/Database/Permissions/UpdatePermission.ts +29 -0
- package/Server/Types/Markdown.ts +41 -0
- package/Server/Types/Workflow/Components/Telegram/SendMessageToChat.ts +27 -1
- package/Server/Utils/AI/Toolbox/SloTools.ts +1 -0
- package/Server/Utils/CommunityEditionSsoReport.ts +361 -0
- package/Server/Utils/EditionEnforcement.ts +233 -0
- package/Server/Utils/FrontendEnvironment.ts +41 -2
- package/Server/Utils/InstanceHealth/RedisHealth.ts +12 -277
- package/Server/Utils/Monitor/AffectedResourceList.ts +148 -0
- package/Server/Utils/Monitor/Criteria/CompareCriteria.ts +1 -1
- package/Server/Utils/Monitor/Criteria/EvaluateOverTime.ts +10 -1
- package/Server/Utils/Monitor/Criteria/MetricMonitorCriteria.ts +1 -1
- package/Server/Utils/Monitor/MonitorCriteriaEvaluator.ts +720 -465
- package/Server/Utils/Monitor/MonitoringIntervalValidator.ts +116 -0
- package/Server/Utils/Monitor/RootCauseList.ts +139 -0
- package/Server/Utils/Rules/RuleRun/RuleRunRegistry.ts +28 -0
- package/Server/Utils/Slo/SloRulePatternValidator.ts +42 -0
- package/Server/Utils/Workspace/Slack/Slack.ts +423 -10
- package/Tests/App/Accounts/LoginPasskey.test.tsx +18 -0
- package/Tests/App/Accounts/LoginSsoEdition.test.tsx +616 -0
- package/Tests/App/AdminDashboard/AdminAuthenticationSsoEdition.test.tsx +217 -0
- package/Tests/App/AdminDashboard/AdminEnterprisePluginPage.test.tsx +357 -0
- package/Tests/App/AdminDashboard/EnterpriseLicensesShell.test.tsx +214 -0
- package/Tests/App/AdminDashboard/GlobalSSOEnterpriseShells.test.tsx +271 -0
- package/Tests/App/AdminDashboard/HealthShells.test.tsx +659 -0
- package/Tests/App/Dashboard/AuditLogsAndComplianceShells.test.tsx +572 -0
- package/Tests/App/Dashboard/EnterpriseFeatureUpgrade.test.tsx +547 -0
- package/Tests/App/Dashboard/EnterprisePluginPage.test.tsx +667 -0
- package/Tests/App/Dashboard/FeedFilterSortIntegration.test.tsx +1632 -0
- package/Tests/App/Dashboard/FeedOptionsLocales.test.ts +250 -0
- package/Tests/App/Dashboard/FeedOrdering.test.ts +279 -9
- package/Tests/App/Dashboard/IdentityEnterpriseShells.test.tsx +319 -0
- package/Tests/App/Dashboard/InvestigationFeedRefresh.test.tsx +60 -1
- package/Tests/App/Dashboard/InvestigationPanel.test.tsx +594 -3
- package/Tests/App/Dashboard/OnboardingSsoEmptyState.test.tsx +185 -0
- package/Tests/App/Dashboard/ProductOrientation.test.tsx +646 -0
- package/Tests/App/Dashboard/ResourceFeed.test.tsx +612 -2
- package/Tests/App/Dashboard/ResourceFeedPageWiring.test.ts +30 -0
- package/Tests/App/Dashboard/ResourceFeedPagesFilterSort.test.tsx +1202 -0
- package/Tests/App/Dashboard/ScheduledMaintenanceFeedRefresh.test.tsx +52 -1
- package/Tests/App/Dashboard/SecurityEventConnectionDiagnostics.test.tsx +45 -9
- package/Tests/App/Dashboard/SecurityEventDetailPanel.test.tsx +399 -0
- package/Tests/App/Dashboard/SecurityEventListRow.test.tsx +214 -0
- package/Tests/App/Dashboard/SecurityEventsEmptyState.test.tsx +1 -83
- package/Tests/App/Dashboard/SecurityEventsNavTabs.test.tsx +248 -0
- package/Tests/App/Dashboard/SecurityEventsViewer.test.tsx +1203 -0
- package/Tests/App/Dashboard/SloFeed.test.tsx +106 -1
- package/Tests/App/Dashboard/SloMonitorRuleCriteria.test.tsx +566 -0
- package/Tests/App/Dashboard/SloNavigationWiring.test.tsx +6 -4
- package/Tests/App/Dashboard/SloNoticeBanner.test.tsx +186 -0
- package/Tests/App/Dashboard/SloOverviewKpiStrip.test.tsx +388 -44
- package/Tests/App/Dashboard/SloOverviewLayout.test.tsx +613 -0
- package/Tests/App/Dashboard/UserEmailCallSites.test.tsx +11 -91
- package/Tests/App/StatusPage/StatusPageSsoEmptyState.test.tsx +319 -0
- package/Tests/Helpers/RefreshAwareApiScan.ts +757 -0
- package/Tests/Helpers/TenantScopedRequestScan.ts +515 -0
- package/Tests/Models/DatabaseModels/ResourceFeedModels.test.ts +0 -8
- package/Tests/Models/DatabaseModels/SloLabelAndOwnerRuleModels.test.ts +404 -0
- package/Tests/Models/DatabaseModels/SloOverhaulModels.test.ts +17 -1
- package/Tests/Models/DatabaseModels/StaticRuleCriteriaInheritance.test.ts +4 -2
- package/Tests/Scripts/GenerateServiceWorker.test.ts +931 -0
- package/Tests/Server/API/BaseAPICreateItemDoesNotMutateModel.test.ts +130 -0
- package/Tests/Server/API/GlobalConfigLicense.test.ts +742 -497
- package/Tests/Server/API/OnCallReadinessAPI.test.ts +35 -909
- package/Tests/Server/API/SsoProviderListingsEdition.test.ts +432 -0
- package/Tests/Server/API/TeamMemberLeaveScimLockEdition.test.ts +252 -0
- package/Tests/Server/Enterprise/EnterpriseEdition.test.ts +824 -0
- package/Tests/Server/Enterprise/EnterpriseFeatureActive.test.ts +643 -0
- package/Tests/Server/Enterprise/EnterpriseLicenseSnapshot.test.ts +294 -0
- package/Tests/Server/Enterprise/EnterpriseModelFeatureMap.test.ts +93 -0
- package/Tests/Server/Enterprise/EnterpriseOnlyModulesLiveInEe.test.ts +582 -0
- package/Tests/Server/Enterprise/EnterpriseServerModule.test.ts +247 -0
- package/Tests/Server/Enterprise/FakeEnterpriseModule.ts +502 -0
- package/Tests/Server/Enterprise/TestBillingFlag.ts +70 -0
- package/Tests/Server/EnvironmentConfigEnterpriseEdition.test.ts +314 -0
- package/Tests/Server/Infrastructure/ContainerBootConfiguration.test.ts +289 -0
- package/Tests/Server/Infrastructure/E2EClickHouseFixtureAccess.test.ts +5 -1
- package/Tests/Server/Infrastructure/Postgres/AddConfigurableRuleCriteriaMigration.test.ts +3 -0
- package/Tests/Server/Infrastructure/Postgres/AddSloLabelAndOwnerRulesMigration.test.ts +407 -0
- package/Tests/Server/Infrastructure/Postgres/AddSloMonitorRuleMonitorTypeMigration.test.ts +171 -0
- package/Tests/Server/Infrastructure/Postgres/SloProductOverhaulMigration.test.ts +88 -4
- package/Tests/Server/Middleware/UserAuthorization.test.ts +37 -2
- package/Tests/Server/Middleware/UserAuthorizationEditionEnforcement.test.ts +516 -0
- package/Tests/Server/Services/AuditLogService.test.ts +460 -990
- package/Tests/Server/Services/CreateAndReadResponsesKeepIds.test.ts +263 -0
- package/Tests/Server/Services/DatabaseServiceRuleCriteriaValidation.test.ts +104 -0
- package/Tests/Server/Services/EnterpriseLicenseServiceKeyGeneration.test.ts +151 -0
- package/Tests/Server/Services/GlobalConfigServiceLicenseColumns.test.ts +357 -0
- package/Tests/Server/Services/MonitorDestinationInfoIPv6.test.ts +101 -0
- package/Tests/Server/Services/MonitorProbeServiceIntervalScheduling.test.ts +333 -0
- package/Tests/Server/Services/MonitorStatusTimelineDailyAggregates.test.ts +303 -0
- package/Tests/Server/Services/ProjectServiceAuditLogLicense.test.ts +701 -0
- package/Tests/Server/Services/ProjectServiceAuditLogSettingsCache.test.ts +31 -35
- package/Tests/Server/Services/RuleRun/LabelRuleEnginesGroupBRun.test.ts +48 -1
- package/Tests/Server/Services/RuleRun/OwnerRuleEnginesGroupBRun.test.ts +30 -0
- package/Tests/Server/Services/ScimPushGroupsTeamLocksEdition.test.ts +431 -0
- package/Tests/Server/Services/ServiceLevelObjectiveLabelAndOwnerRuleEngines.test.ts +1170 -0
- package/Tests/Server/Services/ServiceLevelObjectiveLabelAndOwnerRuleServices.test.ts +172 -0
- package/Tests/Server/Services/ServiceLevelObjectiveMonitorRuleEngineService.test.ts +323 -0
- package/Tests/Server/Services/ServiceLevelObjectiveMonitorRuleService.test.ts +115 -0
- package/Tests/Server/Services/ServiceLevelObjectiveMonitorRuleTriggers.test.ts +21 -2
- package/Tests/Server/Services/ServiceLevelObjectiveMonitorTypePostgres.test.ts +480 -0
- package/Tests/Server/Services/ServiceLevelObjectiveService.test.ts +162 -0
- package/Tests/Server/Services/SsoRequirementReadMasking.test.ts +419 -0
- package/Tests/Server/Services/SsoRequirementWriteGuard.test.ts +769 -0
- package/Tests/Server/Services/StaticRuleCriteriaRuntimeCoverage.test.ts +45 -6
- package/Tests/Server/Services/StatusPagePrivateUserInvitationPolicy.test.ts +94 -0
- package/Tests/Server/Services/UserAuthenticationService.test.ts +35 -0
- package/Tests/Server/Services/UserServiceSeatLimit.test.ts +94 -56
- package/Tests/Server/Types/Database/FeedEventTypeFilterQuery.test.ts +745 -0
- package/Tests/Server/Types/Database/Permissions/EditionPermission.test.ts +1823 -0
- package/Tests/Server/Types/Markdown.test.ts +183 -1
- package/Tests/Server/Types/Workflow/Components/ApiComponentSsrf.test.ts +49 -0
- package/Tests/Server/Types/Workflow/Components/TelegramSendMessageToChat.test.ts +331 -0
- package/Tests/Server/Utils/AI/SloTools.test.ts +10 -0
- package/Tests/Server/Utils/CommunityEditionSsoReport.test.ts +565 -0
- package/Tests/Server/Utils/EditionEnforcement.test.ts +303 -0
- package/Tests/Server/Utils/FrontendEnvironment.test.ts +367 -0
- package/Tests/Server/Utils/InstanceHealth/RedisHealth.test.ts +38 -418
- package/Tests/Server/Utils/Monitor/AffectedResourceList.test.ts +518 -0
- package/Tests/Server/Utils/Monitor/Criteria/EvaluateOverTime.test.ts +24 -4
- package/Tests/Server/Utils/Monitor/Criteria/MetricMonitorCriteriaAnomalyUnits.test.ts +1 -1
- package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluator.test.ts +1339 -96
- package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluatorBreachingSamples.test.ts +1101 -0
- package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluatorMetricUnits.test.ts +106 -80
- package/Tests/Server/Utils/Monitor/MonitoringIntervalValidator.test.ts +188 -0
- package/Tests/Server/Utils/Monitor/RootCauseList.test.ts +252 -0
- package/Tests/Server/Utils/Rules/RuleRun/RuleRunPermission.test.ts +154 -0
- package/Tests/Server/Utils/SSRFProtection.test.ts +111 -0
- package/Tests/Server/Utils/Slo/SloRulePatternValidator.test.ts +67 -0
- package/Tests/Server/Utils/VM/VMRunnerSsrf.test.ts +213 -0
- package/Tests/Server/Utils/Workspace/Slack/SlackMarkdownSectionSplit.test.ts +1209 -0
- package/Tests/Types/API/HostnameFromAuthority.test.ts +20 -10
- package/Tests/Types/API/HostnameIPv6.test.ts +149 -0
- package/Tests/Types/API/Route.test.ts +56 -0
- package/Tests/Types/API/URLSchemeLikePath.test.ts +304 -0
- package/Tests/Types/Database/CanonicalModelInstance.test.ts +190 -0
- package/Tests/UI/Components/EditionLabelLapseCopy.ts +104 -0
- package/Tests/UI/Components/EditionLabelLicenseManagerWiring.test.tsx +254 -0
- package/Tests/UI/Components/EditionLabelLicenseRefresh.test.tsx +84 -178
- package/Tests/UI/Components/EditionLabelLicenseStatus.test.tsx +1586 -0
- package/Tests/UI/Components/EditionLabelLicenseWritesGuard.test.tsx +157 -0
- package/Tests/UI/Components/FeedOptions.test.ts +1404 -0
- package/Tests/UI/Components/FeedOptionsButton.test.tsx +2603 -0
- package/Tests/UI/Components/Graphs/DayUptimeGraph.test.tsx +49 -2
- package/Tests/UI/Components/Icon.test.tsx +26 -0
- package/Tests/UI/Components/MarkdownConverters.test.ts +684 -0
- package/Tests/UI/Components/ModelListEmptyState.test.tsx +289 -0
- package/Tests/UI/Components/RuleCriteria/RuleCriteriaModelTable.test.tsx +3 -3
- package/Tests/UI/Components/TelemetryViewer/TelemetryViewerEmptyContent.test.tsx +131 -0
- package/Tests/UI/Components/useFeedItemsViewKey.test.tsx +1017 -0
- package/Tests/UI/Components/useFeedOptions.test.tsx +1107 -0
- package/Tests/UI/EsbuildEnterpriseAlias.test.ts +1127 -0
- package/Tests/Utils/HostAddressUtil.test.ts +138 -0
- package/Tests/Utils/LabelRuleImportExport.test.ts +102 -0
- package/Tests/Utils/Monitor/MonitorDestinationUtil.test.ts +313 -0
- package/Tests/Utils/Monitor/MonitoringIntervalUtil.test.ts +304 -0
- package/Tests/Utils/Slo/SloDuration.test.ts +115 -24
- package/Tests/Utils/Slo/SloHealth.test.ts +93 -10
- package/Tests/Utils/Slo/SloMonitorRuleCriteria.test.ts +109 -0
- package/Tests/Utils/Slo/SloOverviewText.test.ts +64 -0
- package/Tests/Utils/StatusPage/UptimeDailyAggregateUtil.test.ts +248 -0
- package/Types/API/Hostname.ts +63 -16
- package/Types/API/Route.ts +19 -2
- package/Types/API/URL.ts +26 -2
- package/Types/Database/AccessControl/ColumnAccessControl.ts +19 -7
- package/Types/Database/AccessControl/ColumnBillingAccessControl.ts +19 -7
- package/Types/Database/AccessControl/OwnerOnlyColumn.ts +15 -6
- package/Types/Database/CanonicalModelInstance.ts +102 -0
- package/Types/Database/TableColumn.ts +20 -6
- package/Types/EnterpriseLicense/EnterpriseLicensePeriods.ts +29 -0
- package/Types/IP/IPv6.ts +6 -1
- package/Types/Monitor/MetricMonitor/MetricCriteriaContext.ts +6 -5
- package/Types/Monitor/MetricMonitor/MetricMonitorResponse.ts +9 -0
- package/Types/Monitor/MonitorStep.ts +6 -1
- package/Types/Monitor/ProxmoxAlertTemplates.ts +1 -1
- package/Types/Permission.ts +90 -0
- package/Types/Rules/RuleCriteriaFieldRegistry.ts +11 -0
- package/Types/Rules/RuleRun.ts +4 -0
- package/Types/StatusPage/UptimeDailyAggregate.ts +110 -0
- package/UI/Components/EditionLabel/EditionLabel.tsx +796 -1195
- package/UI/Components/EditionLabel/LicenseManager.ts +119 -0
- package/UI/Components/Feed/FeedOptions.ts +427 -0
- package/UI/Components/Feed/FeedOptionsButton.tsx +692 -0
- package/UI/Components/Feed/useFeedItems.ts +28 -9
- package/UI/Components/Feed/useFeedOptions.ts +225 -0
- package/UI/Components/Graphs/DayUptimeGraph.tsx +123 -15
- package/UI/Components/Icon/Icon.tsx +1 -1
- package/UI/Components/Markdown.tsx/MarkdownConverters.ts +0 -0
- package/UI/Components/ModelList/ModelList.tsx +11 -1
- package/UI/Components/MonitorGraphs/Uptime.tsx +69 -0
- package/UI/Components/TelemetryViewer/TelemetryViewer.tsx +28 -12
- package/UI/esbuild-enterprise.js +263 -0
- package/Utils/EnterpriseLicense/EnterpriseLicenseUsage.ts +7 -2
- package/Utils/HostAddressUtil.ts +94 -0
- package/Utils/LabelRuleImportExport.ts +27 -9
- package/Utils/Monitor/MetricValueFormatter.ts +2 -2
- package/Utils/Monitor/MonitorDestinationUtil.ts +157 -0
- package/Utils/Monitor/MonitoringIntervalUtil.ts +436 -0
- package/Utils/Rules/MonitorTypeRuleCriteria.ts +31 -0
- package/Utils/Slo/SloDuration.ts +22 -6
- package/Utils/Slo/SloHealth.ts +8 -7
- package/Utils/Slo/SloMonitorRuleCriteria.ts +33 -1
- package/Utils/Slo/SloOverviewText.ts +33 -0
- package/Utils/Slo/SloProjection.ts +4 -3
- package/Utils/StatusPage/UptimeDailyAggregateUtil.ts +192 -0
- package/build/dist/Models/AnalyticsModels/AuditLog.js +23 -15
- package/build/dist/Models/AnalyticsModels/AuditLog.js.map +1 -1
- package/build/dist/Models/DatabaseModels/GlobalConfig.js +25 -0
- package/build/dist/Models/DatabaseModels/GlobalConfig.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Index.js +4 -0
- package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Monitor.js +2 -2
- package/build/dist/Models/DatabaseModels/Monitor.js.map +1 -1
- package/build/dist/Models/DatabaseModels/MonitorTemplate.js +2 -1
- package/build/dist/Models/DatabaseModels/MonitorTemplate.js.map +1 -1
- package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveFeed.js +2 -0
- package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveFeed.js.map +1 -1
- package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveLabelRule.js +530 -0
- package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveLabelRule.js.map +1 -0
- package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveMonitorRule.js +39 -4
- package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveMonitorRule.js.map +1 -1
- package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveOwnerRule.js +612 -0
- package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveOwnerRule.js.map +1 -0
- package/build/dist/Server/API/BaseAPI.js +26 -5
- package/build/dist/Server/API/BaseAPI.js.map +1 -1
- package/build/dist/Server/API/GlobalConfigAPI.js +148 -344
- package/build/dist/Server/API/GlobalConfigAPI.js.map +1 -1
- package/build/dist/Server/API/ProjectOIDC.js +24 -16
- package/build/dist/Server/API/ProjectOIDC.js.map +1 -1
- package/build/dist/Server/API/ProjectSSO.js +24 -16
- package/build/dist/Server/API/ProjectSSO.js.map +1 -1
- package/build/dist/Server/API/StatusPageAPI.js +93 -43
- package/build/dist/Server/API/StatusPageAPI.js.map +1 -1
- package/build/dist/Server/API/TeamMemberAPI.js +8 -1
- package/build/dist/Server/API/TeamMemberAPI.js.map +1 -1
- package/build/dist/Server/Enterprise/EnterpriseEdition.js +466 -0
- package/build/dist/Server/Enterprise/EnterpriseEdition.js.map +1 -0
- package/build/dist/Server/Enterprise/EnterpriseFeature.js +39 -0
- package/build/dist/Server/Enterprise/EnterpriseFeature.js.map +1 -0
- package/build/dist/Server/Enterprise/EnterpriseLicenseSnapshot.js +70 -0
- package/build/dist/Server/Enterprise/EnterpriseLicenseSnapshot.js.map +1 -0
- package/build/dist/Server/Enterprise/EnterpriseServerModule.js +84 -0
- package/build/dist/Server/Enterprise/EnterpriseServerModule.js.map +1 -0
- package/build/dist/Server/EnvironmentConfig.js +84 -2
- package/build/dist/Server/EnvironmentConfig.js.map +1 -1
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1793900000000-AddEnterpriseEditionFirstSeenAt.js +18 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1793900000000-AddEnterpriseEditionFirstSeenAt.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794100000000-AddSloLabelAndOwnerRules.js +93 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794100000000-AddSloLabelAndOwnerRules.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794200000000-AddSloMonitorRuleMonitorType.js +12 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794200000000-AddSloMonitorRuleMonitorType.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +6 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
- package/build/dist/Server/Middleware/UserAuthorization.js +30 -11
- package/build/dist/Server/Middleware/UserAuthorization.js.map +1 -1
- package/build/dist/Server/Services/AuditLogService.js +71 -740
- package/build/dist/Server/Services/AuditLogService.js.map +1 -1
- package/build/dist/Server/Services/DatabaseService.js +7 -0
- package/build/dist/Server/Services/DatabaseService.js.map +1 -1
- package/build/dist/Server/Services/EnterpriseLicenseService.js +34 -0
- package/build/dist/Server/Services/EnterpriseLicenseService.js.map +1 -1
- package/build/dist/Server/Services/GlobalConfigService.js +63 -0
- package/build/dist/Server/Services/GlobalConfigService.js.map +1 -1
- package/build/dist/Server/Services/Index.js +4 -0
- package/build/dist/Server/Services/Index.js.map +1 -1
- package/build/dist/Server/Services/MonitorProbeService.js +90 -17
- package/build/dist/Server/Services/MonitorProbeService.js.map +1 -1
- package/build/dist/Server/Services/MonitorService.js +48 -6
- package/build/dist/Server/Services/MonitorService.js.map +1 -1
- package/build/dist/Server/Services/MonitorStatusTimelineService.js +242 -0
- package/build/dist/Server/Services/MonitorStatusTimelineService.js.map +1 -1
- package/build/dist/Server/Services/MonitorTemplateService.js +16 -0
- package/build/dist/Server/Services/MonitorTemplateService.js.map +1 -1
- package/build/dist/Server/Services/ProjectService.js +214 -0
- package/build/dist/Server/Services/ProjectService.js.map +1 -1
- package/build/dist/Server/Services/RumSessionPinService.js +24 -6
- package/build/dist/Server/Services/RumSessionPinService.js.map +1 -1
- package/build/dist/Server/Services/ServiceLevelObjectiveLabelRuleEngineService.js +295 -0
- package/build/dist/Server/Services/ServiceLevelObjectiveLabelRuleEngineService.js.map +1 -0
- package/build/dist/Server/Services/ServiceLevelObjectiveLabelRuleService.js +56 -0
- package/build/dist/Server/Services/ServiceLevelObjectiveLabelRuleService.js.map +1 -0
- package/build/dist/Server/Services/ServiceLevelObjectiveMonitorRuleEngineService.js +59 -14
- package/build/dist/Server/Services/ServiceLevelObjectiveMonitorRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/ServiceLevelObjectiveMonitorRuleService.js +22 -1
- package/build/dist/Server/Services/ServiceLevelObjectiveMonitorRuleService.js.map +1 -1
- package/build/dist/Server/Services/ServiceLevelObjectiveOwnerRuleEngineService.js +400 -0
- package/build/dist/Server/Services/ServiceLevelObjectiveOwnerRuleEngineService.js.map +1 -0
- package/build/dist/Server/Services/ServiceLevelObjectiveOwnerRuleService.js +56 -0
- package/build/dist/Server/Services/ServiceLevelObjectiveOwnerRuleService.js.map +1 -0
- package/build/dist/Server/Services/ServiceLevelObjectiveService.js +21 -0
- package/build/dist/Server/Services/ServiceLevelObjectiveService.js.map +1 -1
- package/build/dist/Server/Services/StatusPagePrivateUserService.js +7 -3
- package/build/dist/Server/Services/StatusPagePrivateUserService.js.map +1 -1
- package/build/dist/Server/Services/StatusPageService.js +71 -0
- package/build/dist/Server/Services/StatusPageService.js.map +1 -1
- package/build/dist/Server/Services/TeamMemberService.js +10 -0
- package/build/dist/Server/Services/TeamMemberService.js.map +1 -1
- package/build/dist/Server/Services/TeamService.js +9 -0
- package/build/dist/Server/Services/TeamService.js.map +1 -1
- package/build/dist/Server/Services/UserService.js +10 -16
- package/build/dist/Server/Services/UserService.js.map +1 -1
- package/build/dist/Server/Types/Database/Permissions/CreatePermission.js +10 -0
- package/build/dist/Server/Types/Database/Permissions/CreatePermission.js.map +1 -1
- package/build/dist/Server/Types/Database/Permissions/EditionPermission.js +154 -14
- package/build/dist/Server/Types/Database/Permissions/EditionPermission.js.map +1 -1
- package/build/dist/Server/Types/Database/Permissions/TablePermission.js +10 -3
- package/build/dist/Server/Types/Database/Permissions/TablePermission.js.map +1 -1
- package/build/dist/Server/Types/Database/Permissions/UpdatePermission.js +17 -0
- package/build/dist/Server/Types/Database/Permissions/UpdatePermission.js.map +1 -1
- package/build/dist/Server/Types/Markdown.js +31 -0
- package/build/dist/Server/Types/Markdown.js.map +1 -1
- package/build/dist/Server/Types/Workflow/Components/Telegram/SendMessageToChat.js +20 -1
- package/build/dist/Server/Types/Workflow/Components/Telegram/SendMessageToChat.js.map +1 -1
- package/build/dist/Server/Utils/AI/Toolbox/SloTools.js +1 -0
- package/build/dist/Server/Utils/AI/Toolbox/SloTools.js.map +1 -1
- package/build/dist/Server/Utils/CommunityEditionSsoReport.js +223 -0
- package/build/dist/Server/Utils/CommunityEditionSsoReport.js.map +1 -0
- package/build/dist/Server/Utils/EditionEnforcement.js +187 -0
- package/build/dist/Server/Utils/EditionEnforcement.js.map +1 -0
- package/build/dist/Server/Utils/FrontendEnvironment.js +31 -2
- package/build/dist/Server/Utils/FrontendEnvironment.js.map +1 -1
- package/build/dist/Server/Utils/InstanceHealth/RedisHealth.js +6 -193
- package/build/dist/Server/Utils/InstanceHealth/RedisHealth.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/AffectedResourceList.js +67 -0
- package/build/dist/Server/Utils/Monitor/AffectedResourceList.js.map +1 -0
- package/build/dist/Server/Utils/Monitor/Criteria/CompareCriteria.js +1 -1
- package/build/dist/Server/Utils/Monitor/Criteria/EvaluateOverTime.js +8 -1
- package/build/dist/Server/Utils/Monitor/Criteria/EvaluateOverTime.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/Criteria/MetricMonitorCriteria.js +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js +585 -367
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitoringIntervalValidator.js +88 -0
- package/build/dist/Server/Utils/Monitor/MonitoringIntervalValidator.js.map +1 -0
- package/build/dist/Server/Utils/Monitor/RootCauseList.js +101 -0
- package/build/dist/Server/Utils/Monitor/RootCauseList.js.map +1 -0
- package/build/dist/Server/Utils/Rules/RuleRun/RuleRunRegistry.js +28 -0
- package/build/dist/Server/Utils/Rules/RuleRun/RuleRunRegistry.js.map +1 -1
- package/build/dist/Server/Utils/Slo/SloRulePatternValidator.js +28 -0
- package/build/dist/Server/Utils/Slo/SloRulePatternValidator.js.map +1 -0
- package/build/dist/Server/Utils/Workspace/Slack/Slack.js +331 -11
- package/build/dist/Server/Utils/Workspace/Slack/Slack.js.map +1 -1
- package/build/dist/Types/API/Hostname.js +59 -11
- package/build/dist/Types/API/Hostname.js.map +1 -1
- package/build/dist/Types/API/Route.js +18 -2
- package/build/dist/Types/API/Route.js.map +1 -1
- package/build/dist/Types/API/URL.js +23 -2
- package/build/dist/Types/API/URL.js.map +1 -1
- package/build/dist/Types/Database/AccessControl/ColumnAccessControl.js +19 -7
- package/build/dist/Types/Database/AccessControl/ColumnAccessControl.js.map +1 -1
- package/build/dist/Types/Database/AccessControl/ColumnBillingAccessControl.js +19 -7
- package/build/dist/Types/Database/AccessControl/ColumnBillingAccessControl.js.map +1 -1
- package/build/dist/Types/Database/AccessControl/OwnerOnlyColumn.js +13 -6
- package/build/dist/Types/Database/AccessControl/OwnerOnlyColumn.js.map +1 -1
- package/build/dist/Types/Database/CanonicalModelInstance.js +88 -0
- package/build/dist/Types/Database/CanonicalModelInstance.js.map +1 -0
- package/build/dist/Types/Database/TableColumn.js +19 -6
- package/build/dist/Types/Database/TableColumn.js.map +1 -1
- package/build/dist/Types/EnterpriseLicense/EnterpriseLicensePeriods.js +28 -0
- package/build/dist/Types/EnterpriseLicense/EnterpriseLicensePeriods.js.map +1 -0
- package/build/dist/Types/IP/IPv6.js +6 -1
- package/build/dist/Types/IP/IPv6.js.map +1 -1
- package/build/dist/Types/Monitor/MonitorStep.js +5 -0
- package/build/dist/Types/Monitor/MonitorStep.js.map +1 -1
- package/build/dist/Types/Monitor/ProxmoxAlertTemplates.js +1 -1
- package/build/dist/Types/Permission.js +84 -0
- package/build/dist/Types/Permission.js.map +1 -1
- package/build/dist/Types/Rules/RuleCriteriaFieldRegistry.js +11 -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/StatusPage/UptimeDailyAggregate.js +32 -0
- package/build/dist/Types/StatusPage/UptimeDailyAggregate.js.map +1 -0
- package/build/dist/UI/Components/EditionLabel/EditionLabel.js +414 -585
- package/build/dist/UI/Components/EditionLabel/EditionLabel.js.map +1 -1
- package/build/dist/UI/Components/EditionLabel/LicenseManager.js +2 -0
- package/build/dist/UI/Components/EditionLabel/LicenseManager.js.map +1 -0
- package/build/dist/UI/Components/Feed/FeedOptions.js +235 -0
- package/build/dist/UI/Components/Feed/FeedOptions.js.map +1 -0
- package/build/dist/UI/Components/Feed/FeedOptionsButton.js +346 -0
- package/build/dist/UI/Components/Feed/FeedOptionsButton.js.map +1 -0
- package/build/dist/UI/Components/Feed/useFeedItems.js +17 -7
- package/build/dist/UI/Components/Feed/useFeedItems.js.map +1 -1
- package/build/dist/UI/Components/Feed/useFeedOptions.js +130 -0
- package/build/dist/UI/Components/Feed/useFeedOptions.js.map +1 -0
- package/build/dist/UI/Components/Graphs/DayUptimeGraph.js +90 -17
- package/build/dist/UI/Components/Graphs/DayUptimeGraph.js.map +1 -1
- package/build/dist/UI/Components/Icon/Icon.js +1 -1
- package/build/dist/UI/Components/Icon/Icon.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/ModelList/ModelList.js +4 -1
- package/build/dist/UI/Components/ModelList/ModelList.js.map +1 -1
- package/build/dist/UI/Components/MonitorGraphs/Uptime.js +42 -1
- package/build/dist/UI/Components/MonitorGraphs/Uptime.js.map +1 -1
- package/build/dist/UI/Components/TelemetryViewer/TelemetryViewer.js +2 -2
- package/build/dist/UI/Components/TelemetryViewer/TelemetryViewer.js.map +1 -1
- package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseUsage.js +6 -2
- package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseUsage.js.map +1 -1
- package/build/dist/Utils/HostAddressUtil.js +80 -0
- package/build/dist/Utils/HostAddressUtil.js.map +1 -0
- package/build/dist/Utils/LabelRuleImportExport.js +22 -6
- package/build/dist/Utils/LabelRuleImportExport.js.map +1 -1
- package/build/dist/Utils/Monitor/MetricValueFormatter.js +2 -2
- package/build/dist/Utils/Monitor/MonitorDestinationUtil.js +127 -0
- package/build/dist/Utils/Monitor/MonitorDestinationUtil.js.map +1 -0
- package/build/dist/Utils/Monitor/MonitoringIntervalUtil.js +374 -0
- package/build/dist/Utils/Monitor/MonitoringIntervalUtil.js.map +1 -0
- package/build/dist/Utils/Rules/MonitorTypeRuleCriteria.js +18 -0
- package/build/dist/Utils/Rules/MonitorTypeRuleCriteria.js.map +1 -0
- package/build/dist/Utils/Slo/SloDuration.js +13 -5
- package/build/dist/Utils/Slo/SloDuration.js.map +1 -1
- package/build/dist/Utils/Slo/SloHealth.js +8 -7
- package/build/dist/Utils/Slo/SloHealth.js.map +1 -1
- package/build/dist/Utils/Slo/SloMonitorRuleCriteria.js +16 -1
- package/build/dist/Utils/Slo/SloMonitorRuleCriteria.js.map +1 -1
- package/build/dist/Utils/Slo/SloOverviewText.js +16 -0
- package/build/dist/Utils/Slo/SloOverviewText.js.map +1 -1
- package/build/dist/Utils/Slo/SloProjection.js.map +1 -1
- package/build/dist/Utils/StatusPage/UptimeDailyAggregateUtil.js +148 -0
- package/build/dist/Utils/StatusPage/UptimeDailyAggregateUtil.js.map +1 -0
- package/jest.config.json +3 -1
- package/package.json +1 -1
- package/test-setup.sh +103 -34
- package/tsconfig.json +13 -0
- package/Server/API/EnterpriseLicenseAPI.ts +0 -925
- package/Server/API/TeamComplianceAPI.ts +0 -158
- package/Server/Middleware/SCIMAuthorization.ts +0 -141
- package/Server/Services/TeamComplianceService.ts +0 -733
- package/Server/Utils/EnterpriseLicense/EnterpriseLicenseSeatUtil.ts +0 -186
- package/Server/Utils/InstanceHealth/PostgresHealth.ts +0 -286
- package/Tests/App/AdminDashboard/EnterpriseLicenseInstanceActivity.test.tsx +0 -451
- package/Tests/App/Dashboard/AuditLogsTable.test.tsx +0 -598
- package/Tests/App/Dashboard/SecurityEventsExplorer.test.tsx +0 -761
- package/Tests/App/Dashboard/SecurityEventsSideMenu.test.tsx +0 -247
- package/Tests/App/Dashboard/SecurityEventsTableColumns.test.tsx +0 -382
- package/Tests/App/Dashboard/SecurityEventsVolumeChart.test.tsx +0 -321
- package/Tests/Server/API/EnterpriseLicenseReportUserCount.test.ts +0 -1851
- package/Tests/Server/Middleware/SCIMAuthorization.test.ts +0 -525
- package/Tests/Server/Services/TeamComplianceServiceBehaviour.test.ts +0 -1845
- package/Tests/Server/Utils/EnterpriseLicense/EnterpriseLicenseSeatUtil.test.ts +0 -495
- package/Tests/Server/Utils/InstanceHealth/PostgresHealth.test.ts +0 -337
- package/Tests/Utils/EnterpriseLicenseSeats.test.ts +0 -576
- package/Tests/Utils/EnterpriseLicenseSync.test.ts +0 -568
- package/Utils/EnterpriseLicense/EnterpriseLicenseSeats.ts +0 -287
- package/Utils/EnterpriseLicense/EnterpriseLicenseSync.ts +0 -244
- package/build/dist/Server/API/EnterpriseLicenseAPI.js +0 -646
- package/build/dist/Server/API/EnterpriseLicenseAPI.js.map +0 -1
- package/build/dist/Server/API/TeamComplianceAPI.js +0 -111
- package/build/dist/Server/API/TeamComplianceAPI.js.map +0 -1
- package/build/dist/Server/Middleware/SCIMAuthorization.js +0 -124
- package/build/dist/Server/Middleware/SCIMAuthorization.js.map +0 -1
- package/build/dist/Server/Services/TeamComplianceService.js +0 -537
- package/build/dist/Server/Services/TeamComplianceService.js.map +0 -1
- package/build/dist/Server/Utils/EnterpriseLicense/EnterpriseLicenseSeatUtil.js +0 -145
- package/build/dist/Server/Utils/EnterpriseLicense/EnterpriseLicenseSeatUtil.js.map +0 -1
- package/build/dist/Server/Utils/InstanceHealth/PostgresHealth.js +0 -194
- package/build/dist/Server/Utils/InstanceHealth/PostgresHealth.js.map +0 -1
- package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseSeats.js +0 -168
- package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseSeats.js.map +0 -1
- package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseSync.js +0 -174
- package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseSync.js.map +0 -1
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
import { describe, expect, it } from "@jest/globals";
|
|
2
|
+
import DOMPurify from "dompurify";
|
|
3
|
+
import { marked, Token, Tokens } from "marked";
|
|
4
|
+
import AffectedResourceList, {
|
|
5
|
+
AffectedResourceListEntry,
|
|
6
|
+
} from "../../../Server/Utils/Monitor/AffectedResourceList";
|
|
2
7
|
import {
|
|
3
8
|
htmlToMarkdown,
|
|
4
9
|
markdownToHtml,
|
|
@@ -273,6 +278,167 @@ describe("markdownToHtml", () => {
|
|
|
273
278
|
"<ul><li>a <strong>b</strong></li></ul>",
|
|
274
279
|
);
|
|
275
280
|
});
|
|
281
|
+
|
|
282
|
+
/*
|
|
283
|
+
* An ordered list that does not start at one keeps its first number, so
|
|
284
|
+
* the serializer can write the same numbers back.
|
|
285
|
+
*/
|
|
286
|
+
it("records a first marker other than one as the list's start", () => {
|
|
287
|
+
expect(markdownToHtml("3. a\n4. b")).toBe(
|
|
288
|
+
'<ol start="3"><li>a</li><li>b</li></ol>',
|
|
289
|
+
);
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
it("does not add a start attribute to a list that starts at one", () => {
|
|
293
|
+
expect(markdownToHtml("1. a")).not.toContain("start=");
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
it("keeps an indented continuation line inside its item", () => {
|
|
297
|
+
expect(markdownToHtml("- a\n b")).toBe("<ul><li>a<br>b</li></ul>");
|
|
298
|
+
});
|
|
299
|
+
|
|
300
|
+
/*
|
|
301
|
+
* The fixed two-space indent this converter used to write under every
|
|
302
|
+
* marker. Two spaces is short of the content column of "1.", but a plain
|
|
303
|
+
* line indented past the marker still continues the item (CommonMark's
|
|
304
|
+
* lazy continuation), so documents saved that way read back whole.
|
|
305
|
+
*/
|
|
306
|
+
it("keeps a continuation line indented short of the content column", () => {
|
|
307
|
+
expect(markdownToHtml("1. a\n b")).toBe("<ol><li>a<br>b</li></ol>");
|
|
308
|
+
});
|
|
309
|
+
|
|
310
|
+
it("ends the list at a blank line followed by unindented text", () => {
|
|
311
|
+
expect(markdownToHtml("- a\n\nb")).toBe("<ul><li>a</li></ul><p>b</p>");
|
|
312
|
+
});
|
|
313
|
+
});
|
|
314
|
+
|
|
315
|
+
/*
|
|
316
|
+
* Nesting follows CommonMark, as marked (the email renderer) does: a line
|
|
317
|
+
* belongs to an item when it is indented to the item's content column --
|
|
318
|
+
* the marker's indent, plus the marker, plus one space.
|
|
319
|
+
*/
|
|
320
|
+
describe("nested lists", () => {
|
|
321
|
+
it("nests a bullet list indented to an ordered item's content column", () => {
|
|
322
|
+
expect(markdownToHtml("1. a\n - b\n - c\n2. d")).toBe(
|
|
323
|
+
"<ol><li>a<ul><li>b</li><li>c</li></ul></li><li>d</li></ol>",
|
|
324
|
+
);
|
|
325
|
+
});
|
|
326
|
+
|
|
327
|
+
it("nests a bullet list in a bullet list", () => {
|
|
328
|
+
expect(markdownToHtml("- a\n - b\n- c")).toBe(
|
|
329
|
+
"<ul><li>a<ul><li>b</li></ul></li><li>c</li></ul>",
|
|
330
|
+
);
|
|
331
|
+
});
|
|
332
|
+
|
|
333
|
+
it("nests an ordered list in a bullet list", () => {
|
|
334
|
+
expect(markdownToHtml("- a\n 1. b\n 2. c")).toBe(
|
|
335
|
+
"<ul><li>a<ol><li>b</li><li>c</li></ol></li></ul>",
|
|
336
|
+
);
|
|
337
|
+
});
|
|
338
|
+
|
|
339
|
+
it("nests three levels deep", () => {
|
|
340
|
+
expect(markdownToHtml("- a\n - b\n - c\n- d")).toBe(
|
|
341
|
+
"<ul><li>a<ul><li>b<ul><li>c</li></ul></li></ul></li><li>d</li></ul>",
|
|
342
|
+
);
|
|
343
|
+
});
|
|
344
|
+
|
|
345
|
+
/* Four columns under "10.", not three. */
|
|
346
|
+
it("uses the wider content column of a two-digit marker", () => {
|
|
347
|
+
expect(markdownToHtml("10. a\n - b")).toBe(
|
|
348
|
+
'<ol start="10"><li>a<ul><li>b</li></ul></li></ol>',
|
|
349
|
+
);
|
|
350
|
+
});
|
|
351
|
+
|
|
352
|
+
/*
|
|
353
|
+
* Three spaces is short of the content column of "10.", so the bullet is
|
|
354
|
+
* a sibling of the item, of the other kind, and starts a new list. That
|
|
355
|
+
* is how marked reads it too, and why AffectedResourceList indents item
|
|
356
|
+
* 10's details by four.
|
|
357
|
+
*/
|
|
358
|
+
it("does not nest a list indented short of the content column", () => {
|
|
359
|
+
expect(markdownToHtml("10. a\n - b")).toBe(
|
|
360
|
+
'<ol start="10"><li>a</li></ol><ul><li>b</li></ul>',
|
|
361
|
+
);
|
|
362
|
+
});
|
|
363
|
+
|
|
364
|
+
/*
|
|
365
|
+
* The regression. Changing marker kind used to end the list at any
|
|
366
|
+
* depth, so each item of a ranked list with bullet details became a
|
|
367
|
+
* one-item <ol> with its details stranded in a <ul> after it.
|
|
368
|
+
*/
|
|
369
|
+
it("keeps one ordered list when its items carry bullet lists", () => {
|
|
370
|
+
const html: string = markdownToHtml(
|
|
371
|
+
"1. a\n - x\n2. b\n - y\n3. c\n - z",
|
|
372
|
+
);
|
|
373
|
+
|
|
374
|
+
expect(html).toBe(
|
|
375
|
+
"<ol>" +
|
|
376
|
+
"<li>a<ul><li>x</li></ul></li>" +
|
|
377
|
+
"<li>b<ul><li>y</li></ul></li>" +
|
|
378
|
+
"<li>c<ul><li>z</li></ul></li>" +
|
|
379
|
+
"</ol>",
|
|
380
|
+
);
|
|
381
|
+
});
|
|
382
|
+
|
|
383
|
+
it("still ends a nested list on a marker change at its own indentation", () => {
|
|
384
|
+
expect(markdownToHtml("- a\n - b\n 1. c")).toBe(
|
|
385
|
+
"<ul><li>a<ul><li>b</li></ul><ol><li>c</li></ol></li></ul>",
|
|
386
|
+
);
|
|
387
|
+
});
|
|
388
|
+
|
|
389
|
+
it("nests a tab-indented list", () => {
|
|
390
|
+
expect(markdownToHtml("1. a\n\t- b")).toBe(
|
|
391
|
+
"<ol><li>a<ul><li>b</li></ul></li></ol>",
|
|
392
|
+
);
|
|
393
|
+
});
|
|
394
|
+
|
|
395
|
+
it("keeps an indented list after a blank line inside the item", () => {
|
|
396
|
+
expect(markdownToHtml("- a\n\n - b")).toBe(
|
|
397
|
+
"<ul><li>a<ul><li>b</li></ul></li></ul>",
|
|
398
|
+
);
|
|
399
|
+
});
|
|
400
|
+
|
|
401
|
+
it("keeps text after a nested list inside the item", () => {
|
|
402
|
+
expect(markdownToHtml("- a\n - b\n\n c")).toBe(
|
|
403
|
+
"<ul><li>a<ul><li>b</li></ul><p>c</p></li></ul>",
|
|
404
|
+
);
|
|
405
|
+
});
|
|
406
|
+
|
|
407
|
+
/*
|
|
408
|
+
* What the serializer writes for an item whose own text was deleted and
|
|
409
|
+
* only its nested list is left.
|
|
410
|
+
*/
|
|
411
|
+
it("reads an item that opens straight onto a marker as a nested list", () => {
|
|
412
|
+
expect(markdownToHtml("1. - a\n - b")).toBe(
|
|
413
|
+
"<ol><li><ul><li>a</li><li>b</li></ul></li></ol>",
|
|
414
|
+
);
|
|
415
|
+
});
|
|
416
|
+
|
|
417
|
+
it("nests a list under a task item", () => {
|
|
418
|
+
const html: string = markdownToHtml("- [ ] a\n - b");
|
|
419
|
+
|
|
420
|
+
expect(html).toContain('<ul class="task-list">');
|
|
421
|
+
expect(html).toContain("> a<ul><li>b</li></ul></li></ul>");
|
|
422
|
+
});
|
|
423
|
+
|
|
424
|
+
it("renders inline markup inside a nested item", () => {
|
|
425
|
+
expect(markdownToHtml("1. a\n - Node: `n-1`")).toBe(
|
|
426
|
+
"<ol><li>a<ul><li>Node: <code>n-1</code></li></ul></li></ol>",
|
|
427
|
+
);
|
|
428
|
+
});
|
|
429
|
+
|
|
430
|
+
it("escapes HTML inside a nested item", () => {
|
|
431
|
+
const html: string = markdownToHtml("- a\n - <script>alert(1)</script>");
|
|
432
|
+
|
|
433
|
+
expect(html).not.toContain("<script>");
|
|
434
|
+
expect(html).toContain("<script>");
|
|
435
|
+
});
|
|
436
|
+
|
|
437
|
+
it("renders a fenced block nested in an item", () => {
|
|
438
|
+
expect(markdownToHtml("- a\n ```\n x\n\n y\n ```")).toBe(
|
|
439
|
+
"<ul><li>a<pre><code>x\n\ny</code></pre></li></ul>",
|
|
440
|
+
);
|
|
441
|
+
});
|
|
276
442
|
});
|
|
277
443
|
|
|
278
444
|
describe("blockquotes", () => {
|
|
@@ -537,6 +703,78 @@ describe("htmlToMarkdown", () => {
|
|
|
537
703
|
it("indents a continuation line so it stays inside its item", () => {
|
|
538
704
|
expect(htmlToMarkdown("<ul><li>a<br>b</li></ul>")).toBe("- a\n b");
|
|
539
705
|
});
|
|
706
|
+
|
|
707
|
+
it("indents a continuation line by the width of an ordered marker", () => {
|
|
708
|
+
expect(htmlToMarkdown("<ol><li>a<br>b</li></ol>")).toBe("1. a\n b");
|
|
709
|
+
});
|
|
710
|
+
|
|
711
|
+
it("starts numbering at the list's start attribute", () => {
|
|
712
|
+
expect(htmlToMarkdown('<ol start="3"><li>a</li><li>b</li></ol>')).toBe(
|
|
713
|
+
"3. a\n4. b",
|
|
714
|
+
);
|
|
715
|
+
});
|
|
716
|
+
|
|
717
|
+
it("keeps a start of zero", () => {
|
|
718
|
+
expect(htmlToMarkdown('<ol start="0"><li>a</li></ol>')).toBe("0. a");
|
|
719
|
+
});
|
|
720
|
+
|
|
721
|
+
it("numbers from one when the start attribute is not a number", () => {
|
|
722
|
+
expect(htmlToMarkdown('<ol start="x"><li>a</li></ol>')).toBe("1. a");
|
|
723
|
+
expect(htmlToMarkdown('<ol start="-2"><li>a</li></ol>')).toBe("1. a");
|
|
724
|
+
});
|
|
725
|
+
|
|
726
|
+
/*
|
|
727
|
+
* A nested list is indented to its item's content column -- three
|
|
728
|
+
* spaces under "1. ". The old fixed two spaces put it outside the item.
|
|
729
|
+
*/
|
|
730
|
+
it("indents a nested list by the width of its item's marker", () => {
|
|
731
|
+
expect(htmlToMarkdown("<ol><li>a<ul><li>b</li></ul></li></ol>")).toBe(
|
|
732
|
+
"1. a\n - b",
|
|
733
|
+
);
|
|
734
|
+
});
|
|
735
|
+
|
|
736
|
+
it("indents a nested list by four under a two-digit marker", () => {
|
|
737
|
+
expect(
|
|
738
|
+
htmlToMarkdown(
|
|
739
|
+
'<ol start="9"><li>a<ul><li>x</li></ul></li><li>b<ul><li>y</li></ul></li></ol>',
|
|
740
|
+
),
|
|
741
|
+
).toBe("9. a\n - x\n10. b\n - y");
|
|
742
|
+
});
|
|
743
|
+
|
|
744
|
+
/*
|
|
745
|
+
* No blank line either side of a nested list: that would make the list
|
|
746
|
+
* loose and, between items, read as the end of the outer list.
|
|
747
|
+
*/
|
|
748
|
+
it("keeps a nested list tight inside its item", () => {
|
|
749
|
+
expect(
|
|
750
|
+
htmlToMarkdown("<ul><li>a<ul><li>b</li></ul></li><li>c</li></ul>"),
|
|
751
|
+
).toBe("- a\n - b\n- c");
|
|
752
|
+
});
|
|
753
|
+
|
|
754
|
+
it("indents every level of a deep nest", () => {
|
|
755
|
+
expect(
|
|
756
|
+
htmlToMarkdown(
|
|
757
|
+
"<ul><li>a<ol><li>b<ul><li>c</li></ul></li></ol></li></ul>",
|
|
758
|
+
),
|
|
759
|
+
).toBe("- a\n 1. b\n - c");
|
|
760
|
+
});
|
|
761
|
+
|
|
762
|
+
it("indents a list nested under a task item by the bullet's width", () => {
|
|
763
|
+
expect(
|
|
764
|
+
htmlToMarkdown(
|
|
765
|
+
'<ul class="task-list"><li class="task-list-item">' +
|
|
766
|
+
'<input type="checkbox" disabled> a<ul><li>b</li></ul></li></ul>',
|
|
767
|
+
),
|
|
768
|
+
).toBe("- [ ] a\n - b");
|
|
769
|
+
});
|
|
770
|
+
|
|
771
|
+
it("does not pad a blank line inside an item with spaces", () => {
|
|
772
|
+
const md: string = htmlToMarkdown(
|
|
773
|
+
"<ul><li>a<ul><li>b</li></ul><p>c</p></li></ul>",
|
|
774
|
+
);
|
|
775
|
+
|
|
776
|
+
expect(md).toBe("- a\n - b\n\n c");
|
|
777
|
+
});
|
|
540
778
|
});
|
|
541
779
|
|
|
542
780
|
describe("tables", () => {
|
|
@@ -684,3 +922,449 @@ describe("markdown round trip", () => {
|
|
|
684
922
|
expect(html).not.toContain("<script>");
|
|
685
923
|
});
|
|
686
924
|
});
|
|
925
|
+
|
|
926
|
+
/*
|
|
927
|
+
* The same property for nested lists, which the loop used to take apart:
|
|
928
|
+
* a change of marker kind ended the list at any depth, and the serializer
|
|
929
|
+
* numbered every <ol> from one and indented by a fixed two spaces.
|
|
930
|
+
*/
|
|
931
|
+
describe("nested list round trip", () => {
|
|
932
|
+
const cases: Array<{ name: string; markdown: string }> = [
|
|
933
|
+
{ name: "a bullet list in a bullet list", markdown: "- a\n - b\n- c" },
|
|
934
|
+
{
|
|
935
|
+
name: "an ordered list in a bullet list",
|
|
936
|
+
markdown: "- a\n 1. b\n 2. c\n- d",
|
|
937
|
+
},
|
|
938
|
+
{
|
|
939
|
+
name: "a bullet list in an ordered list",
|
|
940
|
+
markdown: "1. a\n - b\n2. c\n - d",
|
|
941
|
+
},
|
|
942
|
+
{ name: "three levels", markdown: "- a\n - b\n - c\n- d" },
|
|
943
|
+
{
|
|
944
|
+
name: "three levels of mixed kinds",
|
|
945
|
+
markdown: "1. a\n - b\n 1. c\n2. d",
|
|
946
|
+
},
|
|
947
|
+
{ name: "a list that starts at three", markdown: "3. a\n4. b" },
|
|
948
|
+
{ name: "an ordered list split by a blank line", markdown: "1. a\n\n2. b" },
|
|
949
|
+
{
|
|
950
|
+
name: "a nested list under a two-digit marker",
|
|
951
|
+
markdown: "9. a\n - x\n10. b\n - y",
|
|
952
|
+
},
|
|
953
|
+
{ name: "a continuation line in an ordered item", markdown: "1. a\n b" },
|
|
954
|
+
{
|
|
955
|
+
name: "a task list with a nested list",
|
|
956
|
+
markdown: "- [ ] a\n - b\n- [x] c",
|
|
957
|
+
},
|
|
958
|
+
{
|
|
959
|
+
name: "a nested list after a paragraph",
|
|
960
|
+
markdown: "Intro\n\n1. a\n - b",
|
|
961
|
+
},
|
|
962
|
+
{
|
|
963
|
+
name: "a paragraph after a nested list",
|
|
964
|
+
markdown: "1. a\n - b\n\nOutro",
|
|
965
|
+
},
|
|
966
|
+
{ name: "an item that is only a nested list", markdown: "1. - a\n - b" },
|
|
967
|
+
];
|
|
968
|
+
|
|
969
|
+
for (const testCase of cases) {
|
|
970
|
+
it(`preserves ${testCase.name}`, () => {
|
|
971
|
+
const once: string = htmlToMarkdown(markdownToHtml(testCase.markdown));
|
|
972
|
+
|
|
973
|
+
expect(once).toBe(testCase.markdown);
|
|
974
|
+
});
|
|
975
|
+
}
|
|
976
|
+
|
|
977
|
+
it("preserves an ol start attribute through markdown and back", () => {
|
|
978
|
+
const html: string = '<ol start="3"><li>a</li><li>b</li></ol>';
|
|
979
|
+
const markdown: string = htmlToMarkdown(html);
|
|
980
|
+
|
|
981
|
+
expect(markdown).toBe("3. a\n4. b");
|
|
982
|
+
expect(markdownToHtml(markdown)).toBe(html);
|
|
983
|
+
|
|
984
|
+
// And marked, which renders the same markdown into emails, agrees.
|
|
985
|
+
const list: Tokens.List = marked.lexer(markdown)[0] as Tokens.List;
|
|
986
|
+
|
|
987
|
+
expect(list.type).toBe("list");
|
|
988
|
+
expect(list.start).toBe(3);
|
|
989
|
+
});
|
|
990
|
+
|
|
991
|
+
/*
|
|
992
|
+
* Markdown the serializer would not have written itself -- a blank line
|
|
993
|
+
* inside the item, a deeper indent, another bullet character -- is
|
|
994
|
+
* normalised on the first pass and left alone after that.
|
|
995
|
+
*/
|
|
996
|
+
it("reaches a fixed point for loosely written nested lists", () => {
|
|
997
|
+
for (const source of ["- a\n\n - b", "* a\n * b", "1. a\n - b"]) {
|
|
998
|
+
const first: string = htmlToMarkdown(markdownToHtml(source));
|
|
999
|
+
const second: string = htmlToMarkdown(markdownToHtml(first));
|
|
1000
|
+
|
|
1001
|
+
expect(markdownToHtml(first)).toContain("<li>a<ul><li>b</li></ul></li>");
|
|
1002
|
+
expect(second).toBe(first);
|
|
1003
|
+
}
|
|
1004
|
+
});
|
|
1005
|
+
});
|
|
1006
|
+
|
|
1007
|
+
/*
|
|
1008
|
+
* The document that exposed all of this. Platform monitors (Kubernetes,
|
|
1009
|
+
* Proxmox, VMware, ...) write an "Affected Resources" block into the root
|
|
1010
|
+
* cause of the incidents and alerts they open: a ranked ordered list whose
|
|
1011
|
+
* items each own a bullet list of details. "Edit Root Cause" opens it in this
|
|
1012
|
+
* editor, and before nested lists were supported the first keystroke saved
|
|
1013
|
+
* it back with every resource numbered "1." and its details detached.
|
|
1014
|
+
*/
|
|
1015
|
+
describe("Affected Resources block in the editor", () => {
|
|
1016
|
+
const code: (value: string) => string = (value: string): string => {
|
|
1017
|
+
return AffectedResourceList.code(value);
|
|
1018
|
+
};
|
|
1019
|
+
|
|
1020
|
+
const podEntries: (count: number) => Array<AffectedResourceListEntry> = (
|
|
1021
|
+
count: number,
|
|
1022
|
+
): Array<AffectedResourceListEntry> => {
|
|
1023
|
+
const result: Array<AffectedResourceListEntry> = [
|
|
1024
|
+
{
|
|
1025
|
+
kind: "Pod",
|
|
1026
|
+
name: code("oneuptime-migrate-267-k64qm"),
|
|
1027
|
+
value: "**3**",
|
|
1028
|
+
details: [
|
|
1029
|
+
{ label: "Namespace", value: code("default") },
|
|
1030
|
+
{ label: "Job", value: code("oneuptime-migrate-267") },
|
|
1031
|
+
{
|
|
1032
|
+
label: "Node",
|
|
1033
|
+
value: code("gke-gke-test-cluster-default-pool-662f6819-c6w3"),
|
|
1034
|
+
},
|
|
1035
|
+
],
|
|
1036
|
+
},
|
|
1037
|
+
];
|
|
1038
|
+
|
|
1039
|
+
for (let i: number = 2; i <= count; i++) {
|
|
1040
|
+
result.push({
|
|
1041
|
+
kind: "Pod",
|
|
1042
|
+
name: code(`kube-dns-autoscaler-859854db85-gg5x${i}`),
|
|
1043
|
+
value: `**${i % 3 === 0 ? 1 : 2}**`,
|
|
1044
|
+
details: [
|
|
1045
|
+
{ label: "Namespace", value: code("kube-system") },
|
|
1046
|
+
// An empty detail is dropped by the renderer.
|
|
1047
|
+
{ label: "Deployment", value: i % 2 === 0 ? code("kube-dns") : "" },
|
|
1048
|
+
{
|
|
1049
|
+
label: "Node",
|
|
1050
|
+
value: code(`gke-gke-test-cluster-db-pool-3e2bfa3b-du6${i}`),
|
|
1051
|
+
},
|
|
1052
|
+
],
|
|
1053
|
+
});
|
|
1054
|
+
}
|
|
1055
|
+
|
|
1056
|
+
return result;
|
|
1057
|
+
};
|
|
1058
|
+
|
|
1059
|
+
const renderBlock: (count: number, totalCount: number) => string = (
|
|
1060
|
+
count: number,
|
|
1061
|
+
totalCount: number,
|
|
1062
|
+
): string => {
|
|
1063
|
+
return AffectedResourceList.render({
|
|
1064
|
+
heading: "Affected Resources",
|
|
1065
|
+
overflowNoun: "affected resources",
|
|
1066
|
+
totalCount,
|
|
1067
|
+
entries: podEntries(count),
|
|
1068
|
+
});
|
|
1069
|
+
};
|
|
1070
|
+
|
|
1071
|
+
// A root cause as a monitor saves it: a sentence, then the block.
|
|
1072
|
+
const rootCause: (count: number, totalCount: number) => string = (
|
|
1073
|
+
count: number,
|
|
1074
|
+
totalCount: number,
|
|
1075
|
+
): string => {
|
|
1076
|
+
return `Pods are restarting in cluster \`gke-test\`.${renderBlock(count, totalCount)}`;
|
|
1077
|
+
};
|
|
1078
|
+
|
|
1079
|
+
// The sanitizer config of MarkdownEditor.tsx; its URI rule is not relevant here.
|
|
1080
|
+
const sanitize: (html: string) => string = (html: string): string => {
|
|
1081
|
+
return DOMPurify.sanitize(html, { ADD_ATTR: ["target"] });
|
|
1082
|
+
};
|
|
1083
|
+
|
|
1084
|
+
// Top-level block tokens as marked (the email renderer) sees them.
|
|
1085
|
+
const blockTokens: (markdown: string) => Array<Token> = (
|
|
1086
|
+
markdown: string,
|
|
1087
|
+
): Array<Token> => {
|
|
1088
|
+
return marked.lexer(markdown).filter((token: Token): boolean => {
|
|
1089
|
+
return token.type !== "space";
|
|
1090
|
+
});
|
|
1091
|
+
};
|
|
1092
|
+
|
|
1093
|
+
/*
|
|
1094
|
+
* marked must read the re-serialized markdown as ONE ordered list, with
|
|
1095
|
+
* every item owning a nested bullet list. A string that merely looks right
|
|
1096
|
+
* can still parse as a run of one-item lists.
|
|
1097
|
+
*/
|
|
1098
|
+
const expectOneRankedList: (
|
|
1099
|
+
markdown: string,
|
|
1100
|
+
entries: Array<AffectedResourceListEntry>,
|
|
1101
|
+
) => void = (
|
|
1102
|
+
markdown: string,
|
|
1103
|
+
entries: Array<AffectedResourceListEntry>,
|
|
1104
|
+
): void => {
|
|
1105
|
+
const lists: Array<Tokens.List> = blockTokens(markdown).filter(
|
|
1106
|
+
(token: Token): boolean => {
|
|
1107
|
+
return token.type === "list";
|
|
1108
|
+
},
|
|
1109
|
+
) as Array<Tokens.List>;
|
|
1110
|
+
|
|
1111
|
+
expect(lists).toHaveLength(1);
|
|
1112
|
+
|
|
1113
|
+
const list: Tokens.List = lists[0] as Tokens.List;
|
|
1114
|
+
|
|
1115
|
+
expect(list.ordered).toBe(true);
|
|
1116
|
+
expect(list.start).toBe(1);
|
|
1117
|
+
expect(list.items).toHaveLength(entries.length);
|
|
1118
|
+
|
|
1119
|
+
list.items.forEach((item: Tokens.ListItem, index: number): void => {
|
|
1120
|
+
const nested: Array<Tokens.List> = item.tokens.filter(
|
|
1121
|
+
(token: Token): boolean => {
|
|
1122
|
+
return token.type === "list";
|
|
1123
|
+
},
|
|
1124
|
+
) as Array<Tokens.List>;
|
|
1125
|
+
const expectedDetails: number = (entries[index]?.details || []).filter(
|
|
1126
|
+
(detail: { value: string }): boolean => {
|
|
1127
|
+
return detail.value.length > 0;
|
|
1128
|
+
},
|
|
1129
|
+
).length;
|
|
1130
|
+
|
|
1131
|
+
expect(nested).toHaveLength(1);
|
|
1132
|
+
expect(nested[0]?.ordered).toBe(false);
|
|
1133
|
+
expect(nested[0]?.items).toHaveLength(expectedDetails);
|
|
1134
|
+
});
|
|
1135
|
+
};
|
|
1136
|
+
|
|
1137
|
+
it("round trips a three-entry block unchanged", () => {
|
|
1138
|
+
const block: string = renderBlock(3, 3);
|
|
1139
|
+
const once: string = htmlToMarkdown(markdownToHtml(block));
|
|
1140
|
+
|
|
1141
|
+
// A document's leading blank lines are dropped, as for any document.
|
|
1142
|
+
expect(once).toBe(block.replace(/^\n+/, ""));
|
|
1143
|
+
expectOneRankedList(once, podEntries(3));
|
|
1144
|
+
});
|
|
1145
|
+
|
|
1146
|
+
it("round trips a ten-entry block with its overflow line unchanged", () => {
|
|
1147
|
+
const block: string = renderBlock(10, 83);
|
|
1148
|
+
const once: string = htmlToMarkdown(markdownToHtml(block));
|
|
1149
|
+
|
|
1150
|
+
expect(block).toContain("\n10. **Pod**");
|
|
1151
|
+
expect(block).toContain("\n - Namespace:");
|
|
1152
|
+
expect(block).toContain("*... and 73 more affected resources*");
|
|
1153
|
+
expect(once).toBe(block.replace(/^\n+/, ""));
|
|
1154
|
+
expectOneRankedList(once, podEntries(10));
|
|
1155
|
+
});
|
|
1156
|
+
|
|
1157
|
+
it("round trips a whole root cause unchanged", () => {
|
|
1158
|
+
const source: string = rootCause(10, 83);
|
|
1159
|
+
|
|
1160
|
+
expect(htmlToMarkdown(markdownToHtml(source))).toBe(source);
|
|
1161
|
+
});
|
|
1162
|
+
|
|
1163
|
+
it("renders the block as one ordered list whose items own their details", () => {
|
|
1164
|
+
const container: HTMLDivElement = document.createElement("div");
|
|
1165
|
+
container.innerHTML = markdownToHtml(renderBlock(10, 83));
|
|
1166
|
+
|
|
1167
|
+
const topLevelLists: NodeListOf<Element> = container.querySelectorAll(
|
|
1168
|
+
":scope > ol, :scope > ul",
|
|
1169
|
+
);
|
|
1170
|
+
|
|
1171
|
+
expect(topLevelLists).toHaveLength(1);
|
|
1172
|
+
|
|
1173
|
+
const list: Element = topLevelLists[0] as Element;
|
|
1174
|
+
|
|
1175
|
+
expect(list.tagName).toBe("OL");
|
|
1176
|
+
expect(list.hasAttribute("start")).toBe(false);
|
|
1177
|
+
|
|
1178
|
+
const items: NodeListOf<Element> = list.querySelectorAll(":scope > li");
|
|
1179
|
+
|
|
1180
|
+
expect(items).toHaveLength(10);
|
|
1181
|
+
|
|
1182
|
+
items.forEach((item: Element): void => {
|
|
1183
|
+
const details: NodeListOf<Element> = item.querySelectorAll(":scope > ul");
|
|
1184
|
+
|
|
1185
|
+
expect(details).toHaveLength(1);
|
|
1186
|
+
expect(details[0]?.querySelector(":scope > li")?.textContent).toMatch(
|
|
1187
|
+
/^Namespace: /,
|
|
1188
|
+
);
|
|
1189
|
+
});
|
|
1190
|
+
|
|
1191
|
+
// The heading and the overflow line stay paragraphs around the list.
|
|
1192
|
+
expect(container.firstElementChild?.tagName).toBe("P");
|
|
1193
|
+
expect(container.lastElementChild?.tagName).toBe("P");
|
|
1194
|
+
expect(container.lastElementChild?.textContent).toBe(
|
|
1195
|
+
"... and 73 more affected resources",
|
|
1196
|
+
);
|
|
1197
|
+
});
|
|
1198
|
+
|
|
1199
|
+
/*
|
|
1200
|
+
* The editor sanitizes before injecting. DOMPurify's default allowlist
|
|
1201
|
+
* keeps nested lists and the start attribute; if it ever stopped doing so
|
|
1202
|
+
* the round trip would lose them there instead of here.
|
|
1203
|
+
*/
|
|
1204
|
+
it("survives the editor's sanitizer unchanged", () => {
|
|
1205
|
+
const html: string = markdownToHtml(rootCause(10, 83));
|
|
1206
|
+
|
|
1207
|
+
expect(sanitize(html)).toBe(html);
|
|
1208
|
+
expect(sanitize(markdownToHtml("3. a\n4. b"))).toContain('<ol start="3">');
|
|
1209
|
+
});
|
|
1210
|
+
|
|
1211
|
+
/*
|
|
1212
|
+
* What "Edit Root Cause" actually does: render into the contenteditable,
|
|
1213
|
+
* let the user type, serialize. Adding a note after the list must not
|
|
1214
|
+
* renumber the list or detach any item's details.
|
|
1215
|
+
*/
|
|
1216
|
+
it("keeps numbering and nesting when the user adds a paragraph", () => {
|
|
1217
|
+
const source: string = rootCause(10, 83);
|
|
1218
|
+
const editable: HTMLDivElement = document.createElement("div");
|
|
1219
|
+
editable.innerHTML = sanitize(markdownToHtml(source));
|
|
1220
|
+
|
|
1221
|
+
const note: HTMLParagraphElement = document.createElement("p");
|
|
1222
|
+
note.textContent = "Rolled back the migration job.";
|
|
1223
|
+
editable.appendChild(note);
|
|
1224
|
+
|
|
1225
|
+
const saved: string = htmlToMarkdown(editable.innerHTML);
|
|
1226
|
+
|
|
1227
|
+
expect(saved).toBe(`${source}\n\nRolled back the migration job.`);
|
|
1228
|
+
expectOneRankedList(saved, podEntries(10));
|
|
1229
|
+
});
|
|
1230
|
+
|
|
1231
|
+
it("keeps numbering and nesting when the user edits a nested detail", () => {
|
|
1232
|
+
const source: string = rootCause(10, 83);
|
|
1233
|
+
const editable: HTMLDivElement = document.createElement("div");
|
|
1234
|
+
editable.innerHTML = sanitize(markdownToHtml(source));
|
|
1235
|
+
|
|
1236
|
+
const lastDetail: Element | null = editable.querySelector(
|
|
1237
|
+
":scope > ol > li:nth-child(10) > ul > li:last-child",
|
|
1238
|
+
);
|
|
1239
|
+
|
|
1240
|
+
expect(lastDetail?.textContent).toMatch(/^Node: /);
|
|
1241
|
+
lastDetail?.appendChild(document.createTextNode(" (cordoned)"));
|
|
1242
|
+
|
|
1243
|
+
const saved: string = htmlToMarkdown(editable.innerHTML);
|
|
1244
|
+
const nodeTen: string = "`gke-gke-test-cluster-db-pool-3e2bfa3b-du610`";
|
|
1245
|
+
|
|
1246
|
+
expect(saved).toBe(
|
|
1247
|
+
source.replace(
|
|
1248
|
+
` - Node: ${nodeTen}`,
|
|
1249
|
+
` - Node: ${nodeTen} (cordoned)`,
|
|
1250
|
+
),
|
|
1251
|
+
);
|
|
1252
|
+
expectOneRankedList(saved, podEntries(10));
|
|
1253
|
+
});
|
|
1254
|
+
|
|
1255
|
+
it("is a fixed point: a second save changes nothing", () => {
|
|
1256
|
+
const first: string = htmlToMarkdown(markdownToHtml(rootCause(10, 83)));
|
|
1257
|
+
|
|
1258
|
+
expect(htmlToMarkdown(markdownToHtml(first))).toBe(first);
|
|
1259
|
+
});
|
|
1260
|
+
});
|
|
1261
|
+
|
|
1262
|
+
/*
|
|
1263
|
+
* Regressions found while verifying nested-list support.
|
|
1264
|
+
*/
|
|
1265
|
+
describe("nested list edge cases", () => {
|
|
1266
|
+
/*
|
|
1267
|
+
* Each level of nesting parses its item's lines as a document of its own.
|
|
1268
|
+
* Uncapped, a single "- - - … x" line a thousand levels deep overflowed
|
|
1269
|
+
* the stack — in the editor's mount effect, so one such document would
|
|
1270
|
+
* have crashed the editor for everyone who opened it — and a staircase of
|
|
1271
|
+
* indented bullets cost cubic time.
|
|
1272
|
+
*/
|
|
1273
|
+
it("does not overflow the stack on a pathologically deep single line", () => {
|
|
1274
|
+
const deep: string = `${"- ".repeat(1000)}x`;
|
|
1275
|
+
|
|
1276
|
+
let html: string = "";
|
|
1277
|
+
expect(() => {
|
|
1278
|
+
html = markdownToHtml(deep);
|
|
1279
|
+
}).not.toThrow();
|
|
1280
|
+
expect(html).toContain("x");
|
|
1281
|
+
// Nesting stops at the cap; the rest of the item is kept as text.
|
|
1282
|
+
expect((html.match(/<ul>/g) || []).length).toBeLessThanOrEqual(21);
|
|
1283
|
+
});
|
|
1284
|
+
|
|
1285
|
+
it("parses a deep staircase of indented bullets quickly", () => {
|
|
1286
|
+
const lines: Array<string> = [];
|
|
1287
|
+
for (let i: number = 0; i < 1000; i++) {
|
|
1288
|
+
lines.push(`${" ".repeat(i * 2)}- item ${i}`);
|
|
1289
|
+
}
|
|
1290
|
+
|
|
1291
|
+
const startedAt: number = performance.now();
|
|
1292
|
+
const html: string = markdownToHtml(lines.join("\n"));
|
|
1293
|
+
const elapsed: number = performance.now() - startedAt;
|
|
1294
|
+
|
|
1295
|
+
expect(html).toContain("item 0");
|
|
1296
|
+
expect(html).toContain("item 999");
|
|
1297
|
+
// The uncapped parser took about 8 seconds here.
|
|
1298
|
+
expect(elapsed).toBeLessThan(2000);
|
|
1299
|
+
});
|
|
1300
|
+
|
|
1301
|
+
it("still nests normally well inside the cap", () => {
|
|
1302
|
+
const lines: Array<string> = [];
|
|
1303
|
+
for (let i: number = 0; i < 10; i++) {
|
|
1304
|
+
lines.push(`${" ".repeat(i * 2)}- level ${i}`);
|
|
1305
|
+
}
|
|
1306
|
+
const markdown: string = lines.join("\n");
|
|
1307
|
+
|
|
1308
|
+
const html: string = markdownToHtml(markdown);
|
|
1309
|
+
|
|
1310
|
+
expect((html.match(/<ul>/g) || []).length).toBe(10);
|
|
1311
|
+
expect(htmlToMarkdown(html)).toBe(markdown);
|
|
1312
|
+
});
|
|
1313
|
+
|
|
1314
|
+
/*
|
|
1315
|
+
* A loose item's second paragraph is a <p> after the item's text. It used
|
|
1316
|
+
* to come back one newline short, so the saved markdown joined it to the
|
|
1317
|
+
* first paragraph and every save lost another break.
|
|
1318
|
+
*/
|
|
1319
|
+
it("keeps the blank line before a later paragraph of an ordered item", () => {
|
|
1320
|
+
const markdown: string = "1. a\n\n b\n2. c";
|
|
1321
|
+
|
|
1322
|
+
const html: string = markdownToHtml(markdown);
|
|
1323
|
+
|
|
1324
|
+
expect(html).toBe("<ol><li>a<p>b</p></li><li>c</li></ol>");
|
|
1325
|
+
expect(htmlToMarkdown(html)).toBe(markdown);
|
|
1326
|
+
});
|
|
1327
|
+
|
|
1328
|
+
it("keeps every paragraph break of a multi-paragraph bullet, save after save", () => {
|
|
1329
|
+
const markdown: string = "- a\n\n b\n\n c\n- d";
|
|
1330
|
+
|
|
1331
|
+
const once: string = htmlToMarkdown(markdownToHtml(markdown));
|
|
1332
|
+
const twice: string = htmlToMarkdown(markdownToHtml(once));
|
|
1333
|
+
|
|
1334
|
+
expect(once).toBe(markdown);
|
|
1335
|
+
expect(twice).toBe(markdown);
|
|
1336
|
+
});
|
|
1337
|
+
|
|
1338
|
+
it("separates a later paragraph from the item's text when serializing editor HTML", () => {
|
|
1339
|
+
expect(htmlToMarkdown("<ul><li>a<p>b</p></li></ul>")).toBe("- a\n\n b");
|
|
1340
|
+
});
|
|
1341
|
+
|
|
1342
|
+
/*
|
|
1343
|
+
* Enter at the end of a nested bullet leaves an empty <li>. Trimming the
|
|
1344
|
+
* item's content writes it as a bare "-", which used to reopen as a
|
|
1345
|
+
* literal "-" paragraph while marked (the email) read it as an empty item.
|
|
1346
|
+
*/
|
|
1347
|
+
it("reads a bare marker after a list item as an empty item", () => {
|
|
1348
|
+
const saved: string = htmlToMarkdown(
|
|
1349
|
+
"<ol><li>a<ul><li>x</li><li><br></li></ul></li><li>b</li></ol>",
|
|
1350
|
+
);
|
|
1351
|
+
|
|
1352
|
+
expect(saved).toBe("1. a\n - x\n -\n2. b");
|
|
1353
|
+
|
|
1354
|
+
const html: string = markdownToHtml(saved);
|
|
1355
|
+
expect(html).toBe(
|
|
1356
|
+
"<ol><li>a<ul><li>x</li><li></li></ul></li><li>b</li></ol>",
|
|
1357
|
+
);
|
|
1358
|
+
expect(html).not.toContain("<p>-</p>");
|
|
1359
|
+
expect(htmlToMarkdown(html)).toBe(saved);
|
|
1360
|
+
});
|
|
1361
|
+
|
|
1362
|
+
it("an empty ordered item after another is read as an item too", () => {
|
|
1363
|
+
expect(markdownToHtml("1. a\n2.")).toBe("<ol><li>a</li><li></li></ol>");
|
|
1364
|
+
});
|
|
1365
|
+
|
|
1366
|
+
it("a bare marker cannot START a list, so a lone number stays text", () => {
|
|
1367
|
+
expect(markdownToHtml("2021.")).toBe("<p>2021.</p>");
|
|
1368
|
+
expect(markdownToHtml("-")).not.toContain("<li>");
|
|
1369
|
+
});
|
|
1370
|
+
});
|