@oneuptime/common 12.0.4 → 12.0.6

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 (838) hide show
  1. package/Models/DatabaseModels/AIRun.ts +71 -1
  2. package/Models/DatabaseModels/AlertFeed.ts +30 -0
  3. package/Models/DatabaseModels/Dashboard.ts +28 -0
  4. package/Models/DatabaseModels/DataSource.ts +744 -0
  5. package/Models/DatabaseModels/Incident.ts +2 -0
  6. package/Models/DatabaseModels/IncidentEpisode.ts +1 -0
  7. package/Models/DatabaseModels/IncidentEpisodePublicNote.ts +1 -0
  8. package/Models/DatabaseModels/IncidentEpisodeStateTimeline.ts +1 -0
  9. package/Models/DatabaseModels/IncidentFeed.ts +30 -0
  10. package/Models/DatabaseModels/IncidentPublicNote.ts +1 -0
  11. package/Models/DatabaseModels/IncidentStateTimeline.ts +1 -0
  12. package/Models/DatabaseModels/Index.ts +3 -0
  13. package/Models/DatabaseModels/LogSavedView.ts +33 -0
  14. package/Models/DatabaseModels/Project.ts +231 -9
  15. package/Models/DatabaseModels/ProjectCallSMSConfig.ts +10 -2
  16. package/Models/DatabaseModels/ScheduledMaintenance.ts +1 -0
  17. package/Models/DatabaseModels/ScheduledMaintenancePublicNote.ts +1 -0
  18. package/Models/DatabaseModels/ScheduledMaintenanceStateTimeline.ts +1 -0
  19. package/Models/DatabaseModels/ScheduledMaintenanceTemplateOwnerUser.ts +4 -4
  20. package/Models/DatabaseModels/StatusPage.ts +28 -0
  21. package/Models/DatabaseModels/StatusPageAnnouncement.ts +1 -0
  22. package/Models/DatabaseModels/User.ts +2 -0
  23. package/Models/DatabaseModels/UserOnCallLog.ts +2 -0
  24. package/Models/DatabaseModels/UserOnCallLogTimeline.ts +2 -0
  25. package/Models/DatabaseModels/UserSession.ts +2 -0
  26. package/Models/DatabaseModels/UserTotpAuth.ts +6 -4
  27. package/Models/DatabaseModels/UserWebAuthn.ts +5 -3
  28. package/Server/API/AIAgentDataAPI.ts +44 -55
  29. package/Server/API/AIInsightAPI.ts +47 -4
  30. package/Server/API/AIInvestigationAPI.ts +200 -17
  31. package/Server/API/DashboardAPI.ts +186 -502
  32. package/Server/API/DataSourceAPI.ts +268 -0
  33. package/Server/API/StatusPageAPI.ts +49 -20
  34. package/Server/API/UserAPI.ts +119 -0
  35. package/Server/EnvironmentConfig.ts +16 -0
  36. package/Server/Infrastructure/ClickhouseConfig.ts +74 -1
  37. package/Server/Infrastructure/ClickhouseDatabase.ts +1 -1
  38. package/Server/Infrastructure/Postgres/SchemaMigrations/1786096660558-AddTimeRangeToLogSavedView.ts +27 -0
  39. package/Server/Infrastructure/Postgres/SchemaMigrations/1786101798351-MigrationName.ts +89 -0
  40. package/Server/Infrastructure/Postgres/SchemaMigrations/1786105470826-MigrationName.ts +27 -0
  41. package/Server/Infrastructure/Postgres/SchemaMigrations/1786303472848-AddDataSourceTable.ts +39 -0
  42. package/Server/Infrastructure/Postgres/SchemaMigrations/1786400000000-AddMasterPasswordSalt.ts +40 -0
  43. package/Server/Infrastructure/Postgres/SchemaMigrations/1786500000000-AddInvestigationCodeFixRecommendation.ts +26 -0
  44. package/Server/Infrastructure/Postgres/SchemaMigrations/1786600000000-AddInvestigationAnalysisTldr.ts +24 -0
  45. package/Server/Infrastructure/Postgres/SchemaMigrations/1786700000000-DropProjectCallSMSConfigCredentialUniques.ts +76 -0
  46. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +16 -0
  47. package/Server/Infrastructure/Queue.ts +26 -0
  48. package/Server/Infrastructure/QueueWorker.ts +17 -0
  49. package/Server/Middleware/TelemetryIngest.ts +8 -3
  50. package/Server/Services/AIInsightService.ts +132 -12
  51. package/Server/Services/AIRunService.ts +112 -10
  52. package/Server/Services/AIService.ts +109 -22
  53. package/Server/Services/AlertFeedService.ts +5 -0
  54. package/Server/Services/AlertService.ts +38 -32
  55. package/Server/Services/AnalyticsDatabaseService.ts +37 -4
  56. package/Server/Services/DataSourceService.ts +200 -0
  57. package/Server/Services/DatabaseService.ts +43 -2
  58. package/Server/Services/HostService.ts +92 -0
  59. package/Server/Services/IncidentFeedService.ts +5 -0
  60. package/Server/Services/IncidentService.ts +45 -0
  61. package/Server/Services/Index.ts +2 -0
  62. package/Server/Services/LlmLogService.ts +46 -2
  63. package/Server/Services/MonitorService.ts +49 -0
  64. package/Server/Services/MonitorStatusService.ts +166 -0
  65. package/Server/Services/OpenTelemetryIngestService.ts +255 -184
  66. package/Server/Services/RumSessionPinService.ts +7 -21
  67. package/Server/Services/StatusPageSubscriberService.ts +13 -0
  68. package/Server/Services/UserService.ts +280 -9
  69. package/Server/Static/Vendor/README.md +62 -0
  70. package/Server/Static/Vendor/fonts/InterVariable.woff2 +0 -0
  71. package/Server/Static/Vendor/highlight/highlight.min.js +1244 -0
  72. package/Server/Static/Vendor/highlight/languages/apache.min.js +15 -0
  73. package/Server/Static/Vendor/highlight/languages/bash.min.js +21 -0
  74. package/Server/Static/Vendor/highlight/languages/c.min.js +41 -0
  75. package/Server/Static/Vendor/highlight/languages/cpp.min.js +47 -0
  76. package/Server/Static/Vendor/highlight/languages/csharp.min.js +49 -0
  77. package/Server/Static/Vendor/highlight/languages/css.min.js +31 -0
  78. package/Server/Static/Vendor/highlight/languages/diff.min.js +9 -0
  79. package/Server/Static/Vendor/highlight/languages/dns.min.js +11 -0
  80. package/Server/Static/Vendor/highlight/languages/dockerfile.min.js +8 -0
  81. package/Server/Static/Vendor/highlight/languages/go.min.js +20 -0
  82. package/Server/Static/Vendor/highlight/languages/graphql.min.js +12 -0
  83. package/Server/Static/Vendor/highlight/languages/http.min.js +14 -0
  84. package/Server/Static/Vendor/highlight/languages/ini.min.js +15 -0
  85. package/Server/Static/Vendor/highlight/languages/java.min.js +38 -0
  86. package/Server/Static/Vendor/highlight/languages/javascript.min.js +81 -0
  87. package/Server/Static/Vendor/highlight/languages/json.min.js +8 -0
  88. package/Server/Static/Vendor/highlight/languages/kotlin.min.js +46 -0
  89. package/Server/Static/Vendor/highlight/languages/lua.min.js +15 -0
  90. package/Server/Static/Vendor/highlight/languages/makefile.min.js +14 -0
  91. package/Server/Static/Vendor/highlight/languages/nginx.min.js +21 -0
  92. package/Server/Static/Vendor/highlight/languages/perl.min.js +41 -0
  93. package/Server/Static/Vendor/highlight/languages/php.min.js +59 -0
  94. package/Server/Static/Vendor/highlight/languages/powershell.min.js +39 -0
  95. package/Server/Static/Vendor/highlight/languages/python.min.js +42 -0
  96. package/Server/Static/Vendor/highlight/languages/r.min.js +26 -0
  97. package/Server/Static/Vendor/highlight/languages/ruby.min.js +54 -0
  98. package/Server/Static/Vendor/highlight/languages/rust.min.js +27 -0
  99. package/Server/Static/Vendor/highlight/languages/scala.min.js +28 -0
  100. package/Server/Static/Vendor/highlight/languages/sql.min.js +21 -0
  101. package/Server/Static/Vendor/highlight/languages/swift.min.js +68 -0
  102. package/Server/Static/Vendor/highlight/languages/typescript.min.js +99 -0
  103. package/Server/Static/Vendor/highlight/languages/xml.min.js +29 -0
  104. package/Server/Static/Vendor/highlight/languages/yaml.min.js +28 -0
  105. package/Server/Static/Vendor/highlight/styles/github-dark.min.css +10 -0
  106. package/Server/Static/Vendor/highlight/styles/vs2015.min.css +1 -0
  107. package/Server/Static/Vendor/tailwind/tailwind-3.4.5.js +21028 -0
  108. package/Server/Types/Database/Permissions/BasePermission.ts +7 -0
  109. package/Server/Types/Database/Permissions/DeletePermission.ts +2 -0
  110. package/Server/Types/Database/Permissions/ReadPermission.ts +3 -0
  111. package/Server/Types/Database/Permissions/TenantPermission.ts +101 -16
  112. package/Server/Utils/AI/Chat/ObservabilityAssistant.ts +6 -0
  113. package/Server/Utils/AI/CodeFix/CodeFixAgentCompletion.ts +4 -0
  114. package/Server/Utils/AI/CodeFix/CodeFixReadiness.ts +8 -5
  115. package/Server/Utils/AI/CodeFix/FixRunBudget.ts +90 -16
  116. package/Server/Utils/AI/Remediation/RemediationExecutionRunner.ts +2 -0
  117. package/Server/Utils/AI/Remediation/RemediationPlanRunner.ts +2 -0
  118. package/Server/Utils/AI/SRE/AIInvestigationEngine.ts +311 -31
  119. package/Server/Utils/AI/SRE/AlertInvestigationRunner.ts +26 -24
  120. package/Server/Utils/AI/SRE/ConfidenceSignal.ts +182 -71
  121. package/Server/Utils/AI/SRE/FixFromIncidentTaskTrigger.ts +252 -43
  122. package/Server/Utils/AI/SRE/IncidentInvestigationRunner.ts +26 -24
  123. package/Server/Utils/AI/SRE/Insights/Detectors/ExceptionIdentity.ts +125 -0
  124. package/Server/Utils/AI/SRE/Insights/Detectors/ExceptionSpikeDetector.ts +25 -15
  125. package/Server/Utils/AI/SRE/Insights/Detectors/NewExceptionDetector.ts +256 -57
  126. package/Server/Utils/AI/SRE/Insights/InsightStore.ts +76 -18
  127. package/Server/Utils/AI/SRE/InstrumentationTaskTrigger.ts +47 -13
  128. package/Server/Utils/AI/SRE/InvestigationGrader.ts +9 -5
  129. package/Server/Utils/AI/SRE/InvestigationQueue.ts +141 -24
  130. package/Server/Utils/AI/SRE/InvestigationSubjectLock.ts +66 -0
  131. package/Server/Utils/AI/SRE/InvestigationTldr.ts +352 -0
  132. package/Server/Utils/AI/SRE/PostedRootCause.ts +94 -3
  133. package/Server/Utils/AI/SRE/README.md +1 -1
  134. package/Server/Utils/AI/SRE/SubjectCodeFixRun.ts +132 -10
  135. package/Server/Utils/AnalyticsDatabase/ClusterConfig.ts +24 -0
  136. package/Server/Utils/AnalyticsDatabase/InsertDedupContext.ts +7 -2
  137. package/Server/Utils/Dashboard/PublicDashboardResourceListPolicy.ts +1793 -0
  138. package/Server/Utils/Dashboard/PublicDashboardViewConfig.ts +65 -0
  139. package/Server/Utils/DataSource/ConnectorRegistry.ts +53 -0
  140. package/Server/Utils/DataSource/Connectors/ClickHouseConnector.ts +338 -0
  141. package/Server/Utils/DataSource/Connectors/ElasticsearchConnector.ts +717 -0
  142. package/Server/Utils/DataSource/Connectors/LokiConnector.ts +606 -0
  143. package/Server/Utils/DataSource/Connectors/MySqlConnector.ts +307 -0
  144. package/Server/Utils/DataSource/Connectors/PostgresConnector.ts +260 -0
  145. package/Server/Utils/DataSource/Connectors/PrometheusConnector.ts +555 -0
  146. package/Server/Utils/DataSource/Connectors/RestApiConnector.ts +597 -0
  147. package/Server/Utils/DataSource/Connectors/SqlServerConnector.ts +318 -0
  148. package/Server/Utils/DataSource/EgressGuard.ts +446 -0
  149. package/Server/Utils/DataSource/HttpFetch.ts +221 -0
  150. package/Server/Utils/DataSource/SqlQueryGuard.ts +383 -0
  151. package/Server/Utils/DataSource/SqlResultShaper.ts +372 -0
  152. package/Server/Utils/DataSource/Types.ts +93 -0
  153. package/Server/Utils/Database/PostgresErrorTranslator.ts +172 -17
  154. package/Server/Utils/InProcessMemo.ts +141 -0
  155. package/Server/Utils/InstanceHealth/TelemetryIngestion.ts +628 -0
  156. package/Server/Utils/Monitor/Criteria/APIRequestCriteria.ts +29 -0
  157. package/Server/Utils/Monitor/Criteria/DomainMonitorCriteria.ts +56 -0
  158. package/Server/Utils/Monitor/MonitorMetricUtil.ts +104 -0
  159. package/Server/Utils/Monitor/MonitorResource.ts +14 -0
  160. package/Server/Utils/Monitor/MonitorTemplateUtil.ts +1 -0
  161. package/Server/Utils/PasswordHash.ts +28 -4
  162. package/Server/Utils/Response.ts +12 -1
  163. package/Server/Utils/SSRFProtection.ts +237 -0
  164. package/Server/Utils/StartServer.ts +8 -0
  165. package/Server/Utils/StatusPageSubscriberWebhook.ts +30 -0
  166. package/Server/Utils/Telemetry/CaptureSpan.ts +30 -18
  167. package/Server/Utils/Telemetry/IngestionTimestamp.ts +75 -0
  168. package/Server/Utils/Telemetry/ResourceHeartbeat.ts +99 -7
  169. package/Server/Utils/Telemetry/Telemetry.ts +112 -1
  170. package/Server/Utils/Telemetry.ts +104 -3
  171. package/Server/Utils/VendorAssets.ts +165 -0
  172. package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.ts +28 -5
  173. package/Server/Utils/Workspace/Slack/Slack.ts +5 -0
  174. package/Server/Views/Partials/Head.ejs +21 -7
  175. package/Tests/App/AdminDashboard/AdminProjectsIdFilter.test.tsx +207 -0
  176. package/Tests/App/AdminDashboard/AdminUsersIdFilter.test.tsx +216 -0
  177. package/Tests/App/Dashboard/AIInsightViewActions.test.tsx +422 -0
  178. package/Tests/App/Dashboard/AIInvestigationHeaderStatus.test.tsx +251 -0
  179. package/Tests/App/Dashboard/AddWidgetModal.test.tsx +10 -3
  180. package/Tests/App/Dashboard/AlertsSideMenu.test.tsx +387 -0
  181. package/Tests/App/Dashboard/ChatActivityFeed.test.tsx +199 -0
  182. package/Tests/App/Dashboard/DataSourceChartSyntheticConfig.test.tsx +736 -0
  183. package/Tests/App/Dashboard/DataSourceQueryEditor.test.tsx +868 -0
  184. package/Tests/App/Dashboard/DataSourceWidgetCatalog.test.ts +440 -0
  185. package/Tests/App/Dashboard/DataSourceWidgetFetching.test.tsx +2109 -0
  186. package/Tests/App/Dashboard/DataSourceWidgetViews.test.tsx +726 -0
  187. package/Tests/App/Dashboard/EventStatusPanel.test.tsx +747 -0
  188. package/Tests/App/Dashboard/IncidentsSideMenu.test.tsx +447 -0
  189. package/Tests/App/Dashboard/InvestigationFeedRefresh.test.tsx +480 -0
  190. package/Tests/App/Dashboard/InvestigationPanel.test.tsx +1695 -0
  191. package/Tests/App/Dashboard/InvestigationPanelStatus.test.tsx +500 -0
  192. package/Tests/App/Dashboard/PortMonitorCriteriaFilter.test.ts +93 -0
  193. package/Tests/App/Dashboard/ProductMenuBreadcrumbs.test.tsx +391 -0
  194. package/Tests/App/Dashboard/ScheduledMaintenanceSideMenu.test.tsx +326 -0
  195. package/Tests/App/Dashboard/SideMenuHarness.tsx +187 -0
  196. package/Tests/App/Dashboard/WidgetCatalog.test.ts +6 -1
  197. package/Tests/App/StatusPage/PublicStatusPageAPIErrorHandling.test.ts +117 -0
  198. package/Tests/App/StatusPage/StatusPageModelAPIPolymorphism.test.ts +223 -0
  199. package/Tests/App/StatusPage/StatusPageResourceExplorer.test.tsx +1858 -0
  200. package/Tests/Models/DatabaseModels/DataSourceModelSecrets.test.ts +70 -0
  201. package/Tests/Models/DatabaseModels/PermissionCatalogueCoverage.test.ts +243 -0
  202. package/Tests/Server/API/AIAgentDataFixFromIncidentContext.test.ts +266 -0
  203. package/Tests/Server/API/AIInvestigationAPI.test.ts +781 -0
  204. package/Tests/Server/API/AIInvestigationCreateFixTask.test.ts +80 -0
  205. package/Tests/Server/API/DashboardMasterPasswordAPI.test.ts +172 -1
  206. package/Tests/Server/API/DashboardPublicDataSourceStrip.test.ts +686 -0
  207. package/Tests/Server/API/DashboardPublicResourceListAPI.test.ts +585 -823
  208. package/Tests/Server/API/DataSourceAPIRoutes.test.ts +486 -0
  209. package/Tests/Server/API/StatusPageMasterPasswordAPI.test.ts +335 -0
  210. package/Tests/Server/API/StatusPageSubscriberOwnership.test.ts +291 -0
  211. package/Tests/Server/API/UserAuthenticationAPI.test.ts +641 -0
  212. package/Tests/Server/Infrastructure/ClickhouseKeepAliveOptions.test.ts +441 -0
  213. package/Tests/Server/Middleware/TelemetryIngestTokenLog.test.ts +140 -0
  214. package/Tests/Server/Services/AIInsightService.test.ts +266 -11
  215. package/Tests/Server/Services/AIRunAnalysisTldrPersistence.test.ts +160 -0
  216. package/Tests/Server/Services/AIRunCodeFixClaim.test.ts +59 -5
  217. package/Tests/Server/Services/AIRunHumanVerdict.test.ts +127 -58
  218. package/Tests/Server/Services/AIServiceDailyBudget.test.ts +400 -20
  219. package/Tests/Server/Services/AddMasterPasswordSaltMigration.test.ts +283 -0
  220. package/Tests/Server/Services/AlertMetricResourceAttributes.test.ts +352 -0
  221. package/Tests/Server/Services/AnalyticsDatabaseService.test.ts +25 -1
  222. package/Tests/Server/Services/DataSourceServiceSettings.test.ts +244 -0
  223. package/Tests/Server/Services/DatabaseServicePerUserPasswordSalt.test.ts +45 -35
  224. package/Tests/Server/Services/DatabaseServiceUpdateColumnsWithoutHooks.test.ts +54 -0
  225. package/Tests/Server/Services/FeedAIRunAssociation.test.ts +125 -0
  226. package/Tests/Server/Services/FixFromIncidentTaskTrigger.test.ts +418 -57
  227. package/Tests/Server/Services/HostServiceFindOrCreateMemo.test.ts +397 -0
  228. package/Tests/Server/Services/HostServiceUpdateLastSeen.test.ts +41 -2
  229. package/Tests/Server/Services/IncidentMetricResourceAttributes.test.ts +408 -0
  230. package/Tests/Server/Services/InstrumentationTaskTrigger.test.ts +173 -14
  231. package/Tests/Server/Services/MasterPasswordScrypt.test.ts +567 -0
  232. package/Tests/Server/Services/MonitorStatusServiceDeleteReferenceCleanup.test.ts +351 -0
  233. package/Tests/Server/Services/MonitorStatusServiceValidation.test.ts +171 -0
  234. package/Tests/Server/Services/OpenTelemetryResourceRetentionMemo.test.ts +398 -0
  235. package/Tests/Server/Services/OpenTelemetryServiceResolutionCache.test.ts +19 -0
  236. package/Tests/Server/Services/ProjectCallSMSConfigCredentialUniqueness.test.ts +305 -0
  237. package/Tests/Server/Services/ResourceUpdateLastSeenLivenessFallback.test.ts +36 -1
  238. package/Tests/Server/Services/RumSessionPinUniqueViolationRecovery.test.ts +163 -0
  239. package/Tests/Server/Services/SeparateIncidentAlertAiSettingsMigration.test.ts +194 -0
  240. package/Tests/Server/Services/UserAuthenticationService.test.ts +973 -0
  241. package/Tests/Server/Types/Database/ObjectIdColumnQuery.test.ts +262 -0
  242. package/Tests/Server/Types/Database/Permissions/TenantPermission.test.ts +358 -0
  243. package/Tests/Server/Utils/AI/AIAlertGating.test.ts +37 -4
  244. package/Tests/Server/Utils/AI/AIConfidenceSignal.test.ts +330 -29
  245. package/Tests/Server/Utils/AI/AIIncidentGating.test.ts +25 -0
  246. package/Tests/Server/Utils/AI/AIInvestigationQueue.test.ts +293 -5
  247. package/Tests/Server/Utils/AI/CodeFixAgentCompletion.test.ts +59 -1
  248. package/Tests/Server/Utils/AI/FixFromIncidentAutoTrigger.test.ts +342 -19
  249. package/Tests/Server/Utils/AI/FixRunBudget.test.ts +214 -30
  250. package/Tests/Server/Utils/AI/Insights/ExceptionSpikeDetector.test.ts +6 -1
  251. package/Tests/Server/Utils/AI/Insights/InsightStore.test.ts +121 -4
  252. package/Tests/Server/Utils/AI/Insights/InvestigationQueueInsightSubject.test.ts +2 -0
  253. package/Tests/Server/Utils/AI/Insights/NewExceptionDetector.test.ts +361 -10
  254. package/Tests/Server/Utils/AI/InvestigationGrader.test.ts +65 -17
  255. package/Tests/Server/Utils/AI/InvestigationQueueRemediationExecution.test.ts +3 -0
  256. package/Tests/Server/Utils/AI/InvestigationSettlement.test.ts +605 -20
  257. package/Tests/Server/Utils/AI/InvestigationTldr.test.ts +623 -0
  258. package/Tests/Server/Utils/AI/InvestigationTldrWiring.test.ts +98 -0
  259. package/Tests/Server/Utils/AI/PostedRootCause.test.ts +254 -0
  260. package/Tests/Server/Utils/AI/RemediationExecutionRunner.test.ts +4 -0
  261. package/Tests/Server/Utils/AI/RemediationPlanRunner.test.ts +2 -0
  262. package/Tests/Server/Utils/AI/SubjectCodeFixRunDedupe.test.ts +44 -0
  263. package/Tests/Server/Utils/AnalyticsDatabase/ClusterAwareSchema.test.ts +30 -0
  264. package/Tests/Server/Utils/Dashboard/PublicDashboardResourceListPolicy.test.ts +857 -0
  265. package/Tests/Server/Utils/Dashboard/PublicDashboardViewConfig.test.ts +480 -0
  266. package/Tests/Server/Utils/DataSource/ClickHouseConnector.test.ts +759 -0
  267. package/Tests/Server/Utils/DataSource/ConnectorRegistry.test.ts +37 -0
  268. package/Tests/Server/Utils/DataSource/EgressGuard.test.ts +645 -0
  269. package/Tests/Server/Utils/DataSource/ElasticsearchConnector.test.ts +1206 -0
  270. package/Tests/Server/Utils/DataSource/HttpFetch.test.ts +616 -0
  271. package/Tests/Server/Utils/DataSource/LokiConnector.test.ts +970 -0
  272. package/Tests/Server/Utils/DataSource/MySqlConnector.test.ts +935 -0
  273. package/Tests/Server/Utils/DataSource/PostgresConnector.test.ts +854 -0
  274. package/Tests/Server/Utils/DataSource/PrometheusConnector.test.ts +881 -0
  275. package/Tests/Server/Utils/DataSource/RestApiConnector.test.ts +1020 -0
  276. package/Tests/Server/Utils/DataSource/SqlQueryGuard.test.ts +425 -0
  277. package/Tests/Server/Utils/DataSource/SqlResultShaper.test.ts +555 -0
  278. package/Tests/Server/Utils/DataSource/SqlServerConnector.test.ts +934 -0
  279. package/Tests/Server/Utils/Database/PostgresErrorTranslator.test.ts +228 -7
  280. package/Tests/Server/Utils/InProcessMemo.test.ts +292 -0
  281. package/Tests/Server/Utils/InstanceHealth/TelemetryIngestion.test.ts +960 -0
  282. package/Tests/Server/Utils/MicrosoftTeamsWebhookUrlValidation.test.ts +103 -0
  283. package/Tests/Server/Utils/Monitor/Criteria/APIRequestCriteriaPortTimings.test.ts +212 -0
  284. package/Tests/Server/Utils/Monitor/Criteria/DomainMonitorCriteria.test.ts +401 -0
  285. package/Tests/Server/Utils/Monitor/MonitorMetricResourceAttributes.test.ts +336 -0
  286. package/Tests/Server/Utils/Monitor/MonitorMetricUtilPortTimings.test.ts +243 -0
  287. package/Tests/Server/Utils/OfflineAssetHygiene.test.ts +521 -0
  288. package/Tests/Server/Utils/PasswordHash.test.ts +30 -0
  289. package/Tests/Server/Utils/ResponseRenderAnalytics.test.ts +143 -0
  290. package/Tests/Server/Utils/SSRFProtection.test.ts +193 -0
  291. package/Tests/Server/Utils/StatusPageSubscriberWebhook.test.ts +101 -0
  292. package/Tests/Server/Utils/TailwindBuildCopy.test.ts +225 -0
  293. package/Tests/Server/Utils/Telemetry/ResourceHeartbeatL1Memo.test.ts +355 -0
  294. package/Tests/Server/Utils/Telemetry/TelemetryFanInWriter.test.ts +128 -0
  295. package/Tests/Server/Utils/Telemetry/TelemetryUtilAttributeKeys.test.ts +381 -0
  296. package/Tests/Server/Utils/Telemetry.test.ts +87 -0
  297. package/Tests/Server/Utils/VendorAssetIntegrity.test.ts +343 -0
  298. package/Tests/Server/Utils/VendorAssets.test.ts +671 -0
  299. package/Tests/Server/Views/OfflineRender.test.ts +297 -0
  300. package/Tests/Types/Dashboard/DashboardTemplates.test.ts +111 -0
  301. package/Tests/Types/Dashboard/DataSourceComponentTypes.test.ts +618 -0
  302. package/Tests/Types/DateClickhouseFormat.test.ts +192 -0
  303. package/Tests/Types/Monitor/CephMetricCatalog.test.ts +104 -0
  304. package/Tests/Types/Monitor/CriteriaFilter.test.ts +4 -0
  305. package/Tests/Types/Monitor/DockerMetricCatalog.test.ts +109 -0
  306. package/Tests/Types/Monitor/DockerSwarmMetricCatalog.test.ts +118 -0
  307. package/Tests/Types/Monitor/HostMetricCatalog.test.ts +104 -0
  308. package/Tests/Types/Monitor/IotMetricCatalog.test.ts +104 -0
  309. package/Tests/Types/Monitor/KubernetesMetricCatalog.test.ts +118 -0
  310. package/Tests/Types/Monitor/MonitorCriteriaInstance.test.ts +42 -0
  311. package/Tests/Types/Monitor/MonitorStep.test.ts +38 -0
  312. package/Tests/Types/Monitor/MonitorStepDomainMonitor.test.ts +75 -0
  313. package/Tests/Types/Monitor/PodmanMetricCatalog.test.ts +109 -0
  314. package/Tests/Types/Monitor/ProxmoxMetricCatalog.test.ts +107 -0
  315. package/Tests/Types/Monitor/SnmpMonitor/SnmpVendorTemplate.test.ts +151 -0
  316. package/Tests/Types/Password.test.ts +363 -0
  317. package/Tests/Types/Permission.test.ts +137 -0
  318. package/Tests/Types/Rum/SessionReplayMaskingMode.test.ts +101 -0
  319. package/Tests/UI/Components/AiInvestigationSettingsCard.test.tsx +5 -5
  320. package/Tests/UI/Components/CardModelDetailEdit.test.tsx +3 -5
  321. package/Tests/UI/Components/ConfirmModal.test.tsx +7 -0
  322. package/Tests/UI/Components/ErrorBoundary.test.tsx +211 -0
  323. package/Tests/UI/Components/FeedItemSafeMode.test.tsx +74 -0
  324. package/Tests/UI/Components/Modal.test.tsx +281 -1
  325. package/Tests/UI/Components/MoreMenu.test.tsx +756 -0
  326. package/Tests/UI/Components/ObjectIdFilterPipeline.test.tsx +396 -0
  327. package/Tests/UI/Components/StatusPage/ResourceGroupNavigator.test.tsx +1147 -0
  328. package/Tests/UI/Components/StatusPage/ResourceGroupSection.test.tsx +62 -0
  329. package/Tests/UI/Monitor/PortMonitorView.test.tsx +237 -0
  330. package/Tests/UI/Telemetry/TelemetrySnapshotWindowAlert.test.tsx +91 -0
  331. package/Tests/UI/Utils/Breadcrumb/fixtures/RealBreadcrumbTrails.ts +116 -1
  332. package/Tests/UI/Utils/Breadcrumb/fixtures/RealRoutePatterns.ts +2 -0
  333. package/Tests/UI/Utils/DownloadFile.test.ts +103 -0
  334. package/Tests/UI/Utils/ErrorSupportBundle.test.ts +582 -0
  335. package/Tests/UI/Utils/Project.test.ts +31 -0
  336. package/Tests/UI/Utils/StatusPageModelAPIInjection.test.ts +245 -0
  337. package/Tests/UI/Utils/UseDashboardGridDnd.test.tsx +820 -0
  338. package/Tests/Utils/Analytics.test.ts +23 -0
  339. package/Tests/Utils/Dashboard/Components/DashboardDataSourceComponents.test.ts +640 -0
  340. package/Tests/Utils/Dashboard/DashboardViewConfig.test.ts +329 -0
  341. package/Tests/Utils/Dashboard/GridLayout.test.ts +951 -0
  342. package/Tests/Utils/DataSource/DataSourceQueryText.test.ts +138 -0
  343. package/Tests/Utils/DataSource/DataSourceValueReducer.test.ts +526 -0
  344. package/Tests/Utils/Metrics/MetricResourceAttributeUtil.test.ts +691 -0
  345. package/Tests/Utils/Monitor/MonitorMetricType.test.ts +117 -0
  346. package/Tests/Utils/RecordingRuleExpression.test.ts +327 -0
  347. package/Tests/Utils/StatusPage/GroupHierarchyView.test.ts +1452 -0
  348. package/Tests/Utils/StatusPage/GroupNestingLayout.test.ts +186 -0
  349. package/Tests/Utils/StatusPage/GroupTree.test.ts +456 -0
  350. package/Tests/Utils/StatusPage/OverviewGroupHierarchyVisibility.test.ts +588 -0
  351. package/Tests/Utils/StatusPage/ResourceExplorer.test.ts +931 -0
  352. package/Tests/Utils/Telemetry/CaptureSpanExportGating.test.ts +288 -0
  353. package/Tests/Utils/Telemetry/IngestionTimestamp.test.ts +170 -0
  354. package/Tests/Utils/Telemetry/SavedViewTimeRange.test.ts +244 -0
  355. package/Tests/Utils/Telemetry/TelemetryQueryTimeRange.test.ts +825 -0
  356. package/Types/AI/AIInsightEvidence.ts +6 -0
  357. package/Types/AI/AIRunCodeFixRecommendation.ts +17 -0
  358. package/Types/AI/CodeFixTaskContext.ts +63 -3
  359. package/Types/AI/CodeFixTaskType.ts +3 -3
  360. package/Types/Analytics/RevenueEvent.ts +31 -0
  361. package/Types/Dashboard/DashboardComponentType.ts +31 -0
  362. package/Types/Dashboard/DashboardComponents/DashboardDataSourceChartComponent.ts +27 -0
  363. package/Types/Dashboard/DashboardComponents/DashboardDataSourceGaugeComponent.ts +32 -0
  364. package/Types/Dashboard/DashboardComponents/DashboardDataSourceTableComponent.ts +30 -0
  365. package/Types/Dashboard/DashboardComponents/DashboardDataSourceValueComponent.ts +55 -0
  366. package/Types/DataSource/DataSourceLimits.ts +62 -0
  367. package/Types/DataSource/DataSourceQueryConfig.ts +41 -0
  368. package/Types/DataSource/DataSourceTableResult.ts +38 -0
  369. package/Types/DataSource/DataSourceType.ts +213 -0
  370. package/Types/Date.ts +43 -3
  371. package/Types/HashedString.ts +4 -3
  372. package/Types/Monitor/CriteriaFilter.ts +4 -0
  373. package/Types/Monitor/DomainMonitor/DomainLookupMethod.ts +23 -0
  374. package/Types/Monitor/DomainMonitor/DomainMonitorResponse.ts +7 -0
  375. package/Types/Monitor/MonitorCriteriaInstance.ts +24 -7
  376. package/Types/Monitor/MonitorMetricType.ts +8 -0
  377. package/Types/Monitor/MonitorStep.ts +10 -1
  378. package/Types/Monitor/MonitorStepDomainMonitor.ts +21 -0
  379. package/Types/Monitor/PortMonitor/PortMonitorTimings.ts +10 -0
  380. package/Types/Password.ts +64 -0
  381. package/Types/Permission.ts +69 -175
  382. package/Types/Probe/ProbeMonitorResponse.ts +6 -0
  383. package/Types/UserAuthenticationStatus.ts +34 -0
  384. package/UI/Components/BulkUpdate/BulkUpdateForm.tsx +2 -3
  385. package/UI/Components/Button/Button.tsx +1 -1
  386. package/UI/Components/ErrorBoundary.tsx +549 -71
  387. package/UI/Components/Feed/FeedItem.tsx +9 -2
  388. package/UI/Components/Icon/Icon.tsx +10 -9
  389. package/UI/Components/Modal/ConfirmModal.tsx +6 -1
  390. package/UI/Components/Modal/Modal.tsx +267 -35
  391. package/UI/Components/Modal/ModalFooter.tsx +6 -1
  392. package/UI/Components/ModelDetail/CardModelDetail.tsx +0 -12
  393. package/UI/Components/ModelTable/BaseModelTable.tsx +1 -1
  394. package/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.ts +12 -2
  395. package/UI/Components/MoreMenu/MoreMenu.tsx +301 -98
  396. package/UI/Components/MoreMenu/MoreMenuItem.tsx +13 -5
  397. package/UI/Components/StatusPage/ResourceGrid.tsx +314 -0
  398. package/UI/Components/StatusPage/ResourceGroupNavigator.tsx +808 -0
  399. package/UI/Components/StatusPage/ResourceList.tsx +570 -0
  400. package/UI/Styles/Theme.css +18 -0
  401. package/UI/Utils/API/RequestOptions.ts +7 -0
  402. package/UI/Utils/AnalyticsModelAPI/AnalyticsModelAPI.ts +1 -0
  403. package/UI/Utils/DownloadFile.ts +16 -8
  404. package/UI/Utils/ErrorSupportBundle.ts +805 -0
  405. package/UI/Utils/ModelAPI/ModelAPI.ts +20 -8
  406. package/UI/Utils/Project.ts +4 -0
  407. package/UI/Utils/StatusPage.ts +8 -2
  408. package/UI/Utils/TestDataSource.ts +61 -0
  409. package/UI/Utils/UseDashboardGridDnd.ts +917 -0
  410. package/UI/esbuild-config.js +45 -0
  411. package/Utils/Analytics.ts +15 -0
  412. package/Utils/Dashboard/Components/DashboardDataSourceChartComponent.ts +88 -0
  413. package/Utils/Dashboard/Components/DashboardDataSourceGaugeComponent.ts +123 -0
  414. package/Utils/Dashboard/Components/DashboardDataSourceShared.ts +16 -0
  415. package/Utils/Dashboard/Components/DashboardDataSourceTableComponent.ts +72 -0
  416. package/Utils/Dashboard/Components/DashboardDataSourceValueComponent.ts +126 -0
  417. package/Utils/Dashboard/Components/Index.ts +28 -0
  418. package/Utils/Dashboard/DashboardViewConfig.ts +80 -36
  419. package/Utils/Dashboard/GridLayout.ts +523 -0
  420. package/Utils/DataSource/DataSourceQueryText.ts +94 -0
  421. package/Utils/DataSource/DataSourceValueReducer.ts +156 -0
  422. package/Utils/Metrics/MetricResourceAttributeUtil.ts +380 -0
  423. package/Utils/Metrics/RecordingRuleExpression.ts +19 -17
  424. package/Utils/Monitor/MonitorMetricType.ts +44 -2
  425. package/Utils/NetworkDiscovery/ScanTargetUtil.ts +8 -6
  426. package/Utils/StatusPage/GroupHierarchyView.ts +931 -0
  427. package/Utils/StatusPage/GroupNestingLayout.ts +69 -0
  428. package/Utils/StatusPage/GroupTree.ts +157 -66
  429. package/Utils/StatusPage/ResourceExplorer.ts +853 -0
  430. package/Utils/StatusPage/ResourceUptime.ts +37 -2
  431. package/Utils/Telemetry/SavedViewTimeRange.ts +114 -0
  432. package/Utils/Telemetry/TelemetryQueryTimeRange.ts +334 -0
  433. package/build/dist/Models/DatabaseModels/AIRun.js +73 -1
  434. package/build/dist/Models/DatabaseModels/AIRun.js.map +1 -1
  435. package/build/dist/Models/DatabaseModels/AlertFeed.js +32 -0
  436. package/build/dist/Models/DatabaseModels/AlertFeed.js.map +1 -1
  437. package/build/dist/Models/DatabaseModels/Dashboard.js +29 -0
  438. package/build/dist/Models/DatabaseModels/Dashboard.js.map +1 -1
  439. package/build/dist/Models/DatabaseModels/DataSource.js +774 -0
  440. package/build/dist/Models/DatabaseModels/DataSource.js.map +1 -0
  441. package/build/dist/Models/DatabaseModels/Incident.js +2 -0
  442. package/build/dist/Models/DatabaseModels/Incident.js.map +1 -1
  443. package/build/dist/Models/DatabaseModels/IncidentEpisode.js +1 -0
  444. package/build/dist/Models/DatabaseModels/IncidentEpisode.js.map +1 -1
  445. package/build/dist/Models/DatabaseModels/IncidentEpisodePublicNote.js +1 -0
  446. package/build/dist/Models/DatabaseModels/IncidentEpisodePublicNote.js.map +1 -1
  447. package/build/dist/Models/DatabaseModels/IncidentEpisodeStateTimeline.js +1 -0
  448. package/build/dist/Models/DatabaseModels/IncidentEpisodeStateTimeline.js.map +1 -1
  449. package/build/dist/Models/DatabaseModels/IncidentFeed.js +32 -0
  450. package/build/dist/Models/DatabaseModels/IncidentFeed.js.map +1 -1
  451. package/build/dist/Models/DatabaseModels/IncidentPublicNote.js +1 -0
  452. package/build/dist/Models/DatabaseModels/IncidentPublicNote.js.map +1 -1
  453. package/build/dist/Models/DatabaseModels/IncidentStateTimeline.js +1 -0
  454. package/build/dist/Models/DatabaseModels/IncidentStateTimeline.js.map +1 -1
  455. package/build/dist/Models/DatabaseModels/Index.js +2 -0
  456. package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
  457. package/build/dist/Models/DatabaseModels/LogSavedView.js +33 -0
  458. package/build/dist/Models/DatabaseModels/LogSavedView.js.map +1 -1
  459. package/build/dist/Models/DatabaseModels/Project.js +241 -11
  460. package/build/dist/Models/DatabaseModels/Project.js.map +1 -1
  461. package/build/dist/Models/DatabaseModels/ProjectCallSMSConfig.js +14 -4
  462. package/build/dist/Models/DatabaseModels/ProjectCallSMSConfig.js.map +1 -1
  463. package/build/dist/Models/DatabaseModels/ScheduledMaintenance.js +1 -0
  464. package/build/dist/Models/DatabaseModels/ScheduledMaintenance.js.map +1 -1
  465. package/build/dist/Models/DatabaseModels/ScheduledMaintenancePublicNote.js +1 -0
  466. package/build/dist/Models/DatabaseModels/ScheduledMaintenancePublicNote.js.map +1 -1
  467. package/build/dist/Models/DatabaseModels/ScheduledMaintenanceStateTimeline.js +1 -0
  468. package/build/dist/Models/DatabaseModels/ScheduledMaintenanceStateTimeline.js.map +1 -1
  469. package/build/dist/Models/DatabaseModels/ScheduledMaintenanceTemplateOwnerUser.js +4 -4
  470. package/build/dist/Models/DatabaseModels/StatusPage.js +29 -0
  471. package/build/dist/Models/DatabaseModels/StatusPage.js.map +1 -1
  472. package/build/dist/Models/DatabaseModels/StatusPageAnnouncement.js +1 -0
  473. package/build/dist/Models/DatabaseModels/StatusPageAnnouncement.js.map +1 -1
  474. package/build/dist/Models/DatabaseModels/User.js +2 -0
  475. package/build/dist/Models/DatabaseModels/User.js.map +1 -1
  476. package/build/dist/Models/DatabaseModels/UserOnCallLog.js +2 -0
  477. package/build/dist/Models/DatabaseModels/UserOnCallLog.js.map +1 -1
  478. package/build/dist/Models/DatabaseModels/UserOnCallLogTimeline.js +2 -0
  479. package/build/dist/Models/DatabaseModels/UserOnCallLogTimeline.js.map +1 -1
  480. package/build/dist/Models/DatabaseModels/UserSession.js +2 -0
  481. package/build/dist/Models/DatabaseModels/UserSession.js.map +1 -1
  482. package/build/dist/Models/DatabaseModels/UserTotpAuth.js +6 -4
  483. package/build/dist/Models/DatabaseModels/UserTotpAuth.js.map +1 -1
  484. package/build/dist/Models/DatabaseModels/UserWebAuthn.js +5 -3
  485. package/build/dist/Models/DatabaseModels/UserWebAuthn.js.map +1 -1
  486. package/build/dist/Server/API/AIAgentDataAPI.js +28 -46
  487. package/build/dist/Server/API/AIAgentDataAPI.js.map +1 -1
  488. package/build/dist/Server/API/AIInsightAPI.js +34 -4
  489. package/build/dist/Server/API/AIInsightAPI.js.map +1 -1
  490. package/build/dist/Server/API/AIInvestigationAPI.js +134 -11
  491. package/build/dist/Server/API/AIInvestigationAPI.js.map +1 -1
  492. package/build/dist/Server/API/DashboardAPI.js +127 -438
  493. package/build/dist/Server/API/DashboardAPI.js.map +1 -1
  494. package/build/dist/Server/API/DataSourceAPI.js +173 -0
  495. package/build/dist/Server/API/DataSourceAPI.js.map +1 -0
  496. package/build/dist/Server/API/StatusPageAPI.js +40 -12
  497. package/build/dist/Server/API/StatusPageAPI.js.map +1 -1
  498. package/build/dist/Server/API/UserAPI.js +94 -2
  499. package/build/dist/Server/API/UserAPI.js.map +1 -1
  500. package/build/dist/Server/EnvironmentConfig.js +14 -0
  501. package/build/dist/Server/EnvironmentConfig.js.map +1 -1
  502. package/build/dist/Server/Infrastructure/ClickhouseConfig.js +61 -1
  503. package/build/dist/Server/Infrastructure/ClickhouseConfig.js.map +1 -1
  504. package/build/dist/Server/Infrastructure/ClickhouseDatabase.js +1 -1
  505. package/build/dist/Server/Infrastructure/ClickhouseDatabase.js.map +1 -1
  506. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786096660558-AddTimeRangeToLogSavedView.js +22 -0
  507. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786096660558-AddTimeRangeToLogSavedView.js.map +1 -0
  508. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786101798351-MigrationName.js +36 -0
  509. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786101798351-MigrationName.js.map +1 -0
  510. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786105470826-MigrationName.js +18 -0
  511. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786105470826-MigrationName.js.map +1 -0
  512. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786303472848-AddDataSourceTable.js +20 -0
  513. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786303472848-AddDataSourceTable.js.map +1 -0
  514. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786400000000-AddMasterPasswordSalt.js +19 -0
  515. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786400000000-AddMasterPasswordSalt.js.map +1 -0
  516. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786500000000-AddInvestigationCodeFixRecommendation.js +19 -0
  517. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786500000000-AddInvestigationCodeFixRecommendation.js.map +1 -0
  518. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786600000000-AddInvestigationAnalysisTldr.js +19 -0
  519. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786600000000-AddInvestigationAnalysisTldr.js.map +1 -0
  520. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786700000000-DropProjectCallSMSConfigCredentialUniques.js +64 -0
  521. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786700000000-DropProjectCallSMSConfigCredentialUniques.js.map +1 -0
  522. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +16 -0
  523. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  524. package/build/dist/Server/Infrastructure/Queue.js +27 -0
  525. package/build/dist/Server/Infrastructure/Queue.js.map +1 -1
  526. package/build/dist/Server/Infrastructure/QueueWorker.js +13 -0
  527. package/build/dist/Server/Infrastructure/QueueWorker.js.map +1 -1
  528. package/build/dist/Server/Middleware/TelemetryIngest.js +8 -3
  529. package/build/dist/Server/Middleware/TelemetryIngest.js.map +1 -1
  530. package/build/dist/Server/Services/AIInsightService.js +110 -10
  531. package/build/dist/Server/Services/AIInsightService.js.map +1 -1
  532. package/build/dist/Server/Services/AIRunService.js +92 -12
  533. package/build/dist/Server/Services/AIRunService.js.map +1 -1
  534. package/build/dist/Server/Services/AIService.js +88 -21
  535. package/build/dist/Server/Services/AIService.js.map +1 -1
  536. package/build/dist/Server/Services/AlertFeedService.js +3 -0
  537. package/build/dist/Server/Services/AlertFeedService.js.map +1 -1
  538. package/build/dist/Server/Services/AlertService.js +28 -35
  539. package/build/dist/Server/Services/AlertService.js.map +1 -1
  540. package/build/dist/Server/Services/AnalyticsDatabaseService.js +37 -5
  541. package/build/dist/Server/Services/AnalyticsDatabaseService.js.map +1 -1
  542. package/build/dist/Server/Services/DataSourceService.js +159 -0
  543. package/build/dist/Server/Services/DataSourceService.js.map +1 -0
  544. package/build/dist/Server/Services/DatabaseService.js +21 -2
  545. package/build/dist/Server/Services/DatabaseService.js.map +1 -1
  546. package/build/dist/Server/Services/HostService.js +74 -0
  547. package/build/dist/Server/Services/HostService.js.map +1 -1
  548. package/build/dist/Server/Services/IncidentFeedService.js +3 -0
  549. package/build/dist/Server/Services/IncidentFeedService.js.map +1 -1
  550. package/build/dist/Server/Services/IncidentService.js +35 -24
  551. package/build/dist/Server/Services/IncidentService.js.map +1 -1
  552. package/build/dist/Server/Services/Index.js +2 -0
  553. package/build/dist/Server/Services/Index.js.map +1 -1
  554. package/build/dist/Server/Services/LlmLogService.js +22 -1
  555. package/build/dist/Server/Services/LlmLogService.js.map +1 -1
  556. package/build/dist/Server/Services/MonitorService.js +45 -0
  557. package/build/dist/Server/Services/MonitorService.js.map +1 -1
  558. package/build/dist/Server/Services/MonitorStatusService.js +129 -0
  559. package/build/dist/Server/Services/MonitorStatusService.js.map +1 -1
  560. package/build/dist/Server/Services/OpenTelemetryIngestService.js +222 -159
  561. package/build/dist/Server/Services/OpenTelemetryIngestService.js.map +1 -1
  562. package/build/dist/Server/Services/RumSessionPinService.js +7 -15
  563. package/build/dist/Server/Services/RumSessionPinService.js.map +1 -1
  564. package/build/dist/Server/Services/StatusPageSubscriberService.js +10 -0
  565. package/build/dist/Server/Services/StatusPageSubscriberService.js.map +1 -1
  566. package/build/dist/Server/Services/UserService.js +241 -10
  567. package/build/dist/Server/Services/UserService.js.map +1 -1
  568. package/build/dist/Server/Types/Database/Permissions/BasePermission.js +6 -0
  569. package/build/dist/Server/Types/Database/Permissions/BasePermission.js.map +1 -1
  570. package/build/dist/Server/Types/Database/Permissions/DeletePermission.js +1 -0
  571. package/build/dist/Server/Types/Database/Permissions/DeletePermission.js.map +1 -1
  572. package/build/dist/Server/Types/Database/Permissions/ReadPermission.js +2 -0
  573. package/build/dist/Server/Types/Database/Permissions/ReadPermission.js.map +1 -1
  574. package/build/dist/Server/Types/Database/Permissions/TenantPermission.js +68 -12
  575. package/build/dist/Server/Types/Database/Permissions/TenantPermission.js.map +1 -1
  576. package/build/dist/Server/Utils/AI/Chat/ObservabilityAssistant.js +3 -0
  577. package/build/dist/Server/Utils/AI/Chat/ObservabilityAssistant.js.map +1 -1
  578. package/build/dist/Server/Utils/AI/CodeFix/CodeFixAgentCompletion.js +4 -0
  579. package/build/dist/Server/Utils/AI/CodeFix/CodeFixAgentCompletion.js.map +1 -1
  580. package/build/dist/Server/Utils/AI/CodeFix/CodeFixReadiness.js +8 -5
  581. package/build/dist/Server/Utils/AI/CodeFix/CodeFixReadiness.js.map +1 -1
  582. package/build/dist/Server/Utils/AI/CodeFix/FixRunBudget.js +63 -24
  583. package/build/dist/Server/Utils/AI/CodeFix/FixRunBudget.js.map +1 -1
  584. package/build/dist/Server/Utils/AI/Remediation/RemediationExecutionRunner.js +2 -0
  585. package/build/dist/Server/Utils/AI/Remediation/RemediationExecutionRunner.js.map +1 -1
  586. package/build/dist/Server/Utils/AI/Remediation/RemediationPlanRunner.js +2 -0
  587. package/build/dist/Server/Utils/AI/Remediation/RemediationPlanRunner.js.map +1 -1
  588. package/build/dist/Server/Utils/AI/SRE/AIInvestigationEngine.js +222 -34
  589. package/build/dist/Server/Utils/AI/SRE/AIInvestigationEngine.js.map +1 -1
  590. package/build/dist/Server/Utils/AI/SRE/AlertInvestigationRunner.js +22 -19
  591. package/build/dist/Server/Utils/AI/SRE/AlertInvestigationRunner.js.map +1 -1
  592. package/build/dist/Server/Utils/AI/SRE/ConfidenceSignal.js +128 -49
  593. package/build/dist/Server/Utils/AI/SRE/ConfidenceSignal.js.map +1 -1
  594. package/build/dist/Server/Utils/AI/SRE/FixFromIncidentTaskTrigger.js +170 -31
  595. package/build/dist/Server/Utils/AI/SRE/FixFromIncidentTaskTrigger.js.map +1 -1
  596. package/build/dist/Server/Utils/AI/SRE/IncidentInvestigationRunner.js +22 -19
  597. package/build/dist/Server/Utils/AI/SRE/IncidentInvestigationRunner.js.map +1 -1
  598. package/build/dist/Server/Utils/AI/SRE/Insights/Detectors/ExceptionIdentity.js +97 -0
  599. package/build/dist/Server/Utils/AI/SRE/Insights/Detectors/ExceptionIdentity.js.map +1 -0
  600. package/build/dist/Server/Utils/AI/SRE/Insights/Detectors/ExceptionSpikeDetector.js +17 -15
  601. package/build/dist/Server/Utils/AI/SRE/Insights/Detectors/ExceptionSpikeDetector.js.map +1 -1
  602. package/build/dist/Server/Utils/AI/SRE/Insights/Detectors/NewExceptionDetector.js +178 -54
  603. package/build/dist/Server/Utils/AI/SRE/Insights/Detectors/NewExceptionDetector.js.map +1 -1
  604. package/build/dist/Server/Utils/AI/SRE/Insights/InsightStore.js +65 -16
  605. package/build/dist/Server/Utils/AI/SRE/Insights/InsightStore.js.map +1 -1
  606. package/build/dist/Server/Utils/AI/SRE/InstrumentationTaskTrigger.js +33 -9
  607. package/build/dist/Server/Utils/AI/SRE/InstrumentationTaskTrigger.js.map +1 -1
  608. package/build/dist/Server/Utils/AI/SRE/InvestigationGrader.js +9 -5
  609. package/build/dist/Server/Utils/AI/SRE/InvestigationGrader.js.map +1 -1
  610. package/build/dist/Server/Utils/AI/SRE/InvestigationQueue.js +121 -41
  611. package/build/dist/Server/Utils/AI/SRE/InvestigationQueue.js.map +1 -1
  612. package/build/dist/Server/Utils/AI/SRE/InvestigationSubjectLock.js +46 -0
  613. package/build/dist/Server/Utils/AI/SRE/InvestigationSubjectLock.js.map +1 -0
  614. package/build/dist/Server/Utils/AI/SRE/InvestigationTldr.js +303 -0
  615. package/build/dist/Server/Utils/AI/SRE/InvestigationTldr.js.map +1 -0
  616. package/build/dist/Server/Utils/AI/SRE/PostedRootCause.js +61 -14
  617. package/build/dist/Server/Utils/AI/SRE/PostedRootCause.js.map +1 -1
  618. package/build/dist/Server/Utils/AI/SRE/SubjectCodeFixRun.js +79 -1
  619. package/build/dist/Server/Utils/AI/SRE/SubjectCodeFixRun.js.map +1 -1
  620. package/build/dist/Server/Utils/AnalyticsDatabase/ClusterConfig.js +21 -0
  621. package/build/dist/Server/Utils/AnalyticsDatabase/ClusterConfig.js.map +1 -1
  622. package/build/dist/Server/Utils/AnalyticsDatabase/InsertDedupContext.js.map +1 -1
  623. package/build/dist/Server/Utils/Dashboard/PublicDashboardResourceListPolicy.js +1261 -0
  624. package/build/dist/Server/Utils/Dashboard/PublicDashboardResourceListPolicy.js.map +1 -0
  625. package/build/dist/Server/Utils/Dashboard/PublicDashboardViewConfig.js +47 -0
  626. package/build/dist/Server/Utils/Dashboard/PublicDashboardViewConfig.js.map +1 -0
  627. package/build/dist/Server/Utils/DataSource/ConnectorRegistry.js +42 -0
  628. package/build/dist/Server/Utils/DataSource/ConnectorRegistry.js.map +1 -0
  629. package/build/dist/Server/Utils/DataSource/Connectors/ClickHouseConnector.js +187 -0
  630. package/build/dist/Server/Utils/DataSource/Connectors/ClickHouseConnector.js.map +1 -0
  631. package/build/dist/Server/Utils/DataSource/Connectors/ElasticsearchConnector.js +493 -0
  632. package/build/dist/Server/Utils/DataSource/Connectors/ElasticsearchConnector.js.map +1 -0
  633. package/build/dist/Server/Utils/DataSource/Connectors/LokiConnector.js +399 -0
  634. package/build/dist/Server/Utils/DataSource/Connectors/LokiConnector.js.map +1 -0
  635. package/build/dist/Server/Utils/DataSource/Connectors/MySqlConnector.js +195 -0
  636. package/build/dist/Server/Utils/DataSource/Connectors/MySqlConnector.js.map +1 -0
  637. package/build/dist/Server/Utils/DataSource/Connectors/PostgresConnector.js +149 -0
  638. package/build/dist/Server/Utils/DataSource/Connectors/PostgresConnector.js.map +1 -0
  639. package/build/dist/Server/Utils/DataSource/Connectors/PrometheusConnector.js +362 -0
  640. package/build/dist/Server/Utils/DataSource/Connectors/PrometheusConnector.js.map +1 -0
  641. package/build/dist/Server/Utils/DataSource/Connectors/RestApiConnector.js +342 -0
  642. package/build/dist/Server/Utils/DataSource/Connectors/RestApiConnector.js.map +1 -0
  643. package/build/dist/Server/Utils/DataSource/Connectors/SqlServerConnector.js +186 -0
  644. package/build/dist/Server/Utils/DataSource/Connectors/SqlServerConnector.js.map +1 -0
  645. package/build/dist/Server/Utils/DataSource/EgressGuard.js +305 -0
  646. package/build/dist/Server/Utils/DataSource/EgressGuard.js.map +1 -0
  647. package/build/dist/Server/Utils/DataSource/HttpFetch.js +134 -0
  648. package/build/dist/Server/Utils/DataSource/HttpFetch.js.map +1 -0
  649. package/build/dist/Server/Utils/DataSource/SqlQueryGuard.js +331 -0
  650. package/build/dist/Server/Utils/DataSource/SqlQueryGuard.js.map +1 -0
  651. package/build/dist/Server/Utils/DataSource/SqlResultShaper.js +280 -0
  652. package/build/dist/Server/Utils/DataSource/SqlResultShaper.js.map +1 -0
  653. package/build/dist/Server/Utils/DataSource/Types.js +2 -0
  654. package/build/dist/Server/Utils/DataSource/Types.js.map +1 -0
  655. package/build/dist/Server/Utils/Database/PostgresErrorTranslator.js +103 -9
  656. package/build/dist/Server/Utils/Database/PostgresErrorTranslator.js.map +1 -1
  657. package/build/dist/Server/Utils/InProcessMemo.js +113 -0
  658. package/build/dist/Server/Utils/InProcessMemo.js.map +1 -0
  659. package/build/dist/Server/Utils/InstanceHealth/TelemetryIngestion.js +406 -0
  660. package/build/dist/Server/Utils/InstanceHealth/TelemetryIngestion.js.map +1 -0
  661. package/build/dist/Server/Utils/Monitor/Criteria/APIRequestCriteria.js +20 -3
  662. package/build/dist/Server/Utils/Monitor/Criteria/APIRequestCriteria.js.map +1 -1
  663. package/build/dist/Server/Utils/Monitor/Criteria/DomainMonitorCriteria.js +43 -0
  664. package/build/dist/Server/Utils/Monitor/Criteria/DomainMonitorCriteria.js.map +1 -1
  665. package/build/dist/Server/Utils/Monitor/MonitorMetricUtil.js +67 -0
  666. package/build/dist/Server/Utils/Monitor/MonitorMetricUtil.js.map +1 -1
  667. package/build/dist/Server/Utils/Monitor/MonitorResource.js +14 -0
  668. package/build/dist/Server/Utils/Monitor/MonitorResource.js.map +1 -1
  669. package/build/dist/Server/Utils/Monitor/MonitorTemplateUtil.js +1 -0
  670. package/build/dist/Server/Utils/Monitor/MonitorTemplateUtil.js.map +1 -1
  671. package/build/dist/Server/Utils/PasswordHash.js +25 -4
  672. package/build/dist/Server/Utils/PasswordHash.js.map +1 -1
  673. package/build/dist/Server/Utils/Response.js +9 -1
  674. package/build/dist/Server/Utils/Response.js.map +1 -1
  675. package/build/dist/Server/Utils/SSRFProtection.js +192 -0
  676. package/build/dist/Server/Utils/SSRFProtection.js.map +1 -0
  677. package/build/dist/Server/Utils/StartServer.js +7 -0
  678. package/build/dist/Server/Utils/StartServer.js.map +1 -1
  679. package/build/dist/Server/Utils/StatusPageSubscriberWebhook.js +24 -0
  680. package/build/dist/Server/Utils/StatusPageSubscriberWebhook.js.map +1 -1
  681. package/build/dist/Server/Utils/Telemetry/CaptureSpan.js +25 -11
  682. package/build/dist/Server/Utils/Telemetry/CaptureSpan.js.map +1 -1
  683. package/build/dist/Server/Utils/Telemetry/IngestionTimestamp.js +32 -0
  684. package/build/dist/Server/Utils/Telemetry/IngestionTimestamp.js.map +1 -0
  685. package/build/dist/Server/Utils/Telemetry/ResourceHeartbeat.js +92 -5
  686. package/build/dist/Server/Utils/Telemetry/ResourceHeartbeat.js.map +1 -1
  687. package/build/dist/Server/Utils/Telemetry/Telemetry.js +92 -6
  688. package/build/dist/Server/Utils/Telemetry/Telemetry.js.map +1 -1
  689. package/build/dist/Server/Utils/Telemetry.js +93 -6
  690. package/build/dist/Server/Utils/Telemetry.js.map +1 -1
  691. package/build/dist/Server/Utils/VendorAssets.js +121 -0
  692. package/build/dist/Server/Utils/VendorAssets.js.map +1 -0
  693. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js +25 -4
  694. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js.map +1 -1
  695. package/build/dist/Server/Utils/Workspace/Slack/Slack.js +5 -0
  696. package/build/dist/Server/Utils/Workspace/Slack/Slack.js.map +1 -1
  697. package/build/dist/Types/AI/AIRunCodeFixRecommendation.js +18 -0
  698. package/build/dist/Types/AI/AIRunCodeFixRecommendation.js.map +1 -0
  699. package/build/dist/Types/AI/CodeFixTaskContext.js +23 -3
  700. package/build/dist/Types/AI/CodeFixTaskContext.js.map +1 -1
  701. package/build/dist/Types/AI/CodeFixTaskType.js +3 -3
  702. package/build/dist/Types/Analytics/RevenueEvent.js +26 -0
  703. package/build/dist/Types/Analytics/RevenueEvent.js.map +1 -0
  704. package/build/dist/Types/Dashboard/DashboardComponentType.js +27 -0
  705. package/build/dist/Types/Dashboard/DashboardComponentType.js.map +1 -1
  706. package/build/dist/Types/Dashboard/DashboardComponents/DashboardDataSourceChartComponent.js +2 -0
  707. package/build/dist/Types/Dashboard/DashboardComponents/DashboardDataSourceChartComponent.js.map +1 -0
  708. package/build/dist/Types/Dashboard/DashboardComponents/DashboardDataSourceGaugeComponent.js +2 -0
  709. package/build/dist/Types/Dashboard/DashboardComponents/DashboardDataSourceGaugeComponent.js.map +1 -0
  710. package/build/dist/Types/Dashboard/DashboardComponents/DashboardDataSourceTableComponent.js +2 -0
  711. package/build/dist/Types/Dashboard/DashboardComponents/DashboardDataSourceTableComponent.js.map +1 -0
  712. package/build/dist/Types/Dashboard/DashboardComponents/DashboardDataSourceValueComponent.js +16 -0
  713. package/build/dist/Types/Dashboard/DashboardComponents/DashboardDataSourceValueComponent.js.map +1 -0
  714. package/build/dist/Types/DataSource/DataSourceLimits.js +47 -0
  715. package/build/dist/Types/DataSource/DataSourceLimits.js.map +1 -0
  716. package/build/dist/Types/DataSource/DataSourceQueryConfig.js +10 -0
  717. package/build/dist/Types/DataSource/DataSourceQueryConfig.js.map +1 -0
  718. package/build/dist/Types/DataSource/DataSourceTableResult.js +14 -0
  719. package/build/dist/Types/DataSource/DataSourceTableResult.js.map +1 -0
  720. package/build/dist/Types/DataSource/DataSourceType.js +183 -0
  721. package/build/dist/Types/DataSource/DataSourceType.js.map +1 -0
  722. package/build/dist/Types/Date.js +38 -3
  723. package/build/dist/Types/Date.js.map +1 -1
  724. package/build/dist/Types/HashedString.js +4 -3
  725. package/build/dist/Types/HashedString.js.map +1 -1
  726. package/build/dist/Types/Monitor/CriteriaFilter.js +4 -0
  727. package/build/dist/Types/Monitor/CriteriaFilter.js.map +1 -1
  728. package/build/dist/Types/Monitor/DomainMonitor/DomainLookupMethod.js +24 -0
  729. package/build/dist/Types/Monitor/DomainMonitor/DomainLookupMethod.js.map +1 -0
  730. package/build/dist/Types/Monitor/MonitorCriteriaInstance.js +24 -7
  731. package/build/dist/Types/Monitor/MonitorCriteriaInstance.js.map +1 -1
  732. package/build/dist/Types/Monitor/MonitorMetricType.js +7 -0
  733. package/build/dist/Types/Monitor/MonitorMetricType.js.map +1 -1
  734. package/build/dist/Types/Monitor/MonitorStep.js +6 -1
  735. package/build/dist/Types/Monitor/MonitorStep.js.map +1 -1
  736. package/build/dist/Types/Monitor/MonitorStepDomainMonitor.js +15 -0
  737. package/build/dist/Types/Monitor/MonitorStepDomainMonitor.js.map +1 -1
  738. package/build/dist/Types/Monitor/PortMonitor/PortMonitorTimings.js +2 -0
  739. package/build/dist/Types/Monitor/PortMonitor/PortMonitorTimings.js.map +1 -0
  740. package/build/dist/Types/Password.js +56 -0
  741. package/build/dist/Types/Password.js.map +1 -0
  742. package/build/dist/Types/Permission.js +65 -155
  743. package/build/dist/Types/Permission.js.map +1 -1
  744. package/build/dist/Types/UserAuthenticationStatus.js +2 -0
  745. package/build/dist/Types/UserAuthenticationStatus.js.map +1 -0
  746. package/build/dist/UI/Components/BulkUpdate/BulkUpdateForm.js +2 -5
  747. package/build/dist/UI/Components/BulkUpdate/BulkUpdateForm.js.map +1 -1
  748. package/build/dist/UI/Components/ErrorBoundary.js +427 -52
  749. package/build/dist/UI/Components/ErrorBoundary.js.map +1 -1
  750. package/build/dist/UI/Components/Feed/FeedItem.js +2 -2
  751. package/build/dist/UI/Components/Feed/FeedItem.js.map +1 -1
  752. package/build/dist/UI/Components/Icon/Icon.js +10 -4
  753. package/build/dist/UI/Components/Icon/Icon.js.map +1 -1
  754. package/build/dist/UI/Components/Modal/ConfirmModal.js +1 -1
  755. package/build/dist/UI/Components/Modal/ConfirmModal.js.map +1 -1
  756. package/build/dist/UI/Components/Modal/Modal.js +178 -19
  757. package/build/dist/UI/Components/Modal/Modal.js.map +1 -1
  758. package/build/dist/UI/Components/Modal/ModalFooter.js +3 -1
  759. package/build/dist/UI/Components/Modal/ModalFooter.js.map +1 -1
  760. package/build/dist/UI/Components/ModelDetail/CardModelDetail.js +0 -12
  761. package/build/dist/UI/Components/ModelDetail/CardModelDetail.js.map +1 -1
  762. package/build/dist/UI/Components/ModelTable/BaseModelTable.js +1 -1
  763. package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
  764. package/build/dist/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.js +12 -2
  765. package/build/dist/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.js.map +1 -1
  766. package/build/dist/UI/Components/MoreMenu/MoreMenu.js +197 -66
  767. package/build/dist/UI/Components/MoreMenu/MoreMenu.js.map +1 -1
  768. package/build/dist/UI/Components/MoreMenu/MoreMenuItem.js +7 -1
  769. package/build/dist/UI/Components/MoreMenu/MoreMenuItem.js.map +1 -1
  770. package/build/dist/UI/Components/StatusPage/ResourceGrid.js +119 -0
  771. package/build/dist/UI/Components/StatusPage/ResourceGrid.js.map +1 -0
  772. package/build/dist/UI/Components/StatusPage/ResourceGroupNavigator.js +354 -0
  773. package/build/dist/UI/Components/StatusPage/ResourceGroupNavigator.js.map +1 -0
  774. package/build/dist/UI/Components/StatusPage/ResourceList.js +203 -0
  775. package/build/dist/UI/Components/StatusPage/ResourceList.js.map +1 -0
  776. package/build/dist/UI/Utils/AnalyticsModelAPI/AnalyticsModelAPI.js +1 -6
  777. package/build/dist/UI/Utils/AnalyticsModelAPI/AnalyticsModelAPI.js.map +1 -1
  778. package/build/dist/UI/Utils/DownloadFile.js +15 -8
  779. package/build/dist/UI/Utils/DownloadFile.js.map +1 -1
  780. package/build/dist/UI/Utils/ErrorSupportBundle.js +476 -0
  781. package/build/dist/UI/Utils/ErrorSupportBundle.js.map +1 -0
  782. package/build/dist/UI/Utils/ModelAPI/ModelAPI.js +20 -15
  783. package/build/dist/UI/Utils/ModelAPI/ModelAPI.js.map +1 -1
  784. package/build/dist/UI/Utils/Project.js +3 -0
  785. package/build/dist/UI/Utils/Project.js.map +1 -1
  786. package/build/dist/UI/Utils/StatusPage.js +4 -4
  787. package/build/dist/UI/Utils/StatusPage.js.map +1 -1
  788. package/build/dist/UI/Utils/TestDataSource.js +39 -0
  789. package/build/dist/UI/Utils/TestDataSource.js.map +1 -0
  790. package/build/dist/UI/Utils/UseDashboardGridDnd.js +551 -0
  791. package/build/dist/UI/Utils/UseDashboardGridDnd.js.map +1 -0
  792. package/build/dist/Utils/Analytics.js +4 -0
  793. package/build/dist/Utils/Analytics.js.map +1 -1
  794. package/build/dist/Utils/Dashboard/Components/DashboardDataSourceChartComponent.js +79 -0
  795. package/build/dist/Utils/Dashboard/Components/DashboardDataSourceChartComponent.js.map +1 -0
  796. package/build/dist/Utils/Dashboard/Components/DashboardDataSourceGaugeComponent.js +111 -0
  797. package/build/dist/Utils/Dashboard/Components/DashboardDataSourceGaugeComponent.js.map +1 -0
  798. package/build/dist/Utils/Dashboard/Components/DashboardDataSourceShared.js +15 -0
  799. package/build/dist/Utils/Dashboard/Components/DashboardDataSourceShared.js.map +1 -0
  800. package/build/dist/Utils/Dashboard/Components/DashboardDataSourceTableComponent.js +62 -0
  801. package/build/dist/Utils/Dashboard/Components/DashboardDataSourceTableComponent.js.map +1 -0
  802. package/build/dist/Utils/Dashboard/Components/DashboardDataSourceValueComponent.js +112 -0
  803. package/build/dist/Utils/Dashboard/Components/DashboardDataSourceValueComponent.js.map +1 -0
  804. package/build/dist/Utils/Dashboard/Components/Index.js +16 -0
  805. package/build/dist/Utils/Dashboard/Components/Index.js.map +1 -1
  806. package/build/dist/Utils/Dashboard/DashboardViewConfig.js +42 -26
  807. package/build/dist/Utils/Dashboard/DashboardViewConfig.js.map +1 -1
  808. package/build/dist/Utils/Dashboard/GridLayout.js +338 -0
  809. package/build/dist/Utils/Dashboard/GridLayout.js.map +1 -0
  810. package/build/dist/Utils/DataSource/DataSourceQueryText.js +64 -0
  811. package/build/dist/Utils/DataSource/DataSourceQueryText.js.map +1 -0
  812. package/build/dist/Utils/DataSource/DataSourceValueReducer.js +124 -0
  813. package/build/dist/Utils/DataSource/DataSourceValueReducer.js.map +1 -0
  814. package/build/dist/Utils/Metrics/MetricResourceAttributeUtil.js +281 -0
  815. package/build/dist/Utils/Metrics/MetricResourceAttributeUtil.js.map +1 -0
  816. package/build/dist/Utils/Metrics/RecordingRuleExpression.js +19 -17
  817. package/build/dist/Utils/Metrics/RecordingRuleExpression.js.map +1 -1
  818. package/build/dist/Utils/Monitor/MonitorMetricType.js +38 -6
  819. package/build/dist/Utils/Monitor/MonitorMetricType.js.map +1 -1
  820. package/build/dist/Utils/NetworkDiscovery/ScanTargetUtil.js +8 -6
  821. package/build/dist/Utils/NetworkDiscovery/ScanTargetUtil.js.map +1 -1
  822. package/build/dist/Utils/StatusPage/GroupHierarchyView.js +560 -0
  823. package/build/dist/Utils/StatusPage/GroupHierarchyView.js.map +1 -0
  824. package/build/dist/Utils/StatusPage/GroupNestingLayout.js +46 -0
  825. package/build/dist/Utils/StatusPage/GroupNestingLayout.js.map +1 -1
  826. package/build/dist/Utils/StatusPage/GroupTree.js +79 -34
  827. package/build/dist/Utils/StatusPage/GroupTree.js.map +1 -1
  828. package/build/dist/Utils/StatusPage/ResourceExplorer.js +519 -0
  829. package/build/dist/Utils/StatusPage/ResourceExplorer.js.map +1 -0
  830. package/build/dist/Utils/StatusPage/ResourceUptime.js +22 -1
  831. package/build/dist/Utils/StatusPage/ResourceUptime.js.map +1 -1
  832. package/build/dist/Utils/Telemetry/SavedViewTimeRange.js +79 -0
  833. package/build/dist/Utils/Telemetry/SavedViewTimeRange.js.map +1 -0
  834. package/build/dist/Utils/Telemetry/TelemetryQueryTimeRange.js +236 -0
  835. package/build/dist/Utils/Telemetry/TelemetryQueryTimeRange.js.map +1 -0
  836. package/jest.config.json +1 -0
  837. package/package.json +5 -1
  838. package/tsconfig.json +12 -10
@@ -1,8 +1,8 @@
1
1
  import Dashboard from "../../../Models/DatabaseModels/Dashboard";
2
2
  import DashboardAPI from "../../../Server/API/DashboardAPI";
3
- import DashboardService from "../../../Server/Services/DashboardService";
4
3
  import AlertService from "../../../Server/Services/AlertService";
5
4
  import CephResourceService from "../../../Server/Services/CephResourceService";
5
+ import DashboardService from "../../../Server/Services/DashboardService";
6
6
  import DockerHostService from "../../../Server/Services/DockerHostService";
7
7
  import DockerResourceService from "../../../Server/Services/DockerResourceService";
8
8
  import DockerSwarmResourceService from "../../../Server/Services/DockerSwarmResourceService";
@@ -16,20 +16,25 @@ import PodmanHostService from "../../../Server/Services/PodmanHostService";
16
16
  import PodmanResourceService from "../../../Server/Services/PodmanResourceService";
17
17
  import ProxmoxResourceService from "../../../Server/Services/ProxmoxResourceService";
18
18
  import SpanService from "../../../Server/Services/SpanService";
19
+ import PublicDashboardResourceListPolicy, {
20
+ BuildPublicDashboardResourceListPolicyData,
21
+ PublicDashboardResourceListPolicyResult,
22
+ } from "../../../Server/Utils/Dashboard/PublicDashboardResourceListPolicy";
19
23
  import {
20
24
  ExpressRequest,
21
25
  ExpressResponse,
22
26
  NextFunction,
23
27
  } from "../../../Server/Utils/Express";
28
+ import InBetween from "../../../Types/BaseDatabase/InBetween";
24
29
  import Includes from "../../../Types/BaseDatabase/Includes";
25
30
  import SortOrder from "../../../Types/BaseDatabase/SortOrder";
26
31
  import DashboardComponentType from "../../../Types/Dashboard/DashboardComponentType";
27
32
  import DashboardViewConfig from "../../../Types/Dashboard/DashboardViewConfig";
28
- import { LIMIT_PER_PROJECT } from "../../../Types/Database/LimitMax";
33
+ import { DashboardVariableType } from "../../../Types/Dashboard/DashboardVariable";
29
34
  import BadDataException from "../../../Types/Exception/BadDataException";
30
35
  import NotAuthenticatedException from "../../../Types/Exception/NotAuthenticatedException";
31
36
  import NotFoundException from "../../../Types/Exception/NotFoundException";
32
- import { JSONObject } from "../../../Types/JSON";
37
+ import { JSONObject, JSONValue } from "../../../Types/JSON";
33
38
  import ObjectID from "../../../Types/ObjectID";
34
39
  import { mockRouter } from "./Helpers";
35
40
  import {
@@ -40,6 +45,7 @@ import {
40
45
  expect,
41
46
  it,
42
47
  } from "@jest/globals";
48
+ import { FindOperator } from "typeorm";
43
49
 
44
50
  jest.mock("../../../Server/Utils/Express", () => {
45
51
  return {
@@ -70,419 +76,221 @@ jest.mock("../../../Server/Utils/Response", () => {
70
76
  const RESOURCE_LIST_ROUTE: string =
71
77
  "/dashboard/resource-list/:dashboardId/:resourceType";
72
78
 
73
- /*
74
- * Structural view of the model services the registry lists through — just
75
- * enough to spy on findBy and read back the arguments the API handed it.
76
- */
77
79
  type ListService = {
78
80
  findBy: (findBy: never) => Promise<Array<unknown>>;
79
81
  };
80
82
 
81
- /*
82
- * Every public resource type, the widget that unlocks it, the `kind` that
83
- * widget renders, one filter the widget legitimately sends, one the widget
84
- * never sends (and which therefore must be dropped), a column of the fixed
85
- * select (sortable) and a column outside it (never sortable).
86
- */
87
- interface ResourceCase {
83
+ interface BuiltWidget {
84
+ widget: JSONObject;
85
+ componentId: ObjectID;
86
+ }
87
+
88
+ interface BuildWidgetData {
89
+ componentType: DashboardComponentType;
90
+ argumentsObject?: JSONObject | undefined;
91
+ componentId?: ObjectID | undefined;
92
+ storedIdShape?: "object" | "string" | "serialized" | undefined;
93
+ }
94
+
95
+ interface CallRouteData {
96
+ resourceType: string;
97
+ body?: JSONObject | undefined;
98
+ query?: JSONObject | undefined;
99
+ }
100
+
101
+ interface ResourceRouteCase {
88
102
  resourceType: string;
89
103
  componentType: DashboardComponentType;
90
104
  service: ListService;
91
105
  kind: string | null;
92
- allowedQueryKey: string;
93
- forbiddenQueryKey: string;
94
- selectColumn: string;
95
- nonSelectColumn: string;
96
- selectKeys: Array<string>;
97
106
  }
98
107
 
99
- const RESOURCE_CASES: Array<ResourceCase> = [
108
+ const RESOURCE_ROUTE_CASES: Array<ResourceRouteCase> = [
100
109
  {
101
110
  resourceType: "incident",
102
111
  componentType: DashboardComponentType.IncidentList,
103
112
  service: IncidentService,
104
113
  kind: null,
105
- allowedQueryKey: "incidentSeverityId",
106
- forbiddenQueryKey: "description",
107
- selectColumn: "createdAt",
108
- nonSelectColumn: "description",
109
- selectKeys: [
110
- "_id",
111
- "title",
112
- "createdAt",
113
- "currentIncidentState",
114
- "incidentSeverity",
115
- ],
116
114
  },
117
115
  {
118
116
  resourceType: "alert",
119
117
  componentType: DashboardComponentType.AlertList,
120
118
  service: AlertService,
121
119
  kind: null,
122
- allowedQueryKey: "alertSeverityId",
123
- forbiddenQueryKey: "description",
124
- selectColumn: "createdAt",
125
- nonSelectColumn: "description",
126
- selectKeys: [
127
- "_id",
128
- "title",
129
- "createdAt",
130
- "currentAlertState",
131
- "alertSeverity",
132
- ],
133
120
  },
134
121
  {
135
122
  resourceType: "monitor",
136
123
  componentType: DashboardComponentType.MonitorList,
137
124
  service: MonitorService,
138
125
  kind: null,
139
- allowedQueryKey: "monitorType",
140
- forbiddenQueryKey: "monitorSteps",
141
- selectColumn: "name",
142
- nonSelectColumn: "monitorSteps",
143
- selectKeys: ["_id", "name", "monitorType", "currentMonitorStatus"],
144
126
  },
145
127
  {
146
- /*
147
- * The Network Map draws a FLAT set of pins, so the hierarchy columns
148
- * (parentSiteId, materializedPath, depth) are deliberately outside both
149
- * the allowlist and the select — structure an anonymous viewer would be
150
- * able to walk but the map never shows them.
151
- */
152
128
  resourceType: "network-site",
153
129
  componentType: DashboardComponentType.NetworkMap,
154
130
  service: NetworkSiteService,
155
131
  kind: null,
156
- allowedQueryKey: "networkSiteTypeId",
157
- forbiddenQueryKey: "parentSiteId",
158
- selectColumn: "name",
159
- nonSelectColumn: "address",
160
- selectKeys: [
161
- "_id",
162
- "name",
163
- "networkSiteType",
164
- "latitude",
165
- "longitude",
166
- "currentMonitorStatus",
167
- ],
168
132
  },
169
133
  {
170
134
  resourceType: "host",
171
135
  componentType: DashboardComponentType.HostList,
172
136
  service: HostService,
173
137
  kind: null,
174
- allowedQueryKey: "otelCollectorStatus",
175
- forbiddenQueryKey: "createdAt",
176
- selectColumn: "name",
177
- nonSelectColumn: "createdAt",
178
- selectKeys: [
179
- "_id",
180
- "name",
181
- "hostIdentifier",
182
- "otelCollectorStatus",
183
- "osType",
184
- "osVersion",
185
- "cpuCores",
186
- "totalMemoryBytes",
187
- "lastSeenAt",
188
- ],
189
138
  },
190
139
  {
191
140
  resourceType: "kubernetes-resource",
192
141
  componentType: DashboardComponentType.KubernetesPodList,
193
142
  service: KubernetesResourceService,
194
143
  kind: "Pod",
195
- allowedQueryKey: "namespaceKey",
196
- forbiddenQueryKey: "createdAt",
197
- selectColumn: "name",
198
- nonSelectColumn: "createdAt",
199
- selectKeys: [
200
- "_id",
201
- "name",
202
- "namespaceKey",
203
- "kind",
204
- "phase",
205
- "isReady",
206
- "hasMemoryPressure",
207
- "hasDiskPressure",
208
- "hasPidPressure",
209
- "containerCount",
210
- "latestCpuPercent",
211
- "latestMemoryBytes",
212
- "controllerDeploymentName",
213
- "controllerCronJobName",
214
- "resourceCreationTimestamp",
215
- "lastSeenAt",
216
- "kubernetesClusterId",
217
- "kubernetesCluster",
218
- ],
144
+ },
145
+ {
146
+ resourceType: "kubernetes-resource",
147
+ componentType: DashboardComponentType.KubernetesNodeList,
148
+ service: KubernetesResourceService,
149
+ kind: "Node",
150
+ },
151
+ {
152
+ resourceType: "kubernetes-resource",
153
+ componentType: DashboardComponentType.KubernetesNamespaceList,
154
+ service: KubernetesResourceService,
155
+ kind: "Namespace",
156
+ },
157
+ {
158
+ resourceType: "kubernetes-resource",
159
+ componentType: DashboardComponentType.KubernetesDeploymentList,
160
+ service: KubernetesResourceService,
161
+ kind: "Deployment",
162
+ },
163
+ {
164
+ resourceType: "kubernetes-resource",
165
+ componentType: DashboardComponentType.KubernetesStatefulSetList,
166
+ service: KubernetesResourceService,
167
+ kind: "StatefulSet",
168
+ },
169
+ {
170
+ resourceType: "kubernetes-resource",
171
+ componentType: DashboardComponentType.KubernetesDaemonSetList,
172
+ service: KubernetesResourceService,
173
+ kind: "DaemonSet",
174
+ },
175
+ {
176
+ resourceType: "kubernetes-resource",
177
+ componentType: DashboardComponentType.KubernetesJobList,
178
+ service: KubernetesResourceService,
179
+ kind: "Job",
180
+ },
181
+ {
182
+ resourceType: "kubernetes-resource",
183
+ componentType: DashboardComponentType.KubernetesCronJobList,
184
+ service: KubernetesResourceService,
185
+ kind: "CronJob",
219
186
  },
220
187
  {
221
188
  resourceType: "docker-host",
222
189
  componentType: DashboardComponentType.DockerHostList,
223
190
  service: DockerHostService,
224
191
  kind: null,
225
- allowedQueryKey: "otelCollectorStatus",
226
- forbiddenQueryKey: "createdAt",
227
- selectColumn: "name",
228
- nonSelectColumn: "createdAt",
229
- selectKeys: [
230
- "_id",
231
- "name",
232
- "otelCollectorStatus",
233
- "containersRunning",
234
- "containersStopped",
235
- "containersPaused",
236
- "osType",
237
- "osVersion",
238
- ],
239
192
  },
240
193
  {
241
194
  resourceType: "docker-container",
242
195
  componentType: DashboardComponentType.DockerContainerList,
243
196
  service: DockerResourceService,
244
197
  kind: "Container",
245
- allowedQueryKey: "imageName",
246
- forbiddenQueryKey: "createdAt",
247
- selectColumn: "name",
248
- nonSelectColumn: "createdAt",
249
- selectKeys: [
250
- "_id",
251
- "name",
252
- "imageName",
253
- "state",
254
- "latestCpuPercent",
255
- "latestMemoryBytes",
256
- "dockerHostId",
257
- "dockerHost",
258
- ],
259
198
  },
260
199
  {
261
200
  resourceType: "docker-image",
262
201
  componentType: DashboardComponentType.DockerImageList,
263
202
  service: DockerResourceService,
264
203
  kind: "Image",
265
- allowedQueryKey: "dockerHostId",
266
- forbiddenQueryKey: "state",
267
- selectColumn: "name",
268
- nonSelectColumn: "state",
269
- selectKeys: ["_id", "name", "containerId", "dockerHostId", "dockerHost"],
270
204
  },
271
205
  {
272
206
  resourceType: "docker-network",
273
207
  componentType: DashboardComponentType.DockerNetworkList,
274
208
  service: DockerResourceService,
275
209
  kind: "Network",
276
- allowedQueryKey: "dockerHostId",
277
- forbiddenQueryKey: "imageName",
278
- selectColumn: "name",
279
- nonSelectColumn: "imageName",
280
- selectKeys: ["_id", "name", "state", "dockerHostId", "dockerHost"],
281
210
  },
282
211
  {
283
212
  resourceType: "docker-volume",
284
213
  componentType: DashboardComponentType.DockerVolumeList,
285
214
  service: DockerResourceService,
286
215
  kind: "Volume",
287
- allowedQueryKey: "dockerHostId",
288
- forbiddenQueryKey: "imageName",
289
- selectColumn: "name",
290
- nonSelectColumn: "imageName",
291
- selectKeys: ["_id", "name", "state", "dockerHostId", "dockerHost"],
292
216
  },
293
217
  {
294
218
  resourceType: "podman-host",
295
219
  componentType: DashboardComponentType.PodmanHostList,
296
220
  service: PodmanHostService,
297
221
  kind: null,
298
- allowedQueryKey: "otelCollectorStatus",
299
- forbiddenQueryKey: "createdAt",
300
- selectColumn: "name",
301
- nonSelectColumn: "createdAt",
302
- selectKeys: [
303
- "_id",
304
- "name",
305
- "otelCollectorStatus",
306
- "containersRunning",
307
- "containersStopped",
308
- "containersPaused",
309
- "osType",
310
- "osVersion",
311
- ],
312
222
  },
313
223
  {
314
224
  resourceType: "podman-container",
315
225
  componentType: DashboardComponentType.PodmanContainerList,
316
226
  service: PodmanResourceService,
317
227
  kind: "Container",
318
- allowedQueryKey: "imageName",
319
- forbiddenQueryKey: "createdAt",
320
- selectColumn: "name",
321
- nonSelectColumn: "createdAt",
322
- selectKeys: [
323
- "_id",
324
- "name",
325
- "imageName",
326
- "state",
327
- "latestCpuPercent",
328
- "latestMemoryBytes",
329
- "podmanHostId",
330
- "podmanHost",
331
- ],
332
228
  },
333
229
  {
334
230
  resourceType: "podman-image",
335
231
  componentType: DashboardComponentType.PodmanImageList,
336
232
  service: PodmanResourceService,
337
233
  kind: "Image",
338
- allowedQueryKey: "podmanHostId",
339
- forbiddenQueryKey: "state",
340
- selectColumn: "name",
341
- nonSelectColumn: "state",
342
- selectKeys: ["_id", "name", "containerId", "podmanHostId", "podmanHost"],
343
234
  },
344
235
  {
345
236
  resourceType: "podman-network",
346
237
  componentType: DashboardComponentType.PodmanNetworkList,
347
238
  service: PodmanResourceService,
348
239
  kind: "Network",
349
- allowedQueryKey: "podmanHostId",
350
- forbiddenQueryKey: "imageName",
351
- selectColumn: "name",
352
- nonSelectColumn: "imageName",
353
- selectKeys: ["_id", "name", "state", "podmanHostId", "podmanHost"],
354
240
  },
355
241
  {
356
242
  resourceType: "podman-volume",
357
243
  componentType: DashboardComponentType.PodmanVolumeList,
358
244
  service: PodmanResourceService,
359
245
  kind: "Volume",
360
- allowedQueryKey: "podmanHostId",
361
- forbiddenQueryKey: "imageName",
362
- selectColumn: "name",
363
- nonSelectColumn: "imageName",
364
- selectKeys: ["_id", "name", "state", "podmanHostId", "podmanHost"],
365
246
  },
366
247
  {
367
248
  resourceType: "proxmox-resource",
368
249
  componentType: DashboardComponentType.ProxmoxNodeList,
369
250
  service: ProxmoxResourceService,
370
251
  kind: "Node",
371
- allowedQueryKey: "proxmoxClusterId",
372
- forbiddenQueryKey: "createdAt",
373
- selectColumn: "name",
374
- nonSelectColumn: "createdAt",
375
- selectKeys: [
376
- "_id",
377
- "name",
378
- "externalId",
379
- "kind",
380
- "vmid",
381
- "guestType",
382
- "parentNodeName",
383
- "isUp",
384
- "haState",
385
- "latestCpuPercent",
386
- "latestMemoryPercent",
387
- "lastSeenAt",
388
- "proxmoxClusterId",
389
- "proxmoxCluster",
390
- ],
252
+ },
253
+ {
254
+ resourceType: "proxmox-resource",
255
+ componentType: DashboardComponentType.ProxmoxGuestList,
256
+ service: ProxmoxResourceService,
257
+ kind: "Guest",
391
258
  },
392
259
  {
393
260
  resourceType: "ceph-resource",
394
261
  componentType: DashboardComponentType.CephOsdList,
395
262
  service: CephResourceService,
396
263
  kind: "Osd",
397
- allowedQueryKey: "cephClusterId",
398
- forbiddenQueryKey: "createdAt",
399
- selectColumn: "externalId",
400
- nonSelectColumn: "createdAt",
401
- selectKeys: [
402
- "_id",
403
- "name",
404
- "externalId",
405
- "kind",
406
- "hostname",
407
- "deviceClass",
408
- "isUp",
409
- "isIn",
410
- "statBytes",
411
- "statBytesUsed",
412
- "storedBytes",
413
- "maxAvailBytes",
414
- "objects",
415
- "lastSeenAt",
416
- "cephClusterId",
417
- "cephCluster",
418
- ],
264
+ },
265
+ {
266
+ resourceType: "ceph-resource",
267
+ componentType: DashboardComponentType.CephPoolList,
268
+ service: CephResourceService,
269
+ kind: "Pool",
419
270
  },
420
271
  {
421
272
  resourceType: "docker-swarm-resource",
422
273
  componentType: DashboardComponentType.DockerSwarmNodeList,
423
274
  service: DockerSwarmResourceService,
424
275
  kind: "Node",
425
- allowedQueryKey: "role",
426
- forbiddenQueryKey: "createdAt",
427
- selectColumn: "name",
428
- nonSelectColumn: "createdAt",
429
- selectKeys: [
430
- "_id",
431
- "name",
432
- "externalId",
433
- "kind",
434
- "role",
435
- "state",
436
- "serviceMode",
437
- "desiredReplicas",
438
- "runningReplicas",
439
- "image",
440
- "isReady",
441
- "latestCpuPercent",
442
- "latestMemoryPercent",
443
- "lastSeenAt",
444
- "dockerSwarmClusterId",
445
- "dockerSwarmCluster",
446
- ],
276
+ },
277
+ {
278
+ resourceType: "docker-swarm-resource",
279
+ componentType: DashboardComponentType.DockerSwarmServiceList,
280
+ service: DockerSwarmResourceService,
281
+ kind: "Service",
447
282
  },
448
283
  {
449
284
  resourceType: "span",
450
285
  componentType: DashboardComponentType.TraceList,
451
286
  service: SpanService,
452
287
  kind: null,
453
- allowedQueryKey: "statusCode",
454
- forbiddenQueryKey: "traceId",
455
- selectColumn: "startTime",
456
- nonSelectColumn: "attributes",
457
- selectKeys: [
458
- "startTime",
459
- "name",
460
- "statusCode",
461
- "durationUnixNano",
462
- "traceId",
463
- "spanId",
464
- "kind",
465
- "primaryEntityId",
466
- ],
467
288
  },
468
289
  {
469
290
  resourceType: "log",
470
291
  componentType: DashboardComponentType.LogStream,
471
292
  service: LogService,
472
293
  kind: null,
473
- allowedQueryKey: "severityText",
474
- forbiddenQueryKey: "traceId",
475
- selectColumn: "time",
476
- nonSelectColumn: "severityNumber",
477
- selectKeys: [
478
- "time",
479
- "severityText",
480
- "body",
481
- "primaryEntityId",
482
- "traceId",
483
- "spanId",
484
- "attributes",
485
- ],
486
294
  },
487
295
  ];
488
296
 
@@ -516,54 +324,68 @@ describe("DashboardAPI public resource-list", () => {
516
324
  new DashboardAPI();
517
325
  });
518
326
 
519
- type BuildViewConfigFunction = (
520
- componentTypes: Array<string>,
521
- ) => DashboardViewConfig;
327
+ const buildWidget: (data: BuildWidgetData) => BuiltWidget = (
328
+ data: BuildWidgetData,
329
+ ): BuiltWidget => {
330
+ const componentId: ObjectID = data.componentId || ObjectID.generate();
331
+ let storedComponentId: JSONValue = componentId;
332
+
333
+ if (data.storedIdShape === "string") {
334
+ storedComponentId = componentId.toString();
335
+ } else if (data.storedIdShape === "serialized") {
336
+ storedComponentId = componentId.toJSON();
337
+ }
522
338
 
523
- const buildViewConfig: BuildViewConfigFunction = (
524
- componentTypes: Array<string>,
525
- ): DashboardViewConfig => {
526
339
  return {
340
+ componentId,
341
+ widget: {
342
+ _type: "DashboardComponent",
343
+ componentId: storedComponentId,
344
+ componentType: data.componentType,
345
+ topInDashboardUnits: 0,
346
+ leftInDashboardUnits: 0,
347
+ widthInDashboardUnits: 12,
348
+ heightInDashboardUnits: 6,
349
+ minWidthInDashboardUnits: 1,
350
+ minHeightInDashboardUnits: 1,
351
+ arguments: data.argumentsObject || {},
352
+ },
353
+ };
354
+ };
355
+
356
+ const setDashboardWidgets: (
357
+ widgets: Array<JSONObject>,
358
+ variables?: Array<JSONObject>,
359
+ ) => void = (
360
+ widgets: Array<JSONObject>,
361
+ variables?: Array<JSONObject>,
362
+ ): void => {
363
+ dashboard.dashboardViewConfig = {
527
364
  _type: "DashboardViewConfig",
528
365
  heightInDashboardUnits: 24,
529
- components: componentTypes.map(
530
- (componentType: string, index: number): JSONObject => {
531
- return {
532
- _type: "DashboardComponent",
533
- componentId: ObjectID.generate().toString(),
534
- componentType: componentType,
535
- topInDashboardUnits: index,
536
- leftInDashboardUnits: 0,
537
- widthInDashboardUnits: 12,
538
- heightInDashboardUnits: 6,
539
- minWidthInDashboardUnits: 1,
540
- minHeightInDashboardUnits: 1,
541
- arguments: {},
542
- };
543
- },
544
- ),
366
+ components: widgets,
367
+ ...(variables ? { variables } : {}),
545
368
  } as unknown as DashboardViewConfig;
546
369
  };
547
370
 
548
- type SetDashboardWidgetsFunction = (componentTypes: Array<string>) => void;
371
+ const telemetryQuery: (resourceType: string) => JSONObject = (
372
+ resourceType: string,
373
+ ): JSONObject => {
374
+ const start: Date = new Date("2026-08-09T10:00:00.000Z");
375
+ const end: Date = new Date("2026-08-09T11:00:00.000Z");
549
376
 
550
- const setDashboardWidgets: SetDashboardWidgetsFunction = (
551
- componentTypes: Array<string>,
552
- ): void => {
553
- dashboard.dashboardViewConfig = buildViewConfig(componentTypes);
377
+ if (resourceType === "log") {
378
+ return { time: new InBetween<Date>(start, end).toJSON() };
379
+ }
380
+ if (resourceType === "span") {
381
+ return { startTime: new InBetween<Date>(start, end).toJSON() };
382
+ }
383
+ return {};
554
384
  };
555
385
 
556
- type CallRouteFunction = (data: {
557
- resourceType: string;
558
- body?: JSONObject;
559
- query?: JSONObject;
560
- }) => Promise<void>;
561
-
562
- const callRoute: CallRouteFunction = async (data: {
563
- resourceType: string;
564
- body?: JSONObject;
565
- query?: JSONObject;
566
- }): Promise<void> => {
386
+ const callRoute: (data: CallRouteData) => Promise<void> = async (
387
+ data: CallRouteData,
388
+ ): Promise<void> => {
567
389
  const request: ExpressRequest = {
568
390
  params: {
569
391
  dashboardId: dashboardId.toString(),
@@ -582,33 +404,25 @@ describe("DashboardAPI public resource-list", () => {
582
404
  .handlerFunction(request, mockResponse, nextFunction);
583
405
  };
584
406
 
585
- type GetFindByArgsFunction = (service: ListService) => JSONObject;
586
-
587
- const getFindByArgs: GetFindByArgsFunction = (
407
+ const getFindByArgs: (service: ListService) => JSONObject = (
588
408
  service: ListService,
589
409
  ): JSONObject => {
590
410
  const calls: Array<Array<unknown>> = (service.findBy as jest.Mock).mock
591
411
  .calls as Array<Array<unknown>>;
592
412
 
593
413
  expect(calls.length).toBe(1);
594
-
595
414
  return calls[0]![0] as JSONObject;
596
415
  };
597
416
 
598
- type GetThrownErrorFunction = () => unknown;
599
-
600
- const getThrownError: GetThrownErrorFunction = (): unknown => {
417
+ const getThrownError: () => unknown = (): unknown => {
601
418
  const calls: Array<Array<unknown>> = (nextFunction as jest.Mock).mock
602
419
  .calls as Array<Array<unknown>>;
603
420
 
604
421
  expect(calls.length).toBe(1);
605
-
606
422
  return calls[0]![0];
607
423
  };
608
424
 
609
- type ExpectNothingListedFunction = () => void;
610
-
611
- const expectNothingListed: ExpectNothingListedFunction = (): void => {
425
+ const expectNothingListed: () => void = (): void => {
612
426
  for (const service of ALL_SERVICES) {
613
427
  expect(service.findBy).not.toHaveBeenCalled();
614
428
  }
@@ -619,7 +433,6 @@ describe("DashboardAPI public resource-list", () => {
619
433
 
620
434
  dashboardId = ObjectID.generate();
621
435
  projectId = ObjectID.generate();
622
-
623
436
  dashboard = new Dashboard();
624
437
  dashboard.id = dashboardId;
625
438
  dashboard.projectId = projectId;
@@ -644,7 +457,6 @@ describe("DashboardAPI public resource-list", () => {
644
457
  json: jest.fn(),
645
458
  status: jest.fn().mockReturnThis(),
646
459
  } as unknown as ExpressResponse;
647
-
648
460
  nextFunction = jest.fn();
649
461
  });
650
462
 
@@ -652,178 +464,180 @@ describe("DashboardAPI public resource-list", () => {
652
464
  jest.restoreAllMocks();
653
465
  });
654
466
 
655
- describe("widget allowlist (GHSA-qv79-j844-cc7m)", () => {
656
- it("refuses to stream a project's logs from a dashboard that has no log widget", async () => {
657
- // The advisory's proof of concept: a metrics-only public dashboard.
658
- setDashboardWidgets([
659
- DashboardComponentType.Chart,
660
- DashboardComponentType.Text,
661
- ]);
467
+ describe("exact widget authorization (GHSA-qv79-j844-cc7m)", () => {
468
+ it("serves every registered widget only through its own resource policy", async () => {
469
+ for (const routeCase of RESOURCE_ROUTE_CASES) {
470
+ jest.clearAllMocks();
471
+ const { widget, componentId } = buildWidget({
472
+ componentType: routeCase.componentType,
473
+ });
474
+ setDashboardWidgets([widget]);
662
475
 
663
- await callRoute({
664
- resourceType: "log",
665
- body: {
666
- query: {
667
- severityText: "Error",
476
+ await callRoute({
477
+ resourceType: routeCase.resourceType,
478
+ body: {
479
+ componentId: componentId.toString(),
480
+ query: telemetryQuery(routeCase.resourceType),
668
481
  },
669
- },
670
- });
671
-
672
- const error: unknown = getThrownError();
673
-
674
- expect(error).toBeInstanceOf(BadDataException);
675
- expect((error as BadDataException).message).toBe(
676
- "This resource is not part of this dashboard.",
677
- );
678
- expectNothingListed();
679
- });
680
-
681
- it("refuses to list incidents from a dashboard that only shows monitors", async () => {
682
- setDashboardWidgets([DashboardComponentType.MonitorList]);
683
-
684
- await callRoute({ resourceType: "incident" });
685
-
686
- expect(getThrownError()).toBeInstanceOf(BadDataException);
687
- expect(IncidentService.findBy).not.toHaveBeenCalled();
688
- });
689
-
690
- it("refuses every resource type on a dashboard with no widgets at all", async () => {
691
- for (const resourceCase of RESOURCE_CASES) {
692
- jest.clearAllMocks();
693
- setDashboardWidgets([]);
482
+ });
694
483
 
695
- await callRoute({ resourceType: resourceCase.resourceType });
484
+ expect(nextFunction).not.toHaveBeenCalled();
485
+ const findByArgs: JSONObject = getFindByArgs(routeCase.service);
486
+ const query: JSONObject = findByArgs["query"] as JSONObject;
696
487
 
697
- expect(getThrownError()).toBeInstanceOf(BadDataException);
698
- expectNothingListed();
488
+ expect(query["projectId"]).toBe(projectId);
489
+ if (routeCase.kind) {
490
+ expect(query["kind"]).toBe(routeCase.kind);
491
+ }
492
+ const expectedSelect: JSONObject =
493
+ PublicDashboardResourceListPolicy.build({
494
+ widget,
495
+ dashboardViewConfig: dashboard.dashboardViewConfig,
496
+ requestedVariables: [],
497
+ requestedQuery: telemetryQuery(routeCase.resourceType),
498
+ }).select;
499
+ expect(findByArgs["select"]).toEqual(expectedSelect);
500
+ expect(findByArgs["skip"]).toBe(0);
699
501
  }
700
502
  });
701
503
 
702
- it("refuses every resource type when the stored view config is missing or malformed", async () => {
703
- const malformedConfigs: Array<unknown> = [
704
- null,
705
- undefined,
706
- "not-an-object",
707
- 42,
708
- {},
709
- { components: null },
710
- { components: "not-an-array" },
711
- { components: [null, 7, "widget"] },
712
- { components: [{ componentType: 123 }] },
713
- { components: [{ componentType: "" }] },
504
+ it("does not return sibling-only Proxmox or Swarm fields", async () => {
505
+ const cases: Array<{
506
+ resourceType: string;
507
+ componentType: DashboardComponentType;
508
+ service: ListService;
509
+ included: string;
510
+ excluded: string;
511
+ }> = [
512
+ {
513
+ resourceType: "proxmox-resource",
514
+ componentType: DashboardComponentType.ProxmoxGuestList,
515
+ service: ProxmoxResourceService,
516
+ included: "vmid",
517
+ excluded: "latestCpuPercent",
518
+ },
519
+ {
520
+ resourceType: "proxmox-resource",
521
+ componentType: DashboardComponentType.ProxmoxNodeList,
522
+ service: ProxmoxResourceService,
523
+ included: "latestCpuPercent",
524
+ excluded: "vmid",
525
+ },
526
+ {
527
+ resourceType: "docker-swarm-resource",
528
+ componentType: DashboardComponentType.DockerSwarmServiceList,
529
+ service: DockerSwarmResourceService,
530
+ included: "desiredReplicas",
531
+ excluded: "latestCpuPercent",
532
+ },
533
+ {
534
+ resourceType: "docker-swarm-resource",
535
+ componentType: DashboardComponentType.DockerSwarmNodeList,
536
+ service: DockerSwarmResourceService,
537
+ included: "latestCpuPercent",
538
+ excluded: "desiredReplicas",
539
+ },
714
540
  ];
715
541
 
716
- for (const config of malformedConfigs) {
717
- jest.clearAllMocks();
718
- dashboard.dashboardViewConfig = config as DashboardViewConfig;
719
-
720
- await callRoute({ resourceType: "log" });
721
-
722
- expect(getThrownError()).toBeInstanceOf(BadDataException);
723
- expectNothingListed();
724
- }
725
- });
726
-
727
- it("serves each resource type once its own widget is on the dashboard", async () => {
728
- for (const resourceCase of RESOURCE_CASES) {
542
+ for (const testCase of cases) {
729
543
  jest.clearAllMocks();
730
- setDashboardWidgets([resourceCase.componentType]);
544
+ const selectedWidget: BuiltWidget = buildWidget({
545
+ componentType: testCase.componentType,
546
+ });
547
+ setDashboardWidgets([selectedWidget.widget]);
731
548
 
732
- await callRoute({ resourceType: resourceCase.resourceType });
549
+ await callRoute({
550
+ resourceType: testCase.resourceType,
551
+ body: { componentId: selectedWidget.componentId.toString() },
552
+ });
733
553
 
734
- expect(nextFunction).not.toHaveBeenCalled();
735
- expect(resourceCase.service.findBy).toHaveBeenCalledTimes(1);
554
+ const select: JSONObject = getFindByArgs(testCase.service)[
555
+ "select"
556
+ ] as JSONObject;
557
+ expect(select[testCase.included]).toBe(true);
558
+ expect(select[testCase.excluded]).toBeUndefined();
736
559
  }
737
560
  });
738
561
 
739
- it("does not let one widget unlock a sibling resource served by the same model", async () => {
740
- // A Docker volume list must not become a Docker container reader.
741
- setDashboardWidgets([DashboardComponentType.DockerVolumeList]);
562
+ it("fails closed when the dashboard has no matching top-level widget", async () => {
563
+ const monitor: BuiltWidget = buildWidget({
564
+ componentType: DashboardComponentType.MonitorList,
565
+ argumentsObject: {
566
+ nestedImpostor: buildWidget({
567
+ componentType: DashboardComponentType.LogStream,
568
+ }).widget,
569
+ },
570
+ });
571
+ setDashboardWidgets([monitor.widget]);
742
572
 
743
- await callRoute({ resourceType: "docker-container" });
573
+ await callRoute({
574
+ resourceType: "log",
575
+ body: { query: telemetryQuery("log") },
576
+ });
744
577
 
745
578
  expect(getThrownError()).toBeInstanceOf(BadDataException);
746
- expect(DockerResourceService.findBy).not.toHaveBeenCalled();
747
- });
748
-
749
- it("rejects a resource type that is not in the registry at all", async () => {
750
- setDashboardWidgets([DashboardComponentType.LogStream]);
751
-
752
- await callRoute({ resourceType: "user" });
753
-
754
- const error: unknown = getThrownError();
755
-
756
- expect(error).toBeInstanceOf(BadDataException);
757
- expect((error as BadDataException).message).toBe(
758
- "Unsupported dashboard resource type: user",
759
- );
760
579
  expectNothingListed();
761
580
  });
762
- });
763
581
 
764
- describe("authorization", () => {
765
- it("rejects a dashboard that is not public before reading anything", async () => {
766
- dashboard.isPublicDashboard = false;
767
- setDashboardWidgets([DashboardComponentType.LogStream]);
768
-
769
- await callRoute({ resourceType: "log" });
770
-
771
- expect(getThrownError()).toBeInstanceOf(NotAuthenticatedException);
772
- expectNothingListed();
773
- });
774
-
775
- /*
776
- * A missing dashboard never reaches the resource lookup: hasReadAccess
777
- * fails closed first, so the viewer is told they have no access rather
778
- * than whether the id exists.
779
- */
780
- it("rejects a dashboard that cannot be found", async () => {
781
- setDashboardWidgets([DashboardComponentType.LogStream]);
782
- jest.spyOn(DashboardService, "findOneById").mockResolvedValue(null);
582
+ it("auto-binds only when exactly one widget matches the resource", async () => {
583
+ const log: BuiltWidget = buildWidget({
584
+ componentType: DashboardComponentType.LogStream,
585
+ argumentsObject: { severityFilter: "Error" },
586
+ });
587
+ const monitor: BuiltWidget = buildWidget({
588
+ componentType: DashboardComponentType.MonitorList,
589
+ });
590
+ setDashboardWidgets([log.widget, monitor.widget]);
783
591
 
784
- await callRoute({ resourceType: "log" });
592
+ await callRoute({
593
+ resourceType: "log",
594
+ body: { query: telemetryQuery("log") },
595
+ });
785
596
 
786
- expect(getThrownError()).toBeInstanceOf(NotAuthenticatedException);
787
- expectNothingListed();
597
+ expect(nextFunction).not.toHaveBeenCalled();
598
+ expect(
599
+ (getFindByArgs(LogService)["query"] as JSONObject)["severityText"],
600
+ ).toBe("Error");
788
601
  });
789
602
 
790
- it("rejects a dashboard with no project", async () => {
791
- setDashboardWidgets([DashboardComponentType.LogStream]);
792
- delete dashboard.projectId;
603
+ it("requires componentId when several matching widgets have different policies", async () => {
604
+ const first: BuiltWidget = buildWidget({
605
+ componentType: DashboardComponentType.LogStream,
606
+ argumentsObject: { severityFilter: "Error" },
607
+ });
608
+ const second: BuiltWidget = buildWidget({
609
+ componentType: DashboardComponentType.LogStream,
610
+ argumentsObject: { severityFilter: "Warning" },
611
+ });
612
+ setDashboardWidgets([first.widget, second.widget]);
793
613
 
794
- await callRoute({ resourceType: "log" });
614
+ await callRoute({
615
+ resourceType: "log",
616
+ body: { query: telemetryQuery("log") },
617
+ });
795
618
 
796
- expect(getThrownError()).toBeInstanceOf(NotFoundException);
619
+ expect(getThrownError()).toBeInstanceOf(BadDataException);
797
620
  expectNothingListed();
798
621
  });
799
- });
800
622
 
801
- describe("project scoping", () => {
802
- it("pins every resource type to the dashboard's own project", async () => {
803
- for (const resourceCase of RESOURCE_CASES) {
804
- jest.clearAllMocks();
805
- setDashboardWidgets([resourceCase.componentType]);
806
-
807
- await callRoute({ resourceType: resourceCase.resourceType });
808
-
809
- const findByArgs: JSONObject = getFindByArgs(resourceCase.service);
810
- const query: JSONObject = findByArgs["query"] as JSONObject;
811
-
812
- expect(query["projectId"]).toBe(projectId);
813
- }
814
- });
815
-
816
- it("ignores a client-supplied projectId pointing at another tenant", async () => {
817
- const otherProjectId: ObjectID = ObjectID.generate();
818
-
819
- setDashboardWidgets([DashboardComponentType.LogStream]);
623
+ it("uses the exact selected widget when several widgets share a resource", async () => {
624
+ const first: BuiltWidget = buildWidget({
625
+ componentType: DashboardComponentType.LogStream,
626
+ argumentsObject: { severityFilter: "Error" },
627
+ });
628
+ const second: BuiltWidget = buildWidget({
629
+ componentType: DashboardComponentType.LogStream,
630
+ argumentsObject: { severityFilter: "Warning" },
631
+ });
632
+ setDashboardWidgets([first.widget, second.widget]);
820
633
 
821
634
  await callRoute({
822
635
  resourceType: "log",
823
636
  body: {
637
+ componentId: second.componentId.toString(),
824
638
  query: {
825
- projectId: otherProjectId.toString(),
826
- severityText: "Error",
639
+ ...telemetryQuery("log"),
640
+ severityText: "Debug",
827
641
  },
828
642
  },
829
643
  });
@@ -831,483 +645,431 @@ describe("DashboardAPI public resource-list", () => {
831
645
  const query: JSONObject = getFindByArgs(LogService)[
832
646
  "query"
833
647
  ] as JSONObject;
834
-
835
- expect(query["projectId"]).toBe(projectId);
836
- expect(query["projectId"]).not.toBe(otherProjectId.toString());
837
- expect(query["severityText"]).toBe("Error");
838
- });
839
- });
840
-
841
- describe("query allowlist", () => {
842
- it("keeps the widget's own filter and drops everything else", async () => {
843
- for (const resourceCase of RESOURCE_CASES) {
844
- jest.clearAllMocks();
845
- setDashboardWidgets([resourceCase.componentType]);
846
-
847
- await callRoute({
848
- resourceType: resourceCase.resourceType,
849
- body: {
850
- query: {
851
- [resourceCase.allowedQueryKey]: "allowed-value",
852
- [resourceCase.forbiddenQueryKey]: "smuggled-value",
853
- deletedAt: null,
854
- password: "smuggled-value",
855
- },
856
- },
857
- });
858
-
859
- const query: JSONObject = getFindByArgs(resourceCase.service)[
860
- "query"
861
- ] as JSONObject;
862
-
863
- expect(query[resourceCase.allowedQueryKey]).toBe("allowed-value");
864
- expect(Object.keys(query)).not.toContain(
865
- resourceCase.forbiddenQueryKey,
866
- );
867
- expect(Object.keys(query)).not.toContain("deletedAt");
868
- expect(Object.keys(query)).not.toContain("password");
869
- }
648
+ expect(query["severityText"]).toBe("Warning");
870
649
  });
871
650
 
872
- it("preserves deserialized query operators on allowed keys", async () => {
873
- const severityIds: Array<string> = [
874
- ObjectID.generate().toString(),
875
- ObjectID.generate().toString(),
876
- ];
877
-
878
- setDashboardWidgets([DashboardComponentType.IncidentList]);
651
+ it("rejects a componentId belonging to a different resource", async () => {
652
+ const log: BuiltWidget = buildWidget({
653
+ componentType: DashboardComponentType.LogStream,
654
+ });
655
+ const monitor: BuiltWidget = buildWidget({
656
+ componentType: DashboardComponentType.MonitorList,
657
+ });
658
+ setDashboardWidgets([log.widget, monitor.widget]);
879
659
 
880
660
  await callRoute({
881
- resourceType: "incident",
661
+ resourceType: "log",
882
662
  body: {
883
- query: {
884
- incidentSeverityId: new Includes(severityIds).toJSON(),
885
- currentIncidentState: {
886
- isResolvedState: false,
887
- },
888
- },
663
+ componentId: monitor.componentId.toString(),
664
+ query: telemetryQuery("log"),
889
665
  },
890
666
  });
891
667
 
892
- const query: JSONObject = getFindByArgs(IncidentService)[
893
- "query"
894
- ] as JSONObject;
668
+ expect(getThrownError()).toBeInstanceOf(BadDataException);
669
+ expectNothingListed();
670
+ });
895
671
 
896
- expect(query["incidentSeverityId"]).toBeInstanceOf(Includes);
897
- expect((query["incidentSeverityId"] as Includes).values).toEqual(
898
- severityIds,
899
- );
900
- expect(query["currentIncidentState"]).toEqual({
901
- isResolvedState: false,
672
+ it("requires the requested componentId to be a string UUID", async () => {
673
+ const log: BuiltWidget = buildWidget({
674
+ componentType: DashboardComponentType.LogStream,
902
675
  });
903
- });
676
+ setDashboardWidgets([log.widget]);
904
677
 
905
- it("ignores a query that is not an object", async () => {
906
- const badQueries: Array<unknown> = [
907
- "severityText",
908
- ["severityText"],
678
+ const invalidIds: Array<JSONValue> = [
909
679
  42,
910
- true,
680
+ [],
681
+ {},
682
+ "not-a-uuid",
683
+ ObjectID.generate().toJSON(),
911
684
  ];
912
-
913
- for (const badQuery of badQueries) {
685
+ for (const invalidId of invalidIds) {
914
686
  jest.clearAllMocks();
915
- setDashboardWidgets([DashboardComponentType.LogStream]);
916
-
917
687
  await callRoute({
918
688
  resourceType: "log",
919
- body: { query: badQuery as JSONObject },
689
+ body: {
690
+ componentId: invalidId,
691
+ query: telemetryQuery("log"),
692
+ },
920
693
  });
921
694
 
922
- expect(nextFunction).not.toHaveBeenCalled();
923
-
924
- const query: JSONObject = getFindByArgs(LogService)[
925
- "query"
926
- ] as JSONObject;
927
-
928
- expect(Object.keys(query)).toEqual(["projectId"]);
695
+ expect(getThrownError()).toBeInstanceOf(BadDataException);
696
+ expectNothingListed();
929
697
  }
930
698
  });
931
699
 
932
- it("does not carry prototype-polluting keys into the query", async () => {
933
- setDashboardWidgets([DashboardComponentType.LogStream]);
934
-
935
- /*
936
- * JSON.parse (like the Express body parser) makes "__proto__" a real
937
- * own key rather than setting the prototype, which is how a pollution
938
- * payload actually arrives.
939
- */
940
- const pollutedQuery: JSONObject = JSON.parse(
941
- '{"__proto__":{"polluted":true},"constructor":{"polluted":true},"severityText":"Error"}',
942
- ) as JSONObject;
943
-
944
- await callRoute({
945
- resourceType: "log",
946
- body: { query: pollutedQuery },
947
- });
948
-
949
- const query: JSONObject = getFindByArgs(LogService)[
950
- "query"
951
- ] as JSONObject;
952
-
953
- expect(Object.keys(query).sort()).toEqual(["projectId", "severityText"]);
954
- expect(({} as Record<string, unknown>)["polluted"]).toBeUndefined();
955
- });
956
-
957
- it("sends no query at all when the body is empty", async () => {
958
- setDashboardWidgets([DashboardComponentType.MonitorList]);
700
+ it("matches legacy stored ObjectID, string, and serialized ID shapes", async () => {
701
+ const storedIdShapes: Array<"object" | "string" | "serialized"> = [
702
+ "object",
703
+ "string",
704
+ "serialized",
705
+ ];
959
706
 
960
- await callRoute({ resourceType: "monitor" });
707
+ for (const storedIdShape of storedIdShapes) {
708
+ jest.clearAllMocks();
709
+ const log: BuiltWidget = buildWidget({
710
+ componentType: DashboardComponentType.LogStream,
711
+ storedIdShape,
712
+ });
713
+ setDashboardWidgets([log.widget]);
961
714
 
962
- const query: JSONObject = getFindByArgs(MonitorService)[
963
- "query"
964
- ] as JSONObject;
715
+ await callRoute({
716
+ resourceType: "log",
717
+ body: {
718
+ componentId: log.componentId.toString(),
719
+ query: telemetryQuery("log"),
720
+ },
721
+ });
965
722
 
966
- expect(query).toEqual({ projectId: projectId });
723
+ expect(nextFunction).not.toHaveBeenCalled();
724
+ expect(LogService.findBy).toHaveBeenCalledTimes(1);
725
+ }
967
726
  });
968
- });
969
727
 
970
- describe("kind pinning", () => {
971
- it("pins the kind for every resource type whose model packs several kinds", async () => {
972
- for (const resourceCase of RESOURCE_CASES) {
973
- if (!resourceCase.kind) {
974
- continue;
975
- }
728
+ it("rejects malformed view configs and unsupported resource types", async () => {
729
+ const malformedConfigs: Array<unknown> = [
730
+ null,
731
+ "not-an-object",
732
+ {},
733
+ { components: null },
734
+ { components: [null, 7, { componentType: 123 }] },
735
+ ];
976
736
 
737
+ for (const config of malformedConfigs) {
977
738
  jest.clearAllMocks();
978
- setDashboardWidgets([resourceCase.componentType]);
979
-
980
- await callRoute({ resourceType: resourceCase.resourceType });
981
-
982
- const query: JSONObject = getFindByArgs(resourceCase.service)[
983
- "query"
984
- ] as JSONObject;
985
-
986
- expect(query["kind"]).toBe(resourceCase.kind);
739
+ dashboard.dashboardViewConfig = config as DashboardViewConfig;
740
+ await callRoute({ resourceType: "log" });
741
+ expect(getThrownError()).toBeInstanceOf(BadDataException);
742
+ expectNothingListed();
987
743
  }
744
+
745
+ jest.clearAllMocks();
746
+ setDashboardWidgets([]);
747
+ await callRoute({ resourceType: "user" });
748
+ expect(getThrownError()).toBeInstanceOf(BadDataException);
749
+ expectNothingListed();
988
750
  });
751
+ });
989
752
 
990
- it("rejects a kind the dashboard's widgets do not render", async () => {
991
- setDashboardWidgets([DashboardComponentType.DockerVolumeList]);
753
+ describe("server-owned query policy", () => {
754
+ it("rebuilds log filters, sort, limit, skip, and select from stored policy", async () => {
755
+ const log: BuiltWidget = buildWidget({
756
+ componentType: DashboardComponentType.LogStream,
757
+ argumentsObject: {
758
+ severityFilter: "Error",
759
+ bodyContains: "timeout",
760
+ attributeFilterQuery: "@service.name:api",
761
+ maxRows: 13,
762
+ },
763
+ });
764
+ setDashboardWidgets([log.widget]);
992
765
 
993
766
  await callRoute({
994
- resourceType: "docker-volume",
767
+ resourceType: "log",
995
768
  body: {
769
+ componentId: log.componentId.toString(),
996
770
  query: {
997
- kind: "Container",
771
+ ...telemetryQuery("log"),
772
+ severityText: "Debug",
773
+ body: "",
774
+ attributes: {},
775
+ projectId: ObjectID.generate().toString(),
998
776
  },
777
+ sort: { severityText: SortOrder.Ascending },
778
+ select: { severityNumber: true, password: true },
779
+ limit: 9999,
780
+ skip: 9999,
999
781
  },
782
+ query: { limit: "9999", skip: "9999" },
1000
783
  });
1001
784
 
1002
- const error: unknown = getThrownError();
785
+ const findByArgs: JSONObject = getFindByArgs(LogService);
786
+ const query: JSONObject = findByArgs["query"] as JSONObject;
1003
787
 
1004
- expect(error).toBeInstanceOf(BadDataException);
1005
- expect((error as BadDataException).message).toBe(
1006
- "This resource is not part of this dashboard.",
1007
- );
1008
- expect(DockerResourceService.findBy).not.toHaveBeenCalled();
788
+ expect(query["projectId"]).toBe(projectId);
789
+ expect(query["severityText"]).toBe("Error");
790
+ expect(query["body"]).toBe("timeout");
791
+ expect((query["attributes"] as JSONObject)["service.name"]).toBe("api");
792
+ expect(query["time"]).toBeInstanceOf(InBetween);
793
+ expect(findByArgs["sort"]).toEqual({
794
+ time: SortOrder.Descending,
795
+ });
796
+ expect(findByArgs["limit"]).toBe(13);
797
+ expect(findByArgs["skip"]).toBe(0);
798
+ expect(findByArgs["select"]).toEqual({
799
+ time: true,
800
+ severityText: true,
801
+ body: true,
802
+ });
1009
803
  });
1010
804
 
1011
- it("rejects a non-string kind", async () => {
1012
- setDashboardWidgets([DashboardComponentType.CephPoolList]);
805
+ it("does not let omitted or changed request filters widen stored incident policy", async () => {
806
+ const severityId: ObjectID = ObjectID.generate();
807
+ const incident: BuiltWidget = buildWidget({
808
+ componentType: DashboardComponentType.IncidentList,
809
+ argumentsObject: {
810
+ stateFilter: "unresolved",
811
+ severityIds: [severityId.toString()],
812
+ maxRows: 9,
813
+ },
814
+ });
815
+ setDashboardWidgets([incident.widget]);
1013
816
 
1014
817
  await callRoute({
1015
- resourceType: "ceph-resource",
818
+ resourceType: "incident",
1016
819
  body: {
820
+ componentId: incident.componentId.toString(),
1017
821
  query: {
1018
- kind: { $ne: "Pool" },
822
+ currentIncidentState: { isResolvedState: true },
823
+ incidentSeverityId: [],
1019
824
  },
1020
825
  },
1021
826
  });
1022
827
 
1023
- expect(getThrownError()).toBeInstanceOf(BadDataException);
1024
- expect(CephResourceService.findBy).not.toHaveBeenCalled();
1025
- });
828
+ const findByArgs: JSONObject = getFindByArgs(IncidentService);
829
+ const query: JSONObject = findByArgs["query"] as JSONObject;
1026
830
 
1027
- it("lets a widget pick its own kind when the dashboard renders several", async () => {
1028
- setDashboardWidgets([
1029
- DashboardComponentType.KubernetesPodList,
1030
- DashboardComponentType.KubernetesNodeList,
831
+ expect(query["currentIncidentState"]).toEqual({
832
+ isResolvedState: false,
833
+ });
834
+ expect(query["incidentSeverityId"]).toBeInstanceOf(Includes);
835
+ expect((query["incidentSeverityId"] as Includes).values).toEqual([
836
+ severityId.toString(),
1031
837
  ]);
838
+ expect(findByArgs["sort"]).toEqual({
839
+ createdAt: SortOrder.Descending,
840
+ });
841
+ expect(findByArgs["limit"]).toBe(9);
842
+ expect(findByArgs["skip"]).toBe(0);
843
+ });
844
+
845
+ it("takes kind from the selected widget policy, not from the caller", async () => {
846
+ const pod: BuiltWidget = buildWidget({
847
+ componentType: DashboardComponentType.KubernetesPodList,
848
+ });
849
+ setDashboardWidgets([pod.widget]);
1032
850
 
1033
851
  await callRoute({
1034
852
  resourceType: "kubernetes-resource",
1035
853
  body: {
1036
- query: {
1037
- kind: "Node",
1038
- },
854
+ componentId: pod.componentId.toString(),
855
+ query: { kind: "Node" },
1039
856
  },
1040
857
  });
1041
858
 
1042
859
  const query: JSONObject = getFindByArgs(KubernetesResourceService)[
1043
860
  "query"
1044
861
  ] as JSONObject;
1045
-
1046
- expect(query["kind"]).toBe("Node");
1047
- });
1048
-
1049
- it("falls back to every kind the dashboard renders when none is named", async () => {
1050
- setDashboardWidgets([
1051
- DashboardComponentType.KubernetesPodList,
1052
- DashboardComponentType.KubernetesNodeList,
1053
- ]);
1054
-
1055
- await callRoute({ resourceType: "kubernetes-resource" });
1056
-
1057
- const query: JSONObject = getFindByArgs(KubernetesResourceService)[
1058
- "query"
1059
- ] as JSONObject;
1060
-
1061
- expect(query["kind"]).toBeInstanceOf(Includes);
1062
- expect((query["kind"] as Includes).values).toEqual(["Pod", "Node"]);
862
+ expect(query["kind"]).toBe("Pod");
1063
863
  });
1064
864
 
1065
- it("still rejects a kind that no widget on a multi-widget dashboard renders", async () => {
1066
- setDashboardWidgets([
1067
- DashboardComponentType.KubernetesPodList,
1068
- DashboardComponentType.KubernetesNodeList,
1069
- ]);
1070
-
1071
- await callRoute({
1072
- resourceType: "kubernetes-resource",
1073
- body: {
1074
- query: {
1075
- kind: "Namespace",
1076
- },
865
+ it("passes only dynamic time and bounded variable selections into policy", async () => {
866
+ const buildSpy: ReturnType<typeof jest.spyOn> = jest.spyOn(
867
+ PublicDashboardResourceListPolicy,
868
+ "build",
869
+ );
870
+ const log: BuiltWidget = buildWidget({
871
+ componentType: DashboardComponentType.LogStream,
872
+ argumentsObject: {
873
+ attributeFilterQuery: "@service.name:stored-service",
1077
874
  },
1078
875
  });
1079
-
1080
- expect(getThrownError()).toBeInstanceOf(BadDataException);
1081
- expect(KubernetesResourceService.findBy).not.toHaveBeenCalled();
1082
- });
1083
-
1084
- it("does not add a kind filter to models that have no kinds", async () => {
1085
- setDashboardWidgets([DashboardComponentType.LogStream]);
876
+ const variable: JSONObject = {
877
+ id: "service-variable",
878
+ name: "Service",
879
+ type: DashboardVariableType.TelemetryAttribute,
880
+ attributeKey: "service.name",
881
+ defaultValue: "default-service",
882
+ };
883
+ setDashboardWidgets([log.widget], [variable]);
884
+ const requestedVariables: Array<JSONObject> = [
885
+ {
886
+ id: "service-variable",
887
+ selectedValue: "checkout",
888
+ selectedValues: [],
889
+ },
890
+ ];
1086
891
 
1087
892
  await callRoute({
1088
893
  resourceType: "log",
1089
894
  body: {
1090
- query: {
1091
- kind: "Volume",
1092
- },
895
+ componentId: log.componentId.toString(),
896
+ query: telemetryQuery("log"),
897
+ variables: requestedVariables,
1093
898
  },
1094
899
  });
1095
900
 
901
+ expect(buildSpy).toHaveBeenCalledTimes(1);
902
+ const policyInput: BuildPublicDashboardResourceListPolicyData =
903
+ buildSpy.mock.calls[0]![0];
904
+ expect(policyInput.widget).toBe(log.widget);
905
+ expect(policyInput.dashboardViewConfig).toBe(
906
+ dashboard.dashboardViewConfig,
907
+ );
908
+ expect(policyInput.requestedVariables).toEqual(requestedVariables);
909
+ expect((policyInput.requestedQuery as JSONObject)["time"]).toBeInstanceOf(
910
+ InBetween,
911
+ );
912
+
1096
913
  const query: JSONObject = getFindByArgs(LogService)[
1097
914
  "query"
1098
915
  ] as JSONObject;
1099
-
1100
- expect(Object.keys(query)).not.toContain("kind");
1101
- });
1102
- });
1103
-
1104
- describe("fixed select", () => {
1105
- it("serves exactly the columns the widget renders, whatever the client asks for", async () => {
1106
- for (const resourceCase of RESOURCE_CASES) {
1107
- jest.clearAllMocks();
1108
- setDashboardWidgets([resourceCase.componentType]);
1109
-
1110
- await callRoute({
1111
- resourceType: resourceCase.resourceType,
1112
- body: {
1113
- select: {
1114
- [resourceCase.nonSelectColumn]: true,
1115
- password: true,
1116
- },
1117
- },
1118
- });
1119
-
1120
- const select: JSONObject = getFindByArgs(resourceCase.service)[
1121
- "select"
1122
- ] as JSONObject;
1123
-
1124
- expect(Object.keys(select).sort()).toEqual(
1125
- [...resourceCase.selectKeys].sort(),
1126
- );
1127
- expect(select[resourceCase.selectColumn]).toBe(true);
1128
- expect(Object.keys(select)).not.toContain("password");
1129
- }
916
+ expect((query["attributes"] as JSONObject)["service.name"]).toBe(
917
+ "checkout",
918
+ );
1130
919
  });
1131
920
 
1132
- it("never exposes a log column the log stream widget does not render", async () => {
1133
- setDashboardWidgets([DashboardComponentType.LogStream]);
1134
-
1135
- await callRoute({ resourceType: "log" });
1136
-
1137
- const select: JSONObject = getFindByArgs(LogService)[
1138
- "select"
1139
- ] as JSONObject;
1140
-
1141
- expect(select).toEqual({
1142
- time: true,
1143
- severityText: true,
1144
- body: true,
1145
- primaryEntityId: true,
1146
- traceId: true,
1147
- spanId: true,
1148
- attributes: true,
921
+ it("fails closed when a telemetry request omits its time range", async () => {
922
+ const log: BuiltWidget = buildWidget({
923
+ componentType: DashboardComponentType.LogStream,
1149
924
  });
1150
- });
1151
- });
1152
-
1153
- describe("sort allowlist", () => {
1154
- it("keeps a sort on a rendered column and normalizes the order", async () => {
1155
- setDashboardWidgets([DashboardComponentType.LogStream]);
925
+ setDashboardWidgets([log.widget]);
1156
926
 
1157
927
  await callRoute({
1158
928
  resourceType: "log",
1159
- body: {
1160
- sort: {
1161
- time: "DESC",
1162
- },
1163
- },
929
+ body: { componentId: log.componentId.toString(), query: {} },
1164
930
  });
1165
931
 
1166
- expect(getFindByArgs(LogService)["sort"]).toEqual({
1167
- time: SortOrder.Descending,
1168
- });
932
+ expect(getThrownError()).toBeInstanceOf(BadDataException);
933
+ expectNothingListed();
1169
934
  });
1170
935
 
1171
- it("accepts a lower-case sort order", async () => {
1172
- setDashboardWidgets([DashboardComponentType.LogStream]);
936
+ it("rejects a policy result for any resource other than the URL resource", async () => {
937
+ const log: BuiltWidget = buildWidget({
938
+ componentType: DashboardComponentType.LogStream,
939
+ });
940
+ setDashboardWidgets([log.widget]);
941
+ const mismatchedPolicy: PublicDashboardResourceListPolicyResult = {
942
+ resourceType: "monitor",
943
+ query: {},
944
+ select: {},
945
+ sort: {},
946
+ limit: 1,
947
+ };
948
+ jest
949
+ .spyOn(PublicDashboardResourceListPolicy, "build")
950
+ .mockReturnValue(mismatchedPolicy);
1173
951
 
1174
952
  await callRoute({
1175
953
  resourceType: "log",
1176
- body: {
1177
- sort: {
1178
- time: "desc",
1179
- },
1180
- },
954
+ body: { componentId: log.componentId.toString() },
1181
955
  });
1182
956
 
1183
- expect(getFindByArgs(LogService)["sort"]).toEqual({
1184
- time: SortOrder.Descending,
1185
- });
957
+ expect(getThrownError()).toBeInstanceOf(BadDataException);
958
+ expectNothingListed();
1186
959
  });
1187
960
 
1188
- it("falls back to ascending for an unrecognised sort order", async () => {
1189
- setDashboardWidgets([DashboardComponentType.LogStream]);
961
+ it("pins projectId after policy construction", async () => {
962
+ const otherProjectId: ObjectID = ObjectID.generate();
963
+ const log: BuiltWidget = buildWidget({
964
+ componentType: DashboardComponentType.LogStream,
965
+ });
966
+ setDashboardWidgets([log.widget]);
967
+ const policy: PublicDashboardResourceListPolicyResult = {
968
+ resourceType: "log",
969
+ query: { projectId: otherProjectId },
970
+ select: { time: true },
971
+ sort: { time: SortOrder.Descending },
972
+ limit: 7,
973
+ };
974
+ jest
975
+ .spyOn(PublicDashboardResourceListPolicy, "build")
976
+ .mockReturnValue(policy);
1190
977
 
1191
978
  await callRoute({
1192
979
  resourceType: "log",
1193
- body: {
1194
- sort: {
1195
- time: { $gt: 1 },
1196
- },
1197
- },
980
+ body: { componentId: log.componentId.toString() },
1198
981
  });
1199
982
 
1200
- expect(getFindByArgs(LogService)["sort"]).toEqual({
1201
- time: SortOrder.Ascending,
1202
- });
983
+ const query: JSONObject = getFindByArgs(LogService)[
984
+ "query"
985
+ ] as JSONObject;
986
+ expect(query["projectId"]).toBe(projectId);
987
+ expect(query["projectId"]).not.toBe(otherProjectId);
1203
988
  });
989
+ });
990
+
991
+ describe("public incident and alert privacy", () => {
992
+ it("adds anonymous privacy clauses before root incident and alert reads", async () => {
993
+ const privacyCases: Array<{
994
+ resourceType: "incident" | "alert";
995
+ componentType: DashboardComponentType;
996
+ service: ListService;
997
+ }> = [
998
+ {
999
+ resourceType: "incident",
1000
+ componentType: DashboardComponentType.IncidentList,
1001
+ service: IncidentService,
1002
+ },
1003
+ {
1004
+ resourceType: "alert",
1005
+ componentType: DashboardComponentType.AlertList,
1006
+ service: AlertService,
1007
+ },
1008
+ ];
1204
1009
 
1205
- it("drops a sort on a column the viewer cannot see", async () => {
1206
- for (const resourceCase of RESOURCE_CASES) {
1010
+ for (const privacyCase of privacyCases) {
1207
1011
  jest.clearAllMocks();
1208
- setDashboardWidgets([resourceCase.componentType]);
1012
+ const { widget, componentId } = buildWidget({
1013
+ componentType: privacyCase.componentType,
1014
+ });
1015
+ setDashboardWidgets([widget]);
1209
1016
 
1210
1017
  await callRoute({
1211
- resourceType: resourceCase.resourceType,
1212
- body: {
1213
- sort: {
1214
- [resourceCase.nonSelectColumn]: "DESC",
1215
- [resourceCase.selectColumn]: "DESC",
1216
- },
1217
- },
1018
+ resourceType: privacyCase.resourceType,
1019
+ body: { componentId: componentId.toString() },
1218
1020
  });
1219
1021
 
1220
- expect(getFindByArgs(resourceCase.service)["sort"]).toEqual({
1221
- [resourceCase.selectColumn]: SortOrder.Descending,
1222
- });
1022
+ const findByArgs: JSONObject = getFindByArgs(privacyCase.service);
1023
+ const query: JSONObject = findByArgs["query"] as JSONObject;
1024
+ expect(query["isPrivate"]).toBeInstanceOf(FindOperator);
1025
+ expect(query["projectId"]).toBe(projectId);
1026
+ expect(findByArgs["props"]).toEqual({ isRoot: true });
1223
1027
  }
1224
1028
  });
1029
+ });
1225
1030
 
1226
- it("drops a sort on a related column that is only partially selected", async () => {
1227
- setDashboardWidgets([DashboardComponentType.IncidentList]);
1228
-
1229
- await callRoute({
1230
- resourceType: "incident",
1231
- body: {
1232
- sort: {
1233
- currentIncidentState: "DESC",
1234
- },
1235
- },
1031
+ describe("dashboard authorization", () => {
1032
+ it("rejects a non-public or missing dashboard before listing", async () => {
1033
+ const log: BuiltWidget = buildWidget({
1034
+ componentType: DashboardComponentType.LogStream,
1236
1035
  });
1237
-
1238
- expect(getFindByArgs(IncidentService)["sort"]).toEqual({});
1239
- });
1240
-
1241
- it("ignores a sort that is not an object", async () => {
1242
- setDashboardWidgets([DashboardComponentType.LogStream]);
1036
+ setDashboardWidgets([log.widget]);
1037
+ dashboard.isPublicDashboard = false;
1243
1038
 
1244
1039
  await callRoute({
1245
1040
  resourceType: "log",
1246
- body: { sort: ["time"] as unknown as JSONObject },
1041
+ body: {
1042
+ componentId: log.componentId.toString(),
1043
+ query: telemetryQuery("log"),
1044
+ },
1247
1045
  });
1046
+ expect(getThrownError()).toBeInstanceOf(NotAuthenticatedException);
1047
+ expectNothingListed();
1248
1048
 
1249
- expect(getFindByArgs(LogService)["sort"]).toEqual({});
1250
- });
1251
- });
1252
-
1253
- describe("pagination", () => {
1254
- it("defaults to the dashboard resource limit", async () => {
1255
- setDashboardWidgets([DashboardComponentType.LogStream]);
1256
-
1049
+ jest.clearAllMocks();
1050
+ jest.spyOn(DashboardService, "findOneById").mockResolvedValue(null);
1257
1051
  await callRoute({ resourceType: "log" });
1258
-
1259
- const findByArgs: JSONObject = getFindByArgs(LogService);
1260
-
1261
- expect(findByArgs["limit"]).toBe(100);
1262
- expect(findByArgs["skip"]).toBe(0);
1052
+ expect(getThrownError()).toBeInstanceOf(NotAuthenticatedException);
1053
+ expectNothingListed();
1263
1054
  });
1264
1055
 
1265
- it("clamps an oversized limit to the per-project maximum", async () => {
1266
- setDashboardWidgets([DashboardComponentType.LogStream]);
1267
-
1268
- await callRoute({
1269
- resourceType: "log",
1270
- query: { limit: "10000000" },
1056
+ it("rejects a dashboard with no project", async () => {
1057
+ const log: BuiltWidget = buildWidget({
1058
+ componentType: DashboardComponentType.LogStream,
1271
1059
  });
1272
-
1273
- expect(getFindByArgs(LogService)["limit"]).toBe(LIMIT_PER_PROJECT);
1274
- });
1275
-
1276
- it("falls back to the default for a nonsensical limit or skip", async () => {
1277
- const cases: Array<{ limit: string; skip: string }> = [
1278
- { limit: "-5", skip: "-5" },
1279
- { limit: "0", skip: "not-a-number" },
1280
- { limit: "not-a-number", skip: "0" },
1281
- ];
1282
-
1283
- for (const testCase of cases) {
1284
- jest.clearAllMocks();
1285
- setDashboardWidgets([DashboardComponentType.LogStream]);
1286
-
1287
- await callRoute({
1288
- resourceType: "log",
1289
- query: { limit: testCase.limit, skip: testCase.skip },
1290
- });
1291
-
1292
- const findByArgs: JSONObject = getFindByArgs(LogService);
1293
-
1294
- expect(findByArgs["limit"]).toBe(100);
1295
- expect(findByArgs["skip"]).toBe(0);
1296
- }
1297
- });
1298
-
1299
- it("honours a sensible limit and skip", async () => {
1300
- setDashboardWidgets([DashboardComponentType.LogStream]);
1060
+ setDashboardWidgets([log.widget]);
1061
+ delete dashboard.projectId;
1301
1062
 
1302
1063
  await callRoute({
1303
1064
  resourceType: "log",
1304
- query: { limit: "25", skip: "50" },
1065
+ body: {
1066
+ componentId: log.componentId.toString(),
1067
+ query: telemetryQuery("log"),
1068
+ },
1305
1069
  });
1306
1070
 
1307
- const findByArgs: JSONObject = getFindByArgs(LogService);
1308
-
1309
- expect(findByArgs["limit"]).toBe(25);
1310
- expect(findByArgs["skip"]).toBe(50);
1071
+ expect(getThrownError()).toBeInstanceOf(NotFoundException);
1072
+ expectNothingListed();
1311
1073
  });
1312
1074
  });
1313
1075
  });