@oneuptime/common 11.6.1 → 11.7.0

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 (420) hide show
  1. package/Models/AnalyticsModels/Index.ts +4 -0
  2. package/Models/AnalyticsModels/KubernetesCostAllocation.ts +842 -0
  3. package/Models/AnalyticsModels/NetworkFlow.ts +54 -0
  4. package/Models/AnalyticsModels/SloHistory.ts +243 -0
  5. package/Models/DatabaseModels/Index.ts +20 -0
  6. package/Models/DatabaseModels/NetworkDevice.ts +453 -6
  7. package/Models/DatabaseModels/NetworkDeviceDiscoveryScan.ts +7 -6
  8. package/Models/DatabaseModels/NetworkEndpoint.ts +753 -0
  9. package/Models/DatabaseModels/NetworkSite.ts +1155 -0
  10. package/Models/DatabaseModels/NetworkSiteAssignmentRule.ts +517 -0
  11. package/Models/DatabaseModels/NetworkSiteLink.ts +611 -0
  12. package/Models/DatabaseModels/NetworkSiteStatusTimeline.ts +520 -0
  13. package/Models/DatabaseModels/NetworkSiteType.ts +499 -0
  14. package/Models/DatabaseModels/ServiceLevelObjective.ts +1115 -0
  15. package/Models/DatabaseModels/ServiceLevelObjectiveBurnRateRule.ts +762 -0
  16. package/Models/DatabaseModels/ServiceLevelObjectiveOwnerTeam.ts +444 -0
  17. package/Models/DatabaseModels/ServiceLevelObjectiveOwnerUser.ts +443 -0
  18. package/Server/Infrastructure/Postgres/SchemaMigrations/1784757142154-AddNetworkSiteHierarchyAndEndpoints.ts +359 -0
  19. package/Server/Infrastructure/Postgres/SchemaMigrations/1784897317860-AddNetworkSiteAlerting.ts +48 -0
  20. package/Server/Infrastructure/Postgres/SchemaMigrations/1784970388777-AddNetworkDevicePollingColumns.ts +65 -0
  21. package/Server/Infrastructure/Postgres/SchemaMigrations/1784986826214-AddNetworkSiteTypeTable.ts +88 -0
  22. package/Server/Infrastructure/Postgres/SchemaMigrations/1784987015619-AddServiceLevelObjective.ts +391 -0
  23. package/Server/Infrastructure/Postgres/SchemaMigrations/1785066759532-MigrationName.ts +30 -0
  24. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +12 -0
  25. package/Server/Services/AnalyticsDatabaseService.ts +25 -9
  26. package/Server/Services/Index.ts +24 -0
  27. package/Server/Services/KubernetesCostAllocationService.ts +14 -0
  28. package/Server/Services/MetricService.ts +21 -2
  29. package/Server/Services/MonitorService.ts +22 -0
  30. package/Server/Services/NetworkDeviceService.ts +438 -2
  31. package/Server/Services/NetworkEndpointService.ts +414 -0
  32. package/Server/Services/NetworkSiteAssignmentRuleService.ts +98 -0
  33. package/Server/Services/NetworkSiteLinkService.ts +10 -0
  34. package/Server/Services/NetworkSiteService.ts +1254 -0
  35. package/Server/Services/NetworkSiteStatusTimelineService.ts +10 -0
  36. package/Server/Services/NetworkSiteTypeService.ts +10 -0
  37. package/Server/Services/ProjectService.ts +122 -2
  38. package/Server/Services/ServiceLevelObjectiveBurnRateRuleService.ts +457 -0
  39. package/Server/Services/ServiceLevelObjectiveOwnerTeamService.ts +10 -0
  40. package/Server/Services/ServiceLevelObjectiveOwnerUserService.ts +10 -0
  41. package/Server/Services/ServiceLevelObjectiveService.ts +685 -0
  42. package/Server/Services/SloHistoryService.ts +101 -0
  43. package/Server/Services/UserNotificationSettingService.ts +37 -0
  44. package/Server/Types/AnalyticsDatabase/AggregateBy.ts +9 -0
  45. package/Server/Types/Database/Permissions/OwnerTableRegistry.ts +15 -0
  46. package/Server/Utils/AnalyticsDatabase/Statement.ts +39 -3
  47. package/Server/Utils/AnalyticsDatabase/StatementGenerator.ts +87 -48
  48. package/Server/Utils/Memory.ts +9 -1
  49. package/Server/Utils/Monitor/Criteria/SnmpMonitorCriteria.ts +190 -12
  50. package/Server/Utils/Monitor/Data/OuiVendors.json +6920 -0
  51. package/Server/Utils/Monitor/DnsResolutionCache.ts +129 -0
  52. package/Server/Utils/Monitor/MonitorResource.ts +4 -30
  53. package/Server/Utils/Monitor/NetworkDeviceHydrationUtil.ts +214 -39
  54. package/Server/Utils/Monitor/NetworkDeviceMetricUtil.ts +343 -0
  55. package/Server/Utils/Monitor/NetworkDeviceWalkUtil.ts +251 -0
  56. package/Server/Utils/Monitor/NetworkInventoryUtil.ts +176 -142
  57. package/Server/Utils/Monitor/OuiLookupUtil.ts +49 -0
  58. package/Server/Utils/Monitor/SnmpInterfaceRateUtil.ts +17 -13
  59. package/Server/Utils/WhatsAppTemplateUtil.ts +7 -3
  60. package/Tests/Models/AnalyticsModels/KubernetesCostAllocation.test.ts +135 -0
  61. package/Tests/Models/NetworkSiteHierarchy.test.ts +134 -0
  62. package/Tests/Server/Services/AnalyticsDatabaseService.test.ts +239 -0
  63. package/Tests/Server/Services/KubernetesCostAllocationAggregate.test.ts +338 -0
  64. package/Tests/Server/Services/MetricServiceAggregate.test.ts +142 -0
  65. package/Tests/Server/Services/NetworkDeviceSiteAssignment.test.ts +484 -0
  66. package/Tests/Server/Services/NetworkEndpointServiceUpsert.test.ts +686 -0
  67. package/Tests/Server/Services/NetworkSiteAssignmentRuleService.test.ts +185 -0
  68. package/Tests/Server/Services/NetworkSiteService.test.ts +1354 -0
  69. package/Tests/Server/Services/ServiceLevelObjectiveBurnRateRuleService.test.ts +1313 -0
  70. package/Tests/Server/Services/ServiceLevelObjectiveService.test.ts +1988 -0
  71. package/Tests/Server/Utils/AnalyticsDatabase/Statement.test.ts +22 -0
  72. package/Tests/Server/Utils/AnalyticsDatabase/StatementGenerator.test.ts +404 -0
  73. package/Tests/Server/Utils/Encryption.test.ts +70 -0
  74. package/Tests/Server/Utils/FileAttachmentMarkdownUtil.test.ts +225 -0
  75. package/Tests/Server/Utils/JsonWebToken.test.ts +175 -0
  76. package/Tests/Server/Utils/LocalFile.test.ts +258 -0
  77. package/Tests/Server/Utils/Memory.test.ts +213 -0
  78. package/Tests/Server/Utils/Monitor/Criteria/LogMonitorCriteria.test.ts +30 -0
  79. package/Tests/Server/Utils/Monitor/Criteria/SnmpMonitorCriteria.test.ts +385 -0
  80. package/Tests/Server/Utils/Monitor/DnsResolutionCache.test.ts +194 -0
  81. package/Tests/Server/Utils/Monitor/NetworkDeviceHydrationUtil.test.ts +155 -0
  82. package/Tests/Server/Utils/Monitor/NetworkDeviceWalkUtil.test.ts +600 -0
  83. package/Tests/Server/Utils/Monitor/NetworkInventoryUtil.test.ts +151 -124
  84. package/Tests/Server/Utils/Monitor/SnmpInterfaceRateUtil.test.ts +496 -0
  85. package/Tests/Server/Utils/MonitorCriteriaDataExtractor.test.ts +175 -0
  86. package/Tests/Server/Utils/MonitorCriteriaMessageFormatter.test.ts +282 -0
  87. package/Tests/Server/Utils/OuiLookupUtil.test.ts +59 -0
  88. package/Tests/Server/Utils/SeriesResourceLabels.test.ts +117 -0
  89. package/Tests/Server/Utils/StackTraceParser.test.ts +370 -0
  90. package/Tests/Server/Utils/Stream.test.ts +87 -0
  91. package/Tests/Server/Utils/ValidateGlobalProviderProjectTeams.test.ts +221 -0
  92. package/Tests/Server/Utils/WhatsAppTemplateUtil.test.ts +199 -0
  93. package/Tests/Types/Database/CompareOperatorWireSerialization.test.ts +33 -0
  94. package/Tests/Types/Email.test.ts +198 -0
  95. package/Tests/Types/Kubernetes/KubernetesObjectParser.test.ts +177 -0
  96. package/Tests/Types/Log/LogQueryToFilter.test.ts +111 -0
  97. package/Tests/Types/Monitor/MonitorCriteria.test.ts +155 -0
  98. package/Tests/Types/Monitor/MonitorCriteriaInstance.test.ts +465 -0
  99. package/Tests/Types/Monitor/MonitorStep.test.ts +183 -0
  100. package/Tests/Types/Monitor/MonitorStepNetworkDeviceMonitor.test.ts +141 -1
  101. package/Tests/Types/Monitor/MonitorSteps.test.ts +183 -0
  102. package/Tests/Types/Monitor/MonitorType.test.ts +59 -1
  103. package/Tests/Types/Monitor/NetworkDeviceAlertPack.test.ts +97 -0
  104. package/Tests/Types/Monitor/SnmpEndpointDiscovery.test.ts +151 -0
  105. package/Tests/Types/Monitor/SnmpVendorTemplate.test.ts +110 -6
  106. package/Tests/Types/NetworkSite/DefaultNetworkSiteType.test.ts +129 -0
  107. package/Tests/Types/SerializableObjectDictionary.test.ts +166 -0
  108. package/Tests/Types/Time/RangeStartAndEndDateTime.test.ts +98 -0
  109. package/Tests/Types/WebsiteRequest.test.ts +230 -0
  110. package/Tests/UI/Components/EntityFilterRoundTrip.test.tsx +103 -0
  111. package/Tests/UI/Components/ModelTable/BaseModelTableUrlState.test.tsx +612 -0
  112. package/Tests/UI/Components/ModelTable/FilterDataToQuery.test.ts +275 -0
  113. package/Tests/UI/Utils/LogExport.test.ts +159 -0
  114. package/Tests/UI/Utils/Navigation.test.ts +183 -0
  115. package/Tests/UI/Utils/TableFilterUrlState.test.ts +539 -0
  116. package/Tests/UI/Utils/TableViewUrlState.test.ts +272 -0
  117. package/Tests/Utils/Base64.test.ts +51 -0
  118. package/Tests/Utils/Boolean.test.ts +76 -0
  119. package/Tests/Utils/Crypto.test.ts +48 -0
  120. package/Tests/Utils/Dashboard/DashboardSloComponent.test.ts +259 -0
  121. package/Tests/Utils/Dashboard/ModelQueryVariableInterpolation.test.ts +162 -0
  122. package/Tests/Utils/Enum.test.ts +54 -0
  123. package/Tests/Utils/IpCanonicalUtil.test.ts +85 -0
  124. package/Tests/Utils/Memory.test.ts +44 -0
  125. package/Tests/Utils/Metrics/MetricSeriesFingerprint.test.ts +160 -0
  126. package/Tests/Utils/Monitor/EndpointAttachmentUtil.test.ts +836 -0
  127. package/Tests/Utils/Monitor/MonitorMetricType.test.ts +218 -0
  128. package/Tests/Utils/Monitor/NetworkTopologyUtil.test.ts +447 -0
  129. package/Tests/Utils/NetworkSite/CidrMatchUtil.test.ts +440 -0
  130. package/Tests/Utils/NetworkSite/MaterializedPathUtil.test.ts +205 -0
  131. package/Tests/Utils/NetworkSite/SiteStatusRollupUtil.test.ts +221 -0
  132. package/Tests/Utils/NetworkSite/SiteUptimeUtil.test.ts +283 -0
  133. package/Tests/Utils/ObjectUtil.test.ts +30 -0
  134. package/Tests/Utils/Slo/SloBurnRateRuleState.test.ts +124 -0
  135. package/Tests/Utils/Slo/SloDuration.test.ts +148 -0
  136. package/Tests/Utils/Slo/SloHealth.test.ts +334 -0
  137. package/Tests/Utils/Slo/SloStatusColor.test.ts +89 -0
  138. package/Tests/Utils/Slo/SloUtil.test.ts +1980 -0
  139. package/Tests/Utils/Slo/SloWidgetFormat.test.ts +605 -0
  140. package/Tests/Utils/TechStack.test.ts +50 -0
  141. package/Tests/Utils/Traces/CriticalPath.test.ts +178 -0
  142. package/Types/AnalyticsDatabase/AnalyticsTableName.ts +10 -0
  143. package/Types/BaseDatabase/EqualTo.ts +9 -1
  144. package/Types/BaseDatabase/EqualToOrNull.ts +9 -1
  145. package/Types/BaseDatabase/NotEqual.ts +9 -1
  146. package/Types/Dashboard/DashboardComponentType.ts +1 -0
  147. package/Types/Dashboard/DashboardComponents/ComponentArgument.ts +1 -0
  148. package/Types/Dashboard/DashboardComponents/DashboardSloComponent.ts +42 -0
  149. package/Types/Dashboard/DashboardTemplates.ts +214 -0
  150. package/Types/Email/EmailTemplateType.ts +2 -0
  151. package/Types/Kubernetes/KubernetesCostIngest.ts +79 -0
  152. package/Types/Monitor/CriteriaFilter.ts +9 -0
  153. package/Types/Monitor/MonitorStep.ts +5 -8
  154. package/Types/Monitor/MonitorStepNetworkDeviceMonitor.ts +27 -5
  155. package/Types/Monitor/MonitorType.ts +15 -5
  156. package/Types/Monitor/SnmpMonitor/ArpEntry.ts +14 -0
  157. package/Types/Monitor/SnmpMonitor/FdbEntry.ts +18 -0
  158. package/Types/Monitor/SnmpMonitor/NetworkDeviceAlertPack.ts +10 -3
  159. package/Types/Monitor/SnmpMonitor/NetworkTopology.ts +31 -5
  160. package/Types/Monitor/SnmpMonitor/SnmpMonitorResponse.ts +12 -0
  161. package/Types/Monitor/SnmpMonitor/SnmpVendorTemplate.ts +231 -3
  162. package/Types/NetworkSite/DefaultNetworkSiteType.ts +20 -0
  163. package/Types/NotificationSetting/NotificationSettingEventType.ts +4 -0
  164. package/Types/Permission.ts +449 -0
  165. package/Types/ServiceLevelObjective/SliType.ts +6 -0
  166. package/Types/ServiceLevelObjective/SloMultiMonitorMode.ts +6 -0
  167. package/Types/ServiceLevelObjective/SloStatus.ts +9 -0
  168. package/Types/ServiceLevelObjective/SloWindowType.ts +6 -0
  169. package/Types/Telemetry/ServiceType.ts +1 -0
  170. package/UI/Components/Filters/EntityFilter.tsx +16 -0
  171. package/UI/Components/Filters/FilterViewer.tsx +22 -5
  172. package/UI/Components/List/List.tsx +8 -0
  173. package/UI/Components/ModelTable/BaseModelTable.tsx +309 -106
  174. package/UI/Components/ModelTable/FilterDataToQuery.ts +172 -0
  175. package/UI/Components/Navbar/NavBar.tsx +16 -2
  176. package/UI/Components/Navbar/NavBarMenuModal.tsx +3 -3
  177. package/UI/Utils/Navigation.ts +10 -0
  178. package/UI/Utils/TableFilterUrlState.ts +204 -17
  179. package/UI/Utils/TableViewUrlState.ts +165 -0
  180. package/Utils/Dashboard/Components/DashboardSloComponent.ts +114 -0
  181. package/Utils/Dashboard/Components/Index.ts +7 -0
  182. package/Utils/IpCanonicalUtil.ts +134 -0
  183. package/Utils/Monitor/EndpointAttachmentUtil.ts +508 -0
  184. package/Utils/Monitor/NetworkTopologyUtil.ts +157 -5
  185. package/Utils/NetworkSite/CidrMatchUtil.ts +296 -0
  186. package/Utils/NetworkSite/MaterializedPathUtil.ts +115 -0
  187. package/Utils/NetworkSite/SiteStatusRollupUtil.ts +97 -0
  188. package/Utils/NetworkSite/SiteUptimeUtil.ts +111 -0
  189. package/Utils/Slo/SloBurnRateRuleState.ts +91 -0
  190. package/Utils/Slo/SloDuration.ts +165 -0
  191. package/Utils/Slo/SloEvaluation.ts +22 -0
  192. package/Utils/Slo/SloHealth.ts +302 -0
  193. package/Utils/Slo/SloStatusColor.ts +54 -0
  194. package/Utils/Slo/SloUtil.ts +637 -0
  195. package/Utils/Slo/SloWidgetFormat.ts +383 -0
  196. package/build/dist/Models/AnalyticsModels/Index.js +4 -0
  197. package/build/dist/Models/AnalyticsModels/Index.js.map +1 -1
  198. package/build/dist/Models/AnalyticsModels/KubernetesCostAllocation.js +713 -0
  199. package/build/dist/Models/AnalyticsModels/KubernetesCostAllocation.js.map +1 -0
  200. package/build/dist/Models/AnalyticsModels/NetworkFlow.js +44 -0
  201. package/build/dist/Models/AnalyticsModels/NetworkFlow.js.map +1 -1
  202. package/build/dist/Models/AnalyticsModels/SloHistory.js +218 -0
  203. package/build/dist/Models/AnalyticsModels/SloHistory.js.map +1 -0
  204. package/build/dist/Models/DatabaseModels/Index.js +20 -0
  205. package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
  206. package/build/dist/Models/DatabaseModels/NetworkDevice.js +458 -6
  207. package/build/dist/Models/DatabaseModels/NetworkDevice.js.map +1 -1
  208. package/build/dist/Models/DatabaseModels/NetworkDeviceDiscoveryScan.js +0 -6
  209. package/build/dist/Models/DatabaseModels/NetworkDeviceDiscoveryScan.js.map +1 -1
  210. package/build/dist/Models/DatabaseModels/NetworkEndpoint.js +779 -0
  211. package/build/dist/Models/DatabaseModels/NetworkEndpoint.js.map +1 -0
  212. package/build/dist/Models/DatabaseModels/NetworkSite.js +1180 -0
  213. package/build/dist/Models/DatabaseModels/NetworkSite.js.map +1 -0
  214. package/build/dist/Models/DatabaseModels/NetworkSiteAssignmentRule.js +534 -0
  215. package/build/dist/Models/DatabaseModels/NetworkSiteAssignmentRule.js.map +1 -0
  216. package/build/dist/Models/DatabaseModels/NetworkSiteLink.js +629 -0
  217. package/build/dist/Models/DatabaseModels/NetworkSiteLink.js.map +1 -0
  218. package/build/dist/Models/DatabaseModels/NetworkSiteStatusTimeline.js +538 -0
  219. package/build/dist/Models/DatabaseModels/NetworkSiteStatusTimeline.js.map +1 -0
  220. package/build/dist/Models/DatabaseModels/NetworkSiteType.js +522 -0
  221. package/build/dist/Models/DatabaseModels/NetworkSiteType.js.map +1 -0
  222. package/build/dist/Models/DatabaseModels/ServiceLevelObjective.js +1134 -0
  223. package/build/dist/Models/DatabaseModels/ServiceLevelObjective.js.map +1 -0
  224. package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveBurnRateRule.js +769 -0
  225. package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveBurnRateRule.js.map +1 -0
  226. package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveOwnerTeam.js +460 -0
  227. package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveOwnerTeam.js.map +1 -0
  228. package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveOwnerUser.js +459 -0
  229. package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveOwnerUser.js.map +1 -0
  230. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784757142154-AddNetworkSiteHierarchyAndEndpoints.js +130 -0
  231. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784757142154-AddNetworkSiteHierarchyAndEndpoints.js.map +1 -0
  232. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784897317860-AddNetworkSiteAlerting.js +31 -0
  233. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784897317860-AddNetworkSiteAlerting.js.map +1 -0
  234. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784970388777-AddNetworkDevicePollingColumns.js +36 -0
  235. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784970388777-AddNetworkDevicePollingColumns.js.map +1 -0
  236. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784986826214-AddNetworkSiteTypeTable.js +49 -0
  237. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784986826214-AddNetworkSiteTypeTable.js.map +1 -0
  238. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784987015619-AddServiceLevelObjective.js +140 -0
  239. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784987015619-AddServiceLevelObjective.js.map +1 -0
  240. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785066759532-MigrationName.js +21 -0
  241. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785066759532-MigrationName.js.map +1 -0
  242. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +12 -0
  243. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  244. package/build/dist/Server/Services/AnalyticsDatabaseService.js +23 -6
  245. package/build/dist/Server/Services/AnalyticsDatabaseService.js.map +1 -1
  246. package/build/dist/Server/Services/Index.js +24 -0
  247. package/build/dist/Server/Services/Index.js.map +1 -1
  248. package/build/dist/Server/Services/KubernetesCostAllocationService.js +12 -0
  249. package/build/dist/Server/Services/KubernetesCostAllocationService.js.map +1 -0
  250. package/build/dist/Server/Services/MetricService.js +21 -3
  251. package/build/dist/Server/Services/MetricService.js.map +1 -1
  252. package/build/dist/Server/Services/MonitorService.js +19 -0
  253. package/build/dist/Server/Services/MonitorService.js.map +1 -1
  254. package/build/dist/Server/Services/NetworkDeviceService.js +351 -1
  255. package/build/dist/Server/Services/NetworkDeviceService.js.map +1 -1
  256. package/build/dist/Server/Services/NetworkEndpointService.js +319 -0
  257. package/build/dist/Server/Services/NetworkEndpointService.js.map +1 -0
  258. package/build/dist/Server/Services/NetworkSiteAssignmentRuleService.js +90 -0
  259. package/build/dist/Server/Services/NetworkSiteAssignmentRuleService.js.map +1 -0
  260. package/build/dist/Server/Services/NetworkSiteLinkService.js +9 -0
  261. package/build/dist/Server/Services/NetworkSiteLinkService.js.map +1 -0
  262. package/build/dist/Server/Services/NetworkSiteService.js +1038 -0
  263. package/build/dist/Server/Services/NetworkSiteService.js.map +1 -0
  264. package/build/dist/Server/Services/NetworkSiteStatusTimelineService.js +9 -0
  265. package/build/dist/Server/Services/NetworkSiteStatusTimelineService.js.map +1 -0
  266. package/build/dist/Server/Services/NetworkSiteTypeService.js +9 -0
  267. package/build/dist/Server/Services/NetworkSiteTypeService.js.map +1 -0
  268. package/build/dist/Server/Services/ProjectService.js +98 -2
  269. package/build/dist/Server/Services/ProjectService.js.map +1 -1
  270. package/build/dist/Server/Services/ServiceLevelObjectiveBurnRateRuleService.js +358 -0
  271. package/build/dist/Server/Services/ServiceLevelObjectiveBurnRateRuleService.js.map +1 -0
  272. package/build/dist/Server/Services/ServiceLevelObjectiveOwnerTeamService.js +9 -0
  273. package/build/dist/Server/Services/ServiceLevelObjectiveOwnerTeamService.js.map +1 -0
  274. package/build/dist/Server/Services/ServiceLevelObjectiveOwnerUserService.js +9 -0
  275. package/build/dist/Server/Services/ServiceLevelObjectiveOwnerUserService.js.map +1 -0
  276. package/build/dist/Server/Services/ServiceLevelObjectiveService.js +588 -0
  277. package/build/dist/Server/Services/ServiceLevelObjectiveService.js.map +1 -0
  278. package/build/dist/Server/Services/SloHistoryService.js +77 -0
  279. package/build/dist/Server/Services/SloHistoryService.js.map +1 -0
  280. package/build/dist/Server/Services/UserNotificationSettingService.js +20 -0
  281. package/build/dist/Server/Services/UserNotificationSettingService.js.map +1 -1
  282. package/build/dist/Server/Types/AnalyticsDatabase/AggregateBy.js +9 -0
  283. package/build/dist/Server/Types/AnalyticsDatabase/AggregateBy.js.map +1 -1
  284. package/build/dist/Server/Types/Database/Permissions/OwnerTableRegistry.js +15 -0
  285. package/build/dist/Server/Types/Database/Permissions/OwnerTableRegistry.js.map +1 -1
  286. package/build/dist/Server/Utils/AnalyticsDatabase/Statement.js +31 -0
  287. package/build/dist/Server/Utils/AnalyticsDatabase/Statement.js.map +1 -1
  288. package/build/dist/Server/Utils/AnalyticsDatabase/StatementGenerator.js +76 -48
  289. package/build/dist/Server/Utils/AnalyticsDatabase/StatementGenerator.js.map +1 -1
  290. package/build/dist/Server/Utils/Memory.js +9 -1
  291. package/build/dist/Server/Utils/Memory.js.map +1 -1
  292. package/build/dist/Server/Utils/Monitor/Criteria/SnmpMonitorCriteria.js +132 -10
  293. package/build/dist/Server/Utils/Monitor/Criteria/SnmpMonitorCriteria.js.map +1 -1
  294. package/build/dist/Server/Utils/Monitor/Data/OuiVendors.json +6920 -0
  295. package/build/dist/Server/Utils/Monitor/DnsResolutionCache.js +77 -0
  296. package/build/dist/Server/Utils/Monitor/DnsResolutionCache.js.map +1 -0
  297. package/build/dist/Server/Utils/Monitor/MonitorResource.js +21 -41
  298. package/build/dist/Server/Utils/Monitor/MonitorResource.js.map +1 -1
  299. package/build/dist/Server/Utils/Monitor/NetworkDeviceHydrationUtil.js +152 -40
  300. package/build/dist/Server/Utils/Monitor/NetworkDeviceHydrationUtil.js.map +1 -1
  301. package/build/dist/Server/Utils/Monitor/NetworkDeviceMetricUtil.js +262 -0
  302. package/build/dist/Server/Utils/Monitor/NetworkDeviceMetricUtil.js.map +1 -0
  303. package/build/dist/Server/Utils/Monitor/NetworkDeviceWalkUtil.js +201 -0
  304. package/build/dist/Server/Utils/Monitor/NetworkDeviceWalkUtil.js.map +1 -0
  305. package/build/dist/Server/Utils/Monitor/NetworkInventoryUtil.js +152 -120
  306. package/build/dist/Server/Utils/Monitor/NetworkInventoryUtil.js.map +1 -1
  307. package/build/dist/Server/Utils/Monitor/OuiLookupUtil.js +44 -0
  308. package/build/dist/Server/Utils/Monitor/OuiLookupUtil.js.map +1 -0
  309. package/build/dist/Server/Utils/Monitor/SnmpInterfaceRateUtil.js +10 -10
  310. package/build/dist/Server/Utils/Monitor/SnmpInterfaceRateUtil.js.map +1 -1
  311. package/build/dist/Server/Utils/WhatsAppTemplateUtil.js +5 -0
  312. package/build/dist/Server/Utils/WhatsAppTemplateUtil.js.map +1 -1
  313. package/build/dist/Types/AnalyticsDatabase/AnalyticsTableName.js +10 -0
  314. package/build/dist/Types/AnalyticsDatabase/AnalyticsTableName.js.map +1 -1
  315. package/build/dist/Types/BaseDatabase/EqualTo.js +9 -1
  316. package/build/dist/Types/BaseDatabase/EqualTo.js.map +1 -1
  317. package/build/dist/Types/BaseDatabase/EqualToOrNull.js +9 -1
  318. package/build/dist/Types/BaseDatabase/EqualToOrNull.js.map +1 -1
  319. package/build/dist/Types/BaseDatabase/NotEqual.js +9 -1
  320. package/build/dist/Types/BaseDatabase/NotEqual.js.map +1 -1
  321. package/build/dist/Types/Dashboard/DashboardComponentType.js +1 -0
  322. package/build/dist/Types/Dashboard/DashboardComponentType.js.map +1 -1
  323. package/build/dist/Types/Dashboard/DashboardComponents/ComponentArgument.js +1 -0
  324. package/build/dist/Types/Dashboard/DashboardComponents/ComponentArgument.js.map +1 -1
  325. package/build/dist/Types/Dashboard/DashboardComponents/DashboardSloComponent.js +23 -0
  326. package/build/dist/Types/Dashboard/DashboardComponents/DashboardSloComponent.js.map +1 -0
  327. package/build/dist/Types/Dashboard/DashboardTemplates.js +205 -0
  328. package/build/dist/Types/Dashboard/DashboardTemplates.js.map +1 -1
  329. package/build/dist/Types/Email/EmailTemplateType.js +1 -0
  330. package/build/dist/Types/Email/EmailTemplateType.js.map +1 -1
  331. package/build/dist/Types/Kubernetes/KubernetesCostIngest.js +21 -0
  332. package/build/dist/Types/Kubernetes/KubernetesCostIngest.js.map +1 -0
  333. package/build/dist/Types/Monitor/CriteriaFilter.js +1 -0
  334. package/build/dist/Types/Monitor/CriteriaFilter.js.map +1 -1
  335. package/build/dist/Types/Monitor/MonitorStep.js +5 -5
  336. package/build/dist/Types/Monitor/MonitorStep.js.map +1 -1
  337. package/build/dist/Types/Monitor/MonitorStepNetworkDeviceMonitor.js +8 -0
  338. package/build/dist/Types/Monitor/MonitorStepNetworkDeviceMonitor.js.map +1 -1
  339. package/build/dist/Types/Monitor/MonitorType.js +15 -5
  340. package/build/dist/Types/Monitor/MonitorType.js.map +1 -1
  341. package/build/dist/Types/Monitor/SnmpMonitor/ArpEntry.js +2 -0
  342. package/build/dist/Types/Monitor/SnmpMonitor/ArpEntry.js.map +1 -0
  343. package/build/dist/Types/Monitor/SnmpMonitor/FdbEntry.js +2 -0
  344. package/build/dist/Types/Monitor/SnmpMonitor/FdbEntry.js.map +1 -0
  345. package/build/dist/Types/Monitor/SnmpMonitor/NetworkDeviceAlertPack.js +9 -3
  346. package/build/dist/Types/Monitor/SnmpMonitor/NetworkDeviceAlertPack.js.map +1 -1
  347. package/build/dist/Types/Monitor/SnmpMonitor/SnmpVendorTemplate.js +217 -3
  348. package/build/dist/Types/Monitor/SnmpMonitor/SnmpVendorTemplate.js.map +1 -1
  349. package/build/dist/Types/NetworkSite/DefaultNetworkSiteType.js +21 -0
  350. package/build/dist/Types/NetworkSite/DefaultNetworkSiteType.js.map +1 -0
  351. package/build/dist/Types/NotificationSetting/NotificationSettingEventType.js +3 -0
  352. package/build/dist/Types/NotificationSetting/NotificationSettingEventType.js.map +1 -1
  353. package/build/dist/Types/Permission.js +409 -0
  354. package/build/dist/Types/Permission.js.map +1 -1
  355. package/build/dist/Types/ServiceLevelObjective/SliType.js +7 -0
  356. package/build/dist/Types/ServiceLevelObjective/SliType.js.map +1 -0
  357. package/build/dist/Types/ServiceLevelObjective/SloMultiMonitorMode.js +7 -0
  358. package/build/dist/Types/ServiceLevelObjective/SloMultiMonitorMode.js.map +1 -0
  359. package/build/dist/Types/ServiceLevelObjective/SloStatus.js +10 -0
  360. package/build/dist/Types/ServiceLevelObjective/SloStatus.js.map +1 -0
  361. package/build/dist/Types/ServiceLevelObjective/SloWindowType.js +7 -0
  362. package/build/dist/Types/ServiceLevelObjective/SloWindowType.js.map +1 -0
  363. package/build/dist/Types/Telemetry/ServiceType.js +1 -0
  364. package/build/dist/Types/Telemetry/ServiceType.js.map +1 -1
  365. package/build/dist/UI/Components/Filters/EntityFilter.js +15 -0
  366. package/build/dist/UI/Components/Filters/EntityFilter.js.map +1 -1
  367. package/build/dist/UI/Components/Filters/FilterViewer.js +19 -4
  368. package/build/dist/UI/Components/Filters/FilterViewer.js.map +1 -1
  369. package/build/dist/UI/Components/List/List.js +1 -1
  370. package/build/dist/UI/Components/List/List.js.map +1 -1
  371. package/build/dist/UI/Components/ModelTable/BaseModelTable.js +235 -89
  372. package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
  373. package/build/dist/UI/Components/ModelTable/FilterDataToQuery.js +96 -0
  374. package/build/dist/UI/Components/ModelTable/FilterDataToQuery.js.map +1 -0
  375. package/build/dist/UI/Components/Navbar/NavBar.js +14 -2
  376. package/build/dist/UI/Components/Navbar/NavBar.js.map +1 -1
  377. package/build/dist/UI/Components/Navbar/NavBarMenuModal.js +3 -2
  378. package/build/dist/UI/Components/Navbar/NavBarMenuModal.js.map +1 -1
  379. package/build/dist/UI/Utils/Navigation.js +9 -0
  380. package/build/dist/UI/Utils/Navigation.js.map +1 -1
  381. package/build/dist/UI/Utils/TableFilterUrlState.js +159 -15
  382. package/build/dist/UI/Utils/TableFilterUrlState.js.map +1 -1
  383. package/build/dist/UI/Utils/TableViewUrlState.js +103 -0
  384. package/build/dist/UI/Utils/TableViewUrlState.js.map +1 -0
  385. package/build/dist/Utils/Dashboard/Components/DashboardSloComponent.js +93 -0
  386. package/build/dist/Utils/Dashboard/Components/DashboardSloComponent.js.map +1 -0
  387. package/build/dist/Utils/Dashboard/Components/Index.js +4 -0
  388. package/build/dist/Utils/Dashboard/Components/Index.js.map +1 -1
  389. package/build/dist/Utils/IpCanonicalUtil.js +110 -0
  390. package/build/dist/Utils/IpCanonicalUtil.js.map +1 -0
  391. package/build/dist/Utils/Monitor/EndpointAttachmentUtil.js +311 -0
  392. package/build/dist/Utils/Monitor/EndpointAttachmentUtil.js.map +1 -0
  393. package/build/dist/Utils/Monitor/NetworkTopologyUtil.js +98 -5
  394. package/build/dist/Utils/Monitor/NetworkTopologyUtil.js.map +1 -1
  395. package/build/dist/Utils/NetworkSite/CidrMatchUtil.js +222 -0
  396. package/build/dist/Utils/NetworkSite/CidrMatchUtil.js.map +1 -0
  397. package/build/dist/Utils/NetworkSite/MaterializedPathUtil.js +89 -0
  398. package/build/dist/Utils/NetworkSite/MaterializedPathUtil.js.map +1 -0
  399. package/build/dist/Utils/NetworkSite/SiteStatusRollupUtil.js +60 -0
  400. package/build/dist/Utils/NetworkSite/SiteStatusRollupUtil.js.map +1 -0
  401. package/build/dist/Utils/NetworkSite/SiteUptimeUtil.js +76 -0
  402. package/build/dist/Utils/NetworkSite/SiteUptimeUtil.js.map +1 -0
  403. package/build/dist/Utils/Slo/SloBurnRateRuleState.js +35 -0
  404. package/build/dist/Utils/Slo/SloBurnRateRuleState.js.map +1 -0
  405. package/build/dist/Utils/Slo/SloDuration.js +87 -0
  406. package/build/dist/Utils/Slo/SloDuration.js.map +1 -0
  407. package/build/dist/Utils/Slo/SloEvaluation.js +21 -0
  408. package/build/dist/Utils/Slo/SloEvaluation.js.map +1 -0
  409. package/build/dist/Utils/Slo/SloHealth.js +179 -0
  410. package/build/dist/Utils/Slo/SloHealth.js.map +1 -0
  411. package/build/dist/Utils/Slo/SloStatusColor.js +18 -0
  412. package/build/dist/Utils/Slo/SloStatusColor.js.map +1 -0
  413. package/build/dist/Utils/Slo/SloUtil.js +393 -0
  414. package/build/dist/Utils/Slo/SloUtil.js.map +1 -0
  415. package/build/dist/Utils/Slo/SloWidgetFormat.js +174 -0
  416. package/build/dist/Utils/Slo/SloWidgetFormat.js.map +1 -0
  417. package/package.json +2 -2
  418. package/Types/Dashboard/DashboardComponents/Index.ts +0 -7
  419. package/build/dist/Types/Dashboard/DashboardComponents/Index.js +0 -8
  420. package/build/dist/Types/Dashboard/DashboardComponents/Index.js.map +0 -1
@@ -1,5 +1,4 @@
1
1
  import Includes from "../../../Types/BaseDatabase/Includes";
2
- import QueryOperator from "../../../Types/BaseDatabase/QueryOperator";
3
2
  import { API_DOCS_URL, BILLING_ENABLED, getAllEnvVars } from "../../Config";
4
3
  import { GetReactElementFunction } from "../../Types/FunctionTypes";
5
4
  import SelectEntityField from "../../Types/SelectEntityField";
@@ -13,6 +12,12 @@ import Select from "../../../Types/BaseDatabase/Select";
13
12
  import { Logger } from "../../Utils/Logger";
14
13
  import Navigation from "../../Utils/Navigation";
15
14
  import TableFilterUrlState from "../../Utils/TableFilterUrlState";
15
+ import TableViewUrlState, {
16
+ TableViewUrlStateData,
17
+ } from "../../Utils/TableViewUrlState";
18
+ import buildQueryFromFilterData, {
19
+ sanitizeFilterData,
20
+ } from "./FilterDataToQuery";
16
21
  import PermissionUtil from "../../Utils/Permission";
17
22
  import ProjectUtil from "../../Utils/Project";
18
23
  import User from "../../Utils/User";
@@ -67,8 +72,6 @@ import AccessControlModel from "../../../Models/DatabaseModels/DatabaseBaseModel
67
72
  import Route from "../../../Types/API/Route";
68
73
  import URL from "../../../Types/API/URL";
69
74
  import { ColumnAccessControl } from "../../../Types/BaseDatabase/AccessControl";
70
- import InBetween from "../../../Types/BaseDatabase/InBetween";
71
- import Search from "../../../Types/BaseDatabase/Search";
72
75
  import MultiSearch from "../../../Types/BaseDatabase/MultiSearch";
73
76
  import SortOrder from "../../../Types/BaseDatabase/SortOrder";
74
77
  import SubscriptionPlan, {
@@ -91,7 +94,6 @@ import Permission, {
91
94
  PermissionHelper,
92
95
  UserPermission,
93
96
  } from "../../../Types/Permission";
94
- import Typeof from "../../../Types/Typeof";
95
97
  import React, {
96
98
  MutableRefObject,
97
99
  ReactElement,
@@ -287,6 +289,24 @@ export interface BaseTableProps<
287
289
  * If you do not provide this key, the table will not save the user preferences in local storage.
288
290
  */
289
291
  userPreferencesKey: string;
292
+
293
+ /**
294
+ * Namespace for this table's filter/facet/view state in the URL query
295
+ * string. Defaults to `saveFilterProps.tableId`, falling back to
296
+ * `userPreferencesKey` — both of which are already unique per table, which
297
+ * is what lets several tables share a page without clobbering each other.
298
+ *
299
+ * Only set this explicitly when the same table component is mounted more
300
+ * than once on one route and the two instances must keep separate state.
301
+ */
302
+ urlStateKey?: string | undefined;
303
+
304
+ /**
305
+ * Opt out of mirroring this table's filters into the URL. Use for tables
306
+ * inside modals/side-overs, or transient tables whose filters shouldn't
307
+ * outlive the page.
308
+ */
309
+ disableUrlState?: boolean | undefined;
290
310
  }
291
311
 
292
312
  export interface ComponentProps<
@@ -377,6 +397,61 @@ const BaseModelTable: <TBaseModel extends BaseModel | AnalyticsBaseModel>(
377
397
  return props.initialItemsOnPage || 10;
378
398
  };
379
399
 
400
+ /*
401
+ * ---------------------------------------------------------------------
402
+ * URL-persisted view state
403
+ * ---------------------------------------------------------------------
404
+ *
405
+ * The table mirrors its filters, facets, search, sort and page into the URL
406
+ * query string so that (a) navigating into a row and pressing Back brings
407
+ * the same filtered view back, and (b) the URL can be pasted to a teammate.
408
+ *
409
+ * The snapshot is read *once, synchronously, during the first render* and
410
+ * fed to the `useState` initializers below. Restoring in an effect instead
411
+ * would fire the first fetch against the unfiltered defaults and then throw
412
+ * that response away — a visible flash of the wrong rows plus a wasted
413
+ * request.
414
+ */
415
+ const urlStateKey: string | undefined = props.disableUrlState
416
+ ? undefined
417
+ : props.urlStateKey ||
418
+ props.saveFilterProps?.tableId ||
419
+ props.userPreferencesKey ||
420
+ undefined;
421
+
422
+ const initialUrlState: {
423
+ filter: FilterData<TBaseModel> | null;
424
+ view: TableViewUrlStateData;
425
+ } = useMemo(() => {
426
+ const restoredFilter: JSONObject | null = TableFilterUrlState.read(
427
+ urlStateKey,
428
+ "filter",
429
+ );
430
+
431
+ /*
432
+ * Anything on the URL is user-editable, so keep only the fields this table
433
+ * actually offers a filter for before it reaches the outgoing query.
434
+ */
435
+ const sanitized: FilterData<TBaseModel> | null = restoredFilter
436
+ ? sanitizeFilterData<TBaseModel>({
437
+ filterData: restoredFilter as unknown as FilterData<TBaseModel>,
438
+ filters: props.filters,
439
+ })
440
+ : null;
441
+
442
+ return {
443
+ filter: sanitized && Object.keys(sanitized).length > 0 ? sanitized : null,
444
+ view: TableViewUrlState.fromJSON(
445
+ TableFilterUrlState.read(urlStateKey, "view"),
446
+ ),
447
+ };
448
+ }, []);
449
+
450
+ // Surfaces two tables on one page accidentally sharing a URL namespace.
451
+ useEffect(() => {
452
+ return TableFilterUrlState.claimKey(urlStateKey);
453
+ }, [urlStateKey]);
454
+
380
455
  const [orderedStatesListNewItemOrder, setOrderedStatesListNewItemOrder] =
381
456
  useState<number | null>(null);
382
457
 
@@ -384,8 +459,15 @@ const BaseModelTable: <TBaseModel extends BaseModel | AnalyticsBaseModel>(
384
459
  TBaseModel | undefined
385
460
  >(undefined);
386
461
  const [data, setData] = useState<Array<TBaseModel>>([]);
387
- const [query, setQuery] = useState<Query<TBaseModel>>({});
388
- const [currentPageNumber, setCurrentPageNumber] = useState<number>(1);
462
+ const [query, setQuery] = useState<Query<TBaseModel>>(() => {
463
+ return buildQueryFromFilterData<TBaseModel>({
464
+ filterData: initialUrlState.filter || props.initialFilterData || {},
465
+ filters: props.filters,
466
+ });
467
+ });
468
+ const [currentPageNumber, setCurrentPageNumber] = useState<number>(
469
+ initialUrlState.view.page || 1,
470
+ );
389
471
  const [totalItemsCount, setTotalItemsCount] = useState<number>(0);
390
472
  /*
391
473
  * Analytics endpoints (Log/Span/Metric/...) skip COUNT(*) for
@@ -399,10 +481,18 @@ const BaseModelTable: <TBaseModel extends BaseModel | AnalyticsBaseModel>(
399
481
  const [error, setError] = useState<string>("");
400
482
  const [tableFilterError, setTableFilterError] = useState<string>("");
401
483
 
402
- const [searchText, setSearchText] = useState<string>("");
403
- const [debouncedSearchText, setDebouncedSearchText] = useState<string>("");
484
+ const [searchText, setSearchText] = useState<string>(
485
+ initialUrlState.view.search || "",
486
+ );
487
+ const [debouncedSearchText, setDebouncedSearchText] = useState<string>(
488
+ initialUrlState.view.search || "",
489
+ );
404
490
  const [isSearchFocused, setIsSearchFocused] = useState<boolean>(false);
405
- const [isSearchExpanded, setIsSearchExpanded] = useState<boolean>(false);
491
+ const [isSearchExpanded, setIsSearchExpanded] = useState<boolean>(
492
+ Boolean(
493
+ initialUrlState.view.search || (initialUrlState.view.labels || []).length,
494
+ ),
495
+ );
406
496
  const searchInputRef: React.RefObject<HTMLInputElement> =
407
497
  React.useRef<HTMLInputElement>(null!);
408
498
 
@@ -415,13 +505,36 @@ const BaseModelTable: <TBaseModel extends BaseModel | AnalyticsBaseModel>(
415
505
  const [availableLabels, setAvailableLabels] = useState<
416
506
  Array<SearchLabelOption>
417
507
  >([]);
508
+ /*
509
+ * Restored label chips start as bare IDs — the id is all the query needs, so
510
+ * rows are correct on the very first fetch. The human-readable name/colour
511
+ * are filled in by the hydration effect below once the label list loads.
512
+ */
418
513
  const [selectedLabels, setSelectedLabels] = useState<
419
514
  Array<SearchLabelOption>
420
- >([]);
515
+ >(() => {
516
+ return (initialUrlState.view.labels || []).map((id: string) => {
517
+ return { id: id, name: id, color: "#94a3b8" };
518
+ });
519
+ });
421
520
  const [isLabelsLoading, setIsLabelsLoading] = useState<boolean>(false);
422
521
  const [labelsFetched, setLabelsFetched] = useState<boolean>(false);
423
522
  const [labelDropdownIndex, setLabelDropdownIndex] = useState<number>(0);
424
523
 
524
+ /*
525
+ * Only the *ids* affect the query, so effects key off this instead of the
526
+ * array itself. Without it, merely re-labelling a chip (which happens when
527
+ * URL-restored chips get their display name hydrated) would look like a
528
+ * filter change and trigger a refetch + a jump back to page 1.
529
+ */
530
+ const selectedLabelIds: Array<string> = useMemo(() => {
531
+ return selectedLabels.map((l: SearchLabelOption) => {
532
+ return l.id;
533
+ });
534
+ }, [selectedLabels]);
535
+
536
+ const selectedLabelIdsKey: string = selectedLabelIds.join(",");
537
+
425
538
  useEffect(() => {
426
539
  const handle: ReturnType<typeof setTimeout> = setTimeout(() => {
427
540
  setDebouncedSearchText(searchText);
@@ -477,12 +590,23 @@ const BaseModelTable: <TBaseModel extends BaseModel | AnalyticsBaseModel>(
477
590
  ) {
478
591
  setIsSearchExpanded(true);
479
592
  }
480
- }, [debouncedSearchText, selectedLabels]);
593
+ }, [debouncedSearchText, selectedLabelIdsKey]);
594
+
595
+ /*
596
+ * Effects run on mount too, so without this guard the very first pass would
597
+ * stomp a page number restored from the URL back to 1.
598
+ */
599
+ const isFirstRenderRef: MutableRefObject<boolean> = React.useRef(true);
481
600
 
482
601
  useEffect(() => {
602
+ if (isFirstRenderRef.current) {
603
+ isFirstRenderRef.current = false;
604
+ return;
605
+ }
606
+
483
607
  // reset to first page whenever the active search term or labels change
484
608
  setCurrentPageNumber(1);
485
- }, [debouncedSearchText, selectedLabels]);
609
+ }, [debouncedSearchText, selectedLabelIdsKey]);
486
610
 
487
611
  /*
488
612
  * Auto-detect label support from the existing filters array. We look for
@@ -582,14 +706,52 @@ const BaseModelTable: <TBaseModel extends BaseModel | AnalyticsBaseModel>(
582
706
  };
583
707
  }, [isSearchExpanded, labelFilterConfig, labelsFetched]);
584
708
 
709
+ /*
710
+ * Chips restored from the URL only carry an id. Once the label list lands,
711
+ * swap in the real name and colour so the chip reads "Production" rather
712
+ * than a raw ObjectID. Labels that no longer exist (deleted, or not visible
713
+ * to this user) keep their id — the filter still applies, it just isn't
714
+ * pretty, which beats silently dropping a constraint from a shared link.
715
+ */
716
+ useEffect(() => {
717
+ if (availableLabels.length === 0 || selectedLabels.length === 0) {
718
+ return;
719
+ }
720
+
721
+ let didHydrate: boolean = false;
722
+
723
+ const hydrated: Array<SearchLabelOption> = selectedLabels.map(
724
+ (selected: SearchLabelOption) => {
725
+ const match: SearchLabelOption | undefined = availableLabels.find(
726
+ (available: SearchLabelOption) => {
727
+ return available.id === selected.id;
728
+ },
729
+ );
730
+
731
+ if (!match || match.name === selected.name) {
732
+ return selected;
733
+ }
734
+
735
+ didHydrate = true;
736
+ return match;
737
+ },
738
+ );
739
+
740
+ if (didHydrate) {
741
+ setSelectedLabels(hydrated);
742
+ }
743
+ }, [availableLabels]);
744
+
585
745
  const [showModel, setShowModal] = useState<boolean>(false);
586
746
  const [showFilterModal, setShowFilterModal] = useState<boolean>(false);
587
747
  const [modalType, setModalType] = useState<ModalType>(ModalType.Create);
588
748
  const [sortBy, setSortBy] = useState<keyof TBaseModel | null>(
589
- props.sortBy || null,
749
+ (initialUrlState.view.sortBy as keyof TBaseModel | undefined) ||
750
+ props.sortBy ||
751
+ null,
590
752
  );
591
753
  const [sortOrder, setSortOrder] = useState<SortOrder>(
592
- props.sortOrder || SortOrder.Ascending,
754
+ initialUrlState.view.sortOrder || props.sortOrder || SortOrder.Ascending,
593
755
  );
594
756
  const [showDeleteConfirmModal, setShowDeleteConfirmModal] =
595
757
  useState<boolean>(false);
@@ -598,7 +760,24 @@ const BaseModelTable: <TBaseModel extends BaseModel | AnalyticsBaseModel>(
598
760
  const [currentDeleteableItem, setCurrentDeleteableItem] =
599
761
  useState<TBaseModel | null>(null);
600
762
 
601
- const [itemsOnPage, setItemsOnPage] = useState<number>(getItemsOnPage());
763
+ /*
764
+ * A page size that came in on the URL wins over the viewer's own stored
765
+ * preference — a shared link should render the same slice of rows for
766
+ * everyone who opens it.
767
+ */
768
+ const [itemsOnPage, setItemsOnPage] = useState<number>(
769
+ initialUrlState.view.itemsOnPage || getItemsOnPage(),
770
+ );
771
+
772
+ /*
773
+ * Page size is a personal preference (it already lives in localStorage), so
774
+ * it is only put on the URL once it is explicitly part of *this* view —
775
+ * either it arrived on the link, or the viewer changed it here. Otherwise
776
+ * every table would carry a redundant `itemsOnPage` param.
777
+ */
778
+ const isItemsOnPageExplicitRef: MutableRefObject<boolean> = React.useRef(
779
+ Boolean(initialUrlState.view.itemsOnPage),
780
+ );
602
781
 
603
782
  useEffect(() => {
604
783
  // update items on page in localstorage.
@@ -624,6 +803,24 @@ const BaseModelTable: <TBaseModel extends BaseModel | AnalyticsBaseModel>(
624
803
  // only update if the query has changed.
625
804
  if (JSON.stringify(currentQuery) !== JSON.stringify(newQuery)) {
626
805
  propsQueryRef.current = newQuery;
806
+
807
+ /*
808
+ * This is how facet-bar selections reach the API, so narrowing the
809
+ * result set has to send the user back to page 1 — exactly like the
810
+ * column-filter path does in `onFilterChanged`. Without it, changing a
811
+ * facet while on page 5 re-queries page 5 of a now-shorter list and
812
+ * lands on an empty page (and, since the page number is mirrored into
813
+ * the URL, shares that empty page too).
814
+ *
815
+ * When the page is already 1, `setCurrentPageNumber` is a no-op and the
816
+ * explicit fetch below is what refreshes the list; when it isn't, the
817
+ * state change re-runs the main fetch effect.
818
+ */
819
+ if (currentPageNumber !== 1) {
820
+ setCurrentPageNumber(1);
821
+ return;
822
+ }
823
+
627
824
  fetchItems().catch((err: Error) => {
628
825
  setError(API.getFriendlyMessage(err));
629
826
  });
@@ -1204,6 +1401,31 @@ const BaseModelTable: <TBaseModel extends BaseModel | AnalyticsBaseModel>(
1204
1401
  }
1205
1402
  }, [showFilterModal, props.filters]);
1206
1403
 
1404
+ /*
1405
+ * A table restored from the URL is already filtered, so its chips have to
1406
+ * render immediately — and entity/dropdown chips can only resolve their
1407
+ * labels from `filterDropdownOptions`, which are otherwise fetched lazily
1408
+ * when the filter popup opens. Without this, a shared link (or a Back
1409
+ * navigation) showed a filtered list with no visible indication of *why*,
1410
+ * and no "Clear Filters" button to escape it.
1411
+ */
1412
+ useEffect(() => {
1413
+ if (!initialUrlState.filter) {
1414
+ return;
1415
+ }
1416
+
1417
+ /*
1418
+ * Callers use this to render their own "filters active" affordance. It is
1419
+ * otherwise only fired by the filter form, so a restored view would show a
1420
+ * clean banner over a filtered table.
1421
+ */
1422
+ props.onFilterApplied?.(true);
1423
+
1424
+ getFilterDropdownItems().catch((err: Error) => {
1425
+ setTableFilterError(API.getFriendlyMessage(err));
1426
+ });
1427
+ }, []);
1428
+
1207
1429
  type GetSelectFunction = () => Select<TBaseModel>;
1208
1430
 
1209
1431
  const getSelect: GetSelectFunction = (): Select<TBaseModel> => {
@@ -1284,6 +1506,8 @@ const BaseModelTable: <TBaseModel extends BaseModel | AnalyticsBaseModel>(
1284
1506
  // then set query, sort and items on the page
1285
1507
  setQuery(tableView.query || {});
1286
1508
  setFilterData(tableView.query || {});
1509
+ // a saved view pins its own page size, so it belongs on the URL
1510
+ isItemsOnPageExplicitRef.current = true;
1287
1511
  setItemsOnPage(tableView.itemsOnPage || 10);
1288
1512
  setSortBy((sortBy as keyof TBaseModel) || null);
1289
1513
  setSortOrder(sortOrder);
@@ -1300,6 +1524,13 @@ const BaseModelTable: <TBaseModel extends BaseModel | AnalyticsBaseModel>(
1300
1524
  }
1301
1525
  } else {
1302
1526
  setQuery({});
1527
+ /*
1528
+ * Also clear the filter chips. Leaving `filterData` behind kept
1529
+ * the chips on screen and the `-filter` param in the URL, so the
1530
+ * next visit re-applied the very filters the user just cleared.
1531
+ */
1532
+ setFilterData({});
1533
+ props.onFilterApplied?.(false);
1303
1534
  setSortBy(null);
1304
1535
  setSortOrder(SortOrder.Descending);
1305
1536
  setItemsOnPage(10);
@@ -1427,7 +1658,13 @@ const BaseModelTable: <TBaseModel extends BaseModel | AnalyticsBaseModel>(
1427
1658
  buttonSize: ButtonSize.Small,
1428
1659
  className: "",
1429
1660
  onClick: () => {
1430
- setQuery({});
1661
+ /*
1662
+ * Just open the popup. This used to `setQuery({})` first, which
1663
+ * dropped the active filters (and refetched everything) the moment
1664
+ * the user opened the filter UI — while the chips and the URL still
1665
+ * advertised them. Filters now change only when the form applies
1666
+ * them.
1667
+ */
1431
1668
  setShowFilterModal(true);
1432
1669
  },
1433
1670
  disabled: isFilterFetchLoading,
@@ -1449,7 +1686,7 @@ const BaseModelTable: <TBaseModel extends BaseModel | AnalyticsBaseModel>(
1449
1686
  itemsOnPage,
1450
1687
  query,
1451
1688
  debouncedSearchText,
1452
- selectedLabels,
1689
+ selectedLabelIdsKey,
1453
1690
  props.refreshToggle,
1454
1691
  ]);
1455
1692
 
@@ -1766,7 +2003,7 @@ const BaseModelTable: <TBaseModel extends BaseModel | AnalyticsBaseModel>(
1766
2003
  };
1767
2004
 
1768
2005
  const [filterData, setFilterData] = useState<FilterData<TBaseModel>>(
1769
- props.initialFilterData || {},
2006
+ initialUrlState.filter || props.initialFilterData || {},
1770
2007
  );
1771
2008
 
1772
2009
  type OnFilterChangedFunction = (filterData: FilterData<TBaseModel>) => void;
@@ -1774,100 +2011,56 @@ const BaseModelTable: <TBaseModel extends BaseModel | AnalyticsBaseModel>(
1774
2011
  const onFilterChanged: OnFilterChangedFunction = (
1775
2012
  filterData: FilterData<TBaseModel>,
1776
2013
  ): void => {
1777
- const newQuery: Query<TBaseModel> = {};
1778
-
1779
2014
  setFilterData(filterData);
1780
2015
  setCurrentPageNumber(1);
1781
2016
 
1782
- for (const key in filterData) {
1783
- if (filterData[key] && typeof filterData[key] === Typeof.String) {
1784
- newQuery[key as keyof TBaseModel] = (filterData[key] || "").toString();
1785
- }
1786
-
1787
- if (typeof filterData[key] === Typeof.Boolean) {
1788
- newQuery[key as keyof TBaseModel] = Boolean(filterData[key]);
1789
- }
1790
-
1791
- if (typeof filterData[key] === Typeof.Number) {
1792
- newQuery[key as keyof TBaseModel] = filterData[key];
1793
- }
1794
-
1795
- if (filterData[key] instanceof Date) {
1796
- newQuery[key as keyof TBaseModel] = filterData[key];
1797
- }
1798
-
1799
- if (filterData[key] instanceof Search) {
1800
- newQuery[key as keyof TBaseModel] = filterData[key];
1801
- }
1802
-
1803
- if (filterData[key] instanceof InBetween) {
1804
- newQuery[key as keyof TBaseModel] = filterData[key];
1805
- }
1806
-
1807
- if (
1808
- props.filters.find((f: Filter<TBaseModel>) => {
1809
- return f.field && f.field[key];
1810
- })?.type === FieldType.JSON &&
1811
- typeof filterData[key] === Typeof.Object
1812
- ) {
1813
- newQuery[key as keyof TBaseModel] = filterData[key];
1814
- }
1815
-
1816
- if (Array.isArray(filterData[key])) {
1817
- newQuery[key as keyof TBaseModel] = new Includes(
1818
- filterData[key] as Array<string>,
1819
- );
1820
- }
1821
-
1822
- /*
1823
- * Pass any QueryOperator instance (IncludesAll, IncludesNone, StartsWith,
1824
- * EndsWith, NotContains, EqualTo, NotEqual, GreaterThan, LessThan,
1825
- * InBetween, IsNull, NotNull, ...) through to the query as-is.
1826
- */
1827
- if (filterData[key] instanceof QueryOperator) {
1828
- newQuery[key as keyof TBaseModel] = filterData[key];
1829
- }
1830
- }
1831
-
1832
- setQuery({ ...newQuery });
2017
+ setQuery(
2018
+ buildQueryFromFilterData<TBaseModel>({
2019
+ filterData: filterData,
2020
+ filters: props.filters,
2021
+ }),
2022
+ );
1833
2023
  };
1834
2024
 
1835
2025
  /*
1836
- * URL persistence for classic (column) filters, keyed by the table's
1837
- * `saveFilterProps.tableId`. Mirrors the facet persistence in
1838
- * `useResourceOwners` so filters survive navigating to a detail page and
1839
- * back, and so a filtered view is shareable. `hasRestoredUrlFilters` is
1840
- * state (not a ref) so the persist effect only runs after the restore has
1841
- * been applied never clobbering the snapshot with the empty default.
2026
+ * Mirror the table's view into the URL so Back restores it and the link can
2027
+ * be handed to a teammate. Restoring happens in the `useState` initializers
2028
+ * above (synchronously, before the first fetch), so there is nothing to gate
2029
+ * here: the first write after mount already carries the restored values.
2030
+ *
2031
+ * `replaceState` is used under the hood, so dragging a filter around doesn't
2032
+ * flood the back stack.
1842
2033
  */
1843
- const [hasRestoredUrlFilters, setHasRestoredUrlFilters] =
1844
- useState<boolean>(false);
1845
-
1846
2034
  useEffect(() => {
1847
- const restored: JSONObject | null = TableFilterUrlState.read(
1848
- props.saveFilterProps?.tableId,
1849
- "filter",
1850
- );
1851
- if (restored) {
1852
- /*
1853
- * Re-run through onFilterChanged so the derived query is rebuilt and the
1854
- * first fetch uses the restored filters.
1855
- */
1856
- onFilterChanged(restored as unknown as FilterData<TBaseModel>);
1857
- }
1858
- setHasRestoredUrlFilters(true);
1859
- }, []);
1860
-
1861
- useEffect(() => {
1862
- if (!hasRestoredUrlFilters) {
1863
- return;
1864
- }
1865
- TableFilterUrlState.write(
1866
- props.saveFilterProps?.tableId,
1867
- "filter",
1868
- filterData as unknown as JSONObject,
1869
- );
1870
- }, [hasRestoredUrlFilters, filterData]);
2035
+ TableFilterUrlState.writeMany(urlStateKey, {
2036
+ filter: filterData as unknown as JSONObject,
2037
+ view: TableViewUrlState.toJSON(
2038
+ {
2039
+ search: debouncedSearchText,
2040
+ labels: selectedLabelIds,
2041
+ sortBy: sortBy as string | undefined,
2042
+ sortOrder: sortOrder,
2043
+ page: currentPageNumber,
2044
+ itemsOnPage: isItemsOnPageExplicitRef.current
2045
+ ? itemsOnPage
2046
+ : undefined,
2047
+ },
2048
+ {
2049
+ sortBy: props.sortBy as string | undefined,
2050
+ sortOrder: props.sortOrder,
2051
+ },
2052
+ ),
2053
+ });
2054
+ }, [
2055
+ urlStateKey,
2056
+ filterData,
2057
+ debouncedSearchText,
2058
+ selectedLabelIdsKey,
2059
+ sortBy,
2060
+ sortOrder,
2061
+ currentPageNumber,
2062
+ itemsOnPage,
2063
+ ]);
1871
2064
 
1872
2065
  type GetDeleteBulkActionFunction = () => BulkActionButtonSchema<TBaseModel>;
1873
2066
 
@@ -2161,6 +2354,7 @@ const BaseModelTable: <TBaseModel extends BaseModel | AnalyticsBaseModel>(
2161
2354
 
2162
2355
  if (newItemsOnPage !== itemsOnPage) {
2163
2356
  setTableView(null);
2357
+ isItemsOnPageExplicitRef.current = true;
2164
2358
  }
2165
2359
 
2166
2360
  setItemsOnPage(newItemsOnPage);
@@ -2252,6 +2446,7 @@ const BaseModelTable: <TBaseModel extends BaseModel | AnalyticsBaseModel>(
2252
2446
  await getFilterDropdownItems();
2253
2447
  }}
2254
2448
  filters={classicTableFilters}
2449
+ filterData={filterData}
2255
2450
  filterError={tableFilterError}
2256
2451
  isFilterLoading={isFilterFetchLoading}
2257
2452
  showFilterModal={showFilterModal}
@@ -2294,9 +2489,17 @@ const BaseModelTable: <TBaseModel extends BaseModel | AnalyticsBaseModel>(
2294
2489
  fields={fields}
2295
2490
  itemsOnPage={itemsOnPage}
2296
2491
  disablePagination={props.disablePagination || false}
2297
- onNavigateToPage={async (pageNumber: number, itemsOnPage: number) => {
2492
+ onNavigateToPage={async (
2493
+ pageNumber: number,
2494
+ newItemsOnPage: number,
2495
+ ) => {
2298
2496
  setCurrentPageNumber(pageNumber);
2299
- setItemsOnPage(itemsOnPage);
2497
+
2498
+ if (newItemsOnPage !== itemsOnPage) {
2499
+ isItemsOnPageExplicitRef.current = true;
2500
+ }
2501
+
2502
+ setItemsOnPage(newItemsOnPage);
2300
2503
  }}
2301
2504
  noItemsMessage={props.noItemsMessage || ""}
2302
2505
  onRefreshClick={async () => {