@oneuptime/common 12.0.30 → 12.0.31
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/SecurityEvent.ts +48 -16
- package/Models/AnalyticsModels/ThreatIntelIndicator.ts +10 -5
- package/Models/DatabaseModels/AlertSeverity.ts +44 -0
- package/Models/DatabaseModels/DetectionRule.ts +16 -5
- package/Models/DatabaseModels/GoogleSecOpsConnection.ts +14 -5
- package/Models/DatabaseModels/IncidentSeverity.ts +44 -0
- package/Models/DatabaseModels/Index.ts +2 -0
- package/Models/DatabaseModels/NetworkDevice.ts +113 -3
- package/Models/DatabaseModels/NetworkDeviceAutoImportRule.ts +88 -0
- package/Models/DatabaseModels/NetworkDeviceDiscoveryScan.ts +22 -0
- package/Models/DatabaseModels/NetworkDeviceOidTemplate.ts +499 -0
- package/Models/DatabaseModels/ThreatIntelFeed.ts +16 -5
- package/Server/API/GlobalConfigAPI.ts +362 -183
- package/Server/API/TelemetryAPI.ts +42 -4
- package/Server/EnvironmentConfig.ts +112 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1790500000000-AddNetworkDeviceOidTemplate.ts +59 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1790600000000-AddAutoImportRuleOidTemplate.ts +25 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +4 -0
- package/Server/Middleware/MultipartFormData.ts +118 -32
- package/Server/Services/AlertEpisodeLabelRuleEngineService.ts +9 -1
- package/Server/Services/AlertEpisodeOnCallRuleEngineService.ts +9 -1
- package/Server/Services/AlertEpisodeOwnerRuleEngineService.ts +9 -1
- package/Server/Services/AlertEpisodePrivacyRuleEngineService.ts +9 -1
- package/Server/Services/AlertGroupingEngineService.ts +9 -1
- package/Server/Services/AlertLabelRuleEngineService.ts +9 -1
- package/Server/Services/AlertOnCallRuleEngineService.ts +9 -1
- package/Server/Services/AlertOwnerRuleEngineService.ts +9 -1
- package/Server/Services/AlertPrivacyRuleEngineService.ts +9 -1
- package/Server/Services/AlertReminderRuleService.ts +9 -1
- package/Server/Services/AutoRemediationRuleEngineService.ts +9 -1
- package/Server/Services/CephClusterLabelRuleEngineService.ts +9 -1
- package/Server/Services/CephClusterOwnerRuleEngineService.ts +9 -1
- package/Server/Services/CloudResourceLabelRuleEngineService.ts +9 -1
- package/Server/Services/CloudResourceOwnerRuleEngineService.ts +9 -1
- package/Server/Services/DashboardLabelRuleEngineService.ts +9 -1
- package/Server/Services/DashboardOwnerRuleEngineService.ts +9 -1
- package/Server/Services/DockerHostLabelRuleEngineService.ts +9 -1
- package/Server/Services/DockerHostOwnerRuleEngineService.ts +9 -1
- package/Server/Services/DockerSwarmClusterLabelRuleEngineService.ts +9 -1
- package/Server/Services/DockerSwarmClusterOwnerRuleEngineService.ts +9 -1
- package/Server/Services/HostLabelRuleEngineService.ts +9 -1
- package/Server/Services/HostOwnerRuleEngineService.ts +9 -1
- package/Server/Services/IncidentEpisodeLabelRuleEngineService.ts +9 -1
- package/Server/Services/IncidentEpisodeOnCallRuleEngineService.ts +9 -1
- package/Server/Services/IncidentEpisodeOwnerRuleEngineService.ts +9 -1
- package/Server/Services/IncidentEpisodePrivacyRuleEngineService.ts +9 -1
- package/Server/Services/IncidentGroupingEngineService.ts +9 -1
- package/Server/Services/IncidentLabelRuleEngineService.ts +9 -1
- package/Server/Services/IncidentOnCallRuleEngineService.ts +9 -1
- package/Server/Services/IncidentOwnerRuleEngineService.ts +9 -1
- package/Server/Services/IncidentPrivacyRuleEngineService.ts +9 -1
- package/Server/Services/IncidentReminderRuleService.ts +9 -1
- package/Server/Services/IncidentSlaRuleService.ts +9 -1
- package/Server/Services/IncomingCallPolicyLabelRuleEngineService.ts +9 -1
- package/Server/Services/IncomingCallPolicyOwnerRuleEngineService.ts +9 -1
- package/Server/Services/Index.ts +2 -0
- package/Server/Services/IoTFleetLabelRuleEngineService.ts +9 -1
- package/Server/Services/IoTFleetOwnerRuleEngineService.ts +9 -1
- package/Server/Services/KubernetesClusterLabelRuleEngineService.ts +9 -1
- package/Server/Services/KubernetesClusterOwnerRuleEngineService.ts +9 -1
- package/Server/Services/KubernetesResourceService.ts +5 -1
- package/Server/Services/MonitorLabelRuleEngineService.ts +9 -1
- package/Server/Services/MonitorOwnerRuleEngineService.ts +9 -1
- package/Server/Services/NetworkDeviceAutoImportRuleEngineService.ts +35 -0
- package/Server/Services/NetworkDeviceAutoImportRuleService.ts +96 -0
- package/Server/Services/NetworkDeviceLabelRuleEngineService.ts +9 -1
- package/Server/Services/NetworkDeviceOidTemplateService.ts +201 -0
- package/Server/Services/NetworkDeviceOwnerRuleEngineService.ts +9 -1
- package/Server/Services/NetworkDeviceService.ts +209 -1
- package/Server/Services/OnCallDutyPolicyLabelRuleEngineService.ts +9 -1
- package/Server/Services/OnCallDutyPolicyOwnerRuleEngineService.ts +9 -1
- package/Server/Services/OnCallDutyPolicyScheduleLabelRuleEngineService.ts +9 -1
- package/Server/Services/OnCallDutyPolicyScheduleOwnerRuleEngineService.ts +9 -1
- package/Server/Services/PodmanHostLabelRuleEngineService.ts +9 -1
- package/Server/Services/PodmanHostOwnerRuleEngineService.ts +9 -1
- package/Server/Services/ProxmoxClusterLabelRuleEngineService.ts +9 -1
- package/Server/Services/ProxmoxClusterOwnerRuleEngineService.ts +9 -1
- package/Server/Services/RumApplicationLabelRuleEngineService.ts +9 -1
- package/Server/Services/RumApplicationOwnerRuleEngineService.ts +9 -1
- package/Server/Services/RunbookLabelRuleEngineService.ts +9 -1
- package/Server/Services/RunbookOwnerRuleEngineService.ts +9 -1
- package/Server/Services/RunbookRuleEngineService.ts +9 -1
- package/Server/Services/ScheduledMaintenanceLabelRuleEngineService.ts +9 -1
- package/Server/Services/ScheduledMaintenanceOwnerRuleEngineService.ts +9 -1
- package/Server/Services/ScheduledMaintenanceReminderRuleService.ts +9 -1
- package/Server/Services/ServerlessFunctionLabelRuleEngineService.ts +9 -1
- package/Server/Services/ServerlessFunctionOwnerRuleEngineService.ts +9 -1
- package/Server/Services/ServiceLabelRuleEngineService.ts +9 -1
- package/Server/Services/ServiceOwnerRuleEngineService.ts +9 -1
- package/Server/Services/StatusPageLabelRuleEngineService.ts +9 -1
- package/Server/Services/StatusPageMonitorRuleEngineService.ts +7 -0
- package/Server/Services/StatusPageOwnerRuleEngineService.ts +9 -1
- package/Server/Services/TelemetrySourceMapService.ts +266 -23
- package/Server/Services/UserService.ts +27 -0
- package/Server/Services/WorkflowLabelRuleEngineService.ts +9 -1
- package/Server/Services/WorkflowOwnerRuleEngineService.ts +9 -1
- package/Server/Utils/EnterpriseLicense/EnterpriseLicenseSeatUtil.ts +186 -0
- package/Server/Utils/Monitor/CapturedMetricAttributeUtil.ts +245 -0
- package/Server/Utils/Monitor/Criteria/SnmpMonitorCriteria.ts +21 -2
- package/Server/Utils/Monitor/MonitorMetricUtil.ts +55 -21
- package/Server/Utils/Monitor/MonitorTemplateUtil.ts +32 -0
- package/Server/Utils/Monitor/NetworkDeviceMetricUtil.ts +15 -2
- package/Server/Utils/Monitor/NetworkDeviceWalkUtil.ts +18 -1
- package/Server/Utils/Monitor/NetworkInventoryUtil.ts +10 -0
- package/Server/Utils/Monitor/SeriesResourceLabels.ts +34 -0
- package/Server/Utils/Rules/RuleEngineRuleRead.ts +48 -0
- package/Server/Utils/Telemetry/ExceptionSanitizer.ts +14 -1
- package/Server/Utils/Telemetry/LogExceptionExtractor.ts +14 -2
- package/Server/Utils/Telemetry/SourceMapResolver.ts +16 -5
- package/Server/Utils/Telemetry/StackTraceParser.ts +399 -0
- package/Tests/App/Dashboard/EventOverlayHook.test.tsx +125 -0
- package/Tests/App/Dashboard/HeaderImageAssets.test.tsx +93 -0
- package/Tests/App/Dashboard/OnCallReadinessSurfaces.test.tsx +3 -3
- package/Tests/App/Dashboard/UserElementEmail.test.tsx +12 -4
- package/Tests/App/Dashboard/UserEmailCallSites.test.tsx +1 -1
- package/Tests/Models/DatabaseModels/DomainRoleTierCoverage.test.ts +14 -0
- package/Tests/Models/DatabaseModels/ModelRegistryInvariants.test.ts +469 -0
- package/Tests/Models/SecurityDomainAccessControl.test.ts +429 -0
- package/Tests/Server/API/GlobalConfigLicense.test.ts +657 -0
- package/Tests/Server/API/SecurityEventAttributesAPI.test.ts +84 -6
- package/Tests/Server/API/TelemetryResolveStackTraceAPI.test.ts +805 -0
- package/Tests/Server/Infrastructure/Postgres/AddOnCallCalendarFeedsMigration.test.ts +32 -7
- package/Tests/Server/Middleware/IdentityRateLimit.test.ts +1144 -0
- package/Tests/Server/Middleware/MultipartFormData.test.ts +618 -3
- package/Tests/Server/Services/MonitorLabelRuleEngineScale.test.ts +520 -0
- package/Tests/Server/Services/NetworkDeviceOidTemplateService.test.ts +332 -0
- package/Tests/Server/Services/NetworkDeviceOidTemplateWriteGuards.test.ts +409 -0
- package/Tests/Server/Services/RuleEngineRuleFetchLimit.test.ts +239 -0
- package/Tests/Server/Services/TelemetrySourceMapService.test.ts +1210 -2
- package/Tests/Server/Services/UserServiceSeatLimit.test.ts +182 -0
- package/Tests/Server/Types/AnalyticsDatabase/SecurityEventModelPermission.test.ts +255 -0
- package/Tests/Server/Types/Database/Permissions/ReadBlockPermission.test.ts +212 -0
- package/Tests/Server/Types/Database/Permissions/SecurityRoleAccess.test.ts +413 -0
- package/Tests/Server/Utils/CodeRepository.test.ts +689 -0
- package/Tests/Server/Utils/EnterpriseLicense/EnterpriseLicenseSeatUtil.test.ts +495 -0
- package/Tests/Server/Utils/ExceptionSanitizer.test.ts +77 -0
- package/Tests/Server/Utils/Monitor/CapturedMetricAttributeUtil.test.ts +284 -0
- package/Tests/Server/Utils/Monitor/MonitorCustomMetricAttributes.test.ts +503 -0
- package/Tests/Server/Utils/Monitor/MonitorTemplatePrototypePollution.test.ts +106 -0
- package/Tests/Server/Utils/Monitor/NetworkDeviceWalkLogWritePath.test.ts +33 -4
- package/Tests/Server/Utils/Monitor/NetworkDeviceWalkUtil.test.ts +14 -4
- package/Tests/Server/Utils/Monitor/NetworkInventoryUtil.test.ts +44 -0
- package/Tests/Server/Utils/OpenAPISpec.test.ts +536 -0
- package/Tests/Server/Utils/Rules/RuleEngineRuleRead.test.ts +115 -0
- package/Tests/Server/Utils/StackTraceParser.test.ts +610 -0
- package/Tests/Server/Utils/Telemetry/LogExceptionExtractor.test.ts +0 -0
- package/Tests/Server/Utils/Telemetry/SourceMapLimits.test.ts +656 -0
- package/Tests/Server/Utils/Telemetry/SourceMapResolver.test.ts +100 -0
- package/Tests/Types/Monitor/SnmpMonitor/SnmpOidListUtil.test.ts +454 -0
- package/Tests/Types/SecurityRolePermissions.test.ts +193 -0
- package/Tests/UI/Components/Charts/AnnotationLayout.test.ts +773 -0
- package/Tests/UI/Components/Charts/ChartAnnotationRail.test.tsx +789 -0
- package/Tests/UI/Components/Charts/ChartBucketIdentity.test.ts +254 -0
- package/Tests/UI/Components/Charts/TimeAnnotation.test.ts +471 -0
- package/Tests/UI/Components/EditionLabelLicenseRefresh.test.tsx +405 -0
- package/Tests/UI/Components/ErrorMessageRefreshControl.test.tsx +83 -0
- package/Tests/UI/Components/MarkdownConverters.test.ts +686 -0
- package/Tests/UI/Components/ModelTable/BaseModelTableDeleteAndEmptyStates.test.tsx +341 -0
- package/Tests/UI/Components/OrderedStatesList.test.tsx +5 -5
- package/Tests/UI/Components/PendingProjectInvitations.test.tsx +1 -1
- package/Tests/UI/Components/TableSortAndMobileColumns.test.tsx +195 -0
- package/Tests/UI/Components/XAxis.test.ts +270 -5
- package/Tests/UI/Components/XAxisDaylightSaving.test.ts +113 -0
- package/Tests/UI/Styles/ChartFocusRing.test.ts +153 -0
- package/Tests/UI/Styles/ChartFocusRingCoverage.test.tsx +377 -0
- package/Tests/UI/Styles/ThemeStylesheet.ts +162 -0
- package/Tests/Utils/EnterpriseLicenseSeats.test.ts +507 -0
- package/Tests/Utils/NetworkDiscovery/DiscoveredDeviceBuilder.test.ts +951 -1
- package/Tests/Utils/NetworkDiscovery/DiscoveredHostUtil.test.ts +238 -0
- package/Tests/Utils/NetworkDiscovery/DiscoveryReverseDnsChain.test.ts +1056 -0
- package/Tests/Utils/NetworkDiscovery/ReverseDnsNameUtil.test.ts +882 -0
- package/Types/Date.ts +39 -0
- package/Types/Monitor/SnmpMonitor/SnmpOidListUtil.ts +333 -0
- package/Types/Permission.ts +96 -0
- package/Types/Rum/SessionReplay.ts +21 -0
- package/Types/Telemetry/SourceMap.ts +8 -0
- package/UI/Components/Charts/ChartLibrary/Annotations/AnnotationHoverCard.tsx +176 -0
- package/UI/Components/Charts/ChartLibrary/Annotations/AnnotationLayout.ts +745 -0
- package/UI/Components/Charts/ChartLibrary/Annotations/ChartAnnotationLayer.tsx +576 -0
- package/UI/Components/Charts/ChartLibrary/Annotations/UseChartAnnotations.tsx +204 -0
- package/UI/Components/Charts/ChartLibrary/AreaChart/AreaChart.tsx +491 -544
- package/UI/Components/Charts/ChartLibrary/BarChart/BarChart.tsx +324 -372
- package/UI/Components/Charts/ChartLibrary/LineChart/LineChart.tsx +487 -540
- package/UI/Components/Charts/ChartLibrary/Types/FormattedReferenceRegion.ts +7 -3
- package/UI/Components/Charts/ChartLibrary/Types/FormattedTimeReferenceLine.ts +14 -3
- package/UI/Components/Charts/Types/ChartEventKind.ts +13 -0
- package/UI/Components/Charts/Types/ReferenceRegionProps.ts +6 -0
- package/UI/Components/Charts/Types/TimeReferenceLineProps.ts +20 -3
- package/UI/Components/Charts/Utils/TimeAnnotation.ts +69 -35
- package/UI/Components/Charts/Utils/XAxis.ts +125 -18
- package/UI/Components/EditionLabel/EditionLabel.tsx +280 -26
- package/UI/Components/ErrorMessage/ErrorMessage.tsx +21 -10
- package/UI/Components/Feed/FeedItem.tsx +4 -5
- package/UI/Components/Header/HeaderIconDropdownButton.tsx +1 -2
- package/UI/Components/Header/UserProfile/UserProfile.tsx +1 -2
- package/UI/Components/Image/Image.tsx +20 -3
- package/UI/Components/Markdown.tsx/MarkdownConverters.ts +0 -0
- package/UI/Components/MemberRoleAssignment/MemberRoleAssignment.tsx +1 -2
- package/UI/Components/ModelTable/BaseModelTable.tsx +150 -24
- package/UI/Components/Table/TableHeader.tsx +64 -48
- package/UI/Components/Table/TableRow.tsx +13 -3
- package/UI/Styles/Theme.css +38 -0
- package/Utils/EnterpriseLicense/EnterpriseLicenseSeats.ts +271 -0
- package/Utils/NetworkDiscovery/AutoImportRuleMatcher.ts +6 -0
- package/Utils/NetworkDiscovery/DiscoveredDeviceBuilder.ts +141 -10
- package/Utils/NetworkDiscovery/DiscoveredHostUtil.ts +55 -3
- package/Utils/NetworkDiscovery/ReverseDnsNameUtil.ts +151 -0
- package/Utils/Rules/RuleEngineLimits.ts +32 -0
- package/build/dist/Models/AnalyticsModels/SecurityEvent.js +48 -16
- package/build/dist/Models/AnalyticsModels/SecurityEvent.js.map +1 -1
- package/build/dist/Models/AnalyticsModels/ThreatIntelIndicator.js +10 -5
- package/build/dist/Models/AnalyticsModels/ThreatIntelIndicator.js.map +1 -1
- package/build/dist/Models/DatabaseModels/AlertSeverity.js +46 -1
- package/build/dist/Models/DatabaseModels/AlertSeverity.js.map +1 -1
- package/build/dist/Models/DatabaseModels/DetectionRule.js +16 -5
- package/build/dist/Models/DatabaseModels/DetectionRule.js.map +1 -1
- package/build/dist/Models/DatabaseModels/GoogleSecOpsConnection.js +14 -5
- package/build/dist/Models/DatabaseModels/GoogleSecOpsConnection.js.map +1 -1
- package/build/dist/Models/DatabaseModels/IncidentSeverity.js +46 -1
- package/build/dist/Models/DatabaseModels/IncidentSeverity.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Index.js +2 -0
- package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
- package/build/dist/Models/DatabaseModels/NetworkDevice.js +115 -3
- package/build/dist/Models/DatabaseModels/NetworkDevice.js.map +1 -1
- package/build/dist/Models/DatabaseModels/NetworkDeviceAutoImportRule.js +88 -0
- package/build/dist/Models/DatabaseModels/NetworkDeviceAutoImportRule.js.map +1 -1
- package/build/dist/Models/DatabaseModels/NetworkDeviceDiscoveryScan.js.map +1 -1
- package/build/dist/Models/DatabaseModels/NetworkDeviceOidTemplate.js +519 -0
- package/build/dist/Models/DatabaseModels/NetworkDeviceOidTemplate.js.map +1 -0
- package/build/dist/Models/DatabaseModels/ThreatIntelFeed.js +16 -5
- package/build/dist/Models/DatabaseModels/ThreatIntelFeed.js.map +1 -1
- package/build/dist/Server/API/GlobalConfigAPI.js +293 -176
- package/build/dist/Server/API/GlobalConfigAPI.js.map +1 -1
- package/build/dist/Server/API/TelemetryAPI.js +31 -3
- package/build/dist/Server/API/TelemetryAPI.js.map +1 -1
- package/build/dist/Server/EnvironmentConfig.js +83 -0
- package/build/dist/Server/EnvironmentConfig.js.map +1 -1
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1790500000000-AddNetworkDeviceOidTemplate.js +26 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1790500000000-AddNetworkDeviceOidTemplate.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1790600000000-AddAutoImportRuleOidTemplate.js +14 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1790600000000-AddAutoImportRuleOidTemplate.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +4 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
- package/build/dist/Server/Middleware/MultipartFormData.js +93 -28
- package/build/dist/Server/Middleware/MultipartFormData.js.map +1 -1
- package/build/dist/Server/Services/AlertEpisodeLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/AlertEpisodeLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/AlertEpisodeOnCallRuleEngineService.js +8 -1
- package/build/dist/Server/Services/AlertEpisodeOnCallRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/AlertEpisodeOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/AlertEpisodeOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/AlertEpisodePrivacyRuleEngineService.js +8 -1
- package/build/dist/Server/Services/AlertEpisodePrivacyRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/AlertGroupingEngineService.js +8 -1
- package/build/dist/Server/Services/AlertGroupingEngineService.js.map +1 -1
- package/build/dist/Server/Services/AlertLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/AlertLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/AlertOnCallRuleEngineService.js +8 -1
- package/build/dist/Server/Services/AlertOnCallRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/AlertOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/AlertOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/AlertPrivacyRuleEngineService.js +8 -1
- package/build/dist/Server/Services/AlertPrivacyRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/AlertReminderRuleService.js +8 -1
- package/build/dist/Server/Services/AlertReminderRuleService.js.map +1 -1
- package/build/dist/Server/Services/AutoRemediationRuleEngineService.js +8 -1
- package/build/dist/Server/Services/AutoRemediationRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/CephClusterLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/CephClusterLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/CephClusterOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/CephClusterOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/CloudResourceLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/CloudResourceLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/CloudResourceOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/CloudResourceOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/DashboardLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/DashboardLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/DashboardOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/DashboardOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/DockerHostLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/DockerHostLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/DockerHostOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/DockerHostOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/DockerSwarmClusterLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/DockerSwarmClusterLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/DockerSwarmClusterOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/DockerSwarmClusterOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/HostLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/HostLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/HostOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/HostOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/IncidentEpisodeLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/IncidentEpisodeLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/IncidentEpisodeOnCallRuleEngineService.js +8 -1
- package/build/dist/Server/Services/IncidentEpisodeOnCallRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/IncidentEpisodeOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/IncidentEpisodeOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/IncidentEpisodePrivacyRuleEngineService.js +8 -1
- package/build/dist/Server/Services/IncidentEpisodePrivacyRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/IncidentGroupingEngineService.js +8 -1
- package/build/dist/Server/Services/IncidentGroupingEngineService.js.map +1 -1
- package/build/dist/Server/Services/IncidentLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/IncidentLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/IncidentOnCallRuleEngineService.js +8 -1
- package/build/dist/Server/Services/IncidentOnCallRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/IncidentOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/IncidentOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/IncidentPrivacyRuleEngineService.js +8 -1
- package/build/dist/Server/Services/IncidentPrivacyRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/IncidentReminderRuleService.js +8 -1
- package/build/dist/Server/Services/IncidentReminderRuleService.js.map +1 -1
- package/build/dist/Server/Services/IncidentSlaRuleService.js +8 -1
- package/build/dist/Server/Services/IncidentSlaRuleService.js.map +1 -1
- package/build/dist/Server/Services/IncomingCallPolicyLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/IncomingCallPolicyLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/IncomingCallPolicyOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/IncomingCallPolicyOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/Index.js +2 -0
- package/build/dist/Server/Services/Index.js.map +1 -1
- package/build/dist/Server/Services/IoTFleetLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/IoTFleetLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/IoTFleetOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/IoTFleetOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/KubernetesClusterLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/KubernetesClusterLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/KubernetesClusterOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/KubernetesClusterOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/KubernetesResourceService.js +5 -1
- package/build/dist/Server/Services/KubernetesResourceService.js.map +1 -1
- package/build/dist/Server/Services/MonitorLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/MonitorLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/MonitorOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/MonitorOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/NetworkDeviceAutoImportRuleEngineService.js +30 -21
- package/build/dist/Server/Services/NetworkDeviceAutoImportRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/NetworkDeviceAutoImportRuleService.js +64 -0
- package/build/dist/Server/Services/NetworkDeviceAutoImportRuleService.js.map +1 -1
- package/build/dist/Server/Services/NetworkDeviceLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/NetworkDeviceLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/NetworkDeviceOidTemplateService.js +180 -0
- package/build/dist/Server/Services/NetworkDeviceOidTemplateService.js.map +1 -0
- package/build/dist/Server/Services/NetworkDeviceOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/NetworkDeviceOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/NetworkDeviceService.js +154 -1
- package/build/dist/Server/Services/NetworkDeviceService.js.map +1 -1
- package/build/dist/Server/Services/OnCallDutyPolicyLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/OnCallDutyPolicyLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/OnCallDutyPolicyOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/OnCallDutyPolicyOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/OnCallDutyPolicyScheduleLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/OnCallDutyPolicyScheduleLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/OnCallDutyPolicyScheduleOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/OnCallDutyPolicyScheduleOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/PodmanHostLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/PodmanHostLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/PodmanHostOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/PodmanHostOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/ProxmoxClusterLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/ProxmoxClusterLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/ProxmoxClusterOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/ProxmoxClusterOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/RumApplicationLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/RumApplicationLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/RumApplicationOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/RumApplicationOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/RunbookLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/RunbookLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/RunbookOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/RunbookOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/RunbookRuleEngineService.js +8 -1
- package/build/dist/Server/Services/RunbookRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/ScheduledMaintenanceLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/ScheduledMaintenanceLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/ScheduledMaintenanceOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/ScheduledMaintenanceOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/ScheduledMaintenanceReminderRuleService.js +8 -1
- package/build/dist/Server/Services/ScheduledMaintenanceReminderRuleService.js.map +1 -1
- package/build/dist/Server/Services/ServerlessFunctionLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/ServerlessFunctionLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/ServerlessFunctionOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/ServerlessFunctionOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/ServiceLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/ServiceLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/ServiceOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/ServiceOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/StatusPageLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/StatusPageLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/StatusPageMonitorRuleEngineService.js +6 -0
- package/build/dist/Server/Services/StatusPageMonitorRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/StatusPageOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/StatusPageOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/TelemetrySourceMapService.js +213 -19
- package/build/dist/Server/Services/TelemetrySourceMapService.js.map +1 -1
- package/build/dist/Server/Services/UserService.js +25 -0
- package/build/dist/Server/Services/UserService.js.map +1 -1
- package/build/dist/Server/Services/WorkflowLabelRuleEngineService.js +8 -1
- package/build/dist/Server/Services/WorkflowLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/WorkflowOwnerRuleEngineService.js +8 -1
- package/build/dist/Server/Services/WorkflowOwnerRuleEngineService.js.map +1 -1
- package/build/dist/Server/Utils/EnterpriseLicense/EnterpriseLicenseSeatUtil.js +145 -0
- package/build/dist/Server/Utils/EnterpriseLicense/EnterpriseLicenseSeatUtil.js.map +1 -0
- package/build/dist/Server/Utils/Monitor/CapturedMetricAttributeUtil.js +201 -0
- package/build/dist/Server/Utils/Monitor/CapturedMetricAttributeUtil.js.map +1 -0
- package/build/dist/Server/Utils/Monitor/Criteria/SnmpMonitorCriteria.js +19 -2
- package/build/dist/Server/Utils/Monitor/Criteria/SnmpMonitorCriteria.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorMetricUtil.js +42 -23
- package/build/dist/Server/Utils/Monitor/MonitorMetricUtil.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorTemplateUtil.js +29 -0
- package/build/dist/Server/Utils/Monitor/MonitorTemplateUtil.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/NetworkDeviceMetricUtil.js +11 -2
- package/build/dist/Server/Utils/Monitor/NetworkDeviceMetricUtil.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/NetworkDeviceWalkUtil.js +16 -1
- package/build/dist/Server/Utils/Monitor/NetworkDeviceWalkUtil.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/NetworkInventoryUtil.js +10 -0
- package/build/dist/Server/Utils/Monitor/NetworkInventoryUtil.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/SeriesResourceLabels.js +33 -0
- package/build/dist/Server/Utils/Monitor/SeriesResourceLabels.js.map +1 -1
- package/build/dist/Server/Utils/Rules/RuleEngineRuleRead.js +37 -0
- package/build/dist/Server/Utils/Rules/RuleEngineRuleRead.js.map +1 -0
- package/build/dist/Server/Utils/Telemetry/ExceptionSanitizer.js +12 -1
- package/build/dist/Server/Utils/Telemetry/ExceptionSanitizer.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/LogExceptionExtractor.js +14 -2
- package/build/dist/Server/Utils/Telemetry/LogExceptionExtractor.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/SourceMapResolver.js +15 -5
- package/build/dist/Server/Utils/Telemetry/SourceMapResolver.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/StackTraceParser.js +307 -0
- package/build/dist/Server/Utils/Telemetry/StackTraceParser.js.map +1 -1
- package/build/dist/Types/Date.js +27 -0
- package/build/dist/Types/Date.js.map +1 -1
- package/build/dist/Types/Monitor/SnmpMonitor/SnmpOidListUtil.js +253 -0
- package/build/dist/Types/Monitor/SnmpMonitor/SnmpOidListUtil.js.map +1 -0
- package/build/dist/Types/Permission.js +86 -0
- package/build/dist/Types/Permission.js.map +1 -1
- package/build/dist/Types/Rum/SessionReplay.js +19 -0
- package/build/dist/Types/Rum/SessionReplay.js.map +1 -1
- package/build/dist/UI/Components/Charts/ChartLibrary/Annotations/AnnotationHoverCard.js +83 -0
- package/build/dist/UI/Components/Charts/ChartLibrary/Annotations/AnnotationHoverCard.js.map +1 -0
- package/build/dist/UI/Components/Charts/ChartLibrary/Annotations/AnnotationLayout.js +531 -0
- package/build/dist/UI/Components/Charts/ChartLibrary/Annotations/AnnotationLayout.js.map +1 -0
- package/build/dist/UI/Components/Charts/ChartLibrary/Annotations/ChartAnnotationLayer.js +264 -0
- package/build/dist/UI/Components/Charts/ChartLibrary/Annotations/ChartAnnotationLayer.js.map +1 -0
- package/build/dist/UI/Components/Charts/ChartLibrary/Annotations/UseChartAnnotations.js +122 -0
- package/build/dist/UI/Components/Charts/ChartLibrary/Annotations/UseChartAnnotations.js.map +1 -0
- package/build/dist/UI/Components/Charts/ChartLibrary/AreaChart/AreaChart.js +213 -233
- package/build/dist/UI/Components/Charts/ChartLibrary/AreaChart/AreaChart.js.map +1 -1
- package/build/dist/UI/Components/Charts/ChartLibrary/BarChart/BarChart.js +139 -152
- package/build/dist/UI/Components/Charts/ChartLibrary/BarChart/BarChart.js.map +1 -1
- package/build/dist/UI/Components/Charts/ChartLibrary/LineChart/LineChart.js +212 -232
- package/build/dist/UI/Components/Charts/ChartLibrary/LineChart/LineChart.js.map +1 -1
- package/build/dist/UI/Components/Charts/Types/ChartEventKind.js +14 -0
- package/build/dist/UI/Components/Charts/Types/ChartEventKind.js.map +1 -0
- package/build/dist/UI/Components/Charts/Utils/TimeAnnotation.js +57 -28
- package/build/dist/UI/Components/Charts/Utils/TimeAnnotation.js.map +1 -1
- package/build/dist/UI/Components/Charts/Utils/XAxis.js +103 -17
- package/build/dist/UI/Components/Charts/Utils/XAxis.js.map +1 -1
- package/build/dist/UI/Components/EditionLabel/EditionLabel.js +198 -23
- package/build/dist/UI/Components/EditionLabel/EditionLabel.js.map +1 -1
- package/build/dist/UI/Components/ErrorMessage/ErrorMessage.js +15 -5
- package/build/dist/UI/Components/ErrorMessage/ErrorMessage.js.map +1 -1
- package/build/dist/UI/Components/Feed/FeedItem.js +4 -5
- package/build/dist/UI/Components/Feed/FeedItem.js.map +1 -1
- package/build/dist/UI/Components/Header/HeaderIconDropdownButton.js +1 -2
- package/build/dist/UI/Components/Header/HeaderIconDropdownButton.js.map +1 -1
- package/build/dist/UI/Components/Header/UserProfile/UserProfile.js.map +1 -1
- package/build/dist/UI/Components/Image/Image.js +6 -1
- package/build/dist/UI/Components/Image/Image.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/MemberRoleAssignment/MemberRoleAssignment.js +1 -2
- package/build/dist/UI/Components/MemberRoleAssignment/MemberRoleAssignment.js.map +1 -1
- package/build/dist/UI/Components/ModelTable/BaseModelTable.js +104 -23
- package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
- package/build/dist/UI/Components/Table/TableHeader.js +20 -22
- package/build/dist/UI/Components/Table/TableHeader.js.map +1 -1
- package/build/dist/UI/Components/Table/TableRow.js +13 -4
- package/build/dist/UI/Components/Table/TableRow.js.map +1 -1
- package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseSeats.js +153 -0
- package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseSeats.js.map +1 -0
- package/build/dist/Utils/NetworkDiscovery/AutoImportRuleMatcher.js.map +1 -1
- package/build/dist/Utils/NetworkDiscovery/DiscoveredDeviceBuilder.js +127 -7
- package/build/dist/Utils/NetworkDiscovery/DiscoveredDeviceBuilder.js.map +1 -1
- package/build/dist/Utils/NetworkDiscovery/DiscoveredHostUtil.js +50 -3
- package/build/dist/Utils/NetworkDiscovery/DiscoveredHostUtil.js.map +1 -1
- package/build/dist/Utils/NetworkDiscovery/ReverseDnsNameUtil.js +132 -0
- package/build/dist/Utils/NetworkDiscovery/ReverseDnsNameUtil.js.map +1 -0
- package/build/dist/Utils/Rules/RuleEngineLimits.js +31 -0
- package/build/dist/Utils/Rules/RuleEngineLimits.js.map +1 -0
- package/jest.config.json +1 -0
- package/package.json +2 -2
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import "@testing-library/jest-dom";
|
|
2
|
+
import { render, screen } from "@testing-library/react";
|
|
3
|
+
import React from "react";
|
|
4
|
+
import { describe, expect, jest, test } from "@jest/globals";
|
|
5
|
+
|
|
6
|
+
/*
|
|
7
|
+
* The shape esbuild's file-loader actually hands these components: the imported
|
|
8
|
+
* asset inlined as a "data:" URL (Common/UI/esbuild-config.js,
|
|
9
|
+
* createFileLoaderPlugin). Every existing suite that mocks an .svg mocks it as
|
|
10
|
+
* a plain path like "/blank-profile.svg" — which is exactly the shape that does
|
|
11
|
+
* NOT reproduce this bug, and why the whole test suite stayed green while every
|
|
12
|
+
* dashboard and admin page threw on first render.
|
|
13
|
+
*
|
|
14
|
+
* The "//" in the base64 payload is deliberate. Route collapses /+ into a
|
|
15
|
+
* single /, so the tempting "just let Route accept data: URLs" fix would
|
|
16
|
+
* silently corrupt the image — this payload makes that fix fail here too.
|
|
17
|
+
*
|
|
18
|
+
* ONE constant and ONE jest.mock for both assets on purpose: Common's
|
|
19
|
+
* jest.config.json maps every .svg to Tests/__mocks__/styleMock.js, so two
|
|
20
|
+
* jest.mock() calls naming two different .svg paths resolve to the same module
|
|
21
|
+
* and only the last factory would ever register.
|
|
22
|
+
*/
|
|
23
|
+
const ASSET_DATA_URL: string = "data:image/svg+xml;base64,////bG9nbw==";
|
|
24
|
+
|
|
25
|
+
jest.mock("../../../UI/Images/logos/OneUptimeSVG/3-transparent.svg", () => {
|
|
26
|
+
return ASSET_DATA_URL;
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
import DashboardLogo from "../../../../App/FeatureSet/Dashboard/src/Components/Header/Logo";
|
|
30
|
+
import AdminDashboardLogo from "../../../../App/FeatureSet/AdminDashboard/src/Components/Header/Logo";
|
|
31
|
+
import Image from "../../../UI/Components/Image/Image";
|
|
32
|
+
|
|
33
|
+
/*
|
|
34
|
+
* Regression cover for the crash that blocked every release from 2026-08-31.
|
|
35
|
+
*
|
|
36
|
+
* b2d2da71e8 taught Route to reject scheme-prefixed strings — correctly, it
|
|
37
|
+
* guards an open-redirect. But these components were laundering an <img> src
|
|
38
|
+
* through Route.fromString() purely to satisfy Image's prop type, and an
|
|
39
|
+
* esbuild-inlined asset src is always "data:"-prefixed. So Route threw during
|
|
40
|
+
* render, React unwound to the error boundary, and the dashboard never painted.
|
|
41
|
+
*
|
|
42
|
+
* An image src is not a Route. What these pin is that the header renders the
|
|
43
|
+
* asset straight through as an <img src>, with no Route in the path.
|
|
44
|
+
*/
|
|
45
|
+
describe("header image assets", () => {
|
|
46
|
+
test("the dashboard logo renders the inlined asset as its src", () => {
|
|
47
|
+
render(
|
|
48
|
+
<DashboardLogo
|
|
49
|
+
onClick={() => {
|
|
50
|
+
// no-op: the click target is not what regressed.
|
|
51
|
+
}}
|
|
52
|
+
/>,
|
|
53
|
+
);
|
|
54
|
+
|
|
55
|
+
const logo: HTMLElement = screen.getByAltText("OneUptime");
|
|
56
|
+
expect(logo).toHaveAttribute("src", ASSET_DATA_URL);
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
test("the admin dashboard logo renders the inlined asset as its src", () => {
|
|
60
|
+
render(
|
|
61
|
+
<AdminDashboardLogo
|
|
62
|
+
onClick={() => {
|
|
63
|
+
// no-op
|
|
64
|
+
}}
|
|
65
|
+
/>,
|
|
66
|
+
);
|
|
67
|
+
|
|
68
|
+
const logo: HTMLElement = screen.getByAltText("OneUptime");
|
|
69
|
+
expect(logo).toHaveAttribute("src", ASSET_DATA_URL);
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
/*
|
|
73
|
+
* Straight at the type misuse rather than at one component: any scheme-
|
|
74
|
+
* prefixed src has to survive <Image>. Before the fix this threw inside
|
|
75
|
+
* Route.fromString at the call sites; now the string reaches <img> untouched.
|
|
76
|
+
*/
|
|
77
|
+
test("Image passes a data: URL through to src without validating it", () => {
|
|
78
|
+
render(<Image imageUrl={ASSET_DATA_URL} alt="asset" />);
|
|
79
|
+
|
|
80
|
+
expect(screen.getByAltText("asset")).toHaveAttribute("src", ASSET_DATA_URL);
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
/*
|
|
84
|
+
* An empty src must not fall through to the `file` branch and throw
|
|
85
|
+
* "file or imageUrl required" — it renders an empty <img>, keeping the node
|
|
86
|
+
* (and its test id) in the DOM.
|
|
87
|
+
*/
|
|
88
|
+
test("an empty src renders an image rather than throwing", () => {
|
|
89
|
+
render(<Image imageUrl="" alt="empty" data-testid="empty-image" />);
|
|
90
|
+
|
|
91
|
+
expect(screen.getByTestId("empty-image")).toHaveAttribute("src", "");
|
|
92
|
+
});
|
|
93
|
+
});
|
|
@@ -1293,7 +1293,7 @@ describe("ResponderReadinessCard", () => {
|
|
|
1293
1293
|
expect(
|
|
1294
1294
|
await screen.findByText("Could not load readiness"),
|
|
1295
1295
|
).toBeInTheDocument();
|
|
1296
|
-
expect(screen.
|
|
1296
|
+
expect(screen.getByTestId("refresh-button")).toBeInTheDocument();
|
|
1297
1297
|
});
|
|
1298
1298
|
|
|
1299
1299
|
test("retrying issues another request", async () => {
|
|
@@ -1305,7 +1305,7 @@ describe("ResponderReadinessCard", () => {
|
|
|
1305
1305
|
|
|
1306
1306
|
const callsBefore: number = getMock.mock.calls.length;
|
|
1307
1307
|
|
|
1308
|
-
fireEvent.click(screen.
|
|
1308
|
+
fireEvent.click(screen.getByTestId("refresh-button"));
|
|
1309
1309
|
|
|
1310
1310
|
await waitFor((): void => {
|
|
1311
1311
|
expect(getMock.mock.calls.length).toBeGreaterThan(callsBefore);
|
|
@@ -1784,7 +1784,7 @@ describe("On-call readiness page", () => {
|
|
|
1784
1784
|
expect(
|
|
1785
1785
|
await screen.findByText("Could not load readiness"),
|
|
1786
1786
|
).toBeInTheDocument();
|
|
1787
|
-
expect(screen.
|
|
1787
|
+
expect(screen.getByTestId("refresh-button")).toBeInTheDocument();
|
|
1788
1788
|
});
|
|
1789
1789
|
|
|
1790
1790
|
test("the card chrome survives a failed request", async () => {
|
|
@@ -4,11 +4,19 @@ import React from "react";
|
|
|
4
4
|
import { describe, expect, jest, test } from "@jest/globals";
|
|
5
5
|
|
|
6
6
|
/*
|
|
7
|
-
* The
|
|
8
|
-
*
|
|
9
|
-
*
|
|
7
|
+
* The shape esbuild's file-loader actually hands these components: the asset
|
|
8
|
+
* inlined as a "data:" URL (Common/UI/esbuild-config.js createFileLoaderPlugin).
|
|
9
|
+
* jest's asset mapper turns an .svg import into {} instead, so it has to be
|
|
10
|
+
* mocked - but it must be mocked as a data: URL, not as a plain path like
|
|
11
|
+
* "/blank-profile.svg". A plain path is precisely the shape that does NOT
|
|
12
|
+
* reproduce the crash, which is why this suite stayed green while every
|
|
13
|
+
* dashboard page threw.
|
|
14
|
+
*
|
|
15
|
+
* The "//" in the base64 payload is deliberate. Route collapses /+ into a
|
|
16
|
+
* single /, so a "just let Route accept data: URLs" fix would silently corrupt
|
|
17
|
+
* the image - this constant makes that fix fail here too.
|
|
10
18
|
*/
|
|
11
|
-
const BLANK_PROFILE_PIC: string = "/
|
|
19
|
+
const BLANK_PROFILE_PIC: string = "data:image/svg+xml;base64,////YXZhdGFy";
|
|
12
20
|
|
|
13
21
|
jest.mock("../../../UI/Images/users/blank-profile.svg", () => {
|
|
14
22
|
return BLANK_PROFILE_PIC;
|
|
@@ -27,7 +27,7 @@ import {
|
|
|
27
27
|
* default avatar) and silent in every other suite, so they are pinned here.
|
|
28
28
|
*/
|
|
29
29
|
|
|
30
|
-
const BLANK_PROFILE_PIC: string = "/
|
|
30
|
+
const BLANK_PROFILE_PIC: string = "data:image/svg+xml;base64,////YXZhdGFy";
|
|
31
31
|
|
|
32
32
|
jest.mock("../../../UI/Images/users/blank-profile.svg", () => {
|
|
33
33
|
return BLANK_PROFILE_PIC;
|
|
@@ -47,6 +47,7 @@ const DOMAIN_PREFIXES: Array<[string, string]> = [
|
|
|
47
47
|
["Monitor", "Monitor"],
|
|
48
48
|
["Workflow", "Workflow"],
|
|
49
49
|
["Runbook", "Runbook"],
|
|
50
|
+
["Security", "Security"],
|
|
50
51
|
];
|
|
51
52
|
|
|
52
53
|
/*
|
|
@@ -63,6 +64,19 @@ const DOMAIN_BY_MODEL: Record<string, string> = {
|
|
|
63
64
|
LogSavedView: "Telemetry",
|
|
64
65
|
MetricSavedView: "Telemetry",
|
|
65
66
|
TraceSavedView: "Telemetry",
|
|
67
|
+
|
|
68
|
+
/*
|
|
69
|
+
* The whole SIEM, and not one table of it is named for its domain: a Sigma
|
|
70
|
+
* rule, a TAXII subscription and a Chronicle connector. They shipped reading
|
|
71
|
+
* through the Telemetry tiers because they arrived beside logs and traces in
|
|
72
|
+
* ClickHouse, which made "can read every log in the project" and "can read the
|
|
73
|
+
* security events" one decision. Splitting them is what the Security tiers are
|
|
74
|
+
* for, and naming the three models here is what keeps a fourth from quietly
|
|
75
|
+
* shipping back under Telemetry.
|
|
76
|
+
*/
|
|
77
|
+
DetectionRule: "Security",
|
|
78
|
+
ThreatIntelFeed: "Security",
|
|
79
|
+
GoogleSecOpsConnection: "Security",
|
|
66
80
|
};
|
|
67
81
|
|
|
68
82
|
/*
|
|
@@ -0,0 +1,469 @@
|
|
|
1
|
+
import AllModelTypes from "../../../Models/DatabaseModels/Index";
|
|
2
|
+
import AllAnalyticsModelTypes from "../../../Models/AnalyticsModels/Index";
|
|
3
|
+
import BaseModel from "../../../Models/DatabaseModels/DatabaseBaseModel/DatabaseBaseModel";
|
|
4
|
+
import AnalyticsBaseModel from "../../../Models/AnalyticsModels/AnalyticsBaseModel/AnalyticsBaseModel";
|
|
5
|
+
import { describe, expect, it } from "@jest/globals";
|
|
6
|
+
|
|
7
|
+
/*
|
|
8
|
+
* Registry-wide identity invariants.
|
|
9
|
+
*
|
|
10
|
+
* Every entity in the product is declared once, in a decorator block, and
|
|
11
|
+
* added to Models/DatabaseModels/Index.ts by hand. New entities are almost
|
|
12
|
+
* always written by copying the closest existing one, which makes the
|
|
13
|
+
* failure mode here a very specific and very quiet kind: a value that was
|
|
14
|
+
* meant to be changed during the copy and was not.
|
|
15
|
+
*
|
|
16
|
+
* What makes that worth a sweep rather than a review checklist is that the
|
|
17
|
+
* two identity values below are read at runtime by machinery that has no way
|
|
18
|
+
* to notice a collision:
|
|
19
|
+
*
|
|
20
|
+
* - `tableName` is the Postgres table the entity is persisted to. Two models
|
|
21
|
+
* naming one table are two different shapes writing to the same rows.
|
|
22
|
+
* - `crudApiPath` is the route BaseAPI registers CRUD under. Two models
|
|
23
|
+
* naming one path means whichever registers second shadows the first, and
|
|
24
|
+
* an entire entity's API silently answers as another entity.
|
|
25
|
+
*
|
|
26
|
+
* Neither produces an error at startup. Both produce a product that is wrong
|
|
27
|
+
* in a way that looks like a data bug from the outside.
|
|
28
|
+
*
|
|
29
|
+
* The remaining assertions cover the values the generated OpenAPI document
|
|
30
|
+
* and the dashboard read off a model -- a documented model with no
|
|
31
|
+
* description, or no display name, is a hole in the published API reference
|
|
32
|
+
* rather than a crash, which is exactly why nobody notices it.
|
|
33
|
+
*
|
|
34
|
+
* Sweeping every model rather than asserting on a list is the point: a
|
|
35
|
+
* mis-copied value in a model nobody is looking at fails here rather than in
|
|
36
|
+
* production.
|
|
37
|
+
*/
|
|
38
|
+
|
|
39
|
+
type ModelType = { new (): BaseModel };
|
|
40
|
+
type AnalyticsModelType = { new (): AnalyticsBaseModel };
|
|
41
|
+
|
|
42
|
+
const MODEL_TYPES: Array<ModelType> = AllModelTypes as Array<ModelType>;
|
|
43
|
+
|
|
44
|
+
const ANALYTICS_MODEL_TYPES: Array<AnalyticsModelType> =
|
|
45
|
+
AllAnalyticsModelTypes as unknown as Array<AnalyticsModelType>;
|
|
46
|
+
|
|
47
|
+
/*
|
|
48
|
+
* A flat snapshot of the declarations, NOT the model instances.
|
|
49
|
+
*
|
|
50
|
+
* The first version of this file kept all 416 constructed models alive for the
|
|
51
|
+
* lifetime of the file, which is a large object graph resident in a Jest
|
|
52
|
+
* worker whose heap ceiling is deliberately tight (see the note in
|
|
53
|
+
* .github/workflows/test.common.yaml: 2 workers x 4 GB, live set peaking near
|
|
54
|
+
* 3.5 GB). This file shares a shard with the isolated-vm SSRF suite, which
|
|
55
|
+
* needs CPU and memory of its own and reports starvation as a script timeout
|
|
56
|
+
* rather than as an out-of-memory.
|
|
57
|
+
*
|
|
58
|
+
* Every assertion below is about scalar declarations, so the instances exist
|
|
59
|
+
* only long enough to read those off and are collectable immediately after.
|
|
60
|
+
*/
|
|
61
|
+
interface RegisteredModel {
|
|
62
|
+
className: string;
|
|
63
|
+
tableName: string | null;
|
|
64
|
+
crudApiPath: string | null;
|
|
65
|
+
singularName: string | null;
|
|
66
|
+
pluralName: string | null;
|
|
67
|
+
enableDocumentation: boolean;
|
|
68
|
+
tableDescription: string | null;
|
|
69
|
+
slugifyColumn: string | null;
|
|
70
|
+
saveSlugToColumn: string | null;
|
|
71
|
+
columns: Array<string>;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const REGISTERED_MODELS: Array<RegisteredModel> = MODEL_TYPES.map(
|
|
75
|
+
(ModelClass: ModelType): RegisteredModel => {
|
|
76
|
+
const model: BaseModel = new ModelClass();
|
|
77
|
+
|
|
78
|
+
return {
|
|
79
|
+
className: ModelClass.name,
|
|
80
|
+
tableName: model.tableName,
|
|
81
|
+
crudApiPath: model.crudApiPath ? model.crudApiPath.toString() : null,
|
|
82
|
+
singularName: model.singularName,
|
|
83
|
+
pluralName: model.pluralName,
|
|
84
|
+
enableDocumentation: Boolean(model.enableDocumentation),
|
|
85
|
+
tableDescription: model.tableDescription,
|
|
86
|
+
slugifyColumn: model.slugifyColumn,
|
|
87
|
+
saveSlugToColumn: model.saveSlugToColumn,
|
|
88
|
+
columns: model.getTableColumns().columns,
|
|
89
|
+
};
|
|
90
|
+
},
|
|
91
|
+
);
|
|
92
|
+
|
|
93
|
+
/*
|
|
94
|
+
* Collect every class name that claims `key`, so a failure names both sides of
|
|
95
|
+
* the collision rather than only reporting that a count was wrong.
|
|
96
|
+
*/
|
|
97
|
+
const groupBy: (
|
|
98
|
+
keyOf: (entry: RegisteredModel) => string | null,
|
|
99
|
+
) => Array<string> = (
|
|
100
|
+
keyOf: (entry: RegisteredModel) => string | null,
|
|
101
|
+
): Array<string> => {
|
|
102
|
+
const claimants: Map<string, Array<string>> = new Map();
|
|
103
|
+
|
|
104
|
+
for (const entry of REGISTERED_MODELS) {
|
|
105
|
+
const key: string | null = keyOf(entry);
|
|
106
|
+
|
|
107
|
+
if (!key) {
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
claimants.set(key, [...(claimants.get(key) || []), entry.className]);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return Array.from(claimants.entries())
|
|
115
|
+
.filter((pair: [string, Array<string>]) => {
|
|
116
|
+
return pair[1].length > 1;
|
|
117
|
+
})
|
|
118
|
+
.map((pair: [string, Array<string>]) => {
|
|
119
|
+
return `${pair[0]}: ${pair[1].join(", ")}`;
|
|
120
|
+
})
|
|
121
|
+
.sort();
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
describe("Database model registry", () => {
|
|
125
|
+
it("registers at least one model", () => {
|
|
126
|
+
/*
|
|
127
|
+
* Guards every sweep below. An Index.ts that resolved to an empty array
|
|
128
|
+
* would make each of them pass vacuously.
|
|
129
|
+
*/
|
|
130
|
+
expect(REGISTERED_MODELS.length).toBeGreaterThan(0);
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
it("gives every model a table name", () => {
|
|
134
|
+
const missing: Array<string> = REGISTERED_MODELS.filter(
|
|
135
|
+
(entry: RegisteredModel) => {
|
|
136
|
+
return !entry.tableName;
|
|
137
|
+
},
|
|
138
|
+
).map((entry: RegisteredModel) => {
|
|
139
|
+
return entry.className;
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
expect(missing).toEqual([]);
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
/*
|
|
146
|
+
* The collision that persists two different shapes into one set of rows.
|
|
147
|
+
*/
|
|
148
|
+
it("gives every model its own table", () => {
|
|
149
|
+
expect(
|
|
150
|
+
groupBy((entry: RegisteredModel) => {
|
|
151
|
+
return entry.tableName;
|
|
152
|
+
}),
|
|
153
|
+
).toEqual([]);
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
/*
|
|
157
|
+
* The collision where one entity's whole API answers as another's, because
|
|
158
|
+
* BaseAPI registers both under the same route and the second wins.
|
|
159
|
+
*/
|
|
160
|
+
it("gives every model its own CRUD path", () => {
|
|
161
|
+
expect(
|
|
162
|
+
groupBy((entry: RegisteredModel) => {
|
|
163
|
+
return entry.crudApiPath;
|
|
164
|
+
}),
|
|
165
|
+
).toEqual([]);
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
it("gives every model a singular and a plural display name", () => {
|
|
169
|
+
const missing: Array<string> = REGISTERED_MODELS.filter(
|
|
170
|
+
(entry: RegisteredModel) => {
|
|
171
|
+
return !entry.singularName || !entry.pluralName;
|
|
172
|
+
},
|
|
173
|
+
).map((entry: RegisteredModel) => {
|
|
174
|
+
return entry.className;
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
expect(missing).toEqual([]);
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
/*
|
|
181
|
+
* The description is what the generated OpenAPI document publishes as the
|
|
182
|
+
* tag description for the entity. A documented model without one ships a
|
|
183
|
+
* section of the public API reference with no explanation of what it is.
|
|
184
|
+
*/
|
|
185
|
+
it("describes every model it publishes documentation for", () => {
|
|
186
|
+
const undescribed: Array<string> = REGISTERED_MODELS.filter(
|
|
187
|
+
(entry: RegisteredModel) => {
|
|
188
|
+
return entry.enableDocumentation && !entry.tableDescription;
|
|
189
|
+
},
|
|
190
|
+
).map((entry: RegisteredModel) => {
|
|
191
|
+
return entry.className;
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
expect(undescribed).toEqual([]);
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
/*
|
|
198
|
+
* `enableDocumentation` alone publishes nothing: OpenAPIUtil skips any model
|
|
199
|
+
* with no `crudApiPath`, so the pair disagreeing is a model that believes it
|
|
200
|
+
* is documented and is absent from the document.
|
|
201
|
+
*/
|
|
202
|
+
it("gives every documented model a CRUD path to document", () => {
|
|
203
|
+
const undocumentable: Array<string> = REGISTERED_MODELS.filter(
|
|
204
|
+
(entry: RegisteredModel) => {
|
|
205
|
+
return entry.enableDocumentation && !entry.crudApiPath;
|
|
206
|
+
},
|
|
207
|
+
).map((entry: RegisteredModel) => {
|
|
208
|
+
return entry.className;
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
expect(undocumentable).toEqual([]);
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
/*
|
|
215
|
+
* Slug generation reads the source column and writes the destination one BY
|
|
216
|
+
* NAME at save time (DatabaseService.generateSlug), off an object rather
|
|
217
|
+
* than through the schema -- so a name that matches no declared column is a
|
|
218
|
+
* silent misfire rather than an error.
|
|
219
|
+
*
|
|
220
|
+
* Both halves misfire differently and both are live today:
|
|
221
|
+
*
|
|
222
|
+
* - A source that does not exist reads `undefined`, and Slug.getSlug(null)
|
|
223
|
+
* answers with a slug built from Faker.generateName(). The row still gets
|
|
224
|
+
* a unique, non-null slug, so nothing fails -- the slug is simply a
|
|
225
|
+
* random pair of words instead of the object's own name. Incident is the
|
|
226
|
+
* clearest case: it slugifies "name" while its title column is `title`,
|
|
227
|
+
* and its own slug column documents the example
|
|
228
|
+
* "database-connection-failure-in-production", which is a slugified
|
|
229
|
+
* TITLE. Every incident URL in the product is a random name instead.
|
|
230
|
+
*
|
|
231
|
+
* - A destination that does not exist has the slug assigned to a property
|
|
232
|
+
* the table has no column for, and TypeORM drops it on insert. The whole
|
|
233
|
+
* decorator is dead configuration.
|
|
234
|
+
*
|
|
235
|
+
* The fourteen below are pre-existing and are recorded as a baseline rather
|
|
236
|
+
* than fixed here, because each needs its own judgement: the four that mean
|
|
237
|
+
* `title` are a rename, but the nine with no slug column at all are either a
|
|
238
|
+
* missing column (which needs a migration) or a decorator that should be
|
|
239
|
+
* deleted, and picking wrong is a schema change made on a guess.
|
|
240
|
+
*
|
|
241
|
+
* THIS LIST MUST ONLY EVER SHRINK. A new entry means a new misfire; a stale
|
|
242
|
+
* entry means somebody fixed one and this test says so.
|
|
243
|
+
*/
|
|
244
|
+
const KNOWN_SLUG_MISFIRES: Array<string> = [
|
|
245
|
+
/*
|
|
246
|
+
* Source should almost certainly be `title` -- each of these has a title
|
|
247
|
+
* column and a real slug column, so the slug lands but is random.
|
|
248
|
+
*/
|
|
249
|
+
"Incident.slugifyColumn = name",
|
|
250
|
+
"IncidentTemplate.slugifyColumn = name",
|
|
251
|
+
"ScheduledMaintenance.slugifyColumn = name",
|
|
252
|
+
"ScheduledMaintenanceTemplate.slugifyColumn = name",
|
|
253
|
+
|
|
254
|
+
/* No name column and no title column; the slug source is `domain`. */
|
|
255
|
+
"Domain.slugifyColumn = name",
|
|
256
|
+
|
|
257
|
+
/* Has the source column, but no slug column to write to. */
|
|
258
|
+
"AlertState.saveSlugToColumn = slug",
|
|
259
|
+
"MetricType.saveSlugToColumn = slug",
|
|
260
|
+
"StatusPageAnnouncementTemplate.saveSlugToColumn = slug",
|
|
261
|
+
|
|
262
|
+
/* Neither column exists: the decorator does nothing at all. */
|
|
263
|
+
"MonitorStatusTimeline.slugifyColumn = name",
|
|
264
|
+
"MonitorStatusTimeline.saveSlugToColumn = slug",
|
|
265
|
+
"MonitorTest.slugifyColumn = name",
|
|
266
|
+
"MonitorTest.saveSlugToColumn = slug",
|
|
267
|
+
"StatusPageAnnouncement.slugifyColumn = name",
|
|
268
|
+
"StatusPageAnnouncement.saveSlugToColumn = slug",
|
|
269
|
+
"StatusPagePrivateUser.slugifyColumn = name",
|
|
270
|
+
"StatusPagePrivateUser.saveSlugToColumn = slug",
|
|
271
|
+
"StatusPageResource.slugifyColumn = name",
|
|
272
|
+
"StatusPageResource.saveSlugToColumn = slug",
|
|
273
|
+
"StatusPageSubscriber.slugifyColumn = name",
|
|
274
|
+
"StatusPageSubscriber.saveSlugToColumn = slug",
|
|
275
|
+
];
|
|
276
|
+
|
|
277
|
+
const findSlugMisfires: () => Array<string> = (): Array<string> => {
|
|
278
|
+
const dangling: Array<string> = [];
|
|
279
|
+
|
|
280
|
+
for (const entry of REGISTERED_MODELS) {
|
|
281
|
+
const columns: Array<string> = entry.columns;
|
|
282
|
+
|
|
283
|
+
const source: string | null = entry.slugifyColumn;
|
|
284
|
+
const destination: string | null = entry.saveSlugToColumn;
|
|
285
|
+
|
|
286
|
+
if (source && !columns.includes(source)) {
|
|
287
|
+
dangling.push(`${entry.className}.slugifyColumn = ${source}`);
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
if (destination && !columns.includes(destination)) {
|
|
291
|
+
dangling.push(`${entry.className}.saveSlugToColumn = ${destination}`);
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
return dangling.sort();
|
|
296
|
+
};
|
|
297
|
+
|
|
298
|
+
it("introduces no new slug column that does not exist", () => {
|
|
299
|
+
const unexpected: Array<string> = findSlugMisfires().filter(
|
|
300
|
+
(misfire: string) => {
|
|
301
|
+
return !KNOWN_SLUG_MISFIRES.includes(misfire);
|
|
302
|
+
},
|
|
303
|
+
);
|
|
304
|
+
|
|
305
|
+
expect(unexpected).toEqual([]);
|
|
306
|
+
});
|
|
307
|
+
|
|
308
|
+
/*
|
|
309
|
+
* The other direction, so the baseline cannot rot: once a misfire is fixed
|
|
310
|
+
* its entry has to come out of the list above.
|
|
311
|
+
*/
|
|
312
|
+
it("keeps no stale entry in the known slug misfire list", () => {
|
|
313
|
+
const found: Array<string> = findSlugMisfires();
|
|
314
|
+
|
|
315
|
+
const stale: Array<string> = KNOWN_SLUG_MISFIRES.filter(
|
|
316
|
+
(misfire: string) => {
|
|
317
|
+
return !found.includes(misfire);
|
|
318
|
+
},
|
|
319
|
+
);
|
|
320
|
+
|
|
321
|
+
expect(stale).toEqual([]);
|
|
322
|
+
});
|
|
323
|
+
|
|
324
|
+
/*
|
|
325
|
+
* A model that slugifies a column must have somewhere to put the result.
|
|
326
|
+
* Only the pair together produces a slug; either one alone is dead
|
|
327
|
+
* configuration.
|
|
328
|
+
*/
|
|
329
|
+
it("pairs a slug source with a slug destination", () => {
|
|
330
|
+
const unpaired: Array<string> = REGISTERED_MODELS.filter(
|
|
331
|
+
(entry: RegisteredModel) => {
|
|
332
|
+
return Boolean(entry.slugifyColumn) !== Boolean(entry.saveSlugToColumn);
|
|
333
|
+
},
|
|
334
|
+
).map((entry: RegisteredModel) => {
|
|
335
|
+
return entry.className;
|
|
336
|
+
});
|
|
337
|
+
|
|
338
|
+
expect(unpaired).toEqual([]);
|
|
339
|
+
});
|
|
340
|
+
|
|
341
|
+
it("declares at least one column on every model", () => {
|
|
342
|
+
const empty: Array<string> = REGISTERED_MODELS.filter(
|
|
343
|
+
(entry: RegisteredModel) => {
|
|
344
|
+
return entry.columns.length === 0;
|
|
345
|
+
},
|
|
346
|
+
).map((entry: RegisteredModel) => {
|
|
347
|
+
return entry.className;
|
|
348
|
+
});
|
|
349
|
+
|
|
350
|
+
expect(empty).toEqual([]);
|
|
351
|
+
});
|
|
352
|
+
|
|
353
|
+
it("starts every CRUD path with a slash", () => {
|
|
354
|
+
const malformed: Array<string> = REGISTERED_MODELS.filter(
|
|
355
|
+
(entry: RegisteredModel) => {
|
|
356
|
+
const path: string | null = entry.crudApiPath;
|
|
357
|
+
|
|
358
|
+
return path !== null && !path.startsWith("/");
|
|
359
|
+
},
|
|
360
|
+
).map((entry: RegisteredModel) => {
|
|
361
|
+
return entry.className;
|
|
362
|
+
});
|
|
363
|
+
|
|
364
|
+
expect(malformed).toEqual([]);
|
|
365
|
+
});
|
|
366
|
+
});
|
|
367
|
+
|
|
368
|
+
describe("Analytics model registry", () => {
|
|
369
|
+
/* Flattened for the same reason as the database models above. */
|
|
370
|
+
interface RegisteredAnalyticsModel {
|
|
371
|
+
className: string;
|
|
372
|
+
tableName: string | null;
|
|
373
|
+
crudApiPath: string | null;
|
|
374
|
+
columnCount: number;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
const REGISTERED: Array<RegisteredAnalyticsModel> = ANALYTICS_MODEL_TYPES.map(
|
|
378
|
+
(ModelClass: AnalyticsModelType): RegisteredAnalyticsModel => {
|
|
379
|
+
const model: AnalyticsBaseModel = new ModelClass();
|
|
380
|
+
|
|
381
|
+
return {
|
|
382
|
+
className: ModelClass.name,
|
|
383
|
+
tableName: model.tableName,
|
|
384
|
+
crudApiPath: model.crudApiPath ? model.crudApiPath.toString() : null,
|
|
385
|
+
columnCount: (model.tableColumns || []).length,
|
|
386
|
+
};
|
|
387
|
+
},
|
|
388
|
+
);
|
|
389
|
+
|
|
390
|
+
it("registers at least one analytics model", () => {
|
|
391
|
+
expect(REGISTERED.length).toBeGreaterThan(0);
|
|
392
|
+
});
|
|
393
|
+
|
|
394
|
+
it("gives every analytics model a table name", () => {
|
|
395
|
+
const missing: Array<string> = REGISTERED.filter(
|
|
396
|
+
(entry: RegisteredAnalyticsModel) => {
|
|
397
|
+
return !entry.tableName;
|
|
398
|
+
},
|
|
399
|
+
).map((entry: RegisteredAnalyticsModel) => {
|
|
400
|
+
return entry.className;
|
|
401
|
+
});
|
|
402
|
+
|
|
403
|
+
expect(missing).toEqual([]);
|
|
404
|
+
});
|
|
405
|
+
|
|
406
|
+
/*
|
|
407
|
+
* The ClickHouse equivalent of the Postgres collision above: two models
|
|
408
|
+
* writing rows of different shapes into one table.
|
|
409
|
+
*/
|
|
410
|
+
it("gives every analytics model its own table", () => {
|
|
411
|
+
const claimants: Map<string, Array<string>> = new Map();
|
|
412
|
+
|
|
413
|
+
for (const entry of REGISTERED) {
|
|
414
|
+
const key: string | null = entry.tableName;
|
|
415
|
+
|
|
416
|
+
if (!key) {
|
|
417
|
+
continue;
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
claimants.set(key, [...(claimants.get(key) || []), entry.className]);
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
const collisions: Array<string> = Array.from(claimants.entries())
|
|
424
|
+
.filter((pair: [string, Array<string>]) => {
|
|
425
|
+
return pair[1].length > 1;
|
|
426
|
+
})
|
|
427
|
+
.map((pair: [string, Array<string>]) => {
|
|
428
|
+
return `${pair[0]}: ${pair[1].join(", ")}`;
|
|
429
|
+
});
|
|
430
|
+
|
|
431
|
+
expect(collisions).toEqual([]);
|
|
432
|
+
});
|
|
433
|
+
|
|
434
|
+
it("gives every analytics model its own CRUD path", () => {
|
|
435
|
+
const claimants: Map<string, Array<string>> = new Map();
|
|
436
|
+
|
|
437
|
+
for (const entry of REGISTERED) {
|
|
438
|
+
const key: string | null = entry.crudApiPath;
|
|
439
|
+
|
|
440
|
+
if (!key) {
|
|
441
|
+
continue;
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
claimants.set(key, [...(claimants.get(key) || []), entry.className]);
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
const collisions: Array<string> = Array.from(claimants.entries())
|
|
448
|
+
.filter((pair: [string, Array<string>]) => {
|
|
449
|
+
return pair[1].length > 1;
|
|
450
|
+
})
|
|
451
|
+
.map((pair: [string, Array<string>]) => {
|
|
452
|
+
return `${pair[0]}: ${pair[1].join(", ")}`;
|
|
453
|
+
});
|
|
454
|
+
|
|
455
|
+
expect(collisions).toEqual([]);
|
|
456
|
+
});
|
|
457
|
+
|
|
458
|
+
it("declares at least one column on every analytics model", () => {
|
|
459
|
+
const empty: Array<string> = REGISTERED.filter(
|
|
460
|
+
(entry: RegisteredAnalyticsModel) => {
|
|
461
|
+
return entry.columnCount === 0;
|
|
462
|
+
},
|
|
463
|
+
).map((entry: RegisteredAnalyticsModel) => {
|
|
464
|
+
return entry.className;
|
|
465
|
+
});
|
|
466
|
+
|
|
467
|
+
expect(empty).toEqual([]);
|
|
468
|
+
});
|
|
469
|
+
});
|