@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.
Files changed (489) hide show
  1. package/Models/AnalyticsModels/SecurityEvent.ts +48 -16
  2. package/Models/AnalyticsModels/ThreatIntelIndicator.ts +10 -5
  3. package/Models/DatabaseModels/AlertSeverity.ts +44 -0
  4. package/Models/DatabaseModels/DetectionRule.ts +16 -5
  5. package/Models/DatabaseModels/GoogleSecOpsConnection.ts +14 -5
  6. package/Models/DatabaseModels/IncidentSeverity.ts +44 -0
  7. package/Models/DatabaseModels/Index.ts +2 -0
  8. package/Models/DatabaseModels/NetworkDevice.ts +113 -3
  9. package/Models/DatabaseModels/NetworkDeviceAutoImportRule.ts +88 -0
  10. package/Models/DatabaseModels/NetworkDeviceDiscoveryScan.ts +22 -0
  11. package/Models/DatabaseModels/NetworkDeviceOidTemplate.ts +499 -0
  12. package/Models/DatabaseModels/ThreatIntelFeed.ts +16 -5
  13. package/Server/API/GlobalConfigAPI.ts +362 -183
  14. package/Server/API/TelemetryAPI.ts +42 -4
  15. package/Server/EnvironmentConfig.ts +112 -0
  16. package/Server/Infrastructure/Postgres/SchemaMigrations/1790500000000-AddNetworkDeviceOidTemplate.ts +59 -0
  17. package/Server/Infrastructure/Postgres/SchemaMigrations/1790600000000-AddAutoImportRuleOidTemplate.ts +25 -0
  18. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +4 -0
  19. package/Server/Middleware/MultipartFormData.ts +118 -32
  20. package/Server/Services/AlertEpisodeLabelRuleEngineService.ts +9 -1
  21. package/Server/Services/AlertEpisodeOnCallRuleEngineService.ts +9 -1
  22. package/Server/Services/AlertEpisodeOwnerRuleEngineService.ts +9 -1
  23. package/Server/Services/AlertEpisodePrivacyRuleEngineService.ts +9 -1
  24. package/Server/Services/AlertGroupingEngineService.ts +9 -1
  25. package/Server/Services/AlertLabelRuleEngineService.ts +9 -1
  26. package/Server/Services/AlertOnCallRuleEngineService.ts +9 -1
  27. package/Server/Services/AlertOwnerRuleEngineService.ts +9 -1
  28. package/Server/Services/AlertPrivacyRuleEngineService.ts +9 -1
  29. package/Server/Services/AlertReminderRuleService.ts +9 -1
  30. package/Server/Services/AutoRemediationRuleEngineService.ts +9 -1
  31. package/Server/Services/CephClusterLabelRuleEngineService.ts +9 -1
  32. package/Server/Services/CephClusterOwnerRuleEngineService.ts +9 -1
  33. package/Server/Services/CloudResourceLabelRuleEngineService.ts +9 -1
  34. package/Server/Services/CloudResourceOwnerRuleEngineService.ts +9 -1
  35. package/Server/Services/DashboardLabelRuleEngineService.ts +9 -1
  36. package/Server/Services/DashboardOwnerRuleEngineService.ts +9 -1
  37. package/Server/Services/DockerHostLabelRuleEngineService.ts +9 -1
  38. package/Server/Services/DockerHostOwnerRuleEngineService.ts +9 -1
  39. package/Server/Services/DockerSwarmClusterLabelRuleEngineService.ts +9 -1
  40. package/Server/Services/DockerSwarmClusterOwnerRuleEngineService.ts +9 -1
  41. package/Server/Services/HostLabelRuleEngineService.ts +9 -1
  42. package/Server/Services/HostOwnerRuleEngineService.ts +9 -1
  43. package/Server/Services/IncidentEpisodeLabelRuleEngineService.ts +9 -1
  44. package/Server/Services/IncidentEpisodeOnCallRuleEngineService.ts +9 -1
  45. package/Server/Services/IncidentEpisodeOwnerRuleEngineService.ts +9 -1
  46. package/Server/Services/IncidentEpisodePrivacyRuleEngineService.ts +9 -1
  47. package/Server/Services/IncidentGroupingEngineService.ts +9 -1
  48. package/Server/Services/IncidentLabelRuleEngineService.ts +9 -1
  49. package/Server/Services/IncidentOnCallRuleEngineService.ts +9 -1
  50. package/Server/Services/IncidentOwnerRuleEngineService.ts +9 -1
  51. package/Server/Services/IncidentPrivacyRuleEngineService.ts +9 -1
  52. package/Server/Services/IncidentReminderRuleService.ts +9 -1
  53. package/Server/Services/IncidentSlaRuleService.ts +9 -1
  54. package/Server/Services/IncomingCallPolicyLabelRuleEngineService.ts +9 -1
  55. package/Server/Services/IncomingCallPolicyOwnerRuleEngineService.ts +9 -1
  56. package/Server/Services/Index.ts +2 -0
  57. package/Server/Services/IoTFleetLabelRuleEngineService.ts +9 -1
  58. package/Server/Services/IoTFleetOwnerRuleEngineService.ts +9 -1
  59. package/Server/Services/KubernetesClusterLabelRuleEngineService.ts +9 -1
  60. package/Server/Services/KubernetesClusterOwnerRuleEngineService.ts +9 -1
  61. package/Server/Services/KubernetesResourceService.ts +5 -1
  62. package/Server/Services/MonitorLabelRuleEngineService.ts +9 -1
  63. package/Server/Services/MonitorOwnerRuleEngineService.ts +9 -1
  64. package/Server/Services/NetworkDeviceAutoImportRuleEngineService.ts +35 -0
  65. package/Server/Services/NetworkDeviceAutoImportRuleService.ts +96 -0
  66. package/Server/Services/NetworkDeviceLabelRuleEngineService.ts +9 -1
  67. package/Server/Services/NetworkDeviceOidTemplateService.ts +201 -0
  68. package/Server/Services/NetworkDeviceOwnerRuleEngineService.ts +9 -1
  69. package/Server/Services/NetworkDeviceService.ts +209 -1
  70. package/Server/Services/OnCallDutyPolicyLabelRuleEngineService.ts +9 -1
  71. package/Server/Services/OnCallDutyPolicyOwnerRuleEngineService.ts +9 -1
  72. package/Server/Services/OnCallDutyPolicyScheduleLabelRuleEngineService.ts +9 -1
  73. package/Server/Services/OnCallDutyPolicyScheduleOwnerRuleEngineService.ts +9 -1
  74. package/Server/Services/PodmanHostLabelRuleEngineService.ts +9 -1
  75. package/Server/Services/PodmanHostOwnerRuleEngineService.ts +9 -1
  76. package/Server/Services/ProxmoxClusterLabelRuleEngineService.ts +9 -1
  77. package/Server/Services/ProxmoxClusterOwnerRuleEngineService.ts +9 -1
  78. package/Server/Services/RumApplicationLabelRuleEngineService.ts +9 -1
  79. package/Server/Services/RumApplicationOwnerRuleEngineService.ts +9 -1
  80. package/Server/Services/RunbookLabelRuleEngineService.ts +9 -1
  81. package/Server/Services/RunbookOwnerRuleEngineService.ts +9 -1
  82. package/Server/Services/RunbookRuleEngineService.ts +9 -1
  83. package/Server/Services/ScheduledMaintenanceLabelRuleEngineService.ts +9 -1
  84. package/Server/Services/ScheduledMaintenanceOwnerRuleEngineService.ts +9 -1
  85. package/Server/Services/ScheduledMaintenanceReminderRuleService.ts +9 -1
  86. package/Server/Services/ServerlessFunctionLabelRuleEngineService.ts +9 -1
  87. package/Server/Services/ServerlessFunctionOwnerRuleEngineService.ts +9 -1
  88. package/Server/Services/ServiceLabelRuleEngineService.ts +9 -1
  89. package/Server/Services/ServiceOwnerRuleEngineService.ts +9 -1
  90. package/Server/Services/StatusPageLabelRuleEngineService.ts +9 -1
  91. package/Server/Services/StatusPageMonitorRuleEngineService.ts +7 -0
  92. package/Server/Services/StatusPageOwnerRuleEngineService.ts +9 -1
  93. package/Server/Services/TelemetrySourceMapService.ts +266 -23
  94. package/Server/Services/UserService.ts +27 -0
  95. package/Server/Services/WorkflowLabelRuleEngineService.ts +9 -1
  96. package/Server/Services/WorkflowOwnerRuleEngineService.ts +9 -1
  97. package/Server/Utils/EnterpriseLicense/EnterpriseLicenseSeatUtil.ts +186 -0
  98. package/Server/Utils/Monitor/CapturedMetricAttributeUtil.ts +245 -0
  99. package/Server/Utils/Monitor/Criteria/SnmpMonitorCriteria.ts +21 -2
  100. package/Server/Utils/Monitor/MonitorMetricUtil.ts +55 -21
  101. package/Server/Utils/Monitor/MonitorTemplateUtil.ts +32 -0
  102. package/Server/Utils/Monitor/NetworkDeviceMetricUtil.ts +15 -2
  103. package/Server/Utils/Monitor/NetworkDeviceWalkUtil.ts +18 -1
  104. package/Server/Utils/Monitor/NetworkInventoryUtil.ts +10 -0
  105. package/Server/Utils/Monitor/SeriesResourceLabels.ts +34 -0
  106. package/Server/Utils/Rules/RuleEngineRuleRead.ts +48 -0
  107. package/Server/Utils/Telemetry/ExceptionSanitizer.ts +14 -1
  108. package/Server/Utils/Telemetry/LogExceptionExtractor.ts +14 -2
  109. package/Server/Utils/Telemetry/SourceMapResolver.ts +16 -5
  110. package/Server/Utils/Telemetry/StackTraceParser.ts +399 -0
  111. package/Tests/App/Dashboard/EventOverlayHook.test.tsx +125 -0
  112. package/Tests/App/Dashboard/HeaderImageAssets.test.tsx +93 -0
  113. package/Tests/App/Dashboard/OnCallReadinessSurfaces.test.tsx +3 -3
  114. package/Tests/App/Dashboard/UserElementEmail.test.tsx +12 -4
  115. package/Tests/App/Dashboard/UserEmailCallSites.test.tsx +1 -1
  116. package/Tests/Models/DatabaseModels/DomainRoleTierCoverage.test.ts +14 -0
  117. package/Tests/Models/DatabaseModels/ModelRegistryInvariants.test.ts +469 -0
  118. package/Tests/Models/SecurityDomainAccessControl.test.ts +429 -0
  119. package/Tests/Server/API/GlobalConfigLicense.test.ts +657 -0
  120. package/Tests/Server/API/SecurityEventAttributesAPI.test.ts +84 -6
  121. package/Tests/Server/API/TelemetryResolveStackTraceAPI.test.ts +805 -0
  122. package/Tests/Server/Infrastructure/Postgres/AddOnCallCalendarFeedsMigration.test.ts +32 -7
  123. package/Tests/Server/Middleware/IdentityRateLimit.test.ts +1144 -0
  124. package/Tests/Server/Middleware/MultipartFormData.test.ts +618 -3
  125. package/Tests/Server/Services/MonitorLabelRuleEngineScale.test.ts +520 -0
  126. package/Tests/Server/Services/NetworkDeviceOidTemplateService.test.ts +332 -0
  127. package/Tests/Server/Services/NetworkDeviceOidTemplateWriteGuards.test.ts +409 -0
  128. package/Tests/Server/Services/RuleEngineRuleFetchLimit.test.ts +239 -0
  129. package/Tests/Server/Services/TelemetrySourceMapService.test.ts +1210 -2
  130. package/Tests/Server/Services/UserServiceSeatLimit.test.ts +182 -0
  131. package/Tests/Server/Types/AnalyticsDatabase/SecurityEventModelPermission.test.ts +255 -0
  132. package/Tests/Server/Types/Database/Permissions/ReadBlockPermission.test.ts +212 -0
  133. package/Tests/Server/Types/Database/Permissions/SecurityRoleAccess.test.ts +413 -0
  134. package/Tests/Server/Utils/CodeRepository.test.ts +689 -0
  135. package/Tests/Server/Utils/EnterpriseLicense/EnterpriseLicenseSeatUtil.test.ts +495 -0
  136. package/Tests/Server/Utils/ExceptionSanitizer.test.ts +77 -0
  137. package/Tests/Server/Utils/Monitor/CapturedMetricAttributeUtil.test.ts +284 -0
  138. package/Tests/Server/Utils/Monitor/MonitorCustomMetricAttributes.test.ts +503 -0
  139. package/Tests/Server/Utils/Monitor/MonitorTemplatePrototypePollution.test.ts +106 -0
  140. package/Tests/Server/Utils/Monitor/NetworkDeviceWalkLogWritePath.test.ts +33 -4
  141. package/Tests/Server/Utils/Monitor/NetworkDeviceWalkUtil.test.ts +14 -4
  142. package/Tests/Server/Utils/Monitor/NetworkInventoryUtil.test.ts +44 -0
  143. package/Tests/Server/Utils/OpenAPISpec.test.ts +536 -0
  144. package/Tests/Server/Utils/Rules/RuleEngineRuleRead.test.ts +115 -0
  145. package/Tests/Server/Utils/StackTraceParser.test.ts +610 -0
  146. package/Tests/Server/Utils/Telemetry/LogExceptionExtractor.test.ts +0 -0
  147. package/Tests/Server/Utils/Telemetry/SourceMapLimits.test.ts +656 -0
  148. package/Tests/Server/Utils/Telemetry/SourceMapResolver.test.ts +100 -0
  149. package/Tests/Types/Monitor/SnmpMonitor/SnmpOidListUtil.test.ts +454 -0
  150. package/Tests/Types/SecurityRolePermissions.test.ts +193 -0
  151. package/Tests/UI/Components/Charts/AnnotationLayout.test.ts +773 -0
  152. package/Tests/UI/Components/Charts/ChartAnnotationRail.test.tsx +789 -0
  153. package/Tests/UI/Components/Charts/ChartBucketIdentity.test.ts +254 -0
  154. package/Tests/UI/Components/Charts/TimeAnnotation.test.ts +471 -0
  155. package/Tests/UI/Components/EditionLabelLicenseRefresh.test.tsx +405 -0
  156. package/Tests/UI/Components/ErrorMessageRefreshControl.test.tsx +83 -0
  157. package/Tests/UI/Components/MarkdownConverters.test.ts +686 -0
  158. package/Tests/UI/Components/ModelTable/BaseModelTableDeleteAndEmptyStates.test.tsx +341 -0
  159. package/Tests/UI/Components/OrderedStatesList.test.tsx +5 -5
  160. package/Tests/UI/Components/PendingProjectInvitations.test.tsx +1 -1
  161. package/Tests/UI/Components/TableSortAndMobileColumns.test.tsx +195 -0
  162. package/Tests/UI/Components/XAxis.test.ts +270 -5
  163. package/Tests/UI/Components/XAxisDaylightSaving.test.ts +113 -0
  164. package/Tests/UI/Styles/ChartFocusRing.test.ts +153 -0
  165. package/Tests/UI/Styles/ChartFocusRingCoverage.test.tsx +377 -0
  166. package/Tests/UI/Styles/ThemeStylesheet.ts +162 -0
  167. package/Tests/Utils/EnterpriseLicenseSeats.test.ts +507 -0
  168. package/Tests/Utils/NetworkDiscovery/DiscoveredDeviceBuilder.test.ts +951 -1
  169. package/Tests/Utils/NetworkDiscovery/DiscoveredHostUtil.test.ts +238 -0
  170. package/Tests/Utils/NetworkDiscovery/DiscoveryReverseDnsChain.test.ts +1056 -0
  171. package/Tests/Utils/NetworkDiscovery/ReverseDnsNameUtil.test.ts +882 -0
  172. package/Types/Date.ts +39 -0
  173. package/Types/Monitor/SnmpMonitor/SnmpOidListUtil.ts +333 -0
  174. package/Types/Permission.ts +96 -0
  175. package/Types/Rum/SessionReplay.ts +21 -0
  176. package/Types/Telemetry/SourceMap.ts +8 -0
  177. package/UI/Components/Charts/ChartLibrary/Annotations/AnnotationHoverCard.tsx +176 -0
  178. package/UI/Components/Charts/ChartLibrary/Annotations/AnnotationLayout.ts +745 -0
  179. package/UI/Components/Charts/ChartLibrary/Annotations/ChartAnnotationLayer.tsx +576 -0
  180. package/UI/Components/Charts/ChartLibrary/Annotations/UseChartAnnotations.tsx +204 -0
  181. package/UI/Components/Charts/ChartLibrary/AreaChart/AreaChart.tsx +491 -544
  182. package/UI/Components/Charts/ChartLibrary/BarChart/BarChart.tsx +324 -372
  183. package/UI/Components/Charts/ChartLibrary/LineChart/LineChart.tsx +487 -540
  184. package/UI/Components/Charts/ChartLibrary/Types/FormattedReferenceRegion.ts +7 -3
  185. package/UI/Components/Charts/ChartLibrary/Types/FormattedTimeReferenceLine.ts +14 -3
  186. package/UI/Components/Charts/Types/ChartEventKind.ts +13 -0
  187. package/UI/Components/Charts/Types/ReferenceRegionProps.ts +6 -0
  188. package/UI/Components/Charts/Types/TimeReferenceLineProps.ts +20 -3
  189. package/UI/Components/Charts/Utils/TimeAnnotation.ts +69 -35
  190. package/UI/Components/Charts/Utils/XAxis.ts +125 -18
  191. package/UI/Components/EditionLabel/EditionLabel.tsx +280 -26
  192. package/UI/Components/ErrorMessage/ErrorMessage.tsx +21 -10
  193. package/UI/Components/Feed/FeedItem.tsx +4 -5
  194. package/UI/Components/Header/HeaderIconDropdownButton.tsx +1 -2
  195. package/UI/Components/Header/UserProfile/UserProfile.tsx +1 -2
  196. package/UI/Components/Image/Image.tsx +20 -3
  197. package/UI/Components/Markdown.tsx/MarkdownConverters.ts +0 -0
  198. package/UI/Components/MemberRoleAssignment/MemberRoleAssignment.tsx +1 -2
  199. package/UI/Components/ModelTable/BaseModelTable.tsx +150 -24
  200. package/UI/Components/Table/TableHeader.tsx +64 -48
  201. package/UI/Components/Table/TableRow.tsx +13 -3
  202. package/UI/Styles/Theme.css +38 -0
  203. package/Utils/EnterpriseLicense/EnterpriseLicenseSeats.ts +271 -0
  204. package/Utils/NetworkDiscovery/AutoImportRuleMatcher.ts +6 -0
  205. package/Utils/NetworkDiscovery/DiscoveredDeviceBuilder.ts +141 -10
  206. package/Utils/NetworkDiscovery/DiscoveredHostUtil.ts +55 -3
  207. package/Utils/NetworkDiscovery/ReverseDnsNameUtil.ts +151 -0
  208. package/Utils/Rules/RuleEngineLimits.ts +32 -0
  209. package/build/dist/Models/AnalyticsModels/SecurityEvent.js +48 -16
  210. package/build/dist/Models/AnalyticsModels/SecurityEvent.js.map +1 -1
  211. package/build/dist/Models/AnalyticsModels/ThreatIntelIndicator.js +10 -5
  212. package/build/dist/Models/AnalyticsModels/ThreatIntelIndicator.js.map +1 -1
  213. package/build/dist/Models/DatabaseModels/AlertSeverity.js +46 -1
  214. package/build/dist/Models/DatabaseModels/AlertSeverity.js.map +1 -1
  215. package/build/dist/Models/DatabaseModels/DetectionRule.js +16 -5
  216. package/build/dist/Models/DatabaseModels/DetectionRule.js.map +1 -1
  217. package/build/dist/Models/DatabaseModels/GoogleSecOpsConnection.js +14 -5
  218. package/build/dist/Models/DatabaseModels/GoogleSecOpsConnection.js.map +1 -1
  219. package/build/dist/Models/DatabaseModels/IncidentSeverity.js +46 -1
  220. package/build/dist/Models/DatabaseModels/IncidentSeverity.js.map +1 -1
  221. package/build/dist/Models/DatabaseModels/Index.js +2 -0
  222. package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
  223. package/build/dist/Models/DatabaseModels/NetworkDevice.js +115 -3
  224. package/build/dist/Models/DatabaseModels/NetworkDevice.js.map +1 -1
  225. package/build/dist/Models/DatabaseModels/NetworkDeviceAutoImportRule.js +88 -0
  226. package/build/dist/Models/DatabaseModels/NetworkDeviceAutoImportRule.js.map +1 -1
  227. package/build/dist/Models/DatabaseModels/NetworkDeviceDiscoveryScan.js.map +1 -1
  228. package/build/dist/Models/DatabaseModels/NetworkDeviceOidTemplate.js +519 -0
  229. package/build/dist/Models/DatabaseModels/NetworkDeviceOidTemplate.js.map +1 -0
  230. package/build/dist/Models/DatabaseModels/ThreatIntelFeed.js +16 -5
  231. package/build/dist/Models/DatabaseModels/ThreatIntelFeed.js.map +1 -1
  232. package/build/dist/Server/API/GlobalConfigAPI.js +293 -176
  233. package/build/dist/Server/API/GlobalConfigAPI.js.map +1 -1
  234. package/build/dist/Server/API/TelemetryAPI.js +31 -3
  235. package/build/dist/Server/API/TelemetryAPI.js.map +1 -1
  236. package/build/dist/Server/EnvironmentConfig.js +83 -0
  237. package/build/dist/Server/EnvironmentConfig.js.map +1 -1
  238. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1790500000000-AddNetworkDeviceOidTemplate.js +26 -0
  239. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1790500000000-AddNetworkDeviceOidTemplate.js.map +1 -0
  240. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1790600000000-AddAutoImportRuleOidTemplate.js +14 -0
  241. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1790600000000-AddAutoImportRuleOidTemplate.js.map +1 -0
  242. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +4 -0
  243. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  244. package/build/dist/Server/Middleware/MultipartFormData.js +93 -28
  245. package/build/dist/Server/Middleware/MultipartFormData.js.map +1 -1
  246. package/build/dist/Server/Services/AlertEpisodeLabelRuleEngineService.js +8 -1
  247. package/build/dist/Server/Services/AlertEpisodeLabelRuleEngineService.js.map +1 -1
  248. package/build/dist/Server/Services/AlertEpisodeOnCallRuleEngineService.js +8 -1
  249. package/build/dist/Server/Services/AlertEpisodeOnCallRuleEngineService.js.map +1 -1
  250. package/build/dist/Server/Services/AlertEpisodeOwnerRuleEngineService.js +8 -1
  251. package/build/dist/Server/Services/AlertEpisodeOwnerRuleEngineService.js.map +1 -1
  252. package/build/dist/Server/Services/AlertEpisodePrivacyRuleEngineService.js +8 -1
  253. package/build/dist/Server/Services/AlertEpisodePrivacyRuleEngineService.js.map +1 -1
  254. package/build/dist/Server/Services/AlertGroupingEngineService.js +8 -1
  255. package/build/dist/Server/Services/AlertGroupingEngineService.js.map +1 -1
  256. package/build/dist/Server/Services/AlertLabelRuleEngineService.js +8 -1
  257. package/build/dist/Server/Services/AlertLabelRuleEngineService.js.map +1 -1
  258. package/build/dist/Server/Services/AlertOnCallRuleEngineService.js +8 -1
  259. package/build/dist/Server/Services/AlertOnCallRuleEngineService.js.map +1 -1
  260. package/build/dist/Server/Services/AlertOwnerRuleEngineService.js +8 -1
  261. package/build/dist/Server/Services/AlertOwnerRuleEngineService.js.map +1 -1
  262. package/build/dist/Server/Services/AlertPrivacyRuleEngineService.js +8 -1
  263. package/build/dist/Server/Services/AlertPrivacyRuleEngineService.js.map +1 -1
  264. package/build/dist/Server/Services/AlertReminderRuleService.js +8 -1
  265. package/build/dist/Server/Services/AlertReminderRuleService.js.map +1 -1
  266. package/build/dist/Server/Services/AutoRemediationRuleEngineService.js +8 -1
  267. package/build/dist/Server/Services/AutoRemediationRuleEngineService.js.map +1 -1
  268. package/build/dist/Server/Services/CephClusterLabelRuleEngineService.js +8 -1
  269. package/build/dist/Server/Services/CephClusterLabelRuleEngineService.js.map +1 -1
  270. package/build/dist/Server/Services/CephClusterOwnerRuleEngineService.js +8 -1
  271. package/build/dist/Server/Services/CephClusterOwnerRuleEngineService.js.map +1 -1
  272. package/build/dist/Server/Services/CloudResourceLabelRuleEngineService.js +8 -1
  273. package/build/dist/Server/Services/CloudResourceLabelRuleEngineService.js.map +1 -1
  274. package/build/dist/Server/Services/CloudResourceOwnerRuleEngineService.js +8 -1
  275. package/build/dist/Server/Services/CloudResourceOwnerRuleEngineService.js.map +1 -1
  276. package/build/dist/Server/Services/DashboardLabelRuleEngineService.js +8 -1
  277. package/build/dist/Server/Services/DashboardLabelRuleEngineService.js.map +1 -1
  278. package/build/dist/Server/Services/DashboardOwnerRuleEngineService.js +8 -1
  279. package/build/dist/Server/Services/DashboardOwnerRuleEngineService.js.map +1 -1
  280. package/build/dist/Server/Services/DockerHostLabelRuleEngineService.js +8 -1
  281. package/build/dist/Server/Services/DockerHostLabelRuleEngineService.js.map +1 -1
  282. package/build/dist/Server/Services/DockerHostOwnerRuleEngineService.js +8 -1
  283. package/build/dist/Server/Services/DockerHostOwnerRuleEngineService.js.map +1 -1
  284. package/build/dist/Server/Services/DockerSwarmClusterLabelRuleEngineService.js +8 -1
  285. package/build/dist/Server/Services/DockerSwarmClusterLabelRuleEngineService.js.map +1 -1
  286. package/build/dist/Server/Services/DockerSwarmClusterOwnerRuleEngineService.js +8 -1
  287. package/build/dist/Server/Services/DockerSwarmClusterOwnerRuleEngineService.js.map +1 -1
  288. package/build/dist/Server/Services/HostLabelRuleEngineService.js +8 -1
  289. package/build/dist/Server/Services/HostLabelRuleEngineService.js.map +1 -1
  290. package/build/dist/Server/Services/HostOwnerRuleEngineService.js +8 -1
  291. package/build/dist/Server/Services/HostOwnerRuleEngineService.js.map +1 -1
  292. package/build/dist/Server/Services/IncidentEpisodeLabelRuleEngineService.js +8 -1
  293. package/build/dist/Server/Services/IncidentEpisodeLabelRuleEngineService.js.map +1 -1
  294. package/build/dist/Server/Services/IncidentEpisodeOnCallRuleEngineService.js +8 -1
  295. package/build/dist/Server/Services/IncidentEpisodeOnCallRuleEngineService.js.map +1 -1
  296. package/build/dist/Server/Services/IncidentEpisodeOwnerRuleEngineService.js +8 -1
  297. package/build/dist/Server/Services/IncidentEpisodeOwnerRuleEngineService.js.map +1 -1
  298. package/build/dist/Server/Services/IncidentEpisodePrivacyRuleEngineService.js +8 -1
  299. package/build/dist/Server/Services/IncidentEpisodePrivacyRuleEngineService.js.map +1 -1
  300. package/build/dist/Server/Services/IncidentGroupingEngineService.js +8 -1
  301. package/build/dist/Server/Services/IncidentGroupingEngineService.js.map +1 -1
  302. package/build/dist/Server/Services/IncidentLabelRuleEngineService.js +8 -1
  303. package/build/dist/Server/Services/IncidentLabelRuleEngineService.js.map +1 -1
  304. package/build/dist/Server/Services/IncidentOnCallRuleEngineService.js +8 -1
  305. package/build/dist/Server/Services/IncidentOnCallRuleEngineService.js.map +1 -1
  306. package/build/dist/Server/Services/IncidentOwnerRuleEngineService.js +8 -1
  307. package/build/dist/Server/Services/IncidentOwnerRuleEngineService.js.map +1 -1
  308. package/build/dist/Server/Services/IncidentPrivacyRuleEngineService.js +8 -1
  309. package/build/dist/Server/Services/IncidentPrivacyRuleEngineService.js.map +1 -1
  310. package/build/dist/Server/Services/IncidentReminderRuleService.js +8 -1
  311. package/build/dist/Server/Services/IncidentReminderRuleService.js.map +1 -1
  312. package/build/dist/Server/Services/IncidentSlaRuleService.js +8 -1
  313. package/build/dist/Server/Services/IncidentSlaRuleService.js.map +1 -1
  314. package/build/dist/Server/Services/IncomingCallPolicyLabelRuleEngineService.js +8 -1
  315. package/build/dist/Server/Services/IncomingCallPolicyLabelRuleEngineService.js.map +1 -1
  316. package/build/dist/Server/Services/IncomingCallPolicyOwnerRuleEngineService.js +8 -1
  317. package/build/dist/Server/Services/IncomingCallPolicyOwnerRuleEngineService.js.map +1 -1
  318. package/build/dist/Server/Services/Index.js +2 -0
  319. package/build/dist/Server/Services/Index.js.map +1 -1
  320. package/build/dist/Server/Services/IoTFleetLabelRuleEngineService.js +8 -1
  321. package/build/dist/Server/Services/IoTFleetLabelRuleEngineService.js.map +1 -1
  322. package/build/dist/Server/Services/IoTFleetOwnerRuleEngineService.js +8 -1
  323. package/build/dist/Server/Services/IoTFleetOwnerRuleEngineService.js.map +1 -1
  324. package/build/dist/Server/Services/KubernetesClusterLabelRuleEngineService.js +8 -1
  325. package/build/dist/Server/Services/KubernetesClusterLabelRuleEngineService.js.map +1 -1
  326. package/build/dist/Server/Services/KubernetesClusterOwnerRuleEngineService.js +8 -1
  327. package/build/dist/Server/Services/KubernetesClusterOwnerRuleEngineService.js.map +1 -1
  328. package/build/dist/Server/Services/KubernetesResourceService.js +5 -1
  329. package/build/dist/Server/Services/KubernetesResourceService.js.map +1 -1
  330. package/build/dist/Server/Services/MonitorLabelRuleEngineService.js +8 -1
  331. package/build/dist/Server/Services/MonitorLabelRuleEngineService.js.map +1 -1
  332. package/build/dist/Server/Services/MonitorOwnerRuleEngineService.js +8 -1
  333. package/build/dist/Server/Services/MonitorOwnerRuleEngineService.js.map +1 -1
  334. package/build/dist/Server/Services/NetworkDeviceAutoImportRuleEngineService.js +30 -21
  335. package/build/dist/Server/Services/NetworkDeviceAutoImportRuleEngineService.js.map +1 -1
  336. package/build/dist/Server/Services/NetworkDeviceAutoImportRuleService.js +64 -0
  337. package/build/dist/Server/Services/NetworkDeviceAutoImportRuleService.js.map +1 -1
  338. package/build/dist/Server/Services/NetworkDeviceLabelRuleEngineService.js +8 -1
  339. package/build/dist/Server/Services/NetworkDeviceLabelRuleEngineService.js.map +1 -1
  340. package/build/dist/Server/Services/NetworkDeviceOidTemplateService.js +180 -0
  341. package/build/dist/Server/Services/NetworkDeviceOidTemplateService.js.map +1 -0
  342. package/build/dist/Server/Services/NetworkDeviceOwnerRuleEngineService.js +8 -1
  343. package/build/dist/Server/Services/NetworkDeviceOwnerRuleEngineService.js.map +1 -1
  344. package/build/dist/Server/Services/NetworkDeviceService.js +154 -1
  345. package/build/dist/Server/Services/NetworkDeviceService.js.map +1 -1
  346. package/build/dist/Server/Services/OnCallDutyPolicyLabelRuleEngineService.js +8 -1
  347. package/build/dist/Server/Services/OnCallDutyPolicyLabelRuleEngineService.js.map +1 -1
  348. package/build/dist/Server/Services/OnCallDutyPolicyOwnerRuleEngineService.js +8 -1
  349. package/build/dist/Server/Services/OnCallDutyPolicyOwnerRuleEngineService.js.map +1 -1
  350. package/build/dist/Server/Services/OnCallDutyPolicyScheduleLabelRuleEngineService.js +8 -1
  351. package/build/dist/Server/Services/OnCallDutyPolicyScheduleLabelRuleEngineService.js.map +1 -1
  352. package/build/dist/Server/Services/OnCallDutyPolicyScheduleOwnerRuleEngineService.js +8 -1
  353. package/build/dist/Server/Services/OnCallDutyPolicyScheduleOwnerRuleEngineService.js.map +1 -1
  354. package/build/dist/Server/Services/PodmanHostLabelRuleEngineService.js +8 -1
  355. package/build/dist/Server/Services/PodmanHostLabelRuleEngineService.js.map +1 -1
  356. package/build/dist/Server/Services/PodmanHostOwnerRuleEngineService.js +8 -1
  357. package/build/dist/Server/Services/PodmanHostOwnerRuleEngineService.js.map +1 -1
  358. package/build/dist/Server/Services/ProxmoxClusterLabelRuleEngineService.js +8 -1
  359. package/build/dist/Server/Services/ProxmoxClusterLabelRuleEngineService.js.map +1 -1
  360. package/build/dist/Server/Services/ProxmoxClusterOwnerRuleEngineService.js +8 -1
  361. package/build/dist/Server/Services/ProxmoxClusterOwnerRuleEngineService.js.map +1 -1
  362. package/build/dist/Server/Services/RumApplicationLabelRuleEngineService.js +8 -1
  363. package/build/dist/Server/Services/RumApplicationLabelRuleEngineService.js.map +1 -1
  364. package/build/dist/Server/Services/RumApplicationOwnerRuleEngineService.js +8 -1
  365. package/build/dist/Server/Services/RumApplicationOwnerRuleEngineService.js.map +1 -1
  366. package/build/dist/Server/Services/RunbookLabelRuleEngineService.js +8 -1
  367. package/build/dist/Server/Services/RunbookLabelRuleEngineService.js.map +1 -1
  368. package/build/dist/Server/Services/RunbookOwnerRuleEngineService.js +8 -1
  369. package/build/dist/Server/Services/RunbookOwnerRuleEngineService.js.map +1 -1
  370. package/build/dist/Server/Services/RunbookRuleEngineService.js +8 -1
  371. package/build/dist/Server/Services/RunbookRuleEngineService.js.map +1 -1
  372. package/build/dist/Server/Services/ScheduledMaintenanceLabelRuleEngineService.js +8 -1
  373. package/build/dist/Server/Services/ScheduledMaintenanceLabelRuleEngineService.js.map +1 -1
  374. package/build/dist/Server/Services/ScheduledMaintenanceOwnerRuleEngineService.js +8 -1
  375. package/build/dist/Server/Services/ScheduledMaintenanceOwnerRuleEngineService.js.map +1 -1
  376. package/build/dist/Server/Services/ScheduledMaintenanceReminderRuleService.js +8 -1
  377. package/build/dist/Server/Services/ScheduledMaintenanceReminderRuleService.js.map +1 -1
  378. package/build/dist/Server/Services/ServerlessFunctionLabelRuleEngineService.js +8 -1
  379. package/build/dist/Server/Services/ServerlessFunctionLabelRuleEngineService.js.map +1 -1
  380. package/build/dist/Server/Services/ServerlessFunctionOwnerRuleEngineService.js +8 -1
  381. package/build/dist/Server/Services/ServerlessFunctionOwnerRuleEngineService.js.map +1 -1
  382. package/build/dist/Server/Services/ServiceLabelRuleEngineService.js +8 -1
  383. package/build/dist/Server/Services/ServiceLabelRuleEngineService.js.map +1 -1
  384. package/build/dist/Server/Services/ServiceOwnerRuleEngineService.js +8 -1
  385. package/build/dist/Server/Services/ServiceOwnerRuleEngineService.js.map +1 -1
  386. package/build/dist/Server/Services/StatusPageLabelRuleEngineService.js +8 -1
  387. package/build/dist/Server/Services/StatusPageLabelRuleEngineService.js.map +1 -1
  388. package/build/dist/Server/Services/StatusPageMonitorRuleEngineService.js +6 -0
  389. package/build/dist/Server/Services/StatusPageMonitorRuleEngineService.js.map +1 -1
  390. package/build/dist/Server/Services/StatusPageOwnerRuleEngineService.js +8 -1
  391. package/build/dist/Server/Services/StatusPageOwnerRuleEngineService.js.map +1 -1
  392. package/build/dist/Server/Services/TelemetrySourceMapService.js +213 -19
  393. package/build/dist/Server/Services/TelemetrySourceMapService.js.map +1 -1
  394. package/build/dist/Server/Services/UserService.js +25 -0
  395. package/build/dist/Server/Services/UserService.js.map +1 -1
  396. package/build/dist/Server/Services/WorkflowLabelRuleEngineService.js +8 -1
  397. package/build/dist/Server/Services/WorkflowLabelRuleEngineService.js.map +1 -1
  398. package/build/dist/Server/Services/WorkflowOwnerRuleEngineService.js +8 -1
  399. package/build/dist/Server/Services/WorkflowOwnerRuleEngineService.js.map +1 -1
  400. package/build/dist/Server/Utils/EnterpriseLicense/EnterpriseLicenseSeatUtil.js +145 -0
  401. package/build/dist/Server/Utils/EnterpriseLicense/EnterpriseLicenseSeatUtil.js.map +1 -0
  402. package/build/dist/Server/Utils/Monitor/CapturedMetricAttributeUtil.js +201 -0
  403. package/build/dist/Server/Utils/Monitor/CapturedMetricAttributeUtil.js.map +1 -0
  404. package/build/dist/Server/Utils/Monitor/Criteria/SnmpMonitorCriteria.js +19 -2
  405. package/build/dist/Server/Utils/Monitor/Criteria/SnmpMonitorCriteria.js.map +1 -1
  406. package/build/dist/Server/Utils/Monitor/MonitorMetricUtil.js +42 -23
  407. package/build/dist/Server/Utils/Monitor/MonitorMetricUtil.js.map +1 -1
  408. package/build/dist/Server/Utils/Monitor/MonitorTemplateUtil.js +29 -0
  409. package/build/dist/Server/Utils/Monitor/MonitorTemplateUtil.js.map +1 -1
  410. package/build/dist/Server/Utils/Monitor/NetworkDeviceMetricUtil.js +11 -2
  411. package/build/dist/Server/Utils/Monitor/NetworkDeviceMetricUtil.js.map +1 -1
  412. package/build/dist/Server/Utils/Monitor/NetworkDeviceWalkUtil.js +16 -1
  413. package/build/dist/Server/Utils/Monitor/NetworkDeviceWalkUtil.js.map +1 -1
  414. package/build/dist/Server/Utils/Monitor/NetworkInventoryUtil.js +10 -0
  415. package/build/dist/Server/Utils/Monitor/NetworkInventoryUtil.js.map +1 -1
  416. package/build/dist/Server/Utils/Monitor/SeriesResourceLabels.js +33 -0
  417. package/build/dist/Server/Utils/Monitor/SeriesResourceLabels.js.map +1 -1
  418. package/build/dist/Server/Utils/Rules/RuleEngineRuleRead.js +37 -0
  419. package/build/dist/Server/Utils/Rules/RuleEngineRuleRead.js.map +1 -0
  420. package/build/dist/Server/Utils/Telemetry/ExceptionSanitizer.js +12 -1
  421. package/build/dist/Server/Utils/Telemetry/ExceptionSanitizer.js.map +1 -1
  422. package/build/dist/Server/Utils/Telemetry/LogExceptionExtractor.js +14 -2
  423. package/build/dist/Server/Utils/Telemetry/LogExceptionExtractor.js.map +1 -1
  424. package/build/dist/Server/Utils/Telemetry/SourceMapResolver.js +15 -5
  425. package/build/dist/Server/Utils/Telemetry/SourceMapResolver.js.map +1 -1
  426. package/build/dist/Server/Utils/Telemetry/StackTraceParser.js +307 -0
  427. package/build/dist/Server/Utils/Telemetry/StackTraceParser.js.map +1 -1
  428. package/build/dist/Types/Date.js +27 -0
  429. package/build/dist/Types/Date.js.map +1 -1
  430. package/build/dist/Types/Monitor/SnmpMonitor/SnmpOidListUtil.js +253 -0
  431. package/build/dist/Types/Monitor/SnmpMonitor/SnmpOidListUtil.js.map +1 -0
  432. package/build/dist/Types/Permission.js +86 -0
  433. package/build/dist/Types/Permission.js.map +1 -1
  434. package/build/dist/Types/Rum/SessionReplay.js +19 -0
  435. package/build/dist/Types/Rum/SessionReplay.js.map +1 -1
  436. package/build/dist/UI/Components/Charts/ChartLibrary/Annotations/AnnotationHoverCard.js +83 -0
  437. package/build/dist/UI/Components/Charts/ChartLibrary/Annotations/AnnotationHoverCard.js.map +1 -0
  438. package/build/dist/UI/Components/Charts/ChartLibrary/Annotations/AnnotationLayout.js +531 -0
  439. package/build/dist/UI/Components/Charts/ChartLibrary/Annotations/AnnotationLayout.js.map +1 -0
  440. package/build/dist/UI/Components/Charts/ChartLibrary/Annotations/ChartAnnotationLayer.js +264 -0
  441. package/build/dist/UI/Components/Charts/ChartLibrary/Annotations/ChartAnnotationLayer.js.map +1 -0
  442. package/build/dist/UI/Components/Charts/ChartLibrary/Annotations/UseChartAnnotations.js +122 -0
  443. package/build/dist/UI/Components/Charts/ChartLibrary/Annotations/UseChartAnnotations.js.map +1 -0
  444. package/build/dist/UI/Components/Charts/ChartLibrary/AreaChart/AreaChart.js +213 -233
  445. package/build/dist/UI/Components/Charts/ChartLibrary/AreaChart/AreaChart.js.map +1 -1
  446. package/build/dist/UI/Components/Charts/ChartLibrary/BarChart/BarChart.js +139 -152
  447. package/build/dist/UI/Components/Charts/ChartLibrary/BarChart/BarChart.js.map +1 -1
  448. package/build/dist/UI/Components/Charts/ChartLibrary/LineChart/LineChart.js +212 -232
  449. package/build/dist/UI/Components/Charts/ChartLibrary/LineChart/LineChart.js.map +1 -1
  450. package/build/dist/UI/Components/Charts/Types/ChartEventKind.js +14 -0
  451. package/build/dist/UI/Components/Charts/Types/ChartEventKind.js.map +1 -0
  452. package/build/dist/UI/Components/Charts/Utils/TimeAnnotation.js +57 -28
  453. package/build/dist/UI/Components/Charts/Utils/TimeAnnotation.js.map +1 -1
  454. package/build/dist/UI/Components/Charts/Utils/XAxis.js +103 -17
  455. package/build/dist/UI/Components/Charts/Utils/XAxis.js.map +1 -1
  456. package/build/dist/UI/Components/EditionLabel/EditionLabel.js +198 -23
  457. package/build/dist/UI/Components/EditionLabel/EditionLabel.js.map +1 -1
  458. package/build/dist/UI/Components/ErrorMessage/ErrorMessage.js +15 -5
  459. package/build/dist/UI/Components/ErrorMessage/ErrorMessage.js.map +1 -1
  460. package/build/dist/UI/Components/Feed/FeedItem.js +4 -5
  461. package/build/dist/UI/Components/Feed/FeedItem.js.map +1 -1
  462. package/build/dist/UI/Components/Header/HeaderIconDropdownButton.js +1 -2
  463. package/build/dist/UI/Components/Header/HeaderIconDropdownButton.js.map +1 -1
  464. package/build/dist/UI/Components/Header/UserProfile/UserProfile.js.map +1 -1
  465. package/build/dist/UI/Components/Image/Image.js +6 -1
  466. package/build/dist/UI/Components/Image/Image.js.map +1 -1
  467. package/build/dist/UI/Components/Markdown.tsx/MarkdownConverters.js +0 -0
  468. package/build/dist/UI/Components/Markdown.tsx/MarkdownConverters.js.map +1 -1
  469. package/build/dist/UI/Components/MemberRoleAssignment/MemberRoleAssignment.js +1 -2
  470. package/build/dist/UI/Components/MemberRoleAssignment/MemberRoleAssignment.js.map +1 -1
  471. package/build/dist/UI/Components/ModelTable/BaseModelTable.js +104 -23
  472. package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
  473. package/build/dist/UI/Components/Table/TableHeader.js +20 -22
  474. package/build/dist/UI/Components/Table/TableHeader.js.map +1 -1
  475. package/build/dist/UI/Components/Table/TableRow.js +13 -4
  476. package/build/dist/UI/Components/Table/TableRow.js.map +1 -1
  477. package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseSeats.js +153 -0
  478. package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseSeats.js.map +1 -0
  479. package/build/dist/Utils/NetworkDiscovery/AutoImportRuleMatcher.js.map +1 -1
  480. package/build/dist/Utils/NetworkDiscovery/DiscoveredDeviceBuilder.js +127 -7
  481. package/build/dist/Utils/NetworkDiscovery/DiscoveredDeviceBuilder.js.map +1 -1
  482. package/build/dist/Utils/NetworkDiscovery/DiscoveredHostUtil.js +50 -3
  483. package/build/dist/Utils/NetworkDiscovery/DiscoveredHostUtil.js.map +1 -1
  484. package/build/dist/Utils/NetworkDiscovery/ReverseDnsNameUtil.js +132 -0
  485. package/build/dist/Utils/NetworkDiscovery/ReverseDnsNameUtil.js.map +1 -0
  486. package/build/dist/Utils/Rules/RuleEngineLimits.js +31 -0
  487. package/build/dist/Utils/Rules/RuleEngineLimits.js.map +1 -0
  488. package/jest.config.json +1 -0
  489. package/package.json +2 -2
@@ -29,6 +29,7 @@ import {
29
29
  import Alert, { AlertType } from "../Alerts/Alert";
30
30
  import EnterpriseLicenseInstanceSummary from "../../../Types/EnterpriseLicense/EnterpriseLicenseInstanceSummary";
31
31
  import VersionUtil from "../../../Utils/VersionUtil";
32
+ import UserUtil from "../../Utils/User";
32
33
 
33
34
  export interface ComponentProps {
34
35
  className?: string | undefined;
@@ -136,7 +137,24 @@ const EditionLabel: FunctionComponent<ComponentProps> = (
136
137
  const [validationError, setValidationError] = useState<string>("");
137
138
  const [successMessage, setSuccessMessage] = useState<string>("");
138
139
  const [isValidating, setIsValidating] = useState<boolean>(false);
140
+ const [isRefreshingLicense, setIsRefreshingLicense] =
141
+ useState<boolean>(false);
139
142
  const [isChangingLicense, setIsChangingLicense] = useState<boolean>(false);
143
+ /*
144
+ * The seat limit as this installation actually enforces it, rather than as
145
+ * oneuptime.com last reported it. The server computes it from the live User
146
+ * table, so it knows about everybody added since the last daily report -
147
+ * including the person whose invitation is about to be refused.
148
+ *
149
+ * Only returned to a signed-in caller, so all four stay at their "nothing to
150
+ * say" values on the login page.
151
+ */
152
+ const [isSeatLimitEnforced, setIsSeatLimitEnforced] =
153
+ useState<boolean>(false);
154
+ const [enforcedSeatsInUse, setEnforcedSeatsInUse] = useState<number | null>(
155
+ null,
156
+ );
157
+ const [canAddMoreUsers, setCanAddMoreUsers] = useState<boolean>(true);
140
158
  const [licenseInstances, setLicenseInstances] = useState<
141
159
  Array<EnterpriseLicenseInstanceSummary>
142
160
  >([]);
@@ -178,6 +196,29 @@ const EditionLabel: FunctionComponent<ComponentProps> = (
178
196
  return <></>;
179
197
  }
180
198
 
199
+ /*
200
+ * Both the license GET and the two license POSTs answer with the same seat
201
+ * fields, so the three responses are unpacked in one place.
202
+ * isSeatLimitEnforced is what tells "this installation does not enforce a
203
+ * seat limit" apart from "this build did not report one" - without it, an
204
+ * older server's silence would read as a limit of zero.
205
+ */
206
+ const applySeatEnforcementPayload: (payload: JSONObject) => void =
207
+ useCallback((payload: JSONObject): void => {
208
+ setIsSeatLimitEnforced(payload["isSeatLimitEnforced"] === true);
209
+ setEnforcedSeatsInUse(
210
+ typeof payload["seatsInUse"] === "number"
211
+ ? (payload["seatsInUse"] as number)
212
+ : null,
213
+ );
214
+ /*
215
+ * Defaults to true, so a build or a response that says nothing about
216
+ * enforcement never renders a "you cannot add users" warning it has no
217
+ * evidence for.
218
+ */
219
+ setCanAddMoreUsers(payload["canAddMoreUsers"] !== false);
220
+ }, []);
221
+
181
222
  /*
182
223
  * Runs on Community Edition too. The license half of the response is empty
183
224
  * there, but the version and update-check half is not — a community
@@ -278,6 +319,7 @@ const EditionLabel: FunctionComponent<ComponentProps> = (
278
319
  );
279
320
  setIsUpdateAvailable(payload["isUpdateAvailable"] === true);
280
321
  setIsUpdateCheckDisabled(payload["isUpdateCheckDisabled"] === true);
322
+ applySeatEnforcementPayload(payload);
281
323
 
282
324
  if (!licenseInputEditedRef.current) {
283
325
  setLicenseKeyInput(configModel.enterpriseLicenseKey || "");
@@ -293,11 +335,14 @@ const EditionLabel: FunctionComponent<ComponentProps> = (
293
335
  setLatestVersionCheckedAt("");
294
336
  setIsUpdateAvailable(false);
295
337
  setIsUpdateCheckDisabled(false);
338
+ setIsSeatLimitEnforced(false);
339
+ setEnforcedSeatsInUse(null);
340
+ setCanAddMoreUsers(true);
296
341
  setConfigError(API.getFriendlyMessage(err));
297
342
  } finally {
298
343
  setIsConfigLoading(false);
299
344
  }
300
- }, []);
345
+ }, [applySeatEnforcementPayload]);
301
346
 
302
347
  /*
303
348
  * Only Enterprise Edition needs this on mount — its pill reports license
@@ -468,6 +513,25 @@ const EditionLabel: FunctionComponent<ComponentProps> = (
468
513
  : null;
469
514
  }, [globalConfig?.enterpriseLicenseCurrentUserCount]);
470
515
 
516
+ /*
517
+ * The seat figure everything below is measured against.
518
+ *
519
+ * currentUserCount is what oneuptime.com last computed across every instance
520
+ * on this license, which is up to a day old. On an installation that
521
+ * enforces a seat limit the server also sends seatsInUse: the same
522
+ * cross-instance figure reconciled with the live User table here, and the
523
+ * number invitations are actually refused on. Showing anything else would
524
+ * leave the card reading "98 of 100" next to an invitation that had just
525
+ * bounced.
526
+ */
527
+ const effectiveUserCount: number | null = useMemo(() => {
528
+ if (isSeatLimitEnforced && typeof enforcedSeatsInUse === "number") {
529
+ return enforcedSeatsInUse;
530
+ }
531
+
532
+ return currentUserCount;
533
+ }, [isSeatLimitEnforced, enforcedSeatsInUse, currentUserCount]);
534
+
471
535
  const userCountUpdatedAtText: string | null = useMemo(() => {
472
536
  if (!globalConfig?.enterpriseLicenseUserCountUpdatedAt) {
473
537
  return null;
@@ -493,12 +557,12 @@ const EditionLabel: FunctionComponent<ComponentProps> = (
493
557
  return false;
494
558
  }
495
559
 
496
- if (typeof currentUserCount !== "number") {
560
+ if (typeof effectiveUserCount !== "number") {
497
561
  return false;
498
562
  }
499
563
 
500
- return currentUserCount > userLimit;
501
- }, [licenseValid, userLimit, currentUserCount]);
564
+ return effectiveUserCount > userLimit;
565
+ }, [licenseValid, userLimit, effectiveUserCount]);
502
566
 
503
567
  /*
504
568
  * Unclamped and unrounded. The only value that can tell 120/120 apart from
@@ -510,12 +574,12 @@ const EditionLabel: FunctionComponent<ComponentProps> = (
510
574
  return null;
511
575
  }
512
576
 
513
- if (typeof currentUserCount !== "number") {
577
+ if (typeof effectiveUserCount !== "number") {
514
578
  return null;
515
579
  }
516
580
 
517
- return Math.max(0, (currentUserCount / userLimit) * 100);
518
- }, [userLimit, currentUserCount]);
581
+ return Math.max(0, (effectiveUserCount / userLimit) * 100);
582
+ }, [userLimit, effectiveUserCount]);
519
583
 
520
584
  /*
521
585
  * The percent the admin reads, and the one the warning fires on. May exceed
@@ -558,12 +622,12 @@ const EditionLabel: FunctionComponent<ComponentProps> = (
558
622
  return null;
559
623
  }
560
624
 
561
- if (typeof currentUserCount !== "number") {
625
+ if (typeof effectiveUserCount !== "number") {
562
626
  return null;
563
627
  }
564
628
 
565
- return userLimit - currentUserCount;
566
- }, [userLimit, currentUserCount]);
629
+ return userLimit - effectiveUserCount;
630
+ }, [userLimit, effectiveUserCount]);
567
631
 
568
632
  const seatsRemainingText: string = useMemo(() => {
569
633
  if (typeof seatsRemaining !== "number") {
@@ -600,6 +664,16 @@ const EditionLabel: FunctionComponent<ComponentProps> = (
600
664
  return "breached";
601
665
  }
602
666
 
667
+ /*
668
+ * Exactly at the limit is not over it, but it is the point where the
669
+ * installation starts refusing new users - so it gets the red treatment
670
+ * rather than the amber "nearly full" nudge, which would understate a
671
+ * door that is already shut.
672
+ */
673
+ if (isSeatLimitEnforced && !canAddMoreUsers) {
674
+ return "breached";
675
+ }
676
+
603
677
  if (
604
678
  typeof seatUsageDisplayPercent === "number" &&
605
679
  seatUsageDisplayPercent >= SEAT_WARNING_PERCENT
@@ -608,7 +682,13 @@ const EditionLabel: FunctionComponent<ComponentProps> = (
608
682
  }
609
683
 
610
684
  return "healthy";
611
- }, [licenseValid, isUserLimitBreached, seatUsageDisplayPercent]);
685
+ }, [
686
+ licenseValid,
687
+ isUserLimitBreached,
688
+ isSeatLimitEnforced,
689
+ canAddMoreUsers,
690
+ seatUsageDisplayPercent,
691
+ ]);
612
692
 
613
693
  /*
614
694
  * Copy containing apostrophes lives in string literals rather than JSX text,
@@ -618,6 +698,14 @@ const EditionLabel: FunctionComponent<ComponentProps> = (
618
698
  if (seatTone === "breached") {
619
699
  const over: number = Math.abs(seatsRemaining || 0);
620
700
 
701
+ /*
702
+ * Reachable now that "every seat taken" is a breach in its own right:
703
+ * an installation sitting exactly on its limit is not "0 users over".
704
+ */
705
+ if (over === 0) {
706
+ return "Every licensed seat is in use";
707
+ }
708
+
621
709
  return over === 1
622
710
  ? "1 user over your licensed seats"
623
711
  : `${over.toLocaleString()} users over your licensed seats`;
@@ -638,9 +726,19 @@ const EditionLabel: FunctionComponent<ComponentProps> = (
638
726
 
639
727
  const seatAdvisoryBody: string = useMemo(() => {
640
728
  const limitText: string = (userLimit || 0).toLocaleString();
641
- const inUse: string = `${(currentUserCount || 0).toLocaleString()} of ${limitText}`;
729
+ const inUse: string = `${(effectiveUserCount || 0).toLocaleString()} of ${limitText}`;
642
730
 
643
731
  if (seatTone === "breached") {
732
+ /*
733
+ * When the limit is being enforced this is no longer advice, it is a
734
+ * description of what the installation is already doing to invitations
735
+ * and signups - so it says so plainly rather than suggesting an upgrade
736
+ * as though adding people were still an option.
737
+ */
738
+ if (isSeatLimitEnforced && !canAddMoreUsers) {
739
+ return `This installation is using ${inUse} licensed seats. New users cannot be invited, signed up or provisioned until a seat is freed up or the license is expanded.`;
740
+ }
741
+
644
742
  return `This installation is using ${inUse} licensed seats. Expand your license so it covers everyone on the platform.`;
645
743
  }
646
744
 
@@ -649,7 +747,13 @@ const EditionLabel: FunctionComponent<ComponentProps> = (
649
747
  }
650
748
 
651
749
  return "";
652
- }, [seatTone, currentUserCount, userLimit]);
750
+ }, [
751
+ seatTone,
752
+ effectiveUserCount,
753
+ userLimit,
754
+ isSeatLimitEnforced,
755
+ canAddMoreUsers,
756
+ ]);
653
757
 
654
758
  const seatUsageAriaValueText: string = useMemo(() => {
655
759
  if (typeof seatUsageDisplayPercent !== "number") {
@@ -878,7 +982,7 @@ const EditionLabel: FunctionComponent<ComponentProps> = (
878
982
  "We would like to expand the seat count on our enterprise license.",
879
983
  "",
880
984
  `Company: ${globalConfig?.enterpriseCompanyName || "Not specified"}`,
881
- `Seats in use: ${(currentUserCount || 0).toLocaleString()} of ${(
985
+ `Seats in use: ${(effectiveUserCount || 0).toLocaleString()} of ${(
882
986
  userLimit || 0
883
987
  ).toLocaleString()}`,
884
988
  `Instances on this license: ${licenseInstances.length}`,
@@ -958,14 +1062,96 @@ const EditionLabel: FunctionComponent<ComponentProps> = (
958
1062
  void runLicenseValidation(licenseKeyInput, setIsValidating);
959
1063
  };
960
1064
 
1065
+ /*
1066
+ * Re-ask oneuptime.com about the license this installation already holds.
1067
+ *
1068
+ * The seat limit and the expiry are changed on oneuptime.com, and the daily
1069
+ * report job is what normally carries them here - so without this, an
1070
+ * administrator who has just bought seats waits up to a day before the
1071
+ * installation stops refusing invitations. Deliberately sends no key: the
1072
+ * server refreshes the stored one.
1073
+ */
1074
+ const handleRefreshLicense: () => void = useCallback((): void => {
1075
+ if (isRefreshingLicense) {
1076
+ return;
1077
+ }
1078
+
1079
+ const refresh: () => Promise<void> = async (): Promise<void> => {
1080
+ setValidationError("");
1081
+ setSuccessMessage("");
1082
+ setIsRefreshingLicense(true);
1083
+
1084
+ try {
1085
+ const refreshUrl: URL = URL.fromURL(APP_API_URL).addRoute(
1086
+ new Route("/global-config/license/refresh"),
1087
+ );
1088
+
1089
+ const response: HTTPResponse<JSONObject> | HTTPErrorResponse =
1090
+ await API.fetch<JSONObject>({
1091
+ method: HTTPMethod.POST,
1092
+ url: refreshUrl,
1093
+ });
1094
+
1095
+ if (!response.isSuccess()) {
1096
+ throw response;
1097
+ }
1098
+
1099
+ applySeatEnforcementPayload(response.data as JSONObject);
1100
+
1101
+ setSuccessMessage("License refreshed from OneUptime.");
1102
+
1103
+ /*
1104
+ * The POST already returned the new terms, but the modal renders from
1105
+ * what the GET reports - re-reading keeps one source of truth for the
1106
+ * whole dialog instead of two that can disagree.
1107
+ */
1108
+ await fetchGlobalConfig();
1109
+ } catch (err) {
1110
+ setValidationError(API.getFriendlyMessage(err));
1111
+ } finally {
1112
+ setIsRefreshingLicense(false);
1113
+ }
1114
+ };
1115
+
1116
+ void refresh();
1117
+ }, [isRefreshingLicense, fetchGlobalConfig, applySeatEnforcementPayload]);
1118
+
961
1119
  const handleRetryFetch: () => void = () => {
962
1120
  if (!isConfigLoading) {
963
1121
  void fetchGlobalConfig();
964
1122
  }
965
1123
  };
966
1124
 
1125
+ /*
1126
+ * Activating, replacing and refreshing the license are master-admin actions:
1127
+ * the license is instance-wide, and its seat limit is what UserService
1128
+ * enforces against, so being able to rewrite it is being able to raise the
1129
+ * ceiling on the whole installation. The server enforces this
1130
+ * (MasterAdminAuthorization on both POSTs); hiding the controls here just
1131
+ * stops everyone else being offered a button that can only fail.
1132
+ *
1133
+ * False for a signed-out visitor, which is what keeps the license key input
1134
+ * off the login page where this same component renders the edition pill.
1135
+ */
1136
+ const canManageLicense: boolean = useMemo(() => {
1137
+ return Boolean(UserUtil.isMasterAdmin());
1138
+ }, []);
1139
+
967
1140
  const showLicenseKeyInput: boolean =
968
- IS_ENTERPRISE_EDITION && (!licenseValid || isChangingLicense);
1141
+ IS_ENTERPRISE_EDITION &&
1142
+ canManageLicense &&
1143
+ (!licenseValid || isChangingLicense);
1144
+
1145
+ /*
1146
+ * Someone who cannot fix the license still needs to be told why the
1147
+ * installation is behaving like an unlicensed one, and who can fix it.
1148
+ */
1149
+ const showLicenseAdminRequiredNotice: boolean =
1150
+ IS_ENTERPRISE_EDITION &&
1151
+ !configError &&
1152
+ !isConfigLoading &&
1153
+ !licenseValid &&
1154
+ !canManageLicense;
969
1155
 
970
1156
  const shouldShowEnterpriseValidationButton: boolean = showLicenseKeyInput;
971
1157
 
@@ -1066,13 +1252,34 @@ const EditionLabel: FunctionComponent<ComponentProps> = (
1066
1252
  ) : undefined;
1067
1253
 
1068
1254
  const modalLeftFooterElement: ReactElement | undefined =
1069
- showLicenseDetails && !isChangingLicense ? (
1070
- <Button
1071
- title="Change license key"
1072
- icon={IconProp.Edit}
1073
- buttonStyle={ButtonStyleType.NORMAL}
1074
- onClick={handleStartChangingLicense}
1075
- />
1255
+ showLicenseDetails && !isChangingLicense && canManageLicense ? (
1256
+ <div className="flex flex-wrap items-center gap-2">
1257
+ {/*
1258
+ * The seat limit and the expiry are changed on oneuptime.com and reach
1259
+ * this installation through the daily report job. This is the button
1260
+ * for the administrator who has just bought seats and would rather not
1261
+ * wait a day for the installation to stop refusing invitations.
1262
+ */}
1263
+ <Button
1264
+ title="Refresh license"
1265
+ icon={IconProp.Refresh}
1266
+ buttonStyle={ButtonStyleType.NORMAL}
1267
+ onClick={handleRefreshLicense}
1268
+ isLoading={isRefreshingLicense}
1269
+ disabled={isRefreshingLicense || isConfigLoading}
1270
+ tooltip="Fetch the latest seat limit and expiry for this license from OneUptime."
1271
+ dataTestId="refresh-enterprise-license"
1272
+ className="!mt-0 md:!ml-0"
1273
+ />
1274
+ <Button
1275
+ title="Change license key"
1276
+ icon={IconProp.Edit}
1277
+ buttonStyle={ButtonStyleType.NORMAL}
1278
+ onClick={handleStartChangingLicense}
1279
+ disabled={isRefreshingLicense}
1280
+ className="!mt-0 md:!ml-0"
1281
+ />
1282
+ </div>
1076
1283
  ) : undefined;
1077
1284
 
1078
1285
  const pillClassName: string =
@@ -1320,6 +1527,16 @@ const EditionLabel: FunctionComponent<ComponentProps> = (
1320
1527
  <Alert type={AlertType.SUCCESS} title={successMessage} />
1321
1528
  )}
1322
1529
 
1530
+ {/*
1531
+ * A failed refresh has nowhere else to go: the license key
1532
+ * section carries its own copy of this alert, but that
1533
+ * section is not rendered at all while the license is valid,
1534
+ * which is exactly when refreshing is worth doing.
1535
+ */}
1536
+ {!configError && validationError && !showLicenseKeyInput && (
1537
+ <Alert type={AlertType.DANGER} title={validationError} />
1538
+ )}
1539
+
1323
1540
  {configError && (
1324
1541
  <div className="rounded-xl border border-red-200 bg-red-50 p-4">
1325
1542
  <div className="flex items-start gap-2.5">
@@ -1412,15 +1629,15 @@ const EditionLabel: FunctionComponent<ComponentProps> = (
1412
1629
  <p className="flex items-baseline gap-1.5">
1413
1630
  <span
1414
1631
  className={`text-3xl font-semibold leading-none tabular-nums ${
1415
- typeof currentUserCount !== "number"
1632
+ typeof effectiveUserCount !== "number"
1416
1633
  ? "text-gray-300"
1417
1634
  : seatTone === "breached"
1418
1635
  ? "text-red-700"
1419
1636
  : "text-gray-900"
1420
1637
  }`}
1421
1638
  >
1422
- {typeof currentUserCount === "number"
1423
- ? currentUserCount.toLocaleString()
1639
+ {typeof effectiveUserCount === "number"
1640
+ ? effectiveUserCount.toLocaleString()
1424
1641
  : "—"}
1425
1642
  </span>
1426
1643
  <span className="text-sm tabular-nums text-gray-500">
@@ -1568,6 +1785,28 @@ const EditionLabel: FunctionComponent<ComponentProps> = (
1568
1785
  {userCountUpdatedAtText
1569
1786
  ? `Last reported to OneUptime on ${userCountUpdatedAtText}.`
1570
1787
  : "User count has not been reported to OneUptime yet. The first report will be sent within 24 hours."}
1788
+ {isSeatLimitEnforced && (
1789
+ <>
1790
+ {" "}
1791
+ This installation enforces the seat limit: users
1792
+ above it cannot be invited, signed up or
1793
+ provisioned.
1794
+ </>
1795
+ )}
1796
+ {/*
1797
+ * Only pointed at somebody who can actually press it.
1798
+ * The refresh button is master-admin only, so telling
1799
+ * everyone else to use it would be an instruction they
1800
+ * cannot follow.
1801
+ */}
1802
+ {isSeatLimitEnforced && canManageLicense && (
1803
+ <>
1804
+ {" "}
1805
+ Bought more seats? Use &quot;Refresh license&quot;
1806
+ below to apply the new limit without waiting for the
1807
+ next daily report.
1808
+ </>
1809
+ )}
1571
1810
  </p>
1572
1811
  </div>
1573
1812
  </section>
@@ -1729,6 +1968,19 @@ const EditionLabel: FunctionComponent<ComponentProps> = (
1729
1968
  </div>
1730
1969
  )}
1731
1970
 
1971
+ {showLicenseAdminRequiredNotice && (
1972
+ <section className="rounded-xl border border-amber-200 bg-amber-50 p-5">
1973
+ <h4 className="text-sm font-semibold text-amber-900">
1974
+ A master admin has to activate this license
1975
+ </h4>
1976
+ <p className="mt-1 text-xs leading-relaxed text-amber-800">
1977
+ This installation does not have a valid enterprise
1978
+ license. Ask a master admin of this OneUptime installation
1979
+ to enter or refresh the license key from this dialog.
1980
+ </p>
1981
+ </section>
1982
+ )}
1983
+
1732
1984
  {!configError && showLicenseKeyInput && (
1733
1985
  <section className="rounded-xl border border-gray-200 bg-white p-5">
1734
1986
  <div className="flex items-start justify-between gap-4">
@@ -1801,7 +2053,9 @@ const EditionLabel: FunctionComponent<ComponentProps> = (
1801
2053
  What your license unlocks
1802
2054
  </h4>
1803
2055
  <p className="mt-0.5 text-xs text-indigo-700">
1804
- Validate your key above to turn these on immediately.
2056
+ {canManageLicense
2057
+ ? "Validate your key above to turn these on immediately."
2058
+ : "A master admin can activate the license to turn these on."}
1805
2059
  </p>
1806
2060
  <ul className="mt-3 grid grid-cols-1 gap-2 sm:grid-cols-2">
1807
2061
  {enterpriseFeatures.map(
@@ -19,16 +19,27 @@ const ErrorMessage: FunctionComponent<ComponentProps> = (
19
19
  <div className="text-center my-10 text-gray-500 text-sm">
20
20
  {translatedMessage}
21
21
  {props.onRefreshClick ? (
22
- <div
23
- role={"refresh-button"}
24
- onClick={() => {
25
- if (props.onRefreshClick) {
26
- props.onRefreshClick();
27
- }
28
- }}
29
- className="underline cursor-pointer hover:text-gray-700 mt-3"
30
- >
31
- {translateString("Refresh?") ?? "Refresh?"}
22
+ /*
23
+ * This is the only recovery control on the app-wide failure and
24
+ * empty-state surface, and it used to be a <div role="refresh-button">
25
+ * - not focusable, and deaf to Enter and Space, so the single way out
26
+ * of a failed table was the mouse. It is a real <button> now; the
27
+ * data-testid keeps the hook the tests reach for, which the invented
28
+ * role was standing in for.
29
+ */
30
+ <div className="mt-3">
31
+ <button
32
+ type="button"
33
+ data-testid="refresh-button"
34
+ onClick={() => {
35
+ if (props.onRefreshClick) {
36
+ props.onRefreshClick();
37
+ }
38
+ }}
39
+ className="underline cursor-pointer hover:text-gray-700 rounded-sm focus:outline-none focus-visible:ring-2 focus-visible:ring-indigo-500 focus-visible:ring-offset-2"
40
+ >
41
+ {translateString("Refresh?") ?? "Refresh?"}
42
+ </button>
32
43
  </div>
33
44
  ) : (
34
45
  <></>
@@ -2,7 +2,6 @@ import React, { FunctionComponent, ReactElement, useState } from "react";
2
2
  import User from "../../../Models/DatabaseModels/User";
3
3
  import { GetReactElementFunction } from "../../Types/FunctionTypes";
4
4
  import Image from "../Image/Image";
5
- import Route from "../../../Types/API/Route";
6
5
  import BlankProfilePic from "../../Images/users/blank-profile.svg";
7
6
  import UserUtil from "../../Utils/User";
8
7
  import ObjectID from "../../../Types/ObjectID";
@@ -64,15 +63,15 @@ const FeedItem: FunctionComponent<ComponentProps> = (
64
63
  };
65
64
 
66
65
  const getUserIcon: GetReactElementFunction = (): ReactElement => {
67
- const userImageRoute: Route = props.user?.id
68
- ? UserUtil.getProfilePictureRoute(props.user.id as ObjectID)
69
- : Route.fromString(`${BlankProfilePic}`);
66
+ const userImageUrl: string = props.user?.id
67
+ ? UserUtil.getProfilePictureRoute(props.user.id as ObjectID).toString()
68
+ : BlankProfilePic;
70
69
 
71
70
  return (
72
71
  <div>
73
72
  <Image
74
73
  className="flex size-10 items-center justify-center rounded-full bg-gray-400 ring-8 ring-white"
75
- imageUrl={userImageRoute}
74
+ imageUrl={userImageUrl}
76
75
  />
77
76
 
78
77
  {props.icon && (
@@ -9,7 +9,6 @@ import {
9
9
  KeyboardKeyUtil,
10
10
  KeyboardShortcutKey,
11
11
  } from "../KeyboardShortcut/KeyboardKey";
12
- import Route from "../../../Types/API/Route";
13
12
  import IconProp from "../../../Types/Icon/IconProp";
14
13
  import React, {
15
14
  FunctionComponent,
@@ -103,7 +102,7 @@ const HeaderIconDropdownButton: FunctionComponent<ComponentProps> = (
103
102
  onClick={() => {
104
103
  props.onClick?.();
105
104
  }}
106
- imageUrl={Route.fromString(`${props.iconImageUrl}`)}
105
+ imageUrl={props.iconImageUrl}
107
106
  alt={props.name}
108
107
  />
109
108
  )}
@@ -1,6 +1,5 @@
1
1
  import Icon from "../../Icon/Icon";
2
2
  import Image from "../../Image/Image";
3
- import Route from "../../../../Types/API/Route";
4
3
  import URL from "../../../../Types/API/URL";
5
4
  import IconProp from "../../../../Types/Icon/IconProp";
6
5
  import Name from "../../../../Types/Name";
@@ -8,7 +7,7 @@ import React, { FunctionComponent, ReactElement } from "react";
8
7
 
9
8
  export interface ComponentProps {
10
9
  userFullName: Name;
11
- userProfilePicture: URL | Route;
10
+ userProfilePicture: URL | string;
12
11
  onClick: () => void;
13
12
  }
14
13
 
@@ -1,13 +1,25 @@
1
1
  // Taiwind
2
- import Route from "../../../Types/API/Route";
3
2
  import URLFromProject from "../../../Types/API/URL";
4
3
  import BadDataException from "../../../Types/Exception/BadDataException";
5
4
  import File from "../../../Models/DatabaseModels/File";
6
5
  import React, { FunctionComponent, ReactElement } from "react";
7
6
 
7
+ /*
8
+ * The src of an <img>.
9
+ *
10
+ * Deliberately no Route member. A Route is a same-origin application PATH and
11
+ * rejects scheme-prefixed values by design (Common/Types/API/Route.ts). An
12
+ * image src is routinely scheme-prefixed - esbuild's file-loader inlines every
13
+ * .svg/.png import as a "data:" URL (Common/UI/esbuild-config.js). Wrapping one
14
+ * in a Route to satisfy this type is what threw on every dashboard page once
15
+ * Route started rejecting schemes. Pass a string; `someRoute.toString()` if you
16
+ * are starting from a Route.
17
+ */
18
+ export type ImageSource = string | URLFromProject | ReactElement;
19
+
8
20
  export interface ComponentProps {
9
21
  onClick?: () => void | undefined;
10
- imageUrl?: URLFromProject | Route | ReactElement | undefined;
22
+ imageUrl?: ImageSource | undefined;
11
23
  height?: number | undefined;
12
24
  file?: File | undefined;
13
25
  className?: string | undefined;
@@ -55,7 +67,12 @@ const Image: FunctionComponent<ComponentProps> = (
55
67
  );
56
68
  };
57
69
 
58
- if (props.imageUrl) {
70
+ if (props.imageUrl !== undefined && props.imageUrl !== null) {
71
+ /*
72
+ * Not `if (props.imageUrl)`: an empty string is falsy and would fall
73
+ * through to the `file` branch below and throw. Render the <img> with an
74
+ * empty src instead, which keeps data-testid and className on the node.
75
+ */
59
76
  return getImageElement(props.imageUrl.toString());
60
77
  }
61
78
 
@@ -12,7 +12,6 @@ import API from "../../Utils/API/API";
12
12
  import ComponentLoader from "../ComponentLoader/ComponentLoader";
13
13
  import ErrorMessage from "../ErrorMessage/ErrorMessage";
14
14
  import Image from "../Image/Image";
15
- import Route from "../../../Types/API/Route";
16
15
  import Icon from "../Icon/Icon";
17
16
  import ConfirmModal from "../Modal/ConfirmModal";
18
17
  import Modal from "../Modal/Modal";
@@ -229,7 +228,7 @@ const MemberRoleAssignment: FunctionComponent<ComponentProps> = (
229
228
  <div className="flex items-center gap-3">
230
229
  {member.userProfilePictureUrl ? (
231
230
  <Image
232
- imageUrl={Route.fromString(member.userProfilePictureUrl)}
231
+ imageUrl={member.userProfilePictureUrl}
233
232
  alt={member.userName}
234
233
  className="h-8 w-8 rounded-full object-cover"
235
234
  />